จากBlogที่ผมต้องการเขียนขึ้นมาเพื่อบันทึกเรื่องราวในการฝึกงานเป็นบล็อกที่พยายามเขียนบทความไฟฟ้าอิเล็กทรอกนิกส์และคอมพิวเตอร์
ป้ายกำกับ
FIBO
(28)
microcontroller
(16)
CHIPKIT
(6)
robotics
(6)
Camera
(5)
Photo
(5)
arduino
(5)
bluetooth
(5)
communication
(5)
ubuntu
(5)
กล้อง
(5)
ถ่ายรูป
(5)
android
(4)
pid control
(4)
notebook
(2)
Agile
(1)
CI
(1)
Software engineering
(1)
algorithm
(1)
controller
(1)
game
(1)
guitar
(1)
hardware
(1)
programming
(1)
ล๊อตเตอรี่
(1)
สลากกินแบ่งรัฐบาล
(1)
หวย
(1)
22 พฤษภาคม 2555
22 พฤษภาคม 2555 (เพิ่ม Gripperในรถ Bluetooth)
โดยติดไว้ที่ส่วนด้านหน้าของรถสามารถยกขวดน้ำสิ่งของขนาดเล็กทั่วไปได้
โดยต่อบอร์ดIC293 เพิ่มอีกหนึ่งบอร์ด
โดยต่อกับarduinoดังนี้
enable1 : 36 enable2 : 40
motor3 : 38 39
motor4 : 42 43
และแก้โค๊ดโดยเพิ่มตัวแปร และฟังก์ชันดังนี้
//BluetoothCar Project
//author krit
//Date 11/4/2012
int pwm1=9; int pwm2=8;
int m1D1=22; int m1D2=23;
int m2D1=32; int m2D2=33;
int enable1=36; int enable2=40;
int m3D1=38; int m3D2=39;
int m4D1=42; int m4D2=43;
int in;
int total=0;
char state=0;
void countSec();
void go(int speedM);
void back(int speedM);
void tLeft(int speedM);
void tRight(int speedM);
void stopM();
void clip();
void un_clip();
void up();
void down();
void setup()
{
pinMode(m1D1,OUTPUT);
pinMode(m1D2,OUTPUT);
pinMode(m2D1,OUTPUT);
pinMode(m2D2,OUTPUT);
pinMode(m3D1,OUTPUT);
pinMode(m3D2,OUTPUT);
pinMode(m4D1,OUTPUT);
pinMode(m4D2,OUTPUT);
pinMode(enable1,OUTPUT);
pinMode(enable2,OUTPUT);
Serial.begin(9600);
Serial.print("Start\n");
}
void loop()
{
total=0;
state=0;
if(Serial.available()>0){
state=Serial.read();
while(Serial.available()==0 && state!='S'&& state!='C'&& state!='N'&& state!='U'&& state!='D');
if(Serial.available()>0 && state!='S'&& state!='C'&& state!='N'&& state!='U'&& state!='D'){
total=(Serial.read());
//total=(total-66)*10;
}
}
if(state!=0){
switch(state){
case 'C': clip(); break;
case 'N': un_clip(); break;
case 'U': up(); break;
case 'D': down(); break;
case 'G': go(total); break;
case 'B': back(total); break;
case 'L': tLeft(total); break;
case 'R': tRight(total);break;
case 'S': stopM(); break;
default: stopM();
}
}
}
void go(int speedM){
Serial.print("Go!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D1,HIGH);
digitalWrite(m1D2,LOW);
analogWrite(pwm2, speedM);
digitalWrite(m2D1,HIGH);
digitalWrite(m2D2,LOW);
}
void back(int speedM){
Serial.print("Back!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D2,HIGH);
digitalWrite(m1D1,LOW);
analogWrite(pwm2, speedM);
digitalWrite(m2D2,HIGH);
digitalWrite(m2D1,LOW);
}
void tLeft(int speedM){
Serial.print("turnLeft!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D2,HIGH);
digitalWrite(m1D1,LOW);
analogWrite(pwm2, speedM);
digitalWrite(m2D2,LOW);
digitalWrite(m2D1,HIGH);
}
void tRight(int speedM){
Serial.print("turnRight!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D2,LOW);
digitalWrite(m1D1,HIGH);
analogWrite(pwm2, speedM);
digitalWrite(m2D2,HIGH);
digitalWrite(m2D1,LOW);
}
void stopM(){
Serial.print("Stop!\n");
digitalWrite(pwm2, HIGH);
digitalWrite(pwm1, HIGH);
digitalWrite(m1D2,HIGH);
digitalWrite(m1D1,HIGH);
digitalWrite(m2D2,HIGH);
digitalWrite(m2D1,HIGH);
digitalWrite(enable1,HIGH);
digitalWrite(m3D2,LOW);
digitalWrite(m3D1,LOW);
digitalWrite(enable2,HIGH);
digitalWrite(m4D2,LOW);
digitalWrite(m4D1,LOW);
}
void clip(){
digitalWrite(enable2,HIGH);
digitalWrite(m4D2,LOW);
digitalWrite(m4D1,HIGH);
}
void un_clip(){
digitalWrite(enable2,HIGH);
digitalWrite(m4D2,HIGH);
digitalWrite(m4D1,LOW);
}
void up(){
digitalWrite(enable1,HIGH);
digitalWrite(m3D2,LOW);
digitalWrite(m3D1,HIGH);
}
void down(){
digitalWrite(enable1,HIGH);
digitalWrite(m3D2,HIGH);
digitalWrite(m3D1,LOW);
}
โดยต่อบอร์ดIC293 เพิ่มอีกหนึ่งบอร์ด
โดยต่อกับarduinoดังนี้
enable1 : 36 enable2 : 40
motor3 : 38 39
motor4 : 42 43
และแก้โค๊ดโดยเพิ่มตัวแปร และฟังก์ชันดังนี้
//BluetoothCar Project
//author krit
//Date 11/4/2012
int pwm1=9; int pwm2=8;
int m1D1=22; int m1D2=23;
int m2D1=32; int m2D2=33;
int enable1=36; int enable2=40;
int m3D1=38; int m3D2=39;
int m4D1=42; int m4D2=43;
int in;
int total=0;
char state=0;
void countSec();
void go(int speedM);
void back(int speedM);
void tLeft(int speedM);
void tRight(int speedM);
void stopM();
void clip();
void un_clip();
void up();
void down();
void setup()
{
pinMode(m1D1,OUTPUT);
pinMode(m1D2,OUTPUT);
pinMode(m2D1,OUTPUT);
pinMode(m2D2,OUTPUT);
pinMode(m3D1,OUTPUT);
pinMode(m3D2,OUTPUT);
pinMode(m4D1,OUTPUT);
pinMode(m4D2,OUTPUT);
pinMode(enable1,OUTPUT);
pinMode(enable2,OUTPUT);
Serial.begin(9600);
Serial.print("Start\n");
}
void loop()
{
total=0;
state=0;
if(Serial.available()>0){
state=Serial.read();
while(Serial.available()==0 && state!='S'&& state!='C'&& state!='N'&& state!='U'&& state!='D');
if(Serial.available()>0 && state!='S'&& state!='C'&& state!='N'&& state!='U'&& state!='D'){
total=(Serial.read());
//total=(total-66)*10;
}
}
if(state!=0){
switch(state){
case 'C': clip(); break;
case 'N': un_clip(); break;
case 'U': up(); break;
case 'D': down(); break;
case 'G': go(total); break;
case 'B': back(total); break;
case 'L': tLeft(total); break;
case 'R': tRight(total);break;
case 'S': stopM(); break;
default: stopM();
}
}
}
void go(int speedM){
Serial.print("Go!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D1,HIGH);
digitalWrite(m1D2,LOW);
analogWrite(pwm2, speedM);
digitalWrite(m2D1,HIGH);
digitalWrite(m2D2,LOW);
}
void back(int speedM){
Serial.print("Back!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D2,HIGH);
digitalWrite(m1D1,LOW);
analogWrite(pwm2, speedM);
digitalWrite(m2D2,HIGH);
digitalWrite(m2D1,LOW);
}
void tLeft(int speedM){
Serial.print("turnLeft!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D2,HIGH);
digitalWrite(m1D1,LOW);
analogWrite(pwm2, speedM);
digitalWrite(m2D2,LOW);
digitalWrite(m2D1,HIGH);
}
void tRight(int speedM){
Serial.print("turnRight!\t");
Serial.print(speedM);
Serial.print("\n");
analogWrite(pwm1, speedM);
digitalWrite(m1D2,LOW);
digitalWrite(m1D1,HIGH);
analogWrite(pwm2, speedM);
digitalWrite(m2D2,HIGH);
digitalWrite(m2D1,LOW);
}
void stopM(){
Serial.print("Stop!\n");
digitalWrite(pwm2, HIGH);
digitalWrite(pwm1, HIGH);
digitalWrite(m1D2,HIGH);
digitalWrite(m1D1,HIGH);
digitalWrite(m2D2,HIGH);
digitalWrite(m2D1,HIGH);
digitalWrite(enable1,HIGH);
digitalWrite(m3D2,LOW);
digitalWrite(m3D1,LOW);
digitalWrite(enable2,HIGH);
digitalWrite(m4D2,LOW);
digitalWrite(m4D1,LOW);
}
void clip(){
digitalWrite(enable2,HIGH);
digitalWrite(m4D2,LOW);
digitalWrite(m4D1,HIGH);
}
void un_clip(){
digitalWrite(enable2,HIGH);
digitalWrite(m4D2,HIGH);
digitalWrite(m4D1,LOW);
}
void up(){
digitalWrite(enable1,HIGH);
digitalWrite(m3D2,LOW);
digitalWrite(m3D1,HIGH);
}
void down(){
digitalWrite(enable1,HIGH);
digitalWrite(m3D2,HIGH);
digitalWrite(m3D1,LOW);
}
8 พฤษภาคม 2555
2-8 พฤษภาคม 2555 (การนำUNO32ควบคุมมอเตอร์3)
แต่ใน arduno นั้นมี library สำเร็จรูปของ PID อยู่แล้วด้วยโดยสามารถ download ได้ที่ http://arduino.cc/playground/Code/PIDLibrary
โดยเราแต่ปรับค่าตัวแปรบางอย่างภายในก็พอ ส่วนสมการคำสั่ง library จะจัดการคำนวนค่าoutputให้เอง แล้วเราก็จะสามารถนำค่า output ที่ได้ไปควบคุมมอเตอร์ได้ทันทีซึ่งเท่าที่ผู้เขียนเคยใช้ก็ใช้ได้ดีนะ สะดวกกว่าที่เราจะเขียนโค๊ดของสมการขึ้นเองอีก แค่เราอ่านค่า analog input จาก encoder แล้วใส่ใน input แล้วสามารถใช้ค่า output กับมอเตอร์ได้ทันทีโดยฟังก์ชันหลักได้แก่ฃ
PID(double* Input, double* Output, double* Setpoint,double Kp, double Ki, double Kd, int ControllerDirection)
ตามที่เข้าใจเป็นการสร้าง object PID ขึ้นโดย Input คือ พอย์เตอร์ของค่าที่ encoderอ่านได้ Output คือพอย์เตอร์ของค่าที่จะนำไปขับมอเตอร์ Setpoint คือ พอย์เตอร์ของค่าเป้าหมายที่จะให้มอเตอร์หมุน ControllerDirectionคือทิศทางของมอเตอร์ Kp,Ki,Kd คือค่าPID
ตัวอย่าง
PID myPID(&double_Input, &double_Output, &double_Setpoint,double_consKp, double_consKi, double_consKd, DIRECT);
Compute()
คือฟังก์ชันหาค่าPWMที่จะไปหมุนมอเตอร์
ตัวอย่าง
myPID.Compute();
SetOutputLimits(double Min, double Max)
คือฟังก์ชันที่ใช้ในการกำหนดค่า outputไม่ให้เกินกำหนด
ตัวอย่าง
myPID.SetOutputLimits(-max_limit, max_limit);
และฟังก์ชันGetค่าต่างๆภายใน object
double GetKp()
double GetKi()
double GetKd()
int GetMode()
int GetDirection()
โดยเราแต่ปรับค่าตัวแปรบางอย่างภายในก็พอ ส่วนสมการคำสั่ง library จะจัดการคำนวนค่าoutputให้เอง แล้วเราก็จะสามารถนำค่า output ที่ได้ไปควบคุมมอเตอร์ได้ทันทีซึ่งเท่าที่ผู้เขียนเคยใช้ก็ใช้ได้ดีนะ สะดวกกว่าที่เราจะเขียนโค๊ดของสมการขึ้นเองอีก แค่เราอ่านค่า analog input จาก encoder แล้วใส่ใน input แล้วสามารถใช้ค่า output กับมอเตอร์ได้ทันทีโดยฟังก์ชันหลักได้แก่ฃ
PID(double* Input, double* Output, double* Setpoint,double Kp, double Ki, double Kd, int ControllerDirection)
ตามที่เข้าใจเป็นการสร้าง object PID ขึ้นโดย Input คือ พอย์เตอร์ของค่าที่ encoderอ่านได้ Output คือพอย์เตอร์ของค่าที่จะนำไปขับมอเตอร์ Setpoint คือ พอย์เตอร์ของค่าเป้าหมายที่จะให้มอเตอร์หมุน ControllerDirectionคือทิศทางของมอเตอร์ Kp,Ki,Kd คือค่าPID
ตัวอย่าง
PID myPID(&double_Input, &double_Output, &double_Setpoint,double_consKp, double_consKi, double_consKd, DIRECT);
Compute()
คือฟังก์ชันหาค่าPWMที่จะไปหมุนมอเตอร์
ตัวอย่าง
myPID.Compute();
SetOutputLimits(double Min, double Max)
คือฟังก์ชันที่ใช้ในการกำหนดค่า outputไม่ให้เกินกำหนด
ตัวอย่าง
myPID.SetOutputLimits(-max_limit, max_limit);
และฟังก์ชันGetค่าต่างๆภายใน object
double GetKp()
double GetKi()
double GetKd()
int GetMode()
int GetDirection()
6 พฤษภาคม 2555
2-7 พฤษภาคม 2555 (การนำUNO32ควบคุมมอเตอร์2)
เมื่อรู้องศาปัจจุบันของมอเตอร์แล้วก็จะต้องหมุนมอเตอร์ไปยังองศาที่ต้องการโดย หลักการ PID
โดยผู้เขียนไม่สันทัดด้านนี้มากนักจึงขอยืมข้อความจาก wikipedia มาแล้วกันว่ามันคือ " ระบบควบคุมแบบป้อนกลับที่ใช้กันอย่างกว้างขวาง ซึ่งค่าที่นำไปใช้ในการคำนวณเป็นค่าความผิดพลาดที่หามาจากความแตกต่างของตัวแปรในกระบวนการและค่าที่ต้องการ ตัวควบคุมจะพยายามลดค่าผิดพลาดให้เหลือน้อยที่สุดด้วยการปรับค่าสัญญาณขาเข้าของกระบวนการ ค่าตัวแปรของ PID ที่ใช้จะปรับเปลี่ยนตามธรรมชาติของระบบ"หลักการ "วิธีคำนวณของ PID ขึ้นอยู่กับสามตัวแปรคือค่าสัดส่วน, ปริพันธ์ และ อนุพันธ์ ค่าสัดส่วนกำหนดจากผลของความผิดพลาดในปัจจุบัน, ค่าปริพันธ์กำหนดจากผลบนพื้นฐานของผลรวมความผิดพลาดที่ซึ่งพึ่งผ่านพ้นไป, และค่าอนุพันธ์กำหนดจากผลบนพื้นฐานของอัตราการเปลี่ยนแปลงของค่าความผิดพลาด น้ำหนักที่เกิดจากการรวมกันของทั้งสามนี้จะใช้ในการปรับกระบวนการ" อ่านเพิ่มเติมได้ที่ http://th.wikipedia.org/wiki/%E0%B8%A3%E0%B8%B0%E0%B8%9A%E0%B8%9A%E0%B8%84%E0%B8%A7%E0%B8%9A%E0%B8%84%E0%B8%B8%E0%B8%A1%E0%B8%9E%E0%B8%B5%E0%B9%84%E0%B8%AD%E0%B8%94%E0%B8%B5
สรุปก็คือมีสูตรมาแล้วมีตัวแปร Kp Ki Kd แล้วเราปรับไปจะทำให้ output ของสมาการเปลี่ยนไปแล้วเรานำ output นี้ไปควบคุมมอเตอร์ให้หมุนได้แม่นยำโดยหลักการหา PID มีสองแบบแต่ผู้เขียนขอยกมาเฉพาะ จูนด้วยมือจาก wikipedia "การปรับจูนด้วยมือ ถ้าระบบยังคงทำงาน ขั้นแรกให้ตั้งค่า
และ
เป็นศูนย์ เพิ่มค่า
จนกระทั่งสัญญาณขาออกเกิดการแกว่ง (oscillate) แล้วตั้งค่า
ให้เหลือครึ่งหนึ่งของค่าที่ทำให้เกิดการแกว่งสำหรับการตอบสนองชนิด "quarter amplitude decay" แล้วเพิ่ม
จนกระทั่งออฟเซตถูกต้องในเวลาที่พอเพียงของกระบวนการ แต่ถ้า
มากไปจะทำให้ไม่เสถียร สุดท้ายถ้าต้องการ ให้เพิ่มค่า
จนกระทั่งลูปอยู่ในระดับที่ยอมรับได้ แต่ถ้า
มากเกินไปจะเป็นเหตุให้การตอบสนองและโอเวอร์ชูตเกินยอมรับได้ ปกติการปรับจูน PID ถ้าเกิดโอเวอร์ชูตเล็กน้อยจะช่วยให้เข้าสู่จุดที่ต้องการเร็วขึ้น แต่ในบางระบบไม่สามารถยอมให้เกิดโอเวอร์ชูตได้ และถ้าค่า
น้อยเกินไปก็จะทำให้เกิดการแกว่ง"
โดยผู้เขียนไม่สันทัดด้านนี้มากนักจึงขอยืมข้อความจาก wikipedia มาแล้วกันว่ามันคือ " ระบบควบคุมแบบป้อนกลับที่ใช้กันอย่างกว้างขวาง ซึ่งค่าที่นำไปใช้ในการคำนวณเป็นค่าความผิดพลาดที่หามาจากความแตกต่างของตัวแปรในกระบวนการและค่าที่ต้องการ ตัวควบคุมจะพยายามลดค่าผิดพลาดให้เหลือน้อยที่สุดด้วยการปรับค่าสัญญาณขาเข้าของกระบวนการ ค่าตัวแปรของ PID ที่ใช้จะปรับเปลี่ยนตามธรรมชาติของระบบ"หลักการ "วิธีคำนวณของ PID ขึ้นอยู่กับสามตัวแปรคือค่าสัดส่วน, ปริพันธ์ และ อนุพันธ์ ค่าสัดส่วนกำหนดจากผลของความผิดพลาดในปัจจุบัน, ค่าปริพันธ์กำหนดจากผลบนพื้นฐานของผลรวมความผิดพลาดที่ซึ่งพึ่งผ่านพ้นไป, และค่าอนุพันธ์กำหนดจากผลบนพื้นฐานของอัตราการเปลี่ยนแปลงของค่าความผิดพลาด น้ำหนักที่เกิดจากการรวมกันของทั้งสามนี้จะใช้ในการปรับกระบวนการ" อ่านเพิ่มเติมได้ที่ http://th.wikipedia.org/wiki/%E0%B8%A3%E0%B8%B0%E0%B8%9A%E0%B8%9A%E0%B8%84%E0%B8%A7%E0%B8%9A%E0%B8%84%E0%B8%B8%E0%B8%A1%E0%B8%9E%E0%B8%B5%E0%B9%84%E0%B8%AD%E0%B8%94%E0%B8%B5
สรุปก็คือมีสูตรมาแล้วมีตัวแปร Kp Ki Kd แล้วเราปรับไปจะทำให้ output ของสมาการเปลี่ยนไปแล้วเรานำ output นี้ไปควบคุมมอเตอร์ให้หมุนได้แม่นยำโดยหลักการหา PID มีสองแบบแต่ผู้เขียนขอยกมาเฉพาะ จูนด้วยมือจาก wikipedia "การปรับจูนด้วยมือ ถ้าระบบยังคงทำงาน ขั้นแรกให้ตั้งค่า
ตัวแปร | ช่วงเวลาขึ้น (Rise time) | โอเวอร์ชูต (Overshoot) | เวลาสู่สมดุลย์ (Settling time) | ความผิดพลาดสถานะคงตัว (Steady-state error) | เสถียรภาพ[1] |
---|---|---|---|---|---|
ลด | เพิ่ม | เปลี่ยนแปลงเล็กน้อย | ลด | ลด | |
ลด[2] | เพิ่ม | เพิ่ม | ลดลงอย่างมีนัยสำคัญ | ลด | |
ลดลงเล็กน้อย | ลดลงเล็กน้อย | ลดลงเล็กน้อย | ตามทฤษฏีไม่มีผล | ดีขึ้นถ้า |
2-7 พฤษภาคม 2555 (การนำUNO32ควบคุมมอเตอร์1)
หากเราต้องการจะควบคุมมอเตอร์ให้หมุนได้อย่างแม่นยำเราจะใช้ encoderควบคู่กับมอเตอร์ในการระบุตำแหน่งองศาของมอเตอร์โดยนำ encoderติดที่แกนของมอเตอร์แล้วให้มอเตอร์หมุน encoderนั้นซึ่ง encoder คือ อุปกรณ์ทางไฟฟ้าชิ้นหนึ่งที่มีแกนกลางหมุนได้รอบทิศ และมีขั้วสามขั้วเหมือนตัวต้านทางปรับค่าได้สามขั้วที่ว่าจะมีvcc gnd และ voutput ซึ่งvที่outputนี้จะทำให้เรารู้ตำแหน่งองศาที่มอเตอร์หมุนไป และจะได้ควบคุมให้มอเตอร์หมุนได้ถูกตำแหน่ง โดยบอร์ดUNO 32 ก็สามารถรู้ค่าvที่outputจากการอ่านค่าanalogซึ่งใช้คำสั่ง analogRead(ขาที่จะใช้);
โดยคำสั่งนี้จะอ่านค่าanalogจากขาที่จะใช้(ดูได้จากสี่เหลี่ยมสีส้มในรูป)แล้วค่าที่อ่านได้จะมีค่าเป็นเลขจำนวนเต็มตั้งแต่ 0 - 1024 คือATODนี่เอง โดย 1024คือค่าv ref ของวงจรหลังจากนั้นเราก็แบ่ง 0 - 1024 ให้เป็น 0 - 360 องศาแล้วสามารถใช้ หลักการ PID ในการควบคุมให้มอเตอร์หมุนไปในองศาที่ต้องการ
ส่วน PID ติดตามในตอนหน้าแล้วกันครับ
โดยคำสั่งนี้จะอ่านค่าanalogจากขาที่จะใช้(ดูได้จากสี่เหลี่ยมสีส้มในรูป)แล้วค่าที่อ่านได้จะมีค่าเป็นเลขจำนวนเต็มตั้งแต่ 0 - 1024 คือATODนี่เอง โดย 1024คือค่าv ref ของวงจรหลังจากนั้นเราก็แบ่ง 0 - 1024 ให้เป็น 0 - 360 องศาแล้วสามารถใช้ หลักการ PID ในการควบคุมให้มอเตอร์หมุนไปในองศาที่ต้องการ
ส่วน PID ติดตามในตอนหน้าแล้วกันครับ
สมัครสมาชิก:
บทความ (Atom)