หลังจากที่ได้แนะนำการสร้างวงจรจำลองมอเตอร์อิเล็กทรอนิกส์เมื่อสองสัปดาห์ที่ผ่านมา ผู้เขียนไม่ได้คิดว่าจะมีอะไรเขียนเพิ่มเติมในเวลาอันสั้น แต่หลังจากที่ได้ทดสอบเบื้องต้นก็พบว่ามีอะไรสนุกๆ ที่น่าจะมาเล่าสู่ให้ผู้สนใจด้านการอิมพลิเมนต์ระบบควบคุมมอเตอร์ โดยเฉพาะผู้ที่ใช้ผลิตภัณฑ์ dsPIC ของไมโครชิพ (คลิกอ่านภาษาอังกฤษสำหรับการอธิบายที่ละเอียดขึ้น)
การทดสอบ eMotor ทำได้ง่ายๆ คือต่อเข้ากับระบบฝังตัวอีกระบบหนึ่ง ในที่นี้เราใช้บอร์ด JX-dsPIC40 จากบริษัทInnovative Experiment Co.,Ltd . ซึ่งมีอุปกรณ์สนับสนุนให้บนบอร์ดแล้วส่วนหนึ่ง แต่ก็ได้บัดกรีเพิ่มไปอีก รูปที่ 1 แสดงการต่อบอร์ดเข้าด้วยกัน
สำหรับการอ่านสัญญาณเอนโคเดอร์และแปลงเป็นค่าตำแหน่งและความเร็วจะใช้วิธีการที่อธิบายในบทความ Measuring Speed and Position with the QEI Module จากบริษัทไมโครชิพ ซึ่งการตั้งค่าและคำนวนจะไม่แตกต่างจากที่อธิบายในบทความมากนัก ความเร็วที่คำนวนได้จะเก็บในตัวแปร Veli และ Velf โดยตัวแปรแรกเก็บค่าที่มีหน่วยเป็นจำนวนนับพัลซ์ของเอนโคเดอร์ (x 4) และตัวแปรที่สองเก็บค่าที่แปลงหน่วยเป็นจำนวนรอบ/วินาที ค่าความเร็วยังถูกปรับเครื่องหมายโดยตรวจสอบบิตUPDN ของรีจิสเตอร์ QEICON โค้ดที่แสดงด้านล่าวนี้แสดงฟังก์ชันการตั้งค่าเริ่มต้น การอ่านตำแหน่ง และคำนวนความเร็ว
// ----------- quadrature encoder functions ------------------------
void InitQEI(void)
{
ADPCFG |= 0x0038; // Configure QEI pins as digital inputs
QEICONbits.QEIM = 0; // Disable QEI Module
QEICONbits.CNTERR = 0; // Clear any count errors
QEICONbits.QEISIDL = 0; // Continue operation during sleep
QEICONbits.SWPAB = 0; // QEA and QEB not swapped
QEICONbits.PCDOUT = 0; // Normal I/O pin operation
QEICONbits.POSRES = 1; // Index pulse resets position counter
DFLTCONbits.CEID = 1; // Count error interrupts disabled
DFLTCONbits.QEOUT = 1; // Digital filters output enabled for QEn pins
DFLTCONbits.QECK = 5; // 1:64 clock divide for digital filter for QEn
//DFLTCONbits.INDOUT = 1; // Digital filter output enabled for Index pin
//DFLTCONbits.INDCK = 5; // 1:64 clock divide for digital filter for Index
POSCNT = 0; // Reset position counter
QEICONbits.QEIM = 6; // X4 mode with position counter reset by Index
return;
}
// ------------------ calculate angular speed ------------------------
void __attribute__((__interrupt__)) _T2Interrupt (void)
{
IFS0bits.T2IF = 0; // Clear timer 2 interrupt flag
POSCNTcopy = (int)POSCNT;
if (POSCNTcopy < 0)
POSCNTcopy = -POSCNTcopy;
AngPos[1] = AngPos[0];
AngPos[0] = POSCNTcopy;
Veli = AngPos[0] - AngPos[1];
if (Veli >= 0)
{
if (Veli >= (HALFMAXSPEED))
Veli = Veli - MAXSPEED;
}
else
{
if (Veli < -(HALFMAXSPEED))
Veli = Veli + MAXSPEED;
}
Veli *= 2;
Velf = (double)Veli;
Velf = MAXRPS*Velf/MAXSPEEDRAW;
if (!QEICONbits.UPDN) { // adjust direction
Veli = -Veli;
Velf = -Velf;
}
}
สำหรับอัลกอริธึม PID ที่เป็นส่วนสำคัญของระบบป้อนกลับนี้ ถูกอิมพลิเมนต์โดยวิธีการที่อธิบายในบทความ Digital PID Controllers ของผู้เขียน โดยอัลกอริธึมถูกใส่ไว้ใน ISR ของไทเมอร์ 1 ตามที่แสดงด้านล่างนี้
void __attribute__((interrupt, auto_psv)) _T1Interrupt(void)
// The PID algorithm runs every 10 msec
{
_T1IF = 0;
if (SysFlag.VelLoop) { // control loop closed
VLOOPLED = ON; // light loop status LED
e2_v = e1_v; // update error variables
e1_v = e_v;
if (SysFlag.Velin == VR) {
CMDVRval = readADC(0); // read from VR
CMDVRval_avg = (CMDVRval+CMDVRval1+CMDVRval2+CMDVRval3) >> 2; //averaging
adft_v = (double)CMDVRval_avg - (double)ADMID;
RefVelf_vr = (double)adft_v*MAXRPS/ADMID;
e_v = RefVelf_vr - Velf; // compute new error
CMDVRval3 = CMDVRval2; // update old values
CMDVRval2 = CMDVRval1;
CMDVRval1 = CMDVRval;
} else {
e_v = RefVelf - Velf; // compute new error
} // end if(SysFlag.Velin == VR)
delta_u_v = K1_v*e_v + K2_v*e1_v + Kd_v*e2_v; // PID algorithm
u_v += delta_u_v; // update control variable
if (u_v>PWMMID) u_v = (double)PWMMID;
if (u_v<-PWMMID) u_v = (double)-PWMMID;
ui_v = (unsigned int)(u_v + PWMMID);
if (ui_v > PWMMID) {
DIR = CW;
PWMval = 2*(ui_v - PWMMID);
}
else {
DIR = CCW;
PWMval = 2*(PWMMID - ui_v);
} // if(ui > PWMMID)
OC1RS = PWMval;
if (SysFlag.ELed) ShowLED(); // show performance LEDs.
} // if(SysFlag.VelLoop)
}
ผลการทดสอบ
ในการทดสอบเบื้องต้นนี้ยังไม่ได้มีการปรับค่าอัตราขยาย PID ให้ได้ผลตอบสนองที่ดีที่สุดแต่อย่างใด เพียงแต่เปรียบเทียบผลตอบสนองระหว่างระบบลูปเปิดกับระบบป้อนกลับ โดยบนบอร์ด eMotor มีสวิทซ์กดที่แทนการรบกวนแรงบิด (เปรียบง่ายๆ ได้กับการใช้มือจับที่เพลามอเตอร์จริงเพื่อให้หยุด) การสื่อสารระหว่างคอมพิวเตอร์พีซีกับระบบฝังตัวกระทำผ่านพอร์ตอนุกรม โดยใช้สายแปลง UART เป็น USB USB-to-serial cableจากบริษัท FTDI และใช้โปรแกรมเทอร์มินอลง่ายๆ เช่น hyperterminal ในการส่งคำสั่งและเก็บข้อมูล
จากการทดลอง (ดูได้จากวีดีโอคลิปด้านล่าง) เมื่อระบบไม่มีการป้อนกลับ ความเร็วรอบจะตกลงอย่างสังเกตได้ แต่เมื่อปิดลูปป้อนกลับ ตัวควบคุมจะทำการชดเชยเพื่อรักษาความเร็วรอบให้คงที่ รูปที่ 3 และ 4 แสดงการเปรียบเทียบระหว่างผลตอบสนองลูปเปิดกับลูปปิด จะเห็นได้ชัดเจนว่าแม้ในช่วงที่ยังไม่มีการรบกวนแรงบิด ผลตอบสนองลูปเปิดให้ค่าความเร็วรอบที่ไม่ตรงกับค่าคำสั่ง (คือมีค่าผิดพลาดในสถานะนิ่ง) และเมื่อกดสวิทซ์การรบกวน ค่าแตกต่างยิ่งมากขึ้น แต่ในกรณีระบบลูปปิด ค่าความเร็วจริงจะแกว่งอยู่ระหว่างค่าคำสั่ง และเมื่อมีการกดสวิทซ์ ความเร็วจะตกลงในช่วงสั้นๆ แต่หลังจากนั้นตัวควบคุมจะชดเชยให้ค่าความเร็วเข้าสู่ค่าคำสั่งเหมือนเดิม
No comments:
Post a Comment