Tuesday, July 5, 2011

Balancing robot with Kalman filter














จากครั้งที่แล้วหามุมการเอียงของหุ่นย์โดยใช้วิธี complementary filter พบว่าเมื่อหุ่นยนต์ run ไปนานๆแล้วมุมที่อ่านได้จาก sensor มีความผิดพลาดเกิดขึ้นเนื่องจากสัญญาณที่ได้เกิดการ drift เกิดขึ้นที่ gyro sensor ดังนั้นผมเลยเปลี่ยนวิธีในการหามุมเอียงใหม่โดยใช้วิธี sensor fusion kalman filter โดยมีขั้นตอนดังนี้ เริ่มจากการเขียน state-space ของ Predict model เสียก่อน  เรานิยามว่ามุมที่ได้จาก gyro ก็คือผลของการ Integrate สัญญาณจาก gyro นั้นเองและเรายังสามารถนิยาม bias ของสัญญาณขึ้นมาอีกตัวหนึ่งเพื่อที่จะทำการ tracking ค่า bias ให้มีค่าคงที่

หาสมการ  Kalman Predict

Kalman predict equation

x_dot=Ax+Bu
P=APA'+Q;
//***********************************************************************************//

theta_dot=(gyro-bias)    ...........................................................................(1)
bias_dot=0

จากสมการ (1) เรานิยาม state variable ดังนี้ x=[theta;bias]
จากนั้นให้เราหา jacobian matrix ก็คือการทำ partial derivative สมการ (1) เทียบกับ [theta;bias] จะได้ Matrix A,B ดังนี้

A=[0 -1;0 0],  B=[1;0]

เมื่อนำมาเขียนให้อยู่ในรูปของ state-space เราจะได้ดังนี้ จาก
x_dot=A*x+B*u

x_dot=[0 -1;0 0]*x+[1;0]*gyro   ...............................(2)


จะเห็นได้ว่า (2) ยังเป็นสมการที่อยู่ในรูปของระบบแบบ continuous  อยู่แต่ในทางปฎิบัติจริงส่วนมากแล้วเราจะใช้พวก MCU ดังนั้น เราจึง Transform ไปสู่ Discrete model เราจะได้
x_dot=(x(n+1)-x(n))/dt=[0 -1;0 0]*x+[1;0]*gyro;


x1_(n+1)=x1(n)+dt*(gyro-x2(n)) .............................................(3)
x2(n+1)=x2(n)


Ad=[1 -dt;0 1];
Bd=[dt;0];


gyro ก็คือค่า ที่อ่านจาก sensor
x1 คือ theta
x2 คือ bias
dt คือ sampling time

จากนั้นจะคำนวนหา Covariance matrix P จากสมการ
P(n+1)=Ad*P(n)*Ad'+Q    ..........................................(4)

โดยที่
Q=[Q_accelerometer 0;0 Q_gyro];

เมื่อคูณ  Matrix แล้วได้
P(n+1)=[P00 - dt P10 - (P01 - dt P11) dt + Q_accelerometer , P01 - dt P11;
               P10 -dt P11,  P11 + Q_gyro];

P00(n+1)=P00 - dt P10 - (P01 - dt P11) dt + Q_accelerometer ;   .......................(5)
P01(n+1)=P01 - dt P11;
P10(n+1)=P10 -dt P11;
P11(n+1)= P11 + Q_gyro;



จากนั้นพิจรณา Measurement Update
Measurement Update equation:
K=PH'inv(HPH'+R).........................................(6)
P=(I-KH)P......................................................(7)
x=x+K(y-Hx)...................................................(8)

H คือ measure output matrix
y คือ measure sensor
R measurement noise matrix

H=[1 0]; เนื่องจากเราวัดมุมได้อย่างเดียวนั้นคือ accelerometer
P=[P00 P01;P10 P11]

คูณ (6) ได้


K1=P00/(P00+R);
K2=P10/(P00+R);

คูณ (8) ได้


x1=x1+K1*(y-x1);
x2=x2+K2*(y-x2);

คูณ (7) ได้


P00=(1-K1)*P00;
P01=(1-K1)*P01;
P10=-K2*P00+P10;
P11=-K2*P01+P11;

เป็นอันเรียบร้อยในการทำ Kalman filter sensor fusion

จากนั้นเราก็จะนำสมการด้านบนทั้งหมดมาเขียนโปรมแกรมและโหลดลงใน Micro-conroller (CCS Compiler)

