技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 1761|回复: 1
收起左侧

【翻译】嵌入式设计之PID控制系统

[复制链接]

1088

主题

2606

帖子

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
236
威望
474 点
宅币
21362 个
贡献
45937 次
宅之契约
0 份
在线时间
2059 小时
注册时间
2014-1-26
发表于 2021-2-1 05:44:17 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
原文:https://tutorial.cytron.io/2012/06/22/pid-for-embedded-design/
作者:Kong Wai Weng
译者:0xAA55

PID控制系统

PID控制系统 由于其简单而有效的算法,它是目前而言最成熟也是被应用最广泛的工业控制系统之一。

本文将介绍 PID控制系统 的基础概念以及如何在嵌入式系统里将其实现。

介绍

闭环控制系统在嵌入式开发里一直都是一个关键话题,其使用 执行器传感器 ,配合软件上的算法进行工作。

其中典型例子之一是对于开环控制的情况,电机的转动速度可通过改变 PWM输出的高低电平占空比 来控制,但因为没有反馈,电机的实际转动速度是无法被确保的。

在不同的情形下,使用相同的 PWM输出值 去控制电机,得到的实际转速往往是不一样的。比如,即使是同一个 PWM输出值 ,在电机负载较低的时候,其可以达到较高的转速;反之,在负载较高的时候,其转速会降低。

此时我们应该设计闭环控制系统,通过获取反馈来得到电机的实际转速,从而合理控制 PWM输出值 来得到正确的转速。

PID控制系统 除了能控制 转速 以外,还可以控制其它各种各样的参数,比如 位置温度水位稳定性 等。

本文将介绍如何应用 PID控制系统 实现精准的 位置 控制。

开环控制的问题——直流电机转动位置的控制

在我们设计 PID控制器 前,我们需要先了解问题。在这个例子中,我们想要将电机轴从初始位置移动到目标位置。


motor_thumb.png

文中有一些常用的术语,被用于描述PID控制系统,其中主要有:

  • 控制变量 (CV) - 控制循环的输出,比如本文中用于控制电机力度的PWM信号长度。

  • 处理变量 (PV) - 控制系统传感器反馈的信息,比如本文中,电机轴的转动位置是可以被获取到的。

  • 设置点 (SP) - 我们的控制系统想要达到的目标,比如本文中电机轴的目标角度。

  • 误差 (E) - 误差指的是处理变量与设置点的差。换句话说,就是从当前位置到达目标位置之间的距离(角度)。

PID控制器的实现

PID控制器的名字里,P指的是 比例值proportional ),I指的是 积分值integral ),然后D指的是 微分值derivative )。下文将会分别介绍这三个控制系统,并会介绍其合并后的效果。

比例值控制器(P控制器)

当电机轴还远没有达到 目标位置 的时候,我们希望增加供电来让电机更快转动到 目标位置 。当电机轴靠近了 目标位置 ,我们会减少供电来让它的转动慢下来。而当电机轴到达了 目标位置 ,它应该要能停下来。如果电机轴超出了 目标位置 ,我们就得让电机反转,使其回到 目标位置

简而言之就叫 比例值控制器 ,因为我们使用 误差值 作为给电机供电的大小。

可参照以下式子理解 比例值控制器 的工作原理:

误差值 = 设置点 - 处理变量
控制变量 = Kp * 误差值

可以从下示例代码观察如何用C语言来实现 比例值控制器

// 无限循环
while(1)
{
    // 取得当前位置
    current_position = read_current_position();

    // 计算误差
    error = target_position - current_position;

    // 计算控制变量
    pwm = Kp * error;

    // 限制控制变量的范围在 +- 255 以内
    if (pwm > 255) pwm = 255;
    else if (pwm < -255) pwm = -255;

    // 如果控制变量为正,让电机顺时针转动
    if (pwm > 0) motor_cw(pwm);

    // 如果控制变量为负,让电机逆时针转动
    else if (pwm < 0) motor_ccw(-pwm);

    // 如果控制变量为零,停止转动
    else motor_stop();
}

Kp 的数值应该被小心选择以优化系统,较低的数值会让系统运行平滑但响应缓慢:


