THI CÔNG
1. Phần cứng
Tạo nguồn 5v cấp cho vi điều khiển, nguồn 12v cho động cơ. Cách ly nguồn cho mạch động lực và động cơ.
1.3. Mạch công suất
Cách ly xung PWM được đưa vào mạch động lực thông qua opto 6N137. Đây là loại opto tốc độ cao, đáp ứng tần số PWM cao (có thể lên tới 10 KHz).
Chức năng: đưa tín hiệu điều khiển để đảo chiều động cơ.
Nguyên lý hoạt động của mạch động lực:
- Tín hiệu PWM được đưa vào mạch động lực kết hợp với chiều quay điều khiển sẽ cho phép một trong hai IC IR2184 hoạt động. Tác động đến 2 cặp Mosfet IRF 3205 làm cho động cơ quay thuận hoặc quay nghịch.
- Nếu tín hiệu điều khiển được đưa vào chân SD của IR 2184 ở mức thấp thì động cơ dừng.
2. Phần mềm
2.1.Giao diện Visual Basic 2010
3. Hàm truyền thực và thông số bộ PID của động cơ
Đáp ứng của hàm truyền tìm được:
Áp dụng 2 phương pháp xấp xỉ liên tiếp và Ziegler-Nichols ta có được kết quả như sau:
Bốn bộ điều khiển ở hình trên được tìm bằng phương pháp Ziegler Nichols loại 1 và loại 2.
4. Kết quả thi công
Mạch chạy thực tế sẽ ra kết quả như sau:
Sau đây sẽ là kết quả chạy thực với các bộ PID khác nhau: - Lần 1: Kp = 0.03 và Ki = 14.5
- Lần 2: Kp = 0.022 và Ki = 6.6
- Lần 4: Kp = 0.09, Ki = 1.8, Kd = 0.001
Trong đó, kết quả chạy thực 1 và 3 là tốt nhất. 2 và 4 đáp ứng chưa tốt. Cụ thể thì kết quả chạy thực 1 có sai số điều khiển lớn hơn và độ ổn định thấp hơn kết quả 3, nhưng kết quả 3 thì độ vọt lố lớn hơn nhiều so với kết quả 1.
Sau đây là kết quả mô phỏng theo tiêu chuẩn Nyquist
- Với Kp = 0.03 và Ki = 14.5 thì hệ thống có đáp ứng ổn định vì vòng tròn của tiêu chuẩn Nyquist không bao quanh điểm (-1,0)
- Với Kp = 0.068 và Ki = 0.82 thì có đáp ứng ổn định vì vòng tròn tiêu chuẩn ổn định Nyquist không bao quanh điểm (-1,0)
Kết quả mô phỏng theo tiêu chuẩn quỹ đạo nghiệm số:
- Hệ thống có đáp ứng ổn định với thông số Kp = 0.03 và Ki = 14.5 vì theo tiêu chuẩn quỹ đạo nghiệm số thì ta thấy có 2 cực nằm trên trục thực và đều nằm bên trái trục ảo.
- Hệ thống ổn định khi Kp = 0.068 và Ki = 0.82 vì theo tiêu chuẩn quỹ đạo nghiệm số thì ta thấy có 2 cực nằm trên trục thực và đều nằm bên trái trục ảo.
Nhận xét: Mạch chạy ổn định, đáp ứng khá tốt. Ít sai số, độ vọt lố. Giao diện thiết kế đẹp, đơn giản cho người dùng. Có sai lệch giữa tốc độ đặt và tốc độ đo nhưng không đáng kể.
C. PHỤ LỤC
1. Code vi điều khiển PIC 16F887
#include <16F887.h> #fuses HS
#use delay(clock=4000000)
#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7) #include <math.h>
#include <string.h> #include <stdlib.h> #include <stdio.h> #use fast_io(b)
#define buffer_size 8 //do dai cua buffer nhan du lieu truyen tu PC #define sample_time 20 // thoi gian lay mau ms
#define inv_sample_time 50 // 1/thoi gian lay mau ms
float v_dat,v_do_tam; int16 pulse;
char v_do[4]; char chieu_quay[1]; char chieu_quay_dk[1]; unsigned int8 dem,y,j; char v[4];
char c1=0; short mode,PID,v_update,press,counter = 0; char buffer[buffer_size]; char test_nut_thuan = 0; char test_nut_nghich = 0; char test_nut_dung = 0; char test_char_S = 0; char test_char_P = 0; char test_char_I = 0; char test_char_D = 0; char kp_char[5],ki_char[5],kd_char[5]; char S[] = "S"; char P[] = "P"; char I[] = "I"; char D[] = "D"; char QT[] = "t"; char QN[] = "n"; char STOP[]="9999"; int8 duty_cycle; long value_timer1;
float kp,ki,kd,p_part,i_part,d_part; signed long pre_error, cur_error;
#int_RDA
RDA_isr() //chuong trinh phuc vu ngat RS232
{ //chuong trinh se nhan du lieu luu vao buffer c=getc();
if(c=='#') //ma bat dau {
c1=c; xbuff=0; }
if (c=='!' && c1=='#') //nhan dc gia tri dau va gia tri cuoi {
mode = 1; v_update = 1; }
PID = 1; if (c=='@' && c1=='#') press = 1; if (xbuff >= buffer_size) xbuff=0; else buffer[xbuff++]=c; return 0; }
#int_EXT //ngat RB0 de dem xung encoder void EXT_isr(void)
{
pulse++; //tang bien dem pulse de dem so xung encoder if(input(PIN_B4) == 1) //xac dinh chieu quay thuan, nghich chieu_quay = "t";
chieu_quay = "n"; }
#int_timer1 //ngat timer1 lam bo dinh thoi gian lay mau void timer1_isr(void)
{
v_do_tam = pulse * 15; //thoi gian lay mau la 500us, 1 vong 200 xung //Ts=20ms-->15 //Ts=10ms-->30 //Ts=5ms-->60 //Ts=25ms-->12 //Ts=50ms-->6
pulse = 0; //reset so xung do duoc
set_timer1(value_timer1); //cai dat bo dinh thoi lay mau
dem++; //tang bien dem xac dinh thoi diem gui tin hieu //toc do va chieu quay len PC
counter = 1; //cho phep bo PID hoat dong }
void main() {
//thiet dat cac gia tri ban dau cau I/O, timer1 va timer2 //duty_cycle = 150;
mode = 0; //khoi dong can dieu khien tu giao dien PID = 0; // chua cho phep cap nhat thong so PID v_update = 0; // chua cho phep cap nhat toc do dat pulse = 0; // thiet lap so xung ban dau la 0
counter = 0; // chua cho bo PID hoat dong set_tris_b(0xff); // cho B4 va B0 la input
output_low(PIN_C2); //ket hop voi CCP2 dk ON-OFF output_low(PIN_D1); //SD-
output_low(PIN_D0); //SD+
output_high(PIN_D2); //DIR+: Quay thuan output_low(PIN_D3); //DIR-
value_timer1 = 45535; //dinh thoi chu ky lay mau Ts
set_timer1(value_timer1); //25ms: 40535, 20ms: 45535, 10ms: 55535, 5ms: 60535
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //thiet dat bo chia truoc la 1 //nghia la cu 1 chu ky may tang 1 don vi
/////////////////////////////////////////////////////////////////////////////////// //cho phep ngat canh xuong va cac ngat khac
ext_int_edge(H_TO_L); //ngat canh xuong enable_interrupts(int_EXT); //cho phep ngat ngoai enable_interrupts(INT_TIMER1); //cho phep ngat Timer1 enable_interrupts(INT_RDA); //cho phep ngat nhan du lieu enable_interrupts(GLOBAL); //cho phep ngat toan cuc
//////////////////////////////////////////////////////////////////////////////////// // thiet dat toc do dat va cac he so bo ban dau cua PID
//cac thong so ban dau: kp, ki, kd, p_part, i_part, d_part, duty_cycle, pre_error //v_dat = 500; kp = 0; ki = 0; kd = 0; p_part = 0; i_part = 0; d_part = 0; duty_cycle = 0;
//kp = 10; //ki = 0.1; //kd = 0; pre_error = 0; ////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
//////////////////vong lap vo han xu ly cac lenh can lap di lap lai/////////////// while (1)
{
////////////////////////////////////////////////////////////////////////////////// // Ma cho phep hoat dong (mode = 1)
if(mode == 1) {
if(counter == 1) {
output_low(PIN_D0); //+SD: Mo mach dong luc //////////////////////////////////////////////////////////////////////////////////
cur_error = v_dat - v_do_tam; p_part = kp * cur_error;
i_part += ki * (sample_time/1000) * cur_error;
d_part = kd * (cur_error - pre_error) * inv_sample_time; duty_cycle += p_part + i_part + d_part;
////////////////////////////////////////////////////////////////////////////////// // Khau bao hoa xac dinh gioi han cho ngo ra dieu khien if(duty_cycle >= 255) { duty_cycle = 255; } if(duty_cycle <= 0) { duty_cycle = 0; } ///////////////////////////////////////////////////////////////////////////////////
setup_timer_2(T2_DIV_BY_1,255,1); //PWM period ~ 4KHz set_pwm2_duty(duty_cycle); pre_error = cur_error; counter = 0; } } ///////////////////////////////////////////////////////////////////////////////////
/////////////////////////xu ly du lieu gui tu PC xuong VDK///////////////////////// //tach buffer lay toc do dat va chieu quay dieu khien
if(v_update == 1) {
for(j=0;j<=3;j++) {
v[j] = buffer[j+1]; //tach lay toc do dat tu PC }
v_dat = atol(v); //doi toc do tu chuoi sang so //toc do dat duoc cap nhat
//itoa(v_dat,10,v);
v_update = 0; }
//////////////////////////////////////////////////////////////////////////////////// //kiem tra cac nut dieu khien co dieu khien khong
if(press == 1) {
test_nut_dung=strstr(v,STOP); //nut dung if(strncmp(test_nut_dung,STOP,1)==0) { output_high(PIN_D0); setup_ccp2(CCP_OFF); mode = 0; }
test_nut_thuan=strstr(buffer,QT); //nut quay thuan if(strncmp(test_nut_thuan,QT,1)==0)
{
output_high(PIN_D2); }
test_nut_nghich=strstr(buffer,QN); //nut quay nghich if(strncmp(test_nut_nghich,QN,1)==0) { output_low(PIN_D2); } press = 0; } ////////////////////////////////////////////////////////////////////////////////// //cap nhat thong so PID khi co du lieu PID gui xuong if(PID == 1)
{
test_char_P = strstr(buffer,P); // kiem tra lay du lieu Kp if(strncmp(test_char_P,P,1)==0) { for(y=0;y<=4;y++) { kp_char[y] = buffer[y+2]; } kp = atoe(kp_char);
//printf("%s\n\r",kp_char); //printf("%5.3f\n\r",kp); }
test_char_I = strstr(buffer,I); // kiem tra lay du lieu Ki if(strncmp(test_char_I,I,1)==0) { for(y=0;y<=4;y++) { ki_char[y] = buffer[y+2]; } ki = atoe(ki_char); //printf("%s\n\r",ki_char); //printf("%5.3f\n\r",ki); }
test_char_D = strstr(buffer,D); // kiem tra lay du lieu Kd if(strncmp(test_char_D,D,1)==0)
{
for(y=0;y<=4;y++) {
} kd = atoe(kd_char); //printf("%s\n\r",kd_char); //printf("%5.3f\n\r",kd); } PID = 0; } ////////////////////////////////////////////////////////////////////////////////////////
///////////gui thong so toc va chieu quay len PC sau so lan thuc hien ngat timer1/////// if(dem>=2) //sau so lan cua bien "dem" thi se gui cac
{ //thong so can thiet len PC
itoa(v_do_tam,10,v_do); //Chuyen gia tri toc do do tu so sang chuoi if(v_do_tam < 10 & v_do_tam >=0)
{ printf("%s","000"); printf("%s",v_do); printf("%s",chieu_quay); printf("%s","\n"); }
if(v_do_tam >= 10 & v_do_tam <= 99) { printf("%s","00"); printf("%s",v_do); printf("%s",chieu_quay); printf("%s","\n"); }
if(v_do_tam >= 100 & v_do_tam <= 999) { printf("%s","0"); printf("%s",v_do); printf("%s",chieu_quay); printf("%s","\n"); } if(v_do_tam >= 1000) { printf("%s",v_do); printf("%s",chieu_quay); printf("%s","\n");
dem = 0; }
} }
2. Code Visual Basic 2010
Imports System
Imports System.Threading
Imports System.IO.Ports
Imports System.ComponentModel
Imports Microsoft.Office.Interop
Public Class Giao_dien_dieu_khien
Dim myport As Array
Dim inputData, buffer_toc_do, buffer_chieu_quay As String
Dim mang(10) As VariantType Dim i As Integer
Dim toc_do_trung_binh As Int16 Dim tg As Double
Dim dk_chieu_quay As Char
Dim dk_toc_do_dat As String
Dim j As Double
Delegate Sub SetTextCallback(ByVal [text] As String)
Private Sub Giao_dien_dieu_khien_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles MyBase.Load Button_ket_noi.Enabled = True Button_ngat_ket_noi.Enabled = False Button_quay_nghich.Enabled = False Button_quay_thuan.Enabled = False Button_ve.Enabled = False Button_xoa.Enabled = False Button_dung_dong_co.Enabled = False Button_dat_toc_do.Enabled = False Button_thoat.Enabled = True Button_he_so_kd.Enabled = False Button_he_so_ki.Enabled = False Button_he_so_kp.Enabled = False ComboBox_chon_cong_COM.Enabled = True ComboBox_chon_baund_rate.Enabled = True TextBox_toc_do_dat_tam.Enabled = False TextBox_he_so_kd_tam.Enabled = False TextBox_he_so_ki_tam.Enabled = False TextBox_he_so_kp_tam.Enabled = False Timer_update_toc_do_do.Enabled = False
Timer_ve_do_thi.Enabled = False Chart_tocdodat_tocdodo.Enabled = True RichTextBox_bang_du_lieu.Enabled = False If (Val(TextBox_toc_do_dat_tam.Text) <= 0) Then