***********************************  CODE ****************************************
#include <18f458.h>
#device adc=10
#fuses H4, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=40000000)
#define  TxD         PIN_C6
#define  RxD         PIN_C7
#use rs232(baud=115200, xmit=TxD,rcv=RxD)
#include
#include
#include
#include


#use rtos(timer=0,minor_cycle=10ms)




float x[2][1]={{0.47},{0.0}};
float u[1][1];
float P[2][2]={{.01*.01*0.00000135 0 },{0}};
float K[2][1];
float x1=0.4656;



 float Q_roll=0.00000135,Q_roll_bias=.183;
const float R=0.028;
float dt=0.010;
 float fc=1.765;


float roll();
float qm();



float gyro;
float qm(){

set_ADC_channel(0);
delay_cycles(60);
gyro=(float)read_adc()*1/1023;
return(gyro);
}



float ax;
float roll(){

set_ADC_channel(2);
delay_cycles(60);
ax=atan((float)read_adc()*1/1023);
return(ax);
}





// ****************************** LPF ****************************************//
void LPF(){

x1+=dt*(-2*pi*fc*x1+2*pi*fc*ax);




}

float fhc=0.01;
float gyro1_old=0.34,tou,a,y=0;

void HPF(){
tou=1/(2*pi*fhc);
a=tou/(tou+dt);
y=a*y+a*(gyro-gyro1_old);



gyro1_old=gyro;

}

// ************************* KALMAN PREDICT **********************************//
void Kalman_Predict(float qm){
HPF();
   u[0][0]=y;
 
   x[0][0]=x[0][0]+dt*u[0][0]-dt*x[1][0];
   x[1][0]=x[1][0];
 
/* P=A*P*P'+Q */
 
P[0][0]=P[0][0]-dt*P[1][0]-(P[0][1]-dt*P[1][1])*dt+Q_roll;
P[0][1]=P[0][1]-dt*P[1][1];
P[1][0]=P[1][0]-dt*P[1][1];
P[1][1]=P[1][1]+Q_roll_bias;
 
}

//************************ KALMAN MEASURE ************************************//

void Kalman_Measurement(float roll){
LPF();

K[0][0]=P[0][0]/(P[0][0]+R);
K[1][0]=P[1][0]/(P[0][0]+R);

x[0][0]+=K[0][0]*(x1-x[0][0]);
x[1][0]+=K[1][0]*(x1-x[0][0]);

P[0][0]=(1-K[0][0])*P[0][0];
P[0][1]=(1-K[0][0])*P[0][1];
P[1][0]=-K[1][0]*P[0][0]+P[1][0];
P[1][1]=-K[1][0]*P[0][1]+P[1][1];

}



//****************************************************************************//

#task(rate=10ms,max=10ms)
void MAIN_LOOP(){
 
   Kalman_Predict(qm());
   Kalman_measurement(roll());


            }

#task(rate=10ms,max=10ms)
void print(){

printf("%.4f %.4f %.4f %.4f\r\n",ax,x[0][0],K[0][0],K[1][0]);
}


void main(){
    setup_port_a(0x07);
    setup_adc(adc_clock_internal);
    enable_interrupts(GLOBAL);

while(TRUE)

    {
           rtos_run();

     }

}


สนใจติดต่อ : sarayuthassa@gmail.com
                  083-4391356







Monday, April 11, 2011

Labview spectrum

บ่อยครั้งที่ข้อมูลที่อ่านเข้ามายัง PC จะเป็นแบบ Point by point ซึ่งไม่ใช่ Wave form ข้อมูลแบบนี้เมื่อจะนำมันไปวิเคราะห์อะไรก็ค่อนข้างลำบาก วันนี้ผมก็เลยนำเทคนิดเล็กๆ น้อยๆ มาฝากนะครับ คือ จะนำข้อมูลที่เป็น Point มาหา Spectrum ของสัญญาณ เพื่อหาความถี่ของสัญญาณว่ามีค่าเท่าไหร่บ้าง โดยมี Code ดังรูปด้านล่าง นี้








Sunday, April 10, 2011

IMU6DOF via Labview rs-232

บ่อยครั้งที่เราซื้อ sensor แล้วในตัว sensor นั้นมีการติดต่อแบบ serial  มาในตัวเลย  ในบทความนี้จะพูดถึงการอ่านข้อมูลจาก Gyro and accelerometer ที่ส่งข้อมูลแบบ serial  โดยใช้โปรแกรม Labview rs-232 เนื่องจากข้อมูลที่ได้จาก sensor ตัวนี้ไม่ได้ส่งมาเฉพาะตัวเลขแต่จะข้อมูลแบบ string หลักแรก และ หลักสุดท้าย ดังรูปด้านล่าง
ซึ่งถ้าเขียน Labview rs-232 รับมันตามcode ด้านล่างเราก็จะสามารถอ่านข้อมูลจาก Sensor ได้