clip_image009_thumb.jpg

而较高的数值则虽然响应迅速,但会导致电机转动过头,在它稳定之前会引起振动:


clip_image011_thumb.jpg

过高的数值则会导致它反应过大、无限循环震动无法稳定下来:


clip_image013_thumb.jpg

积分值控制器(I控制器)

P控制器 的图表可以看出,当它稳定下来后,并不能到达 目标位置 。这是因为 当前位置 还没有达到 目标位置 ,但是靠近了的时候,其 误差值 过小,计算出来的 PWM输出值 让电机的力度无法对抗摩擦阻力和重力。当系统稳定下来后,这个小额的误差被称作 稳态误差


Steady-State-Error_thumb.png

为了解决 P控制器稳态误差 问题,此处引入了 I控制器 的概念。根据其名字 积分值控制器 ,它的 积分值 相当于从系统开始运行后不断累加的 误差值

积分值 = ∑(误差值)

计算的全部结果被乘以常量 Ki ,并被加到 P控制器 的输出。和 P控制器 不同, I控制器 几乎不会被单独使用,而是通常和 P控制器 或者 PD控制器 合并使用。当系统已经稳定在小数值的 稳态误差 状态后, 积分值 始终能累加 误差值 直到 控制变量 足够大,使其带动 处理变量 到达 设置点PI控制器 的公式如下:

误差值 = 设置点 - 处理变量
积分值 = 积分值 + 误差值
控制变量 = (Kp * 误差值) + (Ki * 积分值)

可以从下示例代码观察如何用C语言来实现 积分值控制器

// 无限循环
while(1)
{
    // 取得当前位置
    current_position = read_current_position();

    // 计算误差
    error = target_position - current_position;

    // 计算积分值
    integral = integral + error;

    // 计算控制变量
    pwm = (Kp * error) + (Ki * integral);

    // 限制控制变量的范围在 +- 255 以内
    if (pwm > 255) pwm = 255;
    else if (pwm < -255) pwm = -255;

    // 如果控制变量为正,让电机顺时针转动
    if (pwm > 0) motor_cw(pwm);

    // 如果控制变量为负,让电机逆时针转动
    else if (pwm < 0) motor_ccw(-pwm);

    // 如果控制变量为零,停止转动
    else motor_stop();
}

就像 P控制器Ki 的数值需要被小心选择。数值太小, 稳态误差 被纠正得太慢;数值太大,系统变得不稳定并开始振动。


clip_image019_thumb1.jpg

因为 积分值 可以在没有到达 设置点 的时候增加得特别快,有的程序在 控制变量 的数值到达 饱和值 的时候停止累加 积分值

微分值控制器(D控制器)

举个例子,比如你在驾驶一辆车,然后你想要让车尽快地做到正好停止在距离当前位置100m远的位置。如果此时你的车正在以10km每小时的速度前行,此时你会想加快速度来到达目标。而如果你的当前速度是100km每小时,你的速度太快所以你会需要开始刹车来让车能停在100m远的位置来防止冲过头。这就是 微分值控制器 所做之事。

任何数值的微分值描述其随时间改变的速度。在 PID控制系统 里, 微分值 指的是 误差值 的变化。他可以按照以下的公式来描述:

微分值 = 误差值 - 上一次的误差值

其中的 上一次的误差值 指的是上一次循环处理时的误差值。

负的 微分值 指示误差信号的改良(降低)。例如,如果上次的误差是20,而这次的误差是10, 积分值 是 -10 。当这些负值被乘上一个常数 Kd 然后加到循环的输出后,当快要达到目标位置的时候,它能让系统慢下来。

就像 I控制器 那样, D控制器 很少被单独使用,而是通常和 P控制器 或者 PI控制器 一起用。 PD控制器 的公式如下所示:

上一次的误差值 = 误差值
误差值 = 设置点 - 处理变量
微分值 = 误差值 - 上一次的误差值
控制变量 = (Kp * 误差值) + (Kd * 微分值)

对应的C代码实现如下所示:

