找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5735|回复: 8
收起左侧

二轮平衡机器人控制器代码

[复制链接]
ID:80436 发表于 2015-5-22 01:06 | 显示全部楼层 |阅读模式



  1. //MCU:Mega16;晶振:8MHz;

  2. //PWM:4KHz;滤波器频率:100Hz;系统频率:100Hz;10ms;

  3. //二轮平衡机器人项目

  4. #include <iom16v.h>

  5. #include <macros.h>

  6. #include <math.h>

  7. //#define checkbit(var,bit)     (var&(0x01<<(bit)))     /*定义查询位函数*/

  8. //#define setbit(var,bit)     (var|=(0x01<<(bit)))     /*定义置位函数*/

  9. //#define clrbit(var,bit)     (var&=(~(0x01<<(bit)))) /*定义清零位函数*/

  10. //-------------------------------------------------------

  11. //输出端口初始化

  12. void PORT_initial(void)

  13. {

  14. DDRA=0B00000000;

  15. PINA=0X00;

  16. PORTA=0X00;

  17. DDRB=0B00000000;

  18. PINB=0X00;

  19. PORTB=0X00;

  20. DDRC=0B00010000;

  21. PINC=0X00;

  22. PORTC=0X00;

  23. DDRD=0B11110010;

  24. PIND=0X00;

  25. PORTD=0X00;

  26. }

  27. //-------------------------------------------------------

  28. //定时器1初始化

  29. void T1_initial(void)       

  30. {

  31. TCCR1A|=(1<<COM1A1)|(1<<WGM10)|(1<<COM1B1);        //T1:8位快速PWM模式、匹配时清0,TOP时置位

  32. TCCR1B|=(1<<WGM12)|(1<<CS11);        //PWM:8分频:8M/8/256=4KHz;

  33. }

  34. //-------------------------------------------------------

  35. //定时器2初始化

  36. void T2_initial(void)        //T2:计数至OCR2时产生中断

  37. {

  38. OCR2=0X4E;        //T2:计数20ms(0X9C)10ms(0X4E)时产生中断;

  39. TIMSK|=(1<<OCIE2);

  40. TCCR2|=(1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);        //CTC模式,1024分频

  41. }

  42. //-------------------------------------------------------

  43. //外部中断初始化

  44. void INT_initial(void)

  45. {

  46. MCUCR|=(1<<ISC01)|(1<<ISC00)|(1<<ISC11)|(1<<ISC10);        //INT0、INT1上升沿有效

  47. GICR|=(1<<INT0)|(1<<INT1);        //外部中断使能

  48. }

  49. //-------------------------------------------------------

  50. //串口初始化;

  51. void USART_initial( void )

  52. {       

  53. UBRRH = 0X00;

  54. UBRRL = 51;        //f=8MHz;设置波特率:9600:51;19200:25;

  55. UCSRB = (1<<RXEN)|(1<<TXEN);        //接收器与发送器使能;

  56. UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);        //设置帧格式: 8 个数据位, 1 个停止位;

  57. UCSRB|=(1<<RXCIE);        //USART接收中断使能

  58. }

  59. //-------------------------------------------------------

  60. //串口发送数据;

  61. void USART_Transmit( unsigned char data )

  62. {

  63. while ( !( UCSRA & (1<<UDRE)));        //等待发送缓冲器为空;

  64. UDR = data;        //将数据放入缓冲器,发送数据;

  65. }

  66. //-------------------------------------------------------

  67. //串口接收数据中断,确定数据输出的状态;

  68. #pragma interrupt_handler USART_Receive_Int:12

  69. static char USART_State;

  70. void USART_Receive_Int(void)

  71. {

  72. USART_State=UDR;//USART_Receive();

  73. }

  74. //-------------------------------------------------------

  75. //计算LH侧轮速:INT0中断;

  76. //-------------------------------------------------------

  77. static int speed_real_LH;

  78. //-------------------------------------------------------

  79. #pragma interrupt_handler SPEEDLHINT_fun:2

  80. void SPEEDLHINT_fun(void)

  81. {

  82. if (0==(PINB&BIT(0)))

  83. {

  84. speed_real_LH-=1;

  85. }

  86. else

  87. {

  88. speed_real_LH+=1;

  89. }

  90. }

  91. //-------------------------------------------------------

  92. //计算RH侧轮速,:INT1中断;

  93. //同时将轮速信号统一成前进方向了;

  94. //-------------------------------------------------------

  95. static int speed_real_RH;

  96. //-------------------------------------------------------

  97. #pragma interrupt_handler SPEEDRHINT_fun:3

  98. void SPEEDRHINT_fun(void)

  99. {

  100. if (0==(PINB&BIT(1)))

  101. {

  102. speed_real_RH+=1;

  103. }

  104. else

  105. {

  106. speed_real_RH-=1;

  107. }

  108. }

  109. //-------------------------------------------------------

  110. //ADport采样:10位,采样基准电压Aref

  111. //-------------------------------------------------------

  112. static int AD_data;

  113. //-------------------------------------------------------

  114. int ADport(unsigned char port)

  115. {

  116. ADMUX=port;

  117. ADCSRA|=(1<<ADEN)|(1<<ADSC)|(1<<ADPS1)|(1<<ADPS0);        //采样频率为8分频;

  118. while(!(ADCSRA&(BIT(ADIF))));

  119. AD_data=ADCL;

  120. AD_data+=ADCH*256;

  121. AD_data-=512;

  122. return (AD_data);

  123. }

  124. //*

  125. //-------------------------------------------------------

  126. //Kalman滤波,8MHz的处理时间约1.8ms;

  127. //-------------------------------------------------------

  128. static float angle, angle_dot; //外部需要引用的变量

  129. //-------------------------------------------------------

  130. static const float Q_angle=0.001, Q_gyro=0.003, R_angle=0.5, dt=0.01;

  131. //注意:dt的取值为kalman滤波器采样时间;

  132. static float P[2][2] = {

  133. { 1, 0 },

  134. { 0, 1 }

  135. };

  136. static float Pdot[4] ={0,0,0,0};

  137. static const char C_0 = 1;

  138. static float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;

  139. //-------------------------------------------------------

  140. void Kalman_Filter(float angle_m,float gyro_m)        //gyro_m:gyro_measure

  141. {

  142. angle+=(gyro_m-q_bias) * dt;

  143. Pdot[0]=Q_angle - P[0][1] - P[1][0];

  144. Pdot[1]=- P[1][1];

  145. Pdot[2]=- P[1][1];

  146. Pdot[3]=Q_gyro;

  147. P[0][0] += Pdot[0] * dt;

  148. P[0][1] += Pdot[1] * dt;

  149. P[1][0] += Pdot[2] * dt;

  150. P[1][1] += Pdot[3] * dt;

  151. angle_err = angle_m - angle;

  152. PCt_0 = C_0 * P[0][0];

  153. PCt_1 = C_0 * P[1][0];

  154. E = R_angle + C_0 * PCt_0;

  155. K_0 = PCt_0 / E;

  156. K_1 = PCt_1 / E;

  157. t_0 = PCt_0;

  158. t_1 = C_0 * P[0][1];

  159. P[0][0] -= K_0 * t_0;

  160. P[0][1] -= K_0 * t_1;

  161. P[1][0] -= K_1 * t_0;

  162. P[1][1] -= K_1 * t_1;

  163. angle        += K_0 * angle_err;

  164. q_bias        += K_1 * angle_err;

  165. angle_dot = gyro_m-q_bias;

  166. }

  167. //*/

  168. /*

  169. //-------------------------------------------------------

  170. //互补滤波

  171. //-------------------------------------------------------

  172. static float angle,angle_dot; //外部需要引用的变量

  173. //-------------------------------------------------------       

  174. static float bias_cf;

  175. static const float dt=0.01;

  176. //-------------------------------------------------------

  177. void complement_filter(float angle_m_cf,float gyro_m_cf)

  178. {

  179. bias_cf*=0.998;        //陀螺仪零飘低通滤波;500次均值;

  180. bias_cf+=gyro_m_cf*0.002;

  181. angle_dot=gyro_m_cf-bias_cf;

  182. angle=(angle+angle_dot*dt)*0.90+angle_m_cf*0.05;       

  183. //加速度低通滤波;20次均值;按100次每秒计算,低通5Hz;

  184. }

  185. */       

  186. //-------------------------------------------------------

  187. //AD采样;

  188. //以角度表示;

  189. //加速度计:1.2V=1g=90°;满量程:1.3V~3.7V;

  190. //陀螺仪:0.5V~4.5V=-80°~+80°;满量程5V=200°=256=200°;

  191. //-------------------------------------------------------

  192. static float gyro,acceler;

  193. //-------------------------------------------------------

  194. void AD_calculate(void)

  195. {

  196. acceler=ADport(2)+28;        //角度校正

  197. gyro=ADport(3);       

  198. acceler*=0.004069;        //系数换算:2.5/(1.2*512); // 5/(1.2*1024);5为参考电压5V;1.2V灵敏度对应加速度1g;1024为AD精度

  199. acceler=asin(acceler);        //反正弦求角度

  200. gyro*=0.00341;        //角速度系数:(3.14/180)* 100/512=0.01364;//(3.14/180)*    (200*0.025)/1024*0.025既5/1024*0.025       

  201. //求得角速度 单位 角度/秒

  202. Kalman_Filter(acceler,gyro);        //卡尔曼滤波 带入角度。角速度

  203. //complement_filter(acceler,gyro);

  204. }

  205. //-------------------------------------------------------

  206. //PWM输出

  207. //-------------------------------------------------------

  208. void PWM_output (int PWM_LH,int PWM_RH)

  209. {

  210. if (PWM_LH<0)

  211. {

  212. PORTD|=BIT(6);

  213. PWM_LH*=-1;

  214. }

  215. else

  216. {

  217. PORTD&=~BIT(6);

  218. }

  219. if (PWM_LH>252)

  220. {

  221. PWM_LH=252;

  222. }

  223. if (PWM_RH<0)

  224. {

  225. PORTD|=BIT(7);

  226. PWM_RH*=-1;

  227. }

  228. else

  229. {

  230. PORTD&=~BIT(7);

  231. }

  232. if (PWM_RH>252)

  233. {

  234. PWM_RH=252;

  235. }

  236. OCR1AH=0;

  237. OCR1AL=PWM_LH;        //OC1A输出;

  238. OCR1BH=0;

  239. OCR1BL=PWM_RH;        //OC1B输出;

  240. }

  241. //-------------------------------------------------------

  242. //计算PWM输出值

  243. //车辆直径:76mm; 12*64pulse/rev; 1m=3216pulses;

  244. //-------------------------------------------------------       

  245. //static int speed_diff,speed_diff_all,speed_diff_adjust;

  246. //static float K_speed_P,K_speed_I;

  247. static float K_voltage,K_angle,K_angle_dot,K_position,K_position_dot;

  248. static float K_angle_AD,K_angle_dot_AD,K_position_AD,K_position_dot_AD;

  249. static float position,position_dot;

  250. static float position_dot_filter;

  251. static float PWM;

  252. static int speed_output_LH,speed_output_RH;

  253. static int Turn_Need,Speed_Need;

  254. //-------------------------------------------------------       

  255. void PWM_calculate(void)       

  256. {

  257. if ( 0==(~PINA&BIT(1)) )        //左转

  258. {

  259. Turn_Need=-40;

  260. }

  261. else if ( 0==(~PINB&BIT(2)) ) //右转

  262. {

  263. Turn_Need=40;

  264. }

  265. else        //不转

  266. {

  267. Turn_Need=0;

  268. }

  269. if ( 0==(~PINC&BIT(0)) )        //前进

  270. {

  271. Speed_Need=-2;

  272. }

  273. else if ( 0==(~PINC&BIT(1)) )        //后退

  274. {

  275. Speed_Need=2;

  276. }

  277. else        //不动

  278. {

  279. Speed_Need=0;

  280. }

  281. K_angle_AD=ADport(4)*0.007;

  282. K_angle_dot_AD=ADport(5)*0.007;

  283. K_position_AD=ADport(6)*0.007;

  284. K_position_dot_AD=ADport(7)*0.007;

  285. position_dot=PWM*0.04;

  286. position_dot_filter*=0.9;        //车轮速度滤波

  287. position_dot_filter+=position_dot*0.1;       

  288. position+=position_dot_filter;

  289. //position+=position_dot;       

  290. position+=Speed_Need;

  291. if (position<-768)        //防止位置误差过大导致的不稳定

  292. {

  293. position=-768;

  294. }

  295. else if  (position>768)

  296. {

  297. position=768;

  298. }

  299. PWM = K_angle*angle *K_angle_AD + K_angle_dot*angle_dot *K_angle_dot_AD +

  300. K_position*position *K_position_AD + K_position_dot*position_dot_filter *K_position_dot_AD;

  301. speed_output_RH = PWM;// - Turn_Need;

  302. speed_output_LH = - PWM;// - Turn_Need ;

  303. /*

  304. speed_diff=speed_real_RH-speed_real_LH;        //左右轮速差PI控制;

  305. speed_diff_all+=speed_diff;

  306. speed_diff_adjust=(K_speed_P*speed_diff+K_speed_I*speed_diff_all)/2;

  307. */

  308. PWM_output (speed_output_LH,speed_output_RH);       

  309. }

  310. //-------------------------------------------------------

  311. //定时器2中断处理

  312. //-------------------------------------------------------

  313. static unsigned char temp;

  314. //-------------------------------------------------------

  315. #pragma interrupt_handler T2INT_fun:4

  316. void T2INT_fun(void)       

  317. {

  318. AD_calculate();

  319. PWM_calculate();

  320. if(temp>=4)        //10ms即中断;每秒计算:100/4=25次;

  321. {       

  322. if (USART_State==0X30)        //ASCII码:0X30代表字符'0'

  323. {

  324. USART_Transmit(angle*57.3+128);

  325. USART_Transmit(angle_dot*57.3+128);

  326. USART_Transmit(128);       

  327. }

  328. else if(USART_State==0X31)        //ASCII码:0X30代表字符'1'

  329. {

  330. USART_Transmit(speed_output_LH+128);

  331. USART_Transmit(speed_output_RH+128);       

  332. USART_Transmit(128);

  333. }

  334. else if(USART_State==0X32)        //ASCII码:0X30代表字符'2'

  335. {

  336. USART_Transmit(speed_real_LH+128);

  337. USART_Transmit(speed_real_RH+128);

  338. USART_Transmit(128);

  339. }

  340. else if(USART_State==0X33)        //ASCII码:0X30代表字符'3'

  341. {

  342. USART_Transmit(K_angle+128);

  343. USART_Transmit(K_angle_dot+128);

  344. USART_Transmit(K_position_dot+128);

  345. }       

  346. temp=0;       

  347. }

  348. speed_real_LH=0;

  349. speed_real_RH=0;       

  350. temp+=1;       

  351. }

  352. //-------------------------------------------------------

  353. int i,j;

  354. //-------------------------------------------------------

  355. void main(void)

  356. {

  357. PORT_initial();

  358. T2_initial();

  359. INT_initial();

  360. USART_initial ();

  361. SEI();

  362. K_position=0.8 * 0.209;        //换算系数:(256/10) * (2*pi/(64*12))=0.20944;//256/10:电压换算至PWM,256对应10V;

  363. K_angle=34 * 25.6;        //换算系数:256/10 =25.6;

  364. K_position_dot=1.09 * 20.9;        //换算系数:(256/10) * (25*2*pi/(64*12))=20.944;

  365. K_angle_dot=2.2 * 25.6;        //换算系数:256/10 =25.6;

  366. for (i=1;i<=500;i++)        //延时启动PWM,等待卡尔曼滤波器稳定

  367. {

  368. for (j=1;j<=300;j++);;

  369. }

  370. T1_initial();

  371. while(1)

  372. {

  373. ;

  374. }

  375. }
复制代码





回复

使用道具 举报

ID:82588 发表于 2015-6-10 10:06 | 显示全部楼层
先收藏再说,谢谢分享
回复

使用道具 举报

ID:82588 发表于 2015-6-14 11:25 | 显示全部楼层
先收藏备用,谢谢分享
回复

使用道具 举报

ID:65957 发表于 2017-4-13 13:11 | 显示全部楼层
好复杂,先备着。谢谢楼主
回复

使用道具 举报

ID:205843 发表于 2017-7-11 03:47 来自手机 | 显示全部楼层
谢谢分享,很好的学习资料
回复

使用道具 举报

ID:48413 发表于 2017-8-16 10:33 | 显示全部楼层
学习一下谢谢!!!!!!!!!!!!!!!!!!!
回复

使用道具 举报

ID:962686 发表于 2022-3-23 23:12 | 显示全部楼层
感觉有点复杂啊,有点头痛
回复

使用道具 举报

ID:1083996 发表于 2023-9-7 11:42 | 显示全部楼层
有没有防止电动车摩托车自行车这种,左右歪倒的东西,比如陀螺仪啥的;
网上貌似很多了,脚踢也不会倾倒
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表