ข้อมูล sensor ที่ผมใช้  http://www.thaieasyelec.com/index.php?lay=show&ac=cat_show_pro_detail&pid=54848

Saturday, February 5, 2011

Mini segway ME KMUTT

หลังจากเหนื่อยมาสามอาทิตย์กับการทำเจ้า Mini segway ตัวน้อยและแล้วมันก็สามารถยืนได้ด้วยตัวเองแล้วโดยการทำให้มันรู้ว่าตัวมันเอียงไปเท่าไหร่แล้วเมื่อเทียบกับพื้นโลก ด้วยวิธี Sensor fusion Kalman filter โดยต้องใช้ Sensor สองตัว นั้นก็คือ Accelerometer and Gyro และ การควบคุมตัวเองไม่ให้มันล้มด้วย State feedback control




อันนี้เป็น VDO ทำ Sensor fusion


อันนี้เป็น VDO การควบคุม Mini segway ตัวน้อย







สนใจติดต่อ : sarayuthassa@gmail.com
                    083-4391356

Friday, December 3, 2010

Inverted pendulum control

หลังจากที่ออกแบบและสร้าง Inverted pendulum ตัวใหม่ออกมา(อันนี้ คือ ตัวเก่า)แล้วและทำการควบคุมมัน ซึ่งผลที่ได้เป็นที่น่าพอใจอย่างมาก ซึ่งตอนนี้มันก็สามารถควบคุมได้แล้ว การควบคุมแบบนี้เรียกว่า State feedback คือ Control law u=-kx โดยที่ x คือ state variable ซึ่งใน Inverted pendulum system x ก็จะมีทั้งหมดสี่ตัว คือ cart position,cart velocity,pendulum angle และ angular velocity ซึ่งเมื่อเราสามารถวัดมาได้ครบ เราก็ทำการออกแบบหาค่า K ด้วยวิธี Pole placement/LQ เมื่อออกแบบหาค่า Kแล้วก็นำมาเขียนลงใน Digital signal processing PIC18F4431


รูปที่.1 อุปกรณ์สำหรับการทดลองทั้งหมด


รูปที่.2 STATE FEEDBACK CONTROL DIAGRAM







สถานที่ถ่ายทำ ภาควิชาวิศวกรรมเครื่องกล มหาวิทยาลัยเทคโนโลยีพระจอมเกล้าธนบุรี


รูปที่.3 กราฟวัดการตอบสนองของระบบ เมื่อมีการรบกวน Rod จะเห็นได้ว่า Cart จะต้องวิ่งเพื่อกำจัด    error ที่เกิดขึ้นกับ Rod หลังจากนั้น Cart ก็จะกลับมาที่ตำแหน่งที่ออกแบบ

สนใจติดต่อ:  sarayuthassa@gmail.com 
                    083-4391356

Saturday, October 23, 2010

Inverted pendulum state feedback control

พอดีทาง FIBO ได้มอบหมายงานชิ้นแรกให้ผม คือ ออกแบบ Control low เพื่อ ควบคุม Inverted pendulum หลังจากทำได้สองอาทิตย์ก็ทำสามารถให้มันตั้งได้แล้วแต่ state ของ cart ยังคง oscillate อยู่เพราะการปรับค่า gain ของระบบที่มีความเป็น Nonlinear และ Unstable มันไม่ใช่เรื่องง่าย และ Mechanic ก็ยังไม่ค่อยดีเท่าไหร่ แต่นี้เป็นแค่การทดสอบ Algorithm ว่า Micro controller รุ่น PIC18f4431 สามารถเขียน Control law u=-k1*(x1-reference)-k2*x2-k3*(x3-reference)-k4*x4-k5*z-k6*z1 ได้หรือเปล่าวโดยที่ x1 คือ Angle ของ pendulum x2 คือ Angular velocity ของ pendulum โดยติดตั้ง Potentiometer ไว้ที่จุดหมุนของ pendulum ส่วน x3 คือ Cart position และ x4 คือ linear velocity ของ cart มี Encoder ติดไว้ที่ motor z1 และ z2 คือ Integral error ของ Pendulum และ Cart x1 to x4 เราเรียกมันว่า State variable จะเห็นว่า x1 และ x3 สามารถวัดได้โดยตรง ส่วน x2 และ x4 ผมนำมันมา Derivative เทียบกับเวลาซึ่งไม่ใช่วิธีการที่ดีเท่าไหร่ แต่คิดไว้แล้วว่าจะใช้ Reduce order observer  หรือ อาจจะใช้ Kalman filter มาประมาณหาความเร็วแต่ทั้งสองวิธีนี้จะต้องมีแบบจำลองทางคณิตศาสตร์ของระบบก่อนวันนี้พอเท่านี้ก่อนแล้วกันครับ ครั้งหน้าจะมาดูว่า
1. หาแบบจำลองอย่างไร
2.หาสัมประสิทธิ์คงที่ ของ Model
3.ออกแบบ Observer 
4.หา Gain K โดยวิธี Lqr  
5.เขียน Code ลงใน PIC18F