// 无限循环
while(1)
{
    // 取得当前位置
    current_position = read_current_position();

    // 计算误差
    error = target_position - current_position;

    // 计算微分值
    derivative = error + last_error;

    // 计算控制变量
    pwm = (Kp * error) + (Kd * derivative);

    // 限制控制变量的范围在 +- 255 以内
    if (pwm > 255) pwm = 255;
    else if (pwm < -255) pwm = -255;

    // 如果控制变量为正,让电机顺时针转动
    if (pwm > 0) motor_cw(pwm);

    // 如果控制变量为负,让电机逆时针转动
    else if (pwm < 0) motor_ccw(-pwm);

    // 如果控制变量为零,停止转动
    else motor_stop();

    // 保存当前误差值用于下一次循环时使用的“上一次的误差值”
    last_error = error;
}

D控制器 的阻尼效果允许系统在拥有较高的 KpKi 值时不会冲过头。因此,它可以让系统在应对 设置点 的变化的时候有更好的反应时间。然而, Kd 的值如果过高,依然会带来反面效果。 D控制器 会在控制系统里增加反馈系统的噪音。如果 Kd 数值过大,而反馈循环有噪声,则整个系统会变得很 逗比


clip_image023_thumb1.jpg

三合一 PID控制器

通过把 P控制器I控制器D控制器 结合到一起,我们可以把每个控制器的优势都发挥出来。我们有 P控制器 的快速响应, I控制器 解决 稳态误差D控制器 添加阻尼来减少过冲。

实际上只需要把这三个控制器的数值累加起来即可,如下所示的公式:

上一次的误差值 = 误差值
误差值 = 设置点 - 处理变量
积分值 = 积分值 + 误差值
微分值 = 误差值 - 上一次的误差值
控制变量 = (Kp * 误差值) + (Ki * 积分值) + (Kd * 微分值)

对应的C代码实现如下所示:

// 无限循环
while(1)
{
    // 取得当前位置
    current_position = read_current_position();

    // 计算误差
    error = target_position - current_position;

    // 计算积分值
    integral = integral + error;

    // 计算微分值
    derivative = error + last_error;

    // 计算控制变量
    pwm = (Kp * error) + (Ki * integral) + (Kd * derivative);

    // 限制控制变量的范围在 +- 255 以内
    if (pwm > 255) pwm = 255;
    else if (pwm < -255) pwm = -255;

    // 如果控制变量为正,让电机顺时针转动
    if (pwm > 0) motor_cw(pwm);

    // 如果控制变量为负,让电机逆时针转动
    else if (pwm < 0) motor_ccw(-pwm);

    // 如果控制变量为零,停止转动
    else motor_stop();

    // 保存当前误差值用于下一次循环时使用的“上一次的误差值”
    last_error = error;
}

clip_image029_thumb1.jpg

总结

PID控制系统 是一种非常简单而又高效的控制系统,被广泛应用于工业生产。而且, PID控制系统 的实现很简单,但调整起来则不容易。调整 PID参数 的过程 ( KpKiKd)是一个不断地试错和纠正的过程。没有能直接算出这三个值的方法,除非整个系统是基于数学进行建模和模拟的。经验在这个地方是一个非常重要的方面,通过不断微调参数可以积累很多的经验。感兴趣的话请多多参与技术宅的结界的交流。

参考

http://en.wikipedia.org/wiki/PID_controller

http://www.expertune.com/tutor.html

http://www.newportus.com/products/techncal/techncal.htm

http://www.dprg.org/tutorials/2003-10a/motorcontrol.pdf





评分

参与人数 1威望 +10 宅币 +30 贡献 +10 收起 理由
watermelon + 10 + 30 + 10 赞!

查看全部评分

回复

使用道具 举报

29

主题

331

帖子

2001

积分

用户组: 上·技术宅

UID
3808
精华
11
威望
105 点
宅币
1240 个
贡献
165 次
宅之契约
0 份
在线时间
379 小时
注册时间
2018-5-6
发表于 2021-2-2 14:03:00 | 显示全部楼层
牛皮,工作量很饱满啊!
Passion Coding!

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2021-10-24 04:04 , Processed in 0.061720 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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