找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4738|回复: 1
收起左侧

Atmega16+mpu6050平衡小车源码 卡尔曼滤波

[复制链接]
ID:260817 发表于 2017-12-12 20:18 | 显示全部楼层 |阅读模式
代码测试通过,卡尔曼滤波
Anyway2.0_新驱动_客户例程->default->Anyway_main.hex  此文件为烧写代码
0.png

单片机源程序如下:
  1. //方能仪器平衡车程序V2.0***************************
  2. //Landforcer 方能仪器版权所有
  3. /*使用到的单片机模块有:
  4. 1、一路定时器中断用于给定卡尔曼滤波周期,大约10ms
  5. 2、七路AD,其中ADC0用于检测转向电位器输出(备用扩展,小车有接口),
  6. ADC1用于检测左轮电机的电流(备用),
  7. ADC2连接外部滑动变阻器RK0,用于调整小车的平衡角度,也就是调零,ADC3连接
  8. RK1用于调节角度的比例系数,ADC4连接RK2用于调节角度的微分系数,ADC5连接
  9. RK3用于调节位置的比例系数,ADC6连接RK4用于调节位置的微分系数,ADC7用于检测
  10. 右轮电机的电流(备用)
  11. 3、两路外部中断,用于检测编码器的输出脉冲数,进而测得车速
  12. 4、两路PWM输出,PWM驱动直流伺服电机
  13. 5、一般IO口,通过发送高低电平控制电机的正反转,
  14. 6、iic接口用于读取MPU6050六轴传感器的数据
  15. 使用到的外部硬件模块有:MPU6050六轴传感器
  16. 电机驱动模块,车轮检测编码器模块和主控板*/
  17. //*************************AnyWay调试说明**********************//
  18. /*RK0为小车的平衡角度调节,也就是零点调节,
  19.   RK1为角度比例系数,顺时针变小,逆时针变大,系数越大车子越有力,但是系数太大会导致抖动造成自激,建议大小为2.0V
  20.   RK2为角度微分系数,顺时针变小,逆时针变大,系数越大车子反应越灵敏,能一定程度上消除RK1导致的自激,但是不能太大,建议为3.6V
  21.   RK3为位置微分系数,顺时针变小,逆7时针变大,系数越大车子越稳定,但是太大会导致自激,建议为0.6V
  22.   RK4为位置比例系数,顺时针变小,逆时针变大,系数越大车子回到原点的速度越快,但是太大也会导致自激,建议为1.0V
  23. */
  24. #include<avr/io.h>
  25. #include<avr/interrupt.h>
  26. //#include<avr/signal.h>
  27. #include "Anyway_uart.h"
  28. #include "Anyway_Kalman.h"
  29. #include "Anyway_mup6050.h"
  30. #include"Anyway_twi.h"
  31. #include <math.h>
  32. #define uchar unsigned char
  33. #define uint unsigned int
  34. /////////////////变量定义区
  35. extern float angle, angle_dot;
  36. volatile unsigned int AD_data;
  37. volatile float PWM;
  38. volatile unsigned char flager,reger;
  39. volatile int speed_output_RH,speed_output_LH,NUMBER;
  40. volatile int speed_real_LH,speed_real_RH;
  41. volatile float gyro,acc,adc_v,angle_t;
  42. volatile int Kp_angle,Kd_angle,Kd_position;
  43. volatile float Kp_position;
  44. volatile float position,position_dot;
  45. volatile float position_dot_filter;
  46. volatile int Turn_Need,Speed_Need;
  47. unsigned char cdis[14]={0,}; //读缓存区
  48. unsigned int aaa,ggg;
  49. #define xtal 16 //以MHz为单位,不同的系统时钟要修改。

  50. void delay_1ms(void)
  51. {
  52. unsigned int i;
  53. for(i=0;i<(unsigned int)(xtal*143-2);i++);
  54. }

  55. void delay_nms(unsigned int num)
  56. {
  57. unsigned int i;
  58. for(i=0;i<num;i++)
  59. delay_1ms();
  60. }
  61. ///////////////////中断初始化
  62. void T1_initial(void)                                       
  63. {
  64.         TCCR1A|=(1<<COM1A1)|(1<<WGM10)|(1<<COM1B1);                                //T1:8位快速PWM模式、匹配时清0,TOP时置位
  65.         TCCR1B|=(1<<WGM12)|(1<<CS11);                        //PWM:8分频:16M/8/256=8KHz;
  66. }

  67. //-------------------------------------------------------
  68. //定时器2初始化
  69. void T2_initial(void)                        //T2:计数至OCR2时产生中断
  70. {
  71.         OCR2=0x30;//0X5E;                        //T2:10ms时产生中断;
  72.         TIMSK|=(1<<OCIE2);
  73.         TCCR2|=(1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);                        //CTC模式,1024分频
  74. }


  75. //-------------------------------------------------------
  76. //外部中断初始化
  77. void INT_initial(void)
  78. {
  79.         MCUCR|=(1<<ISC01)|(1<<ISC00)|(1<<ISC11)|(1<<ISC10);                        //INT0、INT1上升沿有效
  80.         GICR|=(1<<INT0)|(1<<INT1);                        //外部中断使能
  81. }
  82. ///////////////////////ad转换
  83. int mega16_ad(uchar Ch1)
  84. {
  85.      uint addata;
  86.          ADMUX = 0x00 | Ch1;//这个地方注意设置,外部基准源
  87.          ADCSRA|=(1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);;
  88.          while(!(ADCSRA & (1 << ADIF)));
  89.          addata=ADCL;
  90.          addata=addata+ADCH*256;
  91.         // AD_data-=512;
  92.          ADCSRA &= ~(1 << ADIF);
  93.      ADCSRA &= ~(1 << ADEN);
  94.         return addata;
  95. }
  96. void AD_calculate(void)
  97. {aaa=cdis[2]*256+cdis[3]+32768;        
  98. //acc=(mega16_ad(0)-mega16_ad(2))*3.286/800;
  99. acc=(32768-aaa*1.0)/16384;//+(512-mega16_ad(2))*0.004;;
  100. if(acc>1)                 ///这个地方必须限幅,不然会出问题
  101. acc=1;
  102. else if(acc<-1)
  103. acc=-1;
  104. acc=57.3*acc;
  105. //gyro=-(mega16_ad(1)-380)*4.9;
  106. ggg=cdis[10]*256+cdis[11]+32768;
  107. gyro=(32768-ggg*1.0)/131;
  108. angle_t=mega16_ad(7)/5.3;
  109. //Kalman_Filter(acc,gyro);
  110. angle=0.95*(angle)+0.05*acc;
  111. angle_dot=gyro;

  112. }
  113. ////////////////////////////////PWM发送
  114. void PWM_output (int PWM_LH,int PWM_RH)
  115. {
  116.         if (PWM_LH<0)
  117.         {
  118.                 PORTB|=1<<7;
  119.                 PWM_LH*=-1;
  120.         }
  121.         else
  122.         {
  123.                 PORTB&=~(1<<7);
  124.         }
  125.         
  126.         if (PWM_LH>252)
  127.         {
  128.                 PWM_LH=252;
  129.         }
  130.         
  131.         
  132.         if (PWM_RH<0)
  133.         {
  134.                 PORTB|=1<<6;
  135.                 PWM_RH*=-1;
  136.         }
  137.         else
  138.         {
  139.                 PORTB&=~(1<<6);
  140.         }
  141.         
  142.         if (PWM_RH>252)
  143.         {
  144.                 PWM_RH=252;
  145.         }
  146.         
  147.                
  148.         OCR1AH=0;
  149.         OCR1AL=PWM_LH;                        //OC1A输出;
  150.         
  151.         OCR1BH=0;
  152.         OCR1BL=PWM_RH;                        //OC1B输出;
  153.         
  154. }
  155. ///////////////////////////////////PWM 计算
  156. void PWM_calculate(void)        
  157. {
  158.         
  159. //        PORTB|=(1<<6);
  160. /*        if (0x10==(PINB&1<<4) )        //前进
  161.         {
  162.                 Speed_Need=-4;
  163.         }
  164.         else if (0x20==(PINB&1<<5) )        //后退
  165.         {
  166.                 Speed_Need=4;
  167.         }
  168.         else        //不动
  169.         {
  170.                 Speed_Need=0;
  171.         }
  172. */
  173. //position_dot=(speed_real_LH-speed_real_RH)*0.5;     ///B
  174. //                position_dot=(-speed_real_LH-speed_real_RH)*0.5;///D
  175. //        position_dot=(speed_real_LH+speed_real_RH)*0.5; ///A
  176.   position_dot=(-speed_real_LH+speed_real_RH)*0.5;    ///C        
  177.         position_dot_filter*=0.85;                //车轮速度滤波
  178.         position_dot_filter+=position_dot*0.15;        
  179.         
  180.         position+=position_dot_filter;
  181.         position+=Speed_Need;
  182.         position+=Turn_Need;
  183.                 if (position<-768)                //防止位置误差过大导致的不稳定
  184.         {
  185.                 position=-768;
  186.         }
  187.         else if  (position>768)
  188.         {
  189.                 position=768;
  190.         }
  191.                 PWM =-Kp_angle*angle-Kd_angle*angle_dot/*+Kp_position*position*/+Kd_position*(position_dot_filter-Speed_Need);        

  192.         speed_output_RH = PWM+Turn_Need;
  193.         speed_output_LH = PWM-Turn_Need;
  194.         PWM_output (speed_output_LH,speed_output_RH);        
  195. }
  196. ////////////////////////////////////主程序
  197. int main()
  198. {//uchar a;
  199.         DDRB=0B11000000;
  200. //        PORTB=0;
  201.         DDRB &= ~(1<<0 | 1<<1|1<<2|1<<3|1<<4|1<<5);
  202.         PORTB |= 1<<0 | 1<<1|1<<2|1<<3|1<<4|1<<5;
  203.     DDRA=0;
  204.     PORTA=0;
  205.            DDRD=0B11110010;//这个地方不能加PIN,不然会出问题
  206. DDRC |=((1<<PC0)|(1<<PC1));
  207. PORTC|=((1<<PC0)|(1<<PC1));
  208. TWBR=0x0a; //I2C 初始化,400kbps
  209. TWSR|=(1<<TWPS0);

  210. T1_initial();
  211. T2_initial();

  212. USART_Init();

  213. //        PIND=0X00;
  214. //        PORTD=0X00;
  215. //        PORTD|=~(1<<6);
  216.   // SFIOR|=1<<PUD;
  217.   INT_initial();
  218.    sei();
  219. MPU_Init();
  220.          Kp_angle=mega16_ad(3)/10.0;
  221.         Kd_angle=mega16_ad(4)/250.0;
  222.         Kp_position=mega16_ad(5)/500.0;
  223.         Kd_position=mega16_ad(6)/5.0;
  224.         angle_t=mega16_ad(7)/5.3;
  225.    while(1)
  226. {
  227. if(flager==1)
  228. {MPU_6050_Read(cdis);
  229. AD_calculate();
  230. /*flager=0;
  231. AD_calculate();
  232. PWM_calculate();
  233. MPU_6050_Read(cdis);
  234. speed_real_LH=0;//速度计数清零
  235. speed_real_RH=0;
  236. }*/
  237. /*
  238. Putc(0xfd);
  239. Putc(0);
  240. Putc(angle*2+120);
  241. */
  242. Putc(0xff);
  243. Putc(angle+128); //红
  244. Putc(angle_t+10);//绿
  245. Putc(acc+128);   //蓝
  246.   }
  247.    }
  248.    return 0;
  249. }

  250. ISR(TIMER2_COMP_vect)//定时器2中断服务函数
  251. {
  252. flager=1;
  253. NUMBER++;
  254. //MPU_6050_Read(cdis);
  255. //AD_calculate();
  256. }
  257. ISR(INT0_vect)
  258. {
  259.         if (0==(PINB&1<<0))
  260. ……………………

  261. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
Anyway2.0_新驱动_客户例程.zip (96.57 KB, 下载次数: 32)
回复

使用道具 举报

ID:30708 发表于 2019-10-13 15:12 | 显示全部楼层
感谢上传代码
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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