อันนี้เป็น VDO ลองดูเล่นๆก่อน มันยังไม่สมบูรณ์เท่าที่ควรเพราะยังขาด Algorithm บางตัวอยู่ 





Sunday, October 3, 2010

Convert Thermistor Reading

บทความนี้จะพูดถึงการแปรงแรงดันไฟฟ้าไปเป็นอุณหภูมิ ก่อนอื่นมาทำความรู้จักกับเจ้า thermistor ก่อน Thermistor เป็นอุปกรณ์ตรวจรู้ชนิดหนึ่งที่มีคุณสมบัติ คือ เมื่อตัวมันได้รับความร้อนจะทำให้ความต้านทานภายในตัวมันมีการเปลี่ยนแปลง ซึ่งเราจะอาศัยการเปลี่ยนแปลงเหล่านี้ไปหาความสัมพันธ์ระหว่างอุณหภูมิกับความต้านทาน Thermistor เป็นอุปกรณ์แบบ passive คือ มันจะต้องได้รับการกระตุ้นเสียก่อน ซึ่งในที่นี้สิ่งที่มากระตุ้นมันก็คือแรงดันไฟฟ้ากระแสตรง ซึ่งสามารถเขียนวงจรได้ดังรูปด้านล่างนี้




เมื่อใช้กฎของโอห์มแล้วจะได้ความสัมพันธ์ดังนี้

โดยที่ A, B, C คือค่าคงที่ของ Thermistor หาได้จาก data sheet ของ Thermistor เอง
Tk คือ อุณหภูมิที่วัด มีหน่วย (K)
 ขั้นตอนการเขียนโปรแกรม Labview เมื่อเราเปิดโปรแกรม Labview ขึ้นมาแล้วให้ไปที่ Numeric-->Scaling--> Convert Temperature Reading.vi ดังรูปด้านล่าง
จากนั้นเราก็อ่าน ค่า  Voltage เข้ามาในโปรแกรม Labview ถ้ามี DAQ เราก็สามารถวัดได้โดยตรงแต่ถ้าเราไม่มี DAQ เราก็สามารถใช้ RS-232 ก็ได้





หวังว่าบทความนี้จะเป็นประโยชน์กับผู้ที่สนใจเกี่ยวกับ โปรแกรม Labview ไม่มากก็น้อยนะครับ







 

Saturday, October 2, 2010

Labview write To Measurement File

บทความนี้ เราจะมาศึกษาการ Save ข้อมูลของโปรแกรม Labview วิธีก็คือเราต้องการบันทึกข้อมูลที่มีรูปแบบเป็น waveform โดยที่หลัก(column)แรกของข้อมูลจะเป็นเวลา และหลัก(column)ต่อมาจะเป็นข้อมูลที่เราต้องการ และจะให้มันบันทึก ก็ต่อเมื่อเรากดปุ่ม save มันจะบันทึกเพียงครั้งเดียว เพราะถ้าเราไม่เขียนแบบนี้แล้วมันจะบันทึกเองทุกรอบการทำงาน หมายความว่าถ้ามันวน loop 100 ครั้งมันก็บันทึกข้อมูล 100 ครั้งซึ่งนั้นคงไม่ใช่สิ่งที่เราต้องแน่นอน ก่อนอื่นเมื่อเปิดโปรแกรมขึ้นมาแล้วไปที่ file i/o write To Measurement File แล้วจะได้ดังนี้
รูปที่.1
จากนั้นก็ให้เราคลิกช่อง Use next available file name ที่เลือกตัวนี้ก็เพราะมันจะเปลี่ยนชื่อเองโดยอัตโนมัติซึ่งจะสะดวกในการใช้งานเพราะการเก็บข้อมูลอาจจะต้องมีการเก็บหลายครั้ง ต่อจากนั้นให้ดูที่ X Value Column ให้เลือก One column only หมายความว่าเราต้องการข้อมูลเกี่ยวกับเวลาแค่หลักเดียว เมื่อดำเนินตามขั้นต้นเสร็จ ก็คลิก ok
ต่อมาก็เขียนตามรูปด้านล่างนี้
 รูปที่.2
