你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeIDE+PID调参做的动量轮平衡自行车(五)

[复制链接]
STMCU小助手 发布时间:2023-2-9 17:53
本文用于记录平衡自行车的制作过程,及制作中遇到的问题;总体方案如下:采用采用STM32F103C8T6作为主控单元、MPU-6050作为位姿采集单元、0.96寸OLED显示位姿、无刷电机带动动量轮调节小车平衡、1S锂电池配合5V和12V升压模块作为电源、蓝牙模块用于和微信小程序进行无线通讯和PID调试、舵机用于控制行驶方向和支撑小车。


        为了方便进行PID参数的调试,我写了一个微信小程序(蓝牙小车调试助手),操作参考视频里的介绍。PID我也不是很了解,只是照着葫芦画瓢,在定时器回调函数中定时进行PID计算,控制小车的平衡,详细到代码如下:


        Ps:PID真是和孽畜一般的物件,以后不会再玩了,太难调试了!

  1. /* USER CODE BEGIN Header */
  2. /**
  3.   ******************************************************************************
  4.   * @file           : main.c
  5.   * @brief          : Main program body
  6.   ******************************************************************************
  7.   * @attention
  8.   *
  9.   * Copyright (c) 2022 STMicroelectronics.
  10.   * All rights reserved.
  11.   *
  12.   * This software is licensed under terms that can be found in the LICENSE file
  13.   * in the root directory of this software component.
  14.   * If no LICENSE file comes with this software, it is provided AS-IS.
  15.   *
  16.   ******************************************************************************
  17.   */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "dma.h"
  22. #include "i2c.h"
  23. #include "tim.h"
  24. #include "usart.h"
  25. #include "gpio.h"

  26. /* Private includes ----------------------------------------------------------*/
  27. /* USER CODE BEGIN Includes */

  28. #include "mpu6050.h"
  29. #include "stdio.h"
  30. #include "stdlib.h"
  31. #include "string.h"

  32. /* USER CODE END Includes */

  33. /* Private typedef -----------------------------------------------------------*/
  34. /* USER CODE BEGIN PTD */

  35. /* USER CODE END PTD */

  36. /* Private define ------------------------------------------------------------*/
  37. /* USER CODE BEGIN PD */
  38. /* USER CODE END PD */

  39. /* Private macro -------------------------------------------------------------*/
  40. /* USER CODE BEGIN PM */

  41. /* USER CODE END PM */

  42. /* Private variables ---------------------------------------------------------*/

  43. /* USER CODE BEGIN PV */
  44. //定义变量接受微信小程序发送的数据
  45. uint8_t startFlag = 0;
  46. uint8_t displayFlag = 0;
  47. uint8_t driveSpeed = 0;
  48. int16_t driveDirection = -1;
  49. float tempVerticalKp,tempVerticalKi,tempVerticalKd;
  50. float tempVelocityKp,tempVelocityKi,tempVelocityKd;

  51. //串口通讯接受缓存区
  52. uint8_t bufferLen =100;
  53. uint8_t buffer[100];
  54. uint8_t bufferTr[20] = "";

  55. extern float Pitch_Kalman;
  56. extern float GyroY;
  57. float GyroY_Lowout = 0;

  58. int16_t counterA = 0;
  59. int16_t brushless = 0;

  60. //Vertical Parameter
  61. float Vertical_Kp = 800,Vertical_Kd = 30;
  62. float Angle = 0;////自平衡角度
  63. float Angle_mid = 1;//机械中值

  64. //Velocity Parameter
  65. float Velocity_Kp = 0.16, Velocity_Ki=0.00016;
  66. int16_t Encoder_Err=0, Encoder_Sum=0;
  67. int16_t Encoder_lowout=0;
  68. float a=0.7;        //一阶互补滤波系数


  69. /* USER CODE END PV */

  70. /* Private function prototypes -----------------------------------------------*/
  71. void SystemClock_Config(void);
  72. /* USER CODE BEGIN PFP */

  73. /* USER CODE END PFP */

  74. /* Private user code ---------------------------------------------------------*/
  75. /* USER CODE BEGIN 0 */

  76. void PIDControl(){
  77.         /****************************************************************
  78.      速度环PI控制器:
  79.      输出:期望角度,实测角度,实测角速度
  80.      输出:PWM输出
  81.         ****************************************************************/
  82.         //1.计算速度偏差 Encoder_Err
  83.         Encoder_Err  = counterA;
  84.         counterA = 0;
  85.         //2.对速度偏差进行低通滤波 low_out = (1-a)*Ek+a*low_out_last;
  86.         Encoder_lowout = (1-a)*Encoder_Err+a*Encoder_lowout;
  87.         //3.对速度偏差,积分出位移
  88.         Encoder_Sum += Encoder_lowout;
  89.         if(Encoder_Sum>10000)
  90.                 Encoder_Sum = 10000;
  91.         else if(Encoder_Sum<-10000)
  92.                 Encoder_Sum = -10000;
  93.         //4.速度环控制输出——期望角度
  94.         Angle = Velocity_Kp*Encoder_lowout + Velocity_Ki*Encoder_Sum;
  95.         /****************************************************************
  96.      直立环PD控制器:
  97.      输入出:期望角度,实测角度,实测角速度
  98.      输出:PWM输出
  99.         ****************************************************************/
  100.         GyroY_Lowout = 0.3*GyroY + 0.7*GyroY_Lowout;
  101.         brushless =Vertical_Kp*(Pitch_Kalman - Angle_mid + Angle) + Vertical_Kd * GyroY_Lowout;
  102.         //brushless = Vertical_Kp*(Pitch_Kalman - Angle_mid + Angle) + Vertical_Kd * GyroY;
  103. }

  104. /**
  105.   * @brief  EXTI line detection callbacks.
  106.   * @param  GPIO_Pin: Specifies the pins connected EXTI line
  107.   * @retval None
  108.   */
  109. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  110. {
  111.         //Define external interrupt function
  112.         if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)
  113.                 counterA +=1;
  114.         else
  115.                 counterA -=1;
  116. }

  117. /**
  118.   * @brief  Period elapsed callback in non-blocking mode
  119.   * @param  htim TIM handle
  120.   * @retval None
  121.   */
  122. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  123. {
  124.         if (htim->Instance==TIM4)
  125.         {
  126.                 if(startFlag||displayFlag)
  127.                 {
  128.                         //Timer 4 interrupt function
  129.                         GetAngle();//get Pitch_Kalman and GyroY
  130.                         PIDControl();
  131.                         if(brushless > 3600){
  132.                           brushless = 3600;
  133.                         }
  134.                         else if(brushless < -3600){
  135.                           brushless = -3600;
  136.                         }
  137.                         if(brushless>=0){
  138.                                 HAL_GPIO_WritePin(GPIO_DIR_GPIO_Port, GPIO_DIR_Pin, SET);
  139.                                 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1,brushless);
  140.                         }
  141.                         else{
  142.                                 HAL_GPIO_WritePin(GPIO_DIR_GPIO_Port, GPIO_DIR_Pin, RESET);
  143.                                 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1,abs(brushless));
  144.                         }
  145.                 }
  146.         }
  147. }

  148. //get system time us
  149. __STATIC_INLINE uint32_t GXT_SYSTICK_IsActiveCounterFlag(void)
  150. {
  151.   return ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == (SysTick_CTRL_COUNTFLAG_Msk));
  152. }
  153. static uint32_t getCurrentMicros(void)
  154. {
  155.   /* Ensure COUNTFLAG is reset by reading SysTick control and status register */
  156.   GXT_SYSTICK_IsActiveCounterFlag();
  157.   uint32_t m = HAL_GetTick();
  158.   const uint32_t tms = SysTick->LOAD + 1;
  159.   __IO uint32_t u = tms - SysTick->VAL;
  160.   if (GXT_SYSTICK_IsActiveCounterFlag()) {
  161.     m = HAL_GetTick();
  162.     u = tms - SysTick->VAL;
  163.   }
  164.   return (m * 1000 + (u * 1000) / tms);
  165. }
  166. //
  167. uint32_t micros(void)
  168. {
  169.   return getCurrentMicros();
  170. }

  171. /* USER CODE END 0 */

  172. /**
  173.   * @brief  The application entry point.
  174.   * @retval int
  175.   */
  176. int main(void)
  177. {
  178.   /* USER CODE BEGIN 1 */

  179.   /* USER CODE END 1 */

  180.   /* MCU Configuration--------------------------------------------------------*/

  181.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  182.   HAL_Init();

  183.   /* USER CODE BEGIN Init */

  184.   /* USER CODE END Init */

  185.   /* Configure the system clock */
  186.   SystemClock_Config();

  187.   /* USER CODE BEGIN SysInit */

  188.   /* USER CODE END SysInit */

  189.   /* Initialize all configured peripherals */
  190.   MX_GPIO_Init();
  191.   MX_DMA_Init();
  192.   MX_I2C1_Init();
  193.   MX_USART1_UART_Init();
  194.   MX_TIM2_Init();
  195.   MX_TIM3_Init();
  196.   MX_TIM4_Init();
  197.   /* USER CODE BEGIN 2 */

  198.   //MPU-6050 initialization
  199.   while (MPU_Init()){
  200.           //printf("MPU_Init_Fail...");
  201.   }

  202.   //Starts the TIM2 PWM.
  203.   HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);        //direction servo
  204.   HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);        //support servo
  205.   HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);        //direct motor1
  206.   HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);        //direct motor1
  207.   //Set Servo duty cycle 500~2500
  208.   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,1500);
  209.   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,500);
  210.   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3,0);
  211.   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,0);

  212.   //Starts the TIM3 PWM.
  213.   HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);        //brushless motor
  214.   //Set Brushless Motor duty cycle 0~3600
  215.   __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1,0);
  216.   HAL_GPIO_WritePin(GPIO_EN_GPIO_Port, GPIO_EN_Pin, SET);//brushless motor Enable

  217.   //Starts the TIM4 Base generation.
  218.   HAL_TIM_Base_Start_IT(&htim4);        // PID/20ms

  219.   HAL_UART_Receive_DMA(&huart1, buffer, bufferLen);
  220.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//开启空闲中断
  221.   /* USER CODE END 2 */

  222.   /* Infinite loop */
  223.   /* USER CODE BEGIN WHILE */
  224.   while (1)
  225.   {
  226.           if(startFlag||displayFlag){//遥控或调试
  227.                   /* 收起支撑 */
  228.                   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,1500);

  229.                   /* 根据上位机命令,调整运用方向和速度 */
  230.                   if (startFlag) {
  231.                           if (driveDirection == -1)//停止
  232.                           {
  233.                                   //__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,1500);
  234.                                   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3,0);//N20停止
  235.                                   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,0);
  236.                                   HAL_Delay(5);
  237.                           }
  238.                           else{
  239.                                   if(driveDirection>=180){//前进
  240.                                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,(uint16_t)(1500-500*(driveDirection-270)/90));

  241.                                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3,100*driveSpeed);//前进
  242.                                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,0);
  243.                                   }
  244.                                   else{//后退
  245.                                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,(uint16_t)(1500-500*(driveDirection-90)/90));

  246.                                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3,0);//N20后退
  247.                                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,100*driveSpeed);
  248.                                   }
  249.                           }
  250.                   }
  251.                   else{
  252.                          // __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,1500);//direction servo
  253.                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,500);//放下支撑舵机
  254.                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3,0);//N20停止
  255.                           __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,0);
  256.                           HAL_Delay(5);
  257.                   }
  258.           }
  259.           else {//停止

  260.                   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3,0);//N20电机停止
  261.                   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,0);

  262.                   __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,500);//舵机放下支撑
  263.                   //设置平衡角度,延时一段时间后关闭无刷电机
  264.                   HAL_Delay(5);
  265.           }

  266.           /* 串口通讯,发送数据至上位机 */
  267.           if (displayFlag) {
  268.                   switch ((int16_t)tempVerticalKi) {
  269.                         case 1:
  270.                                 sprintf(bufferTr, "%.1f", (double)brushless);
  271.                                 HAL_UART_Transmit_DMA(&huart1, bufferTr, strlen(bufferTr));// send brushless
  272.                                 break;
  273.                         case 2:
  274.                                 sprintf(bufferTr, "%.1f", (double)GyroY_Lowout);
  275.                                 HAL_UART_Transmit_DMA(&huart1, bufferTr, strlen(bufferTr));// send GyroY_Lowout
  276.                                 break;
  277.                         case 3:
  278.                                 sprintf(bufferTr, "%.1f", (double)Encoder_Err);
  279.                                 HAL_UART_Transmit_DMA(&huart1, bufferTr, strlen(bufferTr));// send Encoder_Err
  280.                                 break;
  281.                         case 4:
  282.                                 sprintf(bufferTr, "%.1f", (double)Encoder_Sum);
  283.                                 HAL_UART_Transmit_DMA(&huart1, bufferTr, strlen(bufferTr));// send Encoder_Sum
  284.                                 break;
  285.                         default:
  286.                                 sprintf(bufferTr, "%.1f", Pitch_Kalman);
  287.                                 HAL_UART_Transmit_DMA(&huart1, bufferTr, strlen(bufferTr));// send Pitch
  288.                                 break;
  289.                 }
  290.           }
  291.           HAL_Delay(20);

  292.     /* USER CODE END WHILE */

  293.     /* USER CODE BEGIN 3 */
  294.   }
  295.   /* USER CODE END 3 */
  296. }
复制代码
作者:DIY攻城狮

收藏 评论0 发布时间:2023-2-9 17:53

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版