找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1643|回复: 0
收起左侧

基于STM32的平衡小车核心算法

[复制链接]
ID:807680 发表于 2020-11-1 17:45 | 显示全部楼层 |阅读模式
  1. #include "math.h"
  2. #include "stdio.h"
  3. #include "control.h"
  4. #include "debug.H"
  5. #include "MPU6050.H"
  6. #include "communicate.h"
  7. #include "bsp.h"
  8. #include "ultrasonic.h"
  9. #include "infrare.h"


  10. unsigned char g_u8MainEventCount;
  11. unsigned char g_u8SpeedControlCount;
  12. unsigned char g_u8SpeedControlPeriod;
  13. unsigned char g_u8DirectionControlPeriod;
  14. unsigned char g_u8DirectionControlCount;

  15. unsigned char g_cMotorDisable = 0;//值等于0时电机正常转动,否则停止转动


  16. int g_iGravity_Offset = 0;

  17. /******电机控制参数******/
  18. float g_fSpeedControlOut;
  19. float g_fSpeedControlOutOld;
  20. float g_fSpeedControlOutNew;
  21. float g_fAngleControlOut;
  22. float g_fLeftMotorOut;
  23. float g_fRightMotorOut;

  24. /******速度控制参数******/

  25. short  g_s16LeftMotorPulse;
  26. short  g_s16RightMotorPulse;

  27. int  g_s32LeftMotorPulseOld;
  28. int  g_s32RightMotorPulseOld;
  29. int  g_s32LeftMotorPulseSigma;
  30. int  g_s32RightMotorPulseSigma;

  31. float g_fCarSpeed;
  32. float g_iCarSpeedSet;
  33. float g_fCarSpeedOld;
  34. float g_fCarPosition;

  35. /*-----角度环和速度环PID控制参数-----*/
  36. PID_t g_tCarAnglePID={17.0, 0, 23.0};        //*5 /10
  37. PID_t g_tCarSpeedPID={15.25, 1.08, 0};        //i/10
  38. /******蓝牙控制参数******/
  39. float g_fBluetoothSpeed;
  40. float g_fBluetoothDirection;
  41. float g_fBluetoothDirectionOld;
  42. float g_fBluetoothDirectionNew;
  43. float g_fBluetoothDirectionOut;

  44. float g_fCarAngle;                 //
  45. float g_fGyroAngleSpeed;                //                             
  46. float g_fGravityAngle;                        //


  47. int g_iLeftTurnRoundCnt = 0;
  48. int g_iRightTurnRoundCnt = 0;

  49. static int AbnormalSpinFlag = 0;
  50. /***************************************************************
  51. ** 函数名称: CarUpstandInit
  52. ** 功能描述: 全局变量初始化函数
  53. ***************************************************************/
  54. void CarUpstandInit(void)
  55. {
  56.         //g_iAccelInputVoltage_X_Axis = g_iGyroInputVoltage_Y_Axis = 0;
  57.         g_s16LeftMotorPulse = g_s16RightMotorPulse = 0;
  58.         g_s32LeftMotorPulseOld = g_s32RightMotorPulseOld = 0;
  59.         g_s32LeftMotorPulseSigma = g_s32RightMotorPulseSigma = 0;

  60.         g_fCarSpeed = g_fCarSpeedOld = 0;
  61.         g_fCarPosition = 0;
  62.         g_fCarAngle    = 0;
  63.         g_fGyroAngleSpeed = 0;
  64.         g_fGravityAngle   = 0;

  65.         g_fAngleControlOut = g_fSpeedControlOut = g_fBluetoothDirectionOut = 0;
  66.         g_fLeftMotorOut    = g_fRightMotorOut   = 0;
  67.         g_fBluetoothSpeed  = g_fBluetoothDirection = 0;
  68.         g_fBluetoothDirectionNew = g_fBluetoothDirectionOld = 0;

  69.   g_u8MainEventCount=0;
  70.         g_u8SpeedControlCount=0;
  71.          g_u8SpeedControlPeriod=0;
  72. }


  73. /***************************************************************
  74. ** 函数名称: AbnormalSpinDetect
  75. ** 功能描述: 电机转速异常检测      
  76. ***************************************************************/

  77. void AbnormalSpinDetect(short leftSpeed,short rightSpeed)
  78. {
  79.         static unsigned short count = 0;
  80.         
  81.         //速度设置为0时检测,否则不检测
  82.         if(g_iCarSpeedSet==0)
  83.         {
  84.                 if(((leftSpeed>30)&&(rightSpeed>30)&&(g_fCarAngle > -30) && (g_fCarAngle < 30))
  85.                         ||((leftSpeed<-30)&&(rightSpeed<-30))&&(g_fCarAngle > -30) && (g_fCarAngle < 30))
  86.                 {// 左右电机转速大于30、方向相同、持续时间超过250ms,且车身角度不超过30度,则判断为悬空空转
  87.                         count++;
  88.                         if(count>50){
  89.                                 count = 0;
  90.                                 AbnormalSpinFlag = 1;
  91.                         }
  92.                 }
  93.                 else{
  94.                         count = 0;
  95.                 }
  96.         }
  97.         else{
  98.                 count = 0;
  99.         }
  100. }

  101. /***************************************************************
  102. ** 函数名称: LandingDetect
  103. ** 功能描述: 小车着地检测      
  104. ***************************************************************/
  105. void LandingDetect(void)
  106. {
  107.         static float lastCarAngle = 0;
  108.         static unsigned short count = 0,count1 = 0;
  109.         
  110.         if(AbnormalSpinFlag == 0)return;
  111.         
  112.         // 小车角度5°~-5°启动检测
  113.         if((g_fCarAngle > -5) && (g_fCarAngle < 5))
  114.         {
  115.                 count1++;
  116.                 if(count1 >= 50)
  117.                 {//每隔250ms判断一次小车角度变化量,变化量小于0.8°或大于-0.8°判断为小车静止
  118.                         count1 = 0;
  119.                         if(((g_fCarAngle - lastCarAngle) < 0.8) && ((g_fCarAngle - lastCarAngle) > -0.8))
  120.                         {
  121.                                 count++;
  122.                                 if(count >= 4){
  123.                                         count = 0;
  124.                                         count1 = 0;
  125.                                         g_fCarPosition = 0;
  126.                                         AbnormalSpinFlag = 0;
  127.                                 }
  128.                         }
  129.                         else{
  130.                                 count = 0;
  131.                         }
  132.                         lastCarAngle = g_fCarAngle;
  133.                 }
  134.         }
  135.         else
  136.         {
  137.                 count1 = 0;
  138.                 count = 0;
  139.         }
  140. }

  141. /***************************************************************
  142. ** 函数名称: MotorManage
  143. ** 功能描述: 电机使能/失能控制      
  144. ***************************************************************/
  145. void MotorManage(void)
  146. {

  147.         AbnormalSpinDetect(g_s16LeftMotorPulse, g_s16RightMotorPulse);
  148.                
  149.         LandingDetect();
  150.         
  151.         if(AbnormalSpinFlag)
  152.         {        
  153.                 g_cMotorDisable |= (0x01<<1);
  154.         }
  155.         else
  156.         {
  157.                 g_cMotorDisable &= ~(0x01<<1);
  158.         }
  159.         
  160.         if(g_fCarAngle > 30 || g_fCarAngle < (-30))
  161.         {
  162.                 g_cMotorDisable |= (0x01<<2);
  163.         }
  164.         else
  165.         {
  166.                 g_cMotorDisable &= ~(0x01<<2);
  167.         }
  168.         
  169. }

  170. /***************************************************************
  171. ** 函数名称: SetMotorVoltageAndDirection
  172. ** 功能描述: 电机转速及方向控制函数            
  173. ***************************************************************/
  174. void SetMotorVoltageAndDirection(int i16LeftVoltage,int i16RightVoltage)
  175. {
  176.           if(i16LeftVoltage<0)
  177.     {        
  178.                         GPIO_SetBits(GPIOA, GPIO_Pin_3 );                                    
  179.       GPIO_ResetBits(GPIOA, GPIO_Pin_4 );
  180.       i16LeftVoltage = (-i16LeftVoltage);
  181.     }
  182.     else
  183.     {        
  184.       GPIO_SetBits(GPIOA, GPIO_Pin_4 );                                    
  185.       GPIO_ResetBits(GPIOA, GPIO_Pin_3 );
  186.     }

  187.     if(i16RightVoltage<0)
  188.     {        
  189.              GPIO_SetBits(GPIOB, GPIO_Pin_0 );                                    
  190.       GPIO_ResetBits(GPIOB, GPIO_Pin_1 );
  191.       i16RightVoltage = (-i16RightVoltage);
  192.     }
  193.     else
  194.     {
  195.                         GPIO_SetBits(GPIOB, GPIO_Pin_1 );                                    
  196.                         GPIO_ResetBits(GPIOB, GPIO_Pin_0 );              
  197.     }

  198.         if(i16RightVoltage > MOTOR_OUT_MAX)  
  199.         {
  200.                 i16RightVoltage = MOTOR_OUT_MAX;
  201.         }
  202.         if(i16LeftVoltage > MOTOR_OUT_MAX)
  203.         {
  204.            i16LeftVoltage = MOTOR_OUT_MAX;
  205.         }  
  206.         
  207.         if(g_cMotorDisable)
  208.         {
  209.                 TIM_SetCompare1(TIM3,0);
  210.                 TIM_SetCompare2(TIM3,0);
  211.         }
  212.         else
  213.         {
  214.                 TIM_SetCompare1(TIM3,i16RightVoltage);
  215.                 TIM_SetCompare2(TIM3,i16LeftVoltage);
  216.         }
  217. }


  218. /***************************************************************
  219. ** 函数名称: MotorOutput
  220. ** 功能描述: 电机输出函数
  221.              将直立控制、速度控制、方向控制的输出量进行叠加,并加
  222.                          入死区常量,对输出饱和作出处理。
  223. ***************************************************************/
  224. void MotorOutput(void)
  225. {
  226.         g_fLeftMotorOut  = g_fAngleControlOut - g_fSpeedControlOut - g_fBluetoothDirection ;        
  227.         g_fRightMotorOut = g_fAngleControlOut - g_fSpeedControlOut + g_fBluetoothDirection ;


  228.         /*增加死区常数*/
  229.         if((int)g_fLeftMotorOut>0)       g_fLeftMotorOut  += MOTOR_OUT_DEAD_VAL;
  230.         else if((int)g_fLeftMotorOut<0)  g_fLeftMotorOut  -= MOTOR_OUT_DEAD_VAL;
  231.         if((int)g_fRightMotorOut>0)      g_fRightMotorOut += MOTOR_OUT_DEAD_VAL;
  232.         else if((int)g_fRightMotorOut<0) g_fRightMotorOut -= MOTOR_OUT_DEAD_VAL;

  233.         /*输出饱和处理,防止超出PWM范围*/                        
  234.         if((int)g_fLeftMotorOut  > MOTOR_OUT_MAX)        g_fLeftMotorOut  = MOTOR_OUT_MAX;
  235.         if((int)g_fLeftMotorOut  < MOTOR_OUT_MIN)        g_fLeftMotorOut  = MOTOR_OUT_MIN;
  236.         if((int)g_fRightMotorOut > MOTOR_OUT_MAX)        g_fRightMotorOut = MOTOR_OUT_MAX;
  237.         if((int)g_fRightMotorOut < MOTOR_OUT_MIN)        g_fRightMotorOut = MOTOR_OUT_MIN;
  238.         
  239.     SetMotorVoltageAndDirection((int)g_fLeftMotorOut,(int)g_fRightMotorOut);
  240. }



  241. void GetMotorPulse(void)  //采集电机速度脉冲
  242. {         
  243.   g_s16LeftMotorPulse = TIM_GetCounter(TIM2);     
  244.   g_s16RightMotorPulse= -TIM_GetCounter(TIM4);
  245.   TIM2->CNT = 0;
  246.   TIM4->CNT = 0;   //清零

  247.   g_s32LeftMotorPulseSigma +=  g_s16LeftMotorPulse;
  248.   g_s32RightMotorPulseSigma += g_s16RightMotorPulse;
  249.         
  250.         g_iLeftTurnRoundCnt -= g_s16LeftMotorPulse;
  251.         g_iRightTurnRoundCnt -= g_s16RightMotorPulse;

  252. }

  253. void AngleCalculate(void)
  254. {
  255.         //-------加速度--------------------------
  256.         //量程为±2g时,灵敏度:16384 LSB/g
  257.     g_fGravityAngle = atan2(g_fAccel_y/16384.0,g_fAccel_z/16384.0) * 180.0 / 3.14;
  258.           g_fGravityAngle = g_fGravityAngle - g_iGravity_Offset;

  259.         //-------角速度-------------------------
  260.         //范围为2000deg/s时,换算关系:16.4 LSB/(deg/s)
  261.         g_fGyro_x  = g_fGyro_x / 16.4;  //计算角速度值                           
  262.         g_fGyroAngleSpeed = g_fGyro_x;        
  263.         
  264.         //-------互补滤波---------------
  265.         g_fCarAngle = 0.98 * (g_fCarAngle + g_fGyroAngleSpeed * 0.005) + 0.02 *        g_fGravityAngle;
  266. }
  267. /***************************************************************
  268. ** 函数名称: AngleControl
  269. ** 功能描述: 角度环控制函数           
  270. ***************************************************************/
  271. void AngleControl(void)         
  272. {
  273.         g_fAngleControlOut =  (CAR_ANGLE_SET-g_fCarAngle) * g_tCarAnglePID.P *5 + \
  274.         (CAR_ANGLE_SPEED_SET-g_fGyroAngleSpeed) * (g_tCarAnglePID.D /10);
  275. }



  276. /***************************************************************
  277. ** 函数名称: SpeedControl
  278. ** 功能描述: 速度环控制函数
  279. ***************************************************************/

  280. void SpeedControl(void)
  281. {
  282.           float fP,fI;           
  283.         float fDelta;
  284.         
  285.         
  286.         g_fCarSpeed = (g_s32LeftMotorPulseSigma  + g_s32RightMotorPulseSigma ) * 0.5 ;
  287.   g_s32LeftMotorPulseSigma = g_s32RightMotorPulseSigma = 0;          //全局变量 注意及时清零
  288.             
  289.         g_fCarSpeed = 0.7 * g_fCarSpeedOld + 0.3 * g_fCarSpeed ;//低通滤波,使速度更平滑
  290.         g_fCarSpeedOld = g_fCarSpeed;

  291.         fDelta = CAR_SPEED_SET;
  292.         fDelta -= g_fCarSpeed;   
  293.         
  294.         fP = fDelta * (g_tCarSpeedPID.P);
  295.   fI = fDelta * (g_tCarSpeedPID.I/10.0);

  296.         g_fCarPosition += fI;
  297.         g_fCarPosition += g_fBluetoothSpeed;         
  298.         
  299. //积分上限设限
  300.         if((s16)g_fCarPosition > CAR_POSITION_MAX)    g_fCarPosition = CAR_POSITION_MAX;
  301.         if((s16)g_fCarPosition < CAR_POSITION_MIN)    g_fCarPosition = CAR_POSITION_MIN;
  302.         
  303.         g_fSpeedControlOutOld = g_fSpeedControlOutNew;
  304.   g_fSpeedControlOutNew = fP + g_fCarPosition;
  305. }
  306. /***************************************************************
  307. ** 函数名称: SpeedControlOutput
  308. ** 功能描述: 速度环控制输出函数-分多步逐次逼近最终输出,尽可能将对直立环的干扰降低。
  309. ***************************************************************/
  310. void SpeedControlOutput(void)
  311. {
  312.   float fValue;
  313.   fValue = g_fSpeedControlOutNew - g_fSpeedControlOutOld ;
  314.   g_fSpeedControlOut = fValue * (g_u8SpeedControlPeriod + 1) / SPEED_CONTROL_PERIOD + g_fSpeedControlOutOld;
  315. }


  316. /***************************************************************
  317. ** 函数名称: Scale
  318. ** 功能描述: 量程归一化处理
  319. ***************************************************************/
  320. float Scale(float input, float inputMin, float inputMax, float outputMin, float outputMax) {
  321.   float output;
  322.   if (inputMin < inputMax)
  323.     output = (input - inputMin) / ((inputMax - inputMin) / (outputMax - outputMin));
  324.   else
  325.     output = (inputMin - input) / ((inputMin - inputMax) / (outputMax - outputMin));
  326.   if (output > outputMax)
  327.     output = outputMax;
  328.   else if (output < outputMin)
  329.     output = outputMin;
  330.   return output;
  331. }

  332. /***************************************************************
  333. ** 函数名称: Steer
  334. ** 功能描述: 遥控速度及方向处理函数
  335. ***************************************************************/
  336. void Steer(float direct, float speed)
  337. {
  338.         if(direct > 0)
  339.                 g_fBluetoothDirection = Scale(direct, 0, 10, 0, 400);
  340.         else
  341.                 g_fBluetoothDirection = -Scale(direct, 0, -10, 0, 400);

  342.         if(speed > 0)
  343.                 g_iCarSpeedSet = Scale(speed, 0, 10, 0, 70);
  344.         else
  345.                 g_iCarSpeedSet = -Scale(speed, 0, -10, 0, 70);

  346. }

  347. void UltraControl(int mode)
  348. {
  349.         if(mode == 0)
  350.         {
  351.                 if((Distance >= 0) && (Distance<= 12))
  352.                 {//距离小于12cm则后退
  353.                         Steer(0, -4);
  354.                 }
  355.                 else if((Distance> 18) && (Distance<= 30))        
  356.                 {//距离大于18cm且小于30则前进
  357.                         Steer(0, 4);
  358.                 }
  359.                 else
  360.                         Steer(0, 0);
  361.         }
  362.         else if(mode == 1)
  363.         {
  364.                 if((Distance >= 0) && (Distance<= 20))
  365.                 {//右转750个脉冲计数,转弯角度约为90度
  366.                         Steer(5, 0);
  367.                         g_iLeftTurnRoundCnt = 750;
  368.                         g_iRightTurnRoundCnt = -750;
  369.                 }
  370.                 if((g_iLeftTurnRoundCnt < 0)&&(g_iRightTurnRoundCnt > 0))
  371.                 {
  372.                         Steer(0, 4);
  373.                 }
  374.         }
  375. }

  376. /***************************************************************
  377. ** 函数名称: TailingControl
  378. ** 功能描述: 红外寻迹           
  379. ***************************************************************/
  380. void TailingControl(void)
  381. {
  382. #if INFRARE_DEBUG_EN > 0
  383.         char buff[32];        
  384. #endif
  385.         char result;
  386.         float direct = 0;
  387.         float speed = 0;

  388.         result = InfraredDetect();
  389.         
  390.         if(result & infrared_channel_Lc)
  391.                 direct = -10;
  392.         else if(result & infrared_channel_Lb)
  393.                 direct = -6;
  394.         else if(result & infrared_channel_La)
  395.                 direct = -4;
  396.         else if(result & infrared_channel_Rc)
  397.                 direct = 10;
  398.         else if(result & infrared_channel_Rb)
  399.                 direct = 6;
  400.         else if(result & infrared_channel_Ra)
  401.                 direct = 4;
  402.         else
  403.                 direct = 0.0;

  404.         speed = 3;

  405.         Steer(direct, speed);

  406. #if INFRARE_DEBUG_EN > 0
  407.         sprintf(buff, "Steer:%d, Speed:%d\r\n",(int)direct,  (int)speed);
  408.         DebugOutStr(buff);
  409. #endif
  410. }

复制代码
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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