ที่ Button ที่ชื่อว่า save ที่ผมตั้งชื่อขึ้นเองนี้ให้เราปรับมันนิดหน่อยโดยไปที่ front panel แล้วคลิกขวาที่ปุ่มกด (button) mechanical action แล้วเลือก Latch when released หรือ Latch when pressed ก็ได้ คือ มันจะทำงานเมื่อเรากด หรือ เราปล่อย button ดูตัวอย่างที่รูปด้านล่าง
รูปที่.3
สุดท้ายเมื่อเรากด Save แล้วเราก็จะได้ text file ที่มีหน้าตาดังรูปด้านล่างนี้

Labview Local variable

บทความนี้เราจะศึกษาการเขียนโปรแกรม Labview เรื่อง Labview Local variable กันนะครับก่อนที่จะดูว่ามันสร้างอย่างไรเรามาดูมันก่อนว่ามันมีประโยชน์ อะไรบ้าง Labview Local variable มีไว้สำหรับใช้งานใน vi เดียวกัน แต่สามารถรับส่งข้อมูลกันไปมาระหว่าง loop หนึ่งไปยัง loop อื่นได้ เช่น เราอ่าน visa เข้ามาใน loop แรกแต่คราวนี้เราต้องการนำค่าที่ได้จาก Visaไปใช้งานใน loop อื่นต่อเรา ก็สามารถสร้างLabview Local variable ขึ้นมาเพื่อที่จะนำค่าไปใช้ใน loop อื่นต่อไป ดูได้จากตัวอย่างด้านล่างนี้
รูปที่.1
ตัวอย่างจากรูปที่.1 สมมุติถ้าเราต้องการที่จะนำค่าจาก loop-A มาบวกกับ 10 ในรูป loop B ถ้าเขียนอย่านี้แล้วค่าที่ loop-A จะไม่สามารถส่งข้ามมายัง loop-B ได้จนกว่าเราจะกดปุ่ม stop มันถึงจะส่งข้อมูลตัสุดท้ายออกจาก loop- A ได้ แต่ถ้าเราสร้าง Labview Local variable ขึ้นมามันถึงสามารถส่งข้อมูระหว่าง loop ได้ทุกๆรอบการทำงานของ while loop ดังตัวอย่างด้านล่าง

รูปที่.2 
วิธีการสร้าง Labview Local variable ให้คลิกขวาตัวที่เราต้องการจะสร้าง Labview Local variable

รูปที่.3
แล้วไปที่ Createlocal variable

รูปที่.4

แล้วเราก็จะได้ Labview Local variable ดังนี้

 
เพียงเท่านี้เราก็สามารถสร้าง Labview Local variable ได้แล้วนะครับ

Tuesday, September 28, 2010

Labview Data Analysis program

วันนี้ผมก็มานั่งเปิด Comp ของตัวเองเล่นๆแล้วก็เปิดโปรแกรม Labview ของตัวเองก็ไปเจอโปรแกรมที่ตัวเองเขียนไว้นานแล้ว ก็มานั่งดูก็คิดว่าก็น่าจะเป็นประโยชน์กับผู้ที่สนใจเกี่ยวกับเรื่องนี้ผมก็เลยอยากจะเอามาแบ่งปันกัน โปรแกรมตัวนี้มีไว้สำหรับวิเคราะห์สัญญาณซึ่งการใช้งานนั้นก็ไม่ซับซ้อนอะไรแค่ Import data ที่มีนามสกุล .txt เข้ามาโดยที่ หลักแรกของขู้อมูลจะต้องเป็นเวลา time และหลักถัดจากนั้นก็คือข้อมูลที่เราเก็บมา เราสามารถวัดความถี่ของสัญญาณง่ายๆด้วยการเลื่อน cursor เพื่อเลือกช่วงสัญญาณที่เราต้องการดูมัน จากนั้นมันก็จะแสดงข้อมูลของความถี่มีค่าเท่าไหร่ และ แสดง Amplitude ของสัญญาณด้วยในเวลาเดียวกัน และเรายังสามารถ fit curve ข้อมูลได้ถึง order 6 ถ้าเพื่อนๆ คนไหนสนใจก็ลอง download ไปเล่นได้นะครับโดยต้องลงโปรแกรม Labview 8.2 ก่อนนะครับ

>>DOWNLOAD PROGRAM<<
>>DOWNLOAD DRIVER<<