- Người thực hiện: Lâm Quốc Hưng.
Thân chào các bạn, giải thuật điều khiển PID là một giải thuật điều khiển kinh điển. Theo thống kê thì giải thuật này chiếm khoảng 70% trong các bộ điều khiển sử dụng trong công nghiệp. Chính vì vậy, việc tiếp cận và xây dựng thuật toán điều khiển PID cho vi xử lý là một đề tài rất hay, được nhiều kĩ sư, sinh viên quan tâm. Bài viết này mình xin trình bày giải thuật PID để điều khiển vận tốc động cơ DC trên KIT phát triển của SUNO.
Để thực hiện đề tài này, mình đã sử dụng các công cụ sau:
1. KIT phát triển PIC của SUNO.
2. Module điều khiển động cơ DC SUNO.
3. Mạch nạp PIC SUNO.
4. Động cơ DC 12V - encoder 360 xung /vòng.
5. Trình biên dịch MikroC.
Nội dung của bài viết bao gồm các phần sau:
1. Lí thuyết về thuật toán PID:
2. Xây dựng mạch điều khiển tốc độ động cơ DC:
3. Viết chương trình cho vi điều khiển PIC 18F4431 trên SUNO PIC KIT:
4. Viết chương trình VB xây dựng giao diện điều khiển và giám sát:
5. Kết quả:
Nội dung chi tiết:
1. Lí thuyết về thuật toán PID:
2. Xây dựng mạch điều khiển tốc độ động cơ DC:
Mạch sử dụng vi điều khiển PIC 18F4331, tích hợp module giao tiếp với encoder, thuận lợi cho việc đọc vận tốc của động cơ DC.
Module lái động cơ DC được sử dụng có công suất khoảng 50W, và động cơ sử dụng với điện áp 12V – 1A.
Đoạn chương trình bên dưới có các nhiệm vụ sau:
- Đọc vận tốc động cơ DC, sau thời gian lấy mẫu 200ms ( có thể thay đổi ).
- Hiển thị vận tốc ra LCD16x2.
- Tính toán giá trị PWM để điều khiển động cơ DC từ thuật toán PID.
- Gửi giá trị lên PC, và nhận giá trị vận tốc đặt từ PC.
Chương trình điều khiển:
//----------------------------------------------------------------------------//
// Chuong trinh dieu khien dong co - su dung giai thuat PID so //
// Dieu khien toc do - hien thi LCD 16x2 //
// Nguoi lap trinh: Lam Quoc Hung //
// Cong ty: Sun JSC //
// Version 1.0 - Ngay: 1/6/2009 //
//----------------------------------------------------------------------------//
#define DIR PORTC.F4
#define Umax 50000
// Khai bao bien //
unsigned int Vmotor=0,Vdat=50;
char text[6];
long tam;
unsigned char status_control=0,j=0,i,dutyc=0,value_pwm=0;
unsigned int Kp,Kd,Ki,T;
signed int e0,e1,e2;
signed int u0,u1;
unsigned int heso0,heso1,heso2;
// Chuong trinh con //
void uint2str(unsigned int uint){
unsigned char tam;
text[0]=uint/10000;
uint=uint-text[0]*10000;
text[1]=uint/1000;
uint=uint-text[1]*1000;
text[2]=uint/100;
uint=uint-text[2]*100;
text[3]=uint/10;
text[4]=uint-text[3]*10;
for(i=0;i<=4;i++){
text[i]+=0x30;
}
text[5]='\0';
}
void LCD_Display(void){
Lcd_Config(&PORTD,0,2,1,7,6,5,4);
Lcd_Cmd(LCD_CURSOR_OFF);
LCD_Out(1,2,"SUN JSC PIC KIT");
LCD_Out(2,4,"www.suno.vn");
Delay_ms(1000);
Lcd_Cmd(LCD_CLEAR);
LCD_Out(1,2,"Vdat = ");
LCD_Out(2,2,"Vmotor=");
}
void Display_Vmotor(void){
uint2str(Vmotor);
Lcd_Out(2,10,text);
uint2str(Vdat);
Lcd_Out(1,10,text);
}
unsigned int Read_Enc(void){
unsigned int enc;
i=POSCNTH;
enc=i*255+POSCNTL;
if(enc>=200)
return enc;
}
void Clear_Enc(void){
POSCNTH = 0x00;
POSCNTL = 0x00;
}
void Read_Velo(void){
unsigned long tam;
Vmotor=Read_Enc(); // Doc gia tri Enc
tam=Vmotor;
tam=tam*60/1000;
Vmotor=tam;
Clear_Enc(); // Xoa gia tri Enc
}
void Init_Dual_PWM(void){
// first determine frequency
// 8 mHz clock >> 2.000.000 cycles
// PR of 200 results in ~10 kHz PWM-frequency
// postscaler div 10 results in 1 kHz interrupt's if enabled
PORTC.f1 = 0;
PORTC.f2 = 0;
TRISC.f1 = 0;
TRISC.f2 = 0;
PR2 =200;
CCPR1L= 0;
CCPR2L = 0;
T2CON = 0b01001101; // T2 on , prescaler div 4 , postscaler / 10 to be used at 32 mHz
//T2CON := %01001100; // T2 on , prescaler off , postscaler / 10 to be used at 8 mhz
CCP1CON = 0b00001100; // pwm mode
CCP2CON = 0b00001100; // pwm mode
}
void set_pwm1(unsigned short duty ){ // range 0..200
ccpr1l = duty;
}
void set_pwm2(unsigned short duty ){ // range 0..200
ccpr2l = duty;
}
/// chuong trinh khoi dong ////////
//----------------------------------------------------------------------------//
void Init_PID(void) {
Kp=1;
Ki=1;
Kd=1;
T=1;
heso0=(float)Kp+(float)Kd/(float)T+(float)Ki*(float)T/2; //heso0=Kp+Kd/T+Ki*T/2;
heso1=(float)Ki*(float)T/2-(float)Kp-2*(float)Kd/(float)T; //heso1=-Kp -2*Kd/T+Ki*T/2;
heso2=(float)Kd/(float)T; //heso3=Kd/T;
//chu ki lay mau T=2
u0=0;
u1=0;
e0=0;
e1=0;
e2=0;
}
// Chuong trinh dieu khien vi tich phan ti le //
//----------------------------------------------------------------------------//
void PID_DC(void){
float tam;
char tam1;
e0=Vdat-Vmotor; //tham so k=0-2, tuong ung voi tung vung lo
if (e0>-200 && e0<200){
u0=u1+heso0*e0+heso1*e1+heso2*e2;//u0[k]=u1[k]+heso0*e0[k]+heso1*e1[k]+heso2*e2[k];//calcule signal control
if (u0>Umax){
u0=Umax;
}
if (u0<=0){
u0=0;
}
}
else if (e0>=200){
u0=Umax;
}
else if (e0<=-200){
u0=0;
}
tam=u0;
tam=tam*255/Umax ;
value_pwm=(char)tam;
set_pwm1(255-value_pwm);
u1=u0;
e2=e1;
e1=e0;
Usart_Write(Vmotor);
}
void Initial(void){
ANSEL0=0;
TRISA =0xFF; // PORTA as input
TRISC =0; // PORTC as output
TRISD =0; // PORTD as output
// Cau hinh Encoder
MAXCNTL=0xFF;
MAXCNTH=0xFF;
POSCNTH = 0x00;
POSCNTL = 0x00;
QEICON = 0b10101000;
DFLTCON = 0b00010011;//filter tren chan QEA clock devider 1:16
// PWM
set_pwm1(255);
set_pwm2(255);
DIR=0;
// UART
INTCON.PEIE=1; // cho phep ngat
INTCON.GIE=1;
PIE1.RCIE=1; // cho phep ngat nhan
Usart_Init(9600);
}
// Chuong trinh dieu khien chinh //
void main(void){
Init_Dual_PWM();
Initial();
Init_PID();
LCD_Display();
while(1){
Read_Velo();
PID_DC(); // Dieu khien van toc
Display_Vmotor();// Hien thi van toc ra LCD
Delay_ms(100);
}
}
// chuong trinh phuc vu ngat //
void interrupt(void){
if(PIR1.RCIF==1){ // ngat nhan USART
PIR1.RCIF=0;
Vdat=RCREG;
if(Vdat>=120) {
Vdat=120;
}
}
}
- Do van toc: hiển thị vận tốc đo được, nhận từ vi điều khiển.
- Dat van toc: đặt vần tốc cho động cơ ( giới hạn Vận tốc max khoảng 120rpm).
- Comm Port: chọn cổng Com.
- Connect: cho phép kết nối với cổng Com.
- Exit: thoát khỏi chương trình.
- Send: gửi giá trị vận tốc đặt cho vi điều khiển.
Chương trình VB6:
Option Explicit
Dim command As Byte
Dim status_receive As Byte
Dim StrRcv As String
Dim a As Integer
-----------------------------------------
Private Sub CWNTdat_ValueChanged(Value As Variant, PreviousValue As Variant, ByVal OutOfRange As Boolean)
If CWNTdat.Value >= 120 Then
CWNTdat.Value = 120
End If
If CWNTdat.Value <= 0 Then
CWNTdat.Value = 0
End If
End Sub
---------------------------------------------------
Private Sub Form_Load()
cmd_Send.Enabled = False ' disable send
End Sub
---------------------------------------------------
Private Sub cmd_Connect_Click()
On Error GoTo errlable
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False
If MSComm1.PortOpen = False Then
---------------------------------------------------
' chon cong com
If cmb_Comport.ListIndex >= 0 Then
MSComm1.CommPort = cmb_Comport.ListIndex + 1
Else
MsgBox " Please select Comport.", vbInformation = vbOK, " Attention "
Exit Sub
End If
' MSComm1.CommPort = 1
' chon toc do baudrate
MSComm1.Settings = "9600,n,8,1"
MSComm1.PortOpen = True
MSComm1.InputLen = 0
MSComm1.InputMode = comInputModeText
MSComm1.RThreshold = 1
cmd_Connect.Caption = "Connected"
cmd_Connect.Enabled = False ' disable connect
cmd_Send.Enabled = True ' enable send
cmb_Comport.Enabled = False ' disable comport
MsgBox " Connected. "
End If
errlable:
If Err.Number = 8005 Then ' cong com da duoc mo
MsgBox "COM port are opened", vbInformation = vbOK, " Attention "
End If
If Err.Number = 8002 Then
MsgBox "Select difference COM port ", vbInformation = vbOK, "Attention "
End If
End Sub
---------------------------------------
Private Sub cmd_Exit_Click()
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False
End
End Sub
---------------------------------------
Private Sub mnu_Disconnect_Click() ' dong cong com va cho phep chon lai thong so khac.
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False ' dong cong com.
cmb_Comport.Enabled = True
cmd_Connect.Caption = "Connect"
cmd_Connect.Enabled = True
cmd_Send.Enabled = False ' disable send
End Sub
--------------------------------------
Private Sub mnu_Exit_Click()
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False
End
End Sub
--------------------------------------
Private Sub MSComm1_OnComm()
Dim serialInput As Variant
CWKnob1.Value = Asc(MSComm1.Input)
End Sub
--------------------------------------
Private Sub cmd_Send_Click()
MSComm1.Output = Chr(CWNTdat.Value)
End Sub
5. Kết luận:
Chương trình điều khiển vận tốc với sai số gần như bằng 0 khi hệ thống xác lập. Để cho chất lượng của hệ thống tốt hơn, tìm ra bộ thông số PID thích hợp, chúng ta có thể sử dụng thêm các giải thuật thông minh khác.
Hình – Vận tốc đặt 100 rpm và vận tốc đo về 100 rpm.
- Bản quyền thuộc về: lamquochung.blogspot.com
- Liên hệ: Lâm Quốc Hưng Email: quochung11@gmail.com
- HP: 0906.266.126
Bài viết rất hay và rất thiết thực, các bạn sinh viên đại học có thể chọn đề tài này để làm đồ án cũng rất tốt.
Trả lờiXóa