• 二轮平衡小车3:PID速度环


    使用芯片:STM32 F103 C8T6

    今日继续我的二路平衡小车开发之路,今日编写的是二轮平衡小车的PID速度环,我准备了纸飞机串口助手软件来辅助测试调节PID。

    本文主要贴代码,之前的文章都有原理,代码中相应初始化驱动部分也有注释~~

    文章提供源码,解释以及工程下载,测试效果视频。

    PID基础概念:

     这里简单介绍一下PID算法是反馈调节的算法,只需输入期望值与传感器反馈值即可实现自动调节电机PWM控制速度始终在期望值附近,即:反馈小了就加占空比,反馈大了就减占空比,但却不是简单的加减运算。

    原理之前写过,这里直接贴出文章连接:

    PID输出反馈回路调控算法原理_NULL指向我的博客-CSDN博客

    编码器测速逻辑:

    此处贴出函数,相关逻辑在之前的文章讲过:

    MSP432自主开发笔记1:编码器测速_外部中断捕获法测速\测正反转_msp432编码器_NULL指向我的博客-CSDN博客

    对于速度单位的理解与计算有各种各样,有喜欢算到  (cm/s) (m / s)  (rad / second )等等,需要通过不同电机转速,需求来选定。

    这里我是用的电机减速比比较大,扭矩与载重大,但因此转速就慢,因此我采用每25ms采样的脉冲数作为速度来比较,使速度环闭合。

    1. //定时器3中断服务程序 (编码器捕获脉冲数)
    2. void TIM3_IRQHandler(void)
    3. {
    4. if(TIM_GetITStatus(TIM3, TIM_IT_CC1)) //通道1发生捕获事件
    5. {
    6. Wheel[2].CAPTURE++;
    7. TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);} //每次进入中断都要清空中断标志,否则主函数将无法正常执行
    8. if(TIM_GetITStatus(TIM3, TIM_IT_CC2)) //通道2发生捕获事件
    9. {Wheel[2].CAPTURE++;
    10. TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);} //每次进入中断都要清空中断标志,否则主函数将无法正常执行
    11. if(TIM_GetITStatus(TIM3, TIM_IT_CC3)) //通道3发生捕获事件
    12. {Wheel[1].CAPTURE++;
    13. TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);} //每次进入中断都要清空中断标志,否则主函数将无法正常执行
    14. if(TIM_GetITStatus(TIM3, TIM_IT_CC4)) //通道4发生捕获事件
    15. {Wheel[1].CAPTURE++;
    16. TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);} //每次进入中断都要清空中断标志,否则主函数将无法正常执行
    17. }
    18. void calculate_speed(void)
    19. {
    20. uint16_t tt;
    21. tt=50;
    22. if(SPEED_flag==1)
    23. {
    24. SPEED_flag=0;
    25. Wheel[1].SPEED=Wheel[1].CAPTURE;
    26. Wheel[2].SPEED=Wheel[2].CAPTURE;
    27. // printf("V1=%d,V2=%d\r\n",Wheel[1].SPEED,Wheel[2].SPEED);
    28. printf("P1=%d,P2=%d\r\n",Wheel[1].PWM_DIV,Wheel[2].PWM_DIV);
    29. PRINT(plotter, "%d, %d, %d",Wheel[1].SPEED,Wheel[2].SPEED,tt);
    30. PID_guide_peed(tt,tt);
    31. set_wheels(Wheel[1].PWM_DIV,Wheel[2].PWM_DIV,1,1);
    32. Wheel[1].CAPTURE=0; Wheel[2].CAPTURE=0;
    33. }
    34. }

    PID算法贴出:

     参数需要自己调,玄学调参......

    1. #include "PID.h"
    2. PID_TYPE suduhuan1;
    3. PID_TYPE suduhuan2;
    4. //PID 1~4号轮设置期望速度
    5. void PID_guide_peed(uint16_t w1,uint16_t w2)
    6. {
    7. Pid_increment_Cal(&suduhuan1,w1,Wheel[1].SPEED);
    8. Pid_increment_Cal(&suduhuan2,w2,Wheel[2].SPEED);
    9. Wheel[1].PWM_DIV=suduhuan1.OutPut;
    10. Wheel[2].PWM_DIV=suduhuan2.OutPut;
    11. }
    12. PID_结构体 target_目标 measure_当前值
    13. void Pid_increment_Cal(PID_TYPE *PID, int target, int measure)
    14. {
    15. PID->Error = target - measure; // 误差
    16. PID->Pout = PID->P * (PID->Error - PID->PreError); // 比例控制
    17. PID->Iout = PID->I * PID->Error; // 积分控制
    18. PID->Dout = PID->D * (PID->Error - 2 * PID->PreError + PID->PrePreError); // 微分控制
    19. // 比例 + 积分 + 微分总控制
    20. if (PID->Iout > PID->Irang) // 积分限幅
    21. PID->Iout = PID->Irang;
    22. if (PID->Iout < -PID->Irang) // 积分限幅
    23. PID->Iout = -PID->Irang;
    24. PID->OutPut += PID->Pout + PID->Iout + PID->Dout;
    25. PID->PrePreError = PID->PreError; // 记忆e(k-2)
    26. PID->PreError = PID->Error; // 记忆e(k-1)
    27. }
    28. void PidParameter_init(void)
    29. {
    30. suduhuan1.P =38;
    31. suduhuan1.I=18;
    32. suduhuan1.D=0;
    33. suduhuan1.PreError=0;
    34. suduhuan1.PrePreError=0;
    35. suduhuan1.Irang=12;
    36. suduhuan1.OutPut=0;
    37. suduhuan2.P =38;
    38. suduhuan2.I=18;
    39. suduhuan2.D=0;
    40. suduhuan2.PreError=0;
    41. suduhuan2.PrePreError=0;
    42. suduhuan2.Irang=12;
    43. suduhuan2.OutPut=0;
    44. }
    1. #ifndef _PID_H_
    2. #define _PID_H_
    3. #include "headfire.h"
    4. typedef struct PID
    5. {
    6. int P; //参数
    7. int I;
    8. int D;
    9. float Error; //比例项e(k)
    10. float Integral; //积分项
    11. int Differ; //微分项
    12. int PreError; //e(k-1)
    13. int PrePreError;//e(k-2)
    14. float Ilimit;
    15. float Irang;
    16. int Pout;
    17. int Iout;
    18. int Dout;
    19. int OutPut;
    20. uint8_t Ilimit_flag; //积分分离
    21. }PID_TYPE;
    22. extern PID_TYPE suduhuan1;
    23. extern PID_TYPE suduhuan2;
    24. PID_结构体 target_目标 measure_当前值
    25. void Pid_increment_Cal(PID_TYPE *PID, int target, int measure);
    26. void PidParameter_init(void); //PID参数初始化
    27. //PID 设置期望速度
    28. void PID_guide_peed(uint16_t w1,uint16_t w2);
    29. #endif

  • 相关阅读:
    怎么将自己拍摄的视频静音?详细步骤教会你~
    什么灯适合学生在暑假使用?照度国AA级的舒适护眼灯
    方法递归(黑马)
    sql常用语法记录
    springMVC执行流程详解
    医学YOLOv8 | 脑肿瘤检测 Accuracy 99%
    工控机通过Profinet转Modbus RTU网关连接变频器与电机通讯案例
    网站AI客服,提升现代企业客户服务的利器
    Delphi : 在 SDK 管理器中添加其他 iOS 框架
    ES6 入门教程 26 编程风格 26.7 Map 结构 & 26.8 Class & 26.9 模块 & 26.10 ESLint 的使用
  • 原文地址:https://blog.csdn.net/qq_64257614/article/details/132645179