|
基于單片機(jī)平衡車設(shè)置
PID控制 卡爾曼濾波設(shè)計(jì)實(shí)現(xiàn)自平衡小車設(shè)計(jì)
單片機(jī)源程序如下:
- #include "sys.h"
- #include "usart.h"
- //#include "delay.h"
- // 編碼器:100線;電機(jī)減速比:150
- #include "ofme_led.h"
- #include "ofme_filter.h"
- #include "ofme_iic.h"
- #include "ofme_iic_dev.h"
- #include "ofme_pwm.h"
- #include "ofme_pid.h"
- #include "ofme_encoder.h"
- #include "ofme_io.h"
- #include "ofme_time.h"
- #include "ofme_ir_nec.h"
- #define PI (3.14159265)
- // 度數(shù)表示的角速度*1000
- #define MDPS (70)
- // 弧度表示的角速度
- #define RADPS ((float)MDPS*PI/180000)
- // 每個(gè)查詢周期改變的角度
- #define RADPT (RADPS/(-100))
- // 平衡的角度范圍;+-60度(由于角度計(jì)算采用一階展開,實(shí)際值約為46度)
- #define ANGLE_RANGE_MAX (60*PI/180)
- #define ANGLE_RANGE_MIN (-60*PI/180)
- // 全局變量
- pid_s sPID; // PID控制參數(shù)結(jié)構(gòu)體
- float radian_filted=0; // 濾波后的弧度
- accelerometer_s acc; // 加速度結(jié)構(gòu)體,包含3維變量
- gyroscope_s gyr; // 角速度結(jié)構(gòu)體,包含3維變量
- int speed=0, distance=0; // 小車移動(dòng)的速度,距離
- int tick_flag = 0; // 定時(shí)中斷標(biāo)志
- int pwm_speed = 0; // 電機(jī)pwm控制的偏置值,兩個(gè)電機(jī)的大小、正負(fù)相同,使小車以一定的速度前進(jìn)
- int pwm_turn = 0; // 電機(jī)pwm控制的差異值,兩個(gè)電機(jī)的大小相同,正負(fù)相反,使小車左、右轉(zhuǎn)向
- float angle_balance = 0; // 小車的平衡角度。由于小車重心的偏移,小車的平衡角度不一定是radian_filted為零的時(shí)候
- // 定時(shí)器周期中斷,10ms
- void sys_tick_proc(void)
- {
- static unsigned int i = 0;
- tick_flag++;
- i++;
- if(i>=100) i=0;
- if(i==0) // 綠燈的閃爍周期為1秒
- {
- LED1_OFF();
- }
- else if(i==50)
- {
- LED1_ON();
- }
- }
- void control_proc(void)
- {
- int i = ir_key_proc(); // 將紅外接收到的按鍵值,轉(zhuǎn)換為小車控制的相應(yīng)按鍵值。
- switch(i)
- {
- case KEY_TURN_LEFT:
- if(pwm_turn<500) pwm_turn += 50;
- break;
- case KEY_TURN_RIGHT:
- if(pwm_turn>-500) pwm_turn -= 50;
- break;
- case KEY_TURN_STOP:
- pwm_turn = 0;
- distance = 0;
- pwm_speed = 0;
- break;
- case KEY_SPEED_UP:
- if(pwm_speed<500) pwm_speed+=100;
- break;
- case KEY_SPEED_DOWN:
- if(pwm_speed>-500) pwm_speed-=100;
- break;
- case KEY_SPEED_0:
- pwm_speed = 0;
- break;
- case KEY_SPEED_F1:
- pwm_speed = 150;
- break;
- case KEY_SPEED_F2:
- pwm_speed = 300;
- break;
- case KEY_SPEED_F3:
- pwm_speed = 450;
- break;
- case KEY_SPEED_F4:
- pwm_speed = 600;
- break;
- case KEY_SPEED_F5:
- pwm_speed = 750;
- break;
- case KEY_SPEED_F6:
- pwm_speed = 900;
- break;
- case KEY_SPEED_B1:
- pwm_speed = -150;
- case KEY_SPEED_B2:
- pwm_speed = -300;
- case KEY_SPEED_B3:
- pwm_speed = -450;
- break;
- default:
- break;
- }
- pwm_turn *= 0.9; // pwm_turn的值以0.9的比例衰減,使小車在接收到一個(gè)轉(zhuǎn)向信號后只轉(zhuǎn)動(dòng)一定的時(shí)間后停止轉(zhuǎn)動(dòng)。
- speed = speed*0.7 +0.3*(encoder_read()); // 定周期(10ms)讀取編碼器數(shù)值得到實(shí)時(shí)速度,再對速度進(jìn)行平滑濾波
- if(speed!=0)
- {
- printf("speed: %d, dst: %d, pwm: %d \r\n", speed,distance,(int)(speed*6+distance*0.1));
- }
- encoder_write(0); // 編碼器值重新設(shè)為0
- distance += speed; // 對速度進(jìn)行積分,得到移動(dòng)距離
- if(distance>6000) distance = 6000; // 減少小車懸空、空轉(zhuǎn)對控制的影響
- else if(distance<-6000) distance = -6000;
- }
- void balance_proc(void)
- {
- static unsigned int err_cnt=0;
- // float tFloat;
- int pwm_balance;
- // static float angle;
- // float angle_t;
- float radian, radian_pt; // 當(dāng)前弧度及弧度的微分(角速度,角度值用弧度表示)
- adxl345_read(&acc); // 讀取當(dāng)前加速度。由于傳感器按照的位置原因,傳感器的值在函數(shù)內(nèi)部經(jīng)過處理,變?yōu)樾≤嚨奶摂M坐標(biāo)系。
- l3g4200d_read(&gyr); // 讀取當(dāng)前角速度。同樣經(jīng)過坐標(biāo)系變換。
- // 此段程序用于傳感器出錯(cuò)時(shí)停止小車
- err_cnt = err_cnt*115>>7; // err_cnt以0.9的比例系數(shù)衰減(115>>7的值約為0.9,避免浮點(diǎn)數(shù),提高速度)
- if(acc.flag != 0x0F || gyr.flag != 0x0F) // 讀取的角度、角速度值有誤?赡苁请姶鸥蓴_、iic線太長等導(dǎo)致出錯(cuò)。
- {
- LED0_ON(); // 亮紅燈
- err_cnt +=100; // 等比數(shù)列,比例系數(shù)0.9(115>>7),常數(shù)項(xiàng)100;根據(jù)公式,連續(xù)10項(xiàng)的和約為657
- if(err_cnt>657) goto err; // 當(dāng)連續(xù)發(fā)生約10次(約0.1秒)錯(cuò)誤則超過657而溢出。
- }
- // 此段程序用于倒立或失重時(shí)停止小車
- if(acc.z<=0)
- {
- goto err;
- }
- // 小車的虛擬x軸方向?yàn)樾≤嚽斑M(jìn)方向,虛擬y軸為小車左邊,虛擬z軸為小車上升方向。
- // 前傾角度為負(fù),后傾角度為正。
- // 通過計(jì)算加速度分量,得到小車傾斜弧度(未濾波)
- radian = (float)(acc.x)/acc.z; // 一階展開:Q =f(x)=x-x^3/3+x^5/5+...+(-1)^k*x^(2k+1)/(2k+1)+...
- // 通過角速度傳感器,得到小車的角速度(單位為 弧度/秒)
- radian_pt = gyr.y*RADPT;
- radian_filted = ofme_filter(radian_filted, radian, radian_pt); // 互補(bǔ)濾波得到小車的傾斜角度
- // 此段程序用于小車傾斜角度過大時(shí),停止小車
- if(radian_filted> ANGLE_RANGE_MAX || radian_filted<ANGLE_RANGE_MIN)
- {
- goto err;
- }
- // 通過PID計(jì)算,得到保持小車角度為零所需要的電機(jī)pwm輸出
- pwm_balance = pid_proc(&sPID, radian_filted, radian_pt);
- // printf("%d\r\n",speed);
- // 通過小車移動(dòng)速度與移動(dòng)距離,調(diào)整小車平衡所需的pwm輸出
- pwm_balance += (speed*6+distance*0.1);
- // 在pwm_balance的基礎(chǔ)上,加上速度分量與轉(zhuǎn)動(dòng)分量,調(diào)整小車兩個(gè)電機(jī)的轉(zhuǎn)速。
- pwm_control(pwm_balance+pwm_speed+pwm_turn, pwm_balance+pwm_speed-pwm_turn);
- // 如果pwm超出有效值,紅燈亮。用于調(diào)試,了解系統(tǒng)狀態(tài)。
- if(pwm_balance>=1000||pwm_balance<=-1000) LED1_ON();
- LED0_OFF();
- return;
- err:
- puts("balance error.\r\n");
- pwm_control(0, 0); // 關(guān)閉電機(jī)
- return;
- }
- int main(void)
- {
- // int i=0, t;
- // int pwm;
- // float radian, radian_pt;
- Stm32_Clock_Init(9);//系統(tǒng)時(shí)鐘設(shè)置
- uart_init(72,57600); //串口1初始化
- hw_tick_start(); // 定時(shí)器周期性中斷,用于提供系統(tǒng)脈搏
- ////////////////////////////////////////////////////////////////////////////////
- led_init();
- pwm_init();
- iic_init();
- adxl345_init(&acc);
- l3g4200d_init(&gyr);
- hw_ir_init();
- encoder_init();
- while(0)
- {
- if(tick_flag>100)
- {
- tick_flag = 0;
- printf("count: %d\r\n",encoder_read());
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // pid_init(&sPID, 4500,0,-300);6000--350 ;8000--350;11000--350;
- // pid_init(&sPID, 6000,0,-35000);
- pid_init(&sPID, 7500,0,-35000); // 調(diào)節(jié)PID參數(shù),后3個(gè)形參分別為:比例系數(shù)P,積分系數(shù)I,微分系數(shù)D
- sPID.target = -3.5*PI/180;
- radian_filted = 0;
- adxl345_init(&acc);
- l3g4200d_init(&gyr);
- while(1)
- {
- if(tick_flag)
- {
- tick_flag = 0;
- balance_proc(); // 調(diào)節(jié)小車,保持平衡
- control_proc(); // 根據(jù)遙控接收到的數(shù)據(jù),調(diào)整電機(jī)輸出參數(shù)
- }
- }
- }
復(fù)制代碼
所有資料51hei提供下載:
balance-20130511.rar
(287.53 KB, 下載次數(shù): 102)
2018-7-5 18:29 上傳
點(diǎn)擊文件名下載附件
基于單片機(jī)的平衡車設(shè)計(jì) 下載積分: 黑幣 -5
|
|