• PID控制算法介绍及使用举例


    PID 控制算法是一种常用的反馈控制算法,用于控制系统的稳定性和精度。PID 分别代表比例(Proportional)、积分(Integral)和微分(Derivative),通过组合这三个部分来调节控制输出,以使系统的实际输出值尽可能接近预期的参考值。

    算法介绍

    PID(比例-积分-微分)控制算法是一种广泛使用的控制算法,用于调节系统的输出以匹配所需的参考输入。PID 控制器基于三个基本组件来计算其控制输出:比例(Proportional)、积分(Integral)和微分(Derivative)。

    1. 比例(P)控制
      • 比例控制是最简单的控制形式。控制器的输出是输入误差的一个比例。误差是参考输入与实际系统输出之间的差异。
      • 比例控制可以快速响应误差,但它不能消除稳态误差(即系统稳定后仍然存在的误差)。
      • 如果比例系数设置得太大,系统可能会变得不稳定,出现振荡。
    2. 积分(I)控制
      • 积分控制考虑了过去的误差。它通过对误差进行积分来消除稳态误差。
      • 积分控制有助于减小系统稳定后的误差,但也可能导致系统响应变慢,并可能增加超调(即系统输出超过参考输入的情况)。
      • 如果积分系数设置得太大,系统可能变得对扰动非常敏感,甚至可能产生积分饱和现象(即积分项累积到过大,导致系统响应异常)。
    3. 微分(D)控制
      • 微分控制基于误差的变化率来预测未来的误差,并据此调整控制输出。
      • 微分控制有助于加快系统的响应速度,减少超调,并增加系统的稳定性。
      • 然而,微分控制对噪声非常敏感,因为噪声通常会导致误差的突然变化,这可能被误认为是误差的变化率。

    PID 的基本公式:

    Output = K_p * Error + K_i * Integral(Error) + K_d * Derivative(Error)

    其中,Error 表示期望值与实际值之间的偏差,(K_p)、(K_i) 和 (K_d) 分别表示比例、积分和微分部分的系数。如何使用 PID 控制算法:

    1. 确定系统模型和参数 在应用 PID 控制算法前,需要确定控制对象的数学模型和相关参数,例如比例系数 (K_p)、积分时间 (T_i)、微分时间 (T_d) 等。

    2. 实现 PID 控制器 在代码中实现 PID 控制器,通常需要记录上一次的误差值以及积分值,以便计算出下一次的控制输出。

     

    PID 控制器的调整

    调整 PID 控制器的参数(即 K_pK_i 和 K_d)是 PID 控制中的关键任务。这通常涉及到一些试验和误差调整,或者使用更先进的调优方法。

    对不同工况和“场景”下往往需要设置不同的PID形式,不同的PID参数达到预期控制效果,其实就是需要人工经验设定规则来适应不同工况,所以不能算是自动的控制;相信用过PID的都知道一套口诀,在实际调参依赖口诀调参,然后调出一个理想的控制曲线,调参过程依赖人工。

    也可以借助野火的 PID调试助手工具来调试pid的参数。

    代码示例 

    1. class PIDController {
    2. public:
    3. double compute(double setpoint, double measurement) {
    4. double error = setpoint - measurement;
    5. integral += error * dt;
    6. derivative = (error - prevError) / dt;
    7. output = Kp * error + Ki * integral + Kd * derivative;
    8. prevError = error;
    9. return output;
    10. }
    11. private:
    12. double Kp = 1.0;
    13. double Ki = 0.1;
    14. double Kd = 0.01;
    15. double integral = 0.0;
    16. double derivative = 0.0;
    17. double prevError = 0.0;
    18. double output = 0.0;
    19. double dt = 0.1; // 采样时间
    20. };
    1. 调试和调整参数 调试 PID 控制器需要不断调整参数,观察实际输出值与期望值之间的偏差,逐步优化参数,以实现系统的稳定控制。

    2. 实时应用 在实际控制系统中,将计算得到的 PID 控制器的输出值应用到相应的执行机构或系统中,以实现期望的控制效果。

    以下是一个简单的 C++ 示例,演示如何实现一个基本的 PID 控制器,并在一个简单的模拟系统中应用该控制器。这个例子中,模拟一个以恒定速度运动的小车,通过 PID 控制器调节小车的速度,使其尽快达到期望速度。注意,这只是一个简单的演示,实际系统中可能需要更复杂的控制逻辑和参数调整。

    1. #include
    2. class PIDController {
    3. public:
    4. PIDController(double kp, double ki, double kd, double dt) : Kp(kp), Ki(ki), Kd(kd), dt(dt) {}
    5. double compute(double setpoint, double measurement) {
    6. double error = setpoint - measurement;
    7. integral += error * dt;
    8. derivative = (error - prevError) / dt;
    9. output = Kp * error + Ki * integral + Kd * derivative;
    10. prevError = error;
    11. return output;
    12. }
    13. private:
    14. double Kp;
    15. double Ki;
    16. double Kd;
    17. double dt;
    18. double integral = 0.0;
    19. double derivative = 0.0;
    20. double prevError = 0.0;
    21. double output = 0.0;
    22. };
    23. class Car {
    24. public:
    25. void setSpeed(double speed) {
    26. currentSpeed = speed;
    27. }
    28. void update() {
    29. // 模拟小车运动,这里假设小车以固定加速度加速到目标速度
    30. currentSpeed += acceleration;
    31. std::cout << "Current speed: " << currentSpeed << std::endl;
    32. }
    33. double getSpeed() const {
    34. return currentSpeed;
    35. }
    36. private:
    37. double currentSpeed = 0.0;
    38. double acceleration = 0.1;
    39. };
    40. int main() {
    41. PIDController pid(0.5, 0.01, 0.1, 0.1); // 设置 PID 控制器的参数
    42. Car car;
    43. double targetSpeed = 10.0; // 设置目标速度
    44. for (int i = 0; i < 100; ++i) {
    45. double speedError = targetSpeed - car.getSpeed();
    46. double controlOutput = pid.compute(targetSpeed, car.getSpeed());
    47. std::cout << "speedError: " << speedError << std::endl;
    48. std::cout << "controlOutput: " << controlOutput << std::endl;
    49. car.setSpeed(9+i/50.0); // 应用控制输出调节小车速度
    50. car.update();
    51. }
    52. return 0;
    53. }

    在这个简单的示例中,创建了一个 PIDController 类来模拟 PID 控制器的行为,然后创建了一个 Car 类来模拟一个运动的小车。在主函数中,设置 PID 控制器的参数,并循环调用 PID 控制器来调节小车的速度,直到达到目标速度为止。

    注意,实际的 PID 控制器需要根据具体的控制对象和系统需求进行调整和优化。

    c语言实现

    1. #include "pid.h"
    2. /**************************************************************
    3. *批量复位PID函数
    4. * @param[in]
    5. * @param[out]
    6. * @return
    7. ***************************************************************/
    8. void pidRest(PidObject **pid,const uint8_t len)
    9. {
    10. uint8_t i;
    11. for(i=0;i
    12. {
    13. pid[i]->integ = 0;
    14. pid[i]->prevError = 0;
    15. pid[i]->out = 0;
    16. pid[i]->offset = 0;
    17. }
    18. }
    19. /**************************************************************
    20. * Update the PID parameters.
    21. *
    22. * @param[in] pid A pointer to the pid object.
    23. * @param[in] measured The measured value
    24. * @param[in] updateError Set to TRUE if error should be calculated.
    25. * Set to False if pidSetError() has been used.
    26. * @return PID algorithm output
    27. ***************************************************************/
    28. void pidUpdate(PidObject* pid,const float dt)
    29. {
    30. float error;
    31. float deriv;
    32. error = pid->desired - pid->measured + pid->offset; //当前角度与实际角度的误差
    33. pid->integ += error * dt; //误差积分累加值
    34. // pid->integ = LIMIT(pid->integ,pid->IntegLimitLow,pid->IntegLimitHigh); //进行积分限幅
    35. deriv = (error - pid->prevError)/dt; //前后两次误差做微分
    36. pid->out = pid->kp * error + pid->ki * pid->integ + pid->kd * deriv;//PID输出
    37. //pid->out = LIMIT(pid->out,pid->OutLimitLow,pid->OutLimitHigh); //输出限幅
    38. pid->prevError = error; //更新上次的误差
    39. }
    40. /**************************************************************
    41. * CascadePID
    42. * @param[in]
    43. * @param[out]
    44. * @return
    45. ***************************************************************/
    46. void CascadePID(PidObject* pidRate,PidObject* pidAngE,const float dt) //串级PID
    47. {
    48. pidUpdate(pidAngE,dt); //先计算外环
    49. pidRate->desired = pidAngE->out;
    50. pidUpdate(pidRate,dt); //再计算内环
    51. }

    应用示例

    1. #include "pid.h"
    2. #include
    3. int main()
    4. {
    5. printf("hello pid test \n");
    6. float target_water_level = 100.0; // 目标水位10L
    7. float feedback_water_level = 0.0; // 初始水位0L
    8. PidObject pidRate;
    9. PidObject *pPidObject[]={&pidRate};
    10. pidRest(pPidObject,1);
    11. pidRate.kp = 0.1f; // 比例系数
    12. pidRate.ki = 0.01f; // 积分系数
    13. pidRate.kd = 0.05f; // 微分系数
    14. float dt = 0.003;// 3ms 采样时间
    15. pidRate.measured = 0;
    16. pidRate.desired = 100.00; //控制期望值 10L
    17. // 模拟控制循环
    18. for (int i = 0; i < 100; i++) { // 模拟水位反馈
    19. pidUpdate(&pidRate,dt); //pid处理
    20. feedback_water_level = 91+i/50.00; // 模拟每次循环水位波动 (传感器水位采集反馈值)
    21. pidRate.measured = feedback_water_level;
    22. //pidRate.desired = pidRate.out;
    23. // 输出当前水位和阀门开度补偿值
    24. printf("Feedback Water Level: %.2fL, Valve Openness: %.2f\n", feedback_water_level, pidRate.out);
    25. }
    26. return 0;
    27. }

    为什么pwm可以调速

    pwm占空比就是一个脉冲周期内有效电平在整个周期所占的比例。

    通过调节PWM的占空比就能调节IO口上电压的持续性变化,因此也能够控制外设的功率进行持续性变化,也就能控制直流电机的转速快慢。

    一种情况,对于电阻,直流电机来说,有占空比虽然从微观来说是波,但从宏观来说,就相当于将输入电压打个折扣再输出,输入5伏,占空比是50%,那么输出就是2.5伏,一般来说,直流电机的转速是和其输入电压成正比的。

    还有种情况,就是通过连续改变PWM的占空比,将直流电切成大小不一,有规律的波形,宏观上形成不同频率的正弦波,这就叫斩波。通过斩波可以产生任意频率的交流电。

    其他资源

    PID算法详解及实例分析_pid控制原理详解及实例说明-CSDN博客

    一文搞懂PID控制算法_pid算法-CSDN博客

    什么是PID控制?

    PWM原理 PWM频率与占空比详解-CSDN博客

    电机控制进阶——PID速度控制 - 知乎

    通俗易懂!讲解PID! - 知乎

    编码器计数原理与电机测速原理——多图解析 - 知乎

    电机PID控制补充篇-野火上位机串口协议介绍 - 知乎

    电机控制进阶——PID速度控制

    野火串口调试助手PID功能(文末有工程链接)_野火多功能调试助手-CSDN博客

  • 相关阅读:
    1.HTML-HTML解决中文乱码问题
    【分享】一个神经网络(层数+类型)在线测试 平台
    springboot+jsp+ssm高校图书馆图书借阅收藏评论管理系统617w1
    Linux常用命令——cmp命令
    【java】【SpringBoot】【四】原理篇 bean、starter、核心原理
    卷积神经网络 - Keras入门与残差网络的搭建
    代码随想录算法训练营第三天| 203.移除链表元素 , 707.设计链表 , 206.反转链表
    Deep Learning-Based Object Pose Estimation:A Comprehensive Survey
    LabVIEW使用Deskto pExecution Trace工具包
    图像处理:Python使用OpenCV进行图像锐化 (非锐化掩模、拉普拉斯滤波器)
  • 原文地址:https://blog.csdn.net/qq8864/article/details/138218490