日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

基于AVR单片机: 两轮自平衡智能车

發(fā)布時(shí)間:2024/3/7 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于AVR单片机: 两轮自平衡智能车 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

???

??????? 寒假無(wú)所事事,決定做一個(gè)兩輪平衡車(chē)來(lái)玩玩.個(gè)人覺(jué)得兩輪自平衡車(chē)是集合所有算法的精髓.它就像蛋炒飯,最簡(jiǎn)單也是最困難.他可以用簡(jiǎn)單的算法實(shí)現(xiàn),當(dāng)然也可以用最復(fù)雜的控制理論來(lái)實(shí)現(xiàn). 本質(zhì)上來(lái)說(shuō)它就是個(gè)倒立擺.

個(gè)人原創(chuàng),轉(zhuǎn)載請(qǐng)注明原文出處:

??????????http://www.embbnux.com/2014/02/21/avr_mcu_balance_car/

所需原件:

AVR單片機(jī) : 采用之前的ATmega128開(kāi)發(fā)板

傳感器: ENC03陀螺儀? mma8451加速度計(jì)

電機(jī)驅(qū)動(dòng): L298n

總體思路:

使用陀螺儀測(cè)角速度,使用加速度計(jì)測(cè)角度,使用測(cè)得的這兩個(gè)值進(jìn)行傳感器融合,獲取準(zhǔn)確的角度.由得到的角度來(lái)控制車(chē)子兩個(gè)輪子的轉(zhuǎn)向,轉(zhuǎn)速等參數(shù).進(jìn)而實(shí)現(xiàn)兩輪車(chē)的平衡. 傳感器融合使用卡爾曼濾波算法,不得不大贊一下卡爾曼同學(xué),給了個(gè)這么perfect的算法,傳說(shuō)當(dāng)年挑戰(zhàn)者號(hào)就是用的這個(gè)算法.

角度的測(cè)量:

enc03陀螺儀: 采用的這個(gè)陀螺儀是模擬量的,輸出電壓需要用ATmega128進(jìn)行adc轉(zhuǎn)換成數(shù)字量,測(cè)得電壓,再轉(zhuǎn)換成角速度:

ISR(ADC_vect){if(adc_done_flag==0){adc_read(adc_channel);if(adc_channel==1) {adc_channel=0;}else{adc_channel++;adc_mid_tmp0[cou]=adc_value[0]; //中值濾波cou++;if(cou==3){cou=0;if(adc_mid_tmp0[0]>adc_mid_tmp0[1]){mid_tmp = adc_mid_tmp0[0];adc_mid_tmp0[0] =adc_mid_tmp0[1];adc_mid_tmp0[1] =mid_tmp;}if(adc_mid_tmp0[2]>adc_mid_tmp0[1])adc_mid[0]=adc_mid_tmp0[1] ;else if (adc_mid_tmp0[2]>adc_mid_tmp0[0])adc_mid[0]=adc_mid_tmp0[2] ;elseadc_mid[0]=adc_mid_tmp0[0] ;}}adc_set_channel(adc_channel);adc_done_flag =1; } else adc_done_flag = 0; //ADCSRA|=(1<<ADSC);} float gyro_enc03_w(unsigned int adc_value,float adc_bias){float w_value;//把a(bǔ)dc采集的值轉(zhuǎn)化為電壓w_value = (float)(adc_value)*2540/1024; //mVw_value = w_value-adc_bias;//把電壓轉(zhuǎn)化為角速度w_value = -w_value;w_value = w_value/0.67;return w_value; }

mma8451加速度計(jì): mma8451使用的I2C接口,不過(guò)沒(méi)事,128上面就有一個(gè)了,這里我使用硬件I2C來(lái)實(shí)現(xiàn),代碼較多這里給出關(guān)鍵代碼:


unsigned char i2c_mma8451_Write(unsigned char Address,unsigned char Wdata) {unsigned char i;Start();//I2C啟動(dòng)Wait();if(TestAck()!=START) return 1;//ACKWrite8Bit(MMA845x_IIC_ADDRESS);//寫(xiě)I2C 8451從器件地址和寫(xiě)方式Wait();if(TestAck()!=MT_SLA_ACK) return 1;//ACKWrite8Bit(Address);//寫(xiě)x地址Wait();if(TestAck()!=MT_DATA_ACK) return 1;//ACKWrite8Bit(Wdata);//寫(xiě)入設(shè)備ID及讀信Wait();if(TestAck()!=MT_DATA_ACK) return 1;//ACKStop();//I2C停止for(i=0;i<250;i++);return 0; } //mma8451初始化 //初始化為指定模式 void mma845x_init() { i2c_init();i2c_mma8451_Write(CTRL_REG1,ASLP_RATE_20MS+DATA_RATE_5MS);i2c_mma8451_Write(XYZ_DATA_CFG_REG, FULL_SCALE_2G); //2Gi2c_mma8451_Write(CTRL_REG1, (ACTIVE_MASK+ASLP_RATE_20MS+DATA_RATE_5MS)&(~FREAD_MASK)); //激活狀態(tài) 14bit } // unsigned char i2c_mma8451_Read(unsigned char Address) {unsigned char temp;Start();//I2C啟動(dòng)Wait();if (TestAck()!=START) return 0;//ACKWrite8Bit(MMA845x_IIC_ADDRESS);//寫(xiě)入設(shè)備ID及寫(xiě)信號(hào)Wait();if (TestAck()!=MT_SLA_ACK) return 0;//ACK // //Write8Bit(Address);//寫(xiě)X地址Wait();if (TestAck()!=MT_DATA_ACK) return 0; //? //data1=TestAck();Start();//I2C重新啟動(dòng)Wait();if (TestAck()!=RE_START) return 0;Write8Bit(MMA845x_IIC_ADDRESS+1);//寫(xiě)I2C從器件地址和讀方式Wait();if(TestAck()!=MR_SLA_ACK) return 0;//ACKTwi();//啟動(dòng)主I2C讀方式Wait();if(TestAck()!=MR_DATA_NOACK) return 0;//ACKtemp=TWDR;//讀取I2C接收數(shù)據(jù)Stop();//I2C停止return temp; } //求出加速度原始對(duì)應(yīng)數(shù)值 unsigned int get_mma8451_data(unsigned char Address){unsigned char x;unsigned int wx;unsigned char address_LSB;x = i2c_mma8451_Read(Address);if(Address==OUT_Z_MSB_REG)address_LSB= OUT_Z_LSB_REG;else if(Address==OUT_Y_MSB_REG)address_LSB= OUT_Y_LSB_REG;elseaddress_LSB= OUT_X_LSB_REG;wx = ((i2c_mma8451_Read(address_LSB))|x<<8);return wx; }
使用卡爾曼濾波融合兩個(gè)測(cè)量量:(參考自原來(lái)在阿莫論壇很流行的算法)


float angle, angle_dot; //外部需要引用的變量 //------------------------------------------------------- float Q_angle=0.001, Q_gyro=0.003, R_angle=5.0, dt=0.01; //注意:dt的取值為kalman濾波器采樣時(shí)間; float P[2][2] = {{ 1, 0 },{ 0, 1 } };float Pdot[4] ={0,0,0,0};const char C_0 = 1;float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;void Kalman_Filter(float angle_m,float gyro_m) //gyro_m:gyro_measure {angle+=(gyro_m-q_bias) * dt;//先驗(yàn)估計(jì)Pdot[0]=Q_angle - P[0][1] - P[1][0];// Pk-' 先驗(yàn)估計(jì)誤差協(xié)方差的微分Pdot[1]=- P[1][1];Pdot[2]=- P[1][1];Pdot[3]=Q_gyro;P[0][0] += Pdot[0] * dt;// Pk- 先驗(yàn)估計(jì)誤差協(xié)方差微分的積分 = 先驗(yàn)估計(jì)誤差協(xié)方差P[0][1] += Pdot[1] * dt;P[1][0] += Pdot[2] * dt;P[1][1] += Pdot[3] * dt;angle_err = angle_m - angle;//zk-先驗(yàn)估計(jì)PCt_0 = C_0 * P[0][0];PCt_1 = C_0 * P[1][0];E = R_angle + C_0 * PCt_0;K_0 = PCt_0 / E;//KkK_1 = PCt_1 / E;t_0 = PCt_0;t_1 = C_0 * P[0][1];P[0][0] -= K_0 * t_0;//后驗(yàn)估計(jì)誤差協(xié)方差P[0][1] -= K_0 * t_1;P[1][0] -= K_1 * t_0;P[1][1] -= K_1 * t_1;angle += K_0 * angle_err;//后驗(yàn)估計(jì)q_bias += K_1 * angle_err;//后驗(yàn)估計(jì)angle_dot = gyro_m-q_bias;//輸出值(后驗(yàn)估計(jì))的微分 = 角速度 }

卡爾曼算法是要在定時(shí)器里面不斷的更新,才能發(fā)揮作用.dt就是定時(shí)器的時(shí)間,這里我采用10ms.

主要算法在定時(shí)器中斷里面實(shí)現(xiàn):

定時(shí)器里面完成對(duì)角速度,角度的測(cè)量,卡爾曼更新,以及對(duì)電機(jī)的控制.

//定時(shí)器0 初始化 void timer0_init(void){//設(shè)置計(jì)數(shù)開(kāi)始的初始值TCNT0 = 176 ; // 208>>6ms 176>>10ms//設(shè)置分頻TCCR0 = (1<<CS02)|(1<<CS00)|(1<<CS01); //1024分頻 47次6ms 62.5次8ms//設(shè)置中斷屏蔽寄存器TIMSK = (1<<TOIE0); //設(shè)置溢出使能中斷 } //定時(shí)器0溢出中斷 ISR(TIMER0_OVF_vect){//設(shè)置計(jì)數(shù)開(kāi)始的初始值TCNT0 = 176 ; //10msmma8451_data = get_mma8451_data(OUT_Z_MSB_REG);acc = mma8451_i2c_to_angel(mma8451_data);acc_tmp=acc;gyro = gyro_enc03_w(adc_mid[0],adc_bias);gyro_tmp = gyro;//卡爾曼Kalman_Filter(acc,gyro);//控制車(chē)速 if (angle>0) {car_back();if(angle>15)car_speed(0x2f,0x2f); elsecar_speed(0x4f,0x4f); } else if(angle<0){car_forward();if(angle<-15)car_speed(0x2f,0x2f);elsecar_speed(0x4f,0x4f); }}
對(duì)于車(chē)速的控制,這里只采用簡(jiǎn)單的開(kāi)環(huán)控制,之后會(huì)采用更復(fù)制的DIP控制或者模糊控制等算法,日后持續(xù)更新,敬請(qǐng)關(guān)注本博客,







總結(jié)

以上是生活随笔為你收集整理的基于AVR单片机: 两轮自平衡智能车的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。