首页 > Udacity机器人软件工程师课程笔记(二十三) - 控制(其一)- PID控制及其python实现

Udacity机器人软件工程师课程笔记(二十三) - 控制(其一)- PID控制及其python实现

控制(Controls)

1.PID控制简介

在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。PID控制器问世至今已有近70年历史,它 以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。当被控对象的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的 其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。即当我们不完全了解一个系统和被控对象,或 不能通过有效的测量手段来获得系统参数时,最适合用PID控制技术。PID控制,实际中也有PI和PD控制。PID控制器就是根据系统的误差,利用比例、 积分、微分计算出控制量进行控制的。

在这里插入图片描述

在这里插入图片描述

比例(P)控制

比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差(Steady-state error)。

积分(I)控制

在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的 或简称有差系统(System with Steady-state Error)。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积 分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到接近于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后几乎无稳 态误差。

微分(D)控制

在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用, 其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入 “比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能 够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在 调节过程中的动态特性。

2.PID控制模拟器

这里给出了两个图表。

第一个图是四旋翼的高度与时间的关系图。可以看到我们也画出了10米的设定点。最终的目标是尽可能快地达到这个设定值,并保持最小的振荡和超调。

第二张图是四轴飞行器对时间的速度。理想的情况是,在到达设定值之前,速度增加,到达设定值之后,速度迅速下降,保证四轴飞行器稳定在设定高度。

在这里,我们看到对四轴飞行器施加了1.7的连续控制力。我们可以看到这不是一个好的解决方案,因为四轴飞行器将继续上升超过设定点。我们将构建一个更好的控制器,使之控制工作时的波动,以使我们保持在设定点。

在这里插入图片描述

我们将使用的下一个图表是控制工作量与时间的关系。控制力是执行器为达到设定点而需要施加的力。理想情况下,对于一个良好的控制器,它不包括初始致动以达到设定点,我们希望通过配备一个调整良好的控制器来最大程度地减少控制工作量。

在这里,我们可以看到一直处于1.7的控制之下,它从未被最小化,这是我们需要解决的问题。

首先来看下面三个代码库,熟悉代码库将会有助于接下来的任务。由于我没有使用虚拟机,而是使用了pycharm。所以需要将hover_plot.py等文件所在的路径添加进系统的环境变量中,然后程序才可以运行。

编辑系统环境变量

hover_plot.py:

import numpy as np
import matplotlib.pyplot as plt
from open_controller import Open_Controller
from quad1d_eom import ydot##################################################################################
# 应用一个值为1.7的恒定的作用力。
control_effort = 1.7
################################################################################### 仿真参数
N = 500  # 仿真的点数
t0 = 0  # 起始时间(sec)
tf = 30  # 结束时间(sec)
time = np.linspace(t0, tf, N)
dt = time[1] - time[0]  # delta t, (sec)##################################################################################
# 核心仿真代码
# 初始条件 (i.e., 初始状态向量)
y = [0, 0]#y[0] = initial altitude, (m)#y[1] = initial speed, (m/s)# 初始化数组以存储值
soln = np.zeros((len(time), len(y)))# 创建Open_Controller类的实例
controller = Open_Controller()# 设置作用力
controller.setControlEffort(control_effort)# 设定高度目标
r = 10  # meters
controller.setTarget(r)# 模拟四轴运动
j = 0  # 计数器
for t in time:# 评估下一个时间点的状态y = ydot(y, t, controller)# 储存结果soln[j, :] = yj += 1##################################################################################
# 绘制结果
# 图一:四轴飞行器高度随时间的变化的曲线
SP = np.ones_like(time)*r  # 高度设置点
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(time, soln[:, 0], time, SP, '--')
ax1.set_xlabel('Time, (sec)')
ax1.set_ylabel('Altitude, (m)')# 图二:这是四轴直升机的速度随时间的变化曲线
ax2 = fig.add_subplot(212)
ax2.plot(time, soln[:, 1])
ax2.set_xlabel('Time, (sec)')
ax2.set_ylabel('Speed, (m/s)')
plt.tight_layout()
plt.show()# 图三:这是四轴直升机的作用力随时间变化的曲线
fig2 = plt.figure()
ax3 = fig2.add_subplot(111)
ax3.plot(time, controller.effort_applied, label='effort', linewidth=3, color = 'red')
ax3.set_xlabel('Time, (sec)')
ax3.set_ylabel('Control Effort')
h, l = ax3.get_legend_handles_labels()
ax3.legend(h, l)
plt.tight_layout()
plt.show()
##################
y0 = soln[:, 0]  # 高度
rise_time_index = np.argmax(y0>r)
RT = time[rise_time_index]
print("The rise time is {0:.3f} seconds".format(RT))OS = (np.max(y0) - r)/r*100
if OS < 0:OS = 0
print("The percent overshoot is {0:.1f}%".format(OS))print("The offset from the target at 30 seconds is {0:.3f} meters".format(abs(soln[-1, 0]-r)))

open_controller.py:

##################################################################################
# 这是控制类,我们将在接下来对其进行更改。
################################################################################### 创建一个Open_Controller类
class Open_Controller:# 定义类的初始化序列def __init__(self, start_time=0):# 创建一个类变量来存储启动时间self.start_time_ = start_time# 创建一个类变量来存储作用力self.u = 0# 创建一个类变量来存储最后的时间戳self.last_timestamp_ = 0# 创建一个类变量来存储设置点self.set_point_ = 0# 为所有应用的控制工作创建一个类变量self.effort_applied = []# 设置高度设置点def setTarget(self, target):self.set_point_ = float(target)# 设置所需的作用力def setControlEffort(self, control_effort):self.u = float(control_effort)# 检索当前控制工作效果def getControlEffort(self, time):# 存储最后的时间戳self.last_timestamp_ = time# 储存作用力self.effort_applied.append(self.u)return self.u

quad1d_eom.py

import numpy as np
import matplotlib.pyplot as plt
from open_controller import Open_Controller##################################################################################
# DO NOT MODIFY ANY PORTION OF THIS FILE
# 这个文件代表了一维四旋翼的动力学方程
##################################################################################def ydot(y, t, controller):'''返回下一个时间步长的状态向量参数:----------y(k) = 状态向量, a length 2 list= [高度, 速度]t = time, (sec)pid = PID Controller类的实例return-------y(k+1) = [y[0], y[1]] = y(k) + ydot*dt'''# 模型状态y0 = y[0]  # 高度, (m)y1 = y[1]  # 速度, (m/s)# 模型参数g = -9.81  # 重力, m/s/sm =  1.54  # 四轴飞行器重量, kgc =  10.0  # 机电系统的传输常数# 时间步长, (sec)dt = t - controller.last_timestamp_# 作用力u = controller.getControlEffort(t)# State derivativesif (y0 <= 0.):# 如果控制输入,u <=重力,飞行器在地面上保持静止,这样可以防止四旋翼在推力太小时“坠落”地面。if u <= np.absolute(g*m/c):y0dot = 0.y1dot = 0.else:  # 否则,如果u>重力,则四轴加速向上y0dot = y1y1dot = g + c/m*u - 0.75*y1else:  # 或者四轴飞行器已经升空# y0dot为速度大小y0dot = y1# y1dot为加速度大小,其中0.75*y1为阻力大小y1dot = g + c/m*u - 0.75*y1y0 += y0dot*dty1 += y1dot*dtreturn [y0, y1]

运行hover_plot.py输出如下:

在这里插入图片描述

其实原本输出两个图的,我稍微改了一下程序,让三个图输出在一个图中,这三张图和前面给出的图是一样的。

3.比例控制

(1)比例控制介绍

假设四旋翼飞机的传感器可以完美地测量其高度,也许可以使用气压计,GPS或超声波传感器。最初,四旋翼飞行器已通电,但静止不动在启动板上。激活后,预编程的飞行路径将使四旋翼飞行器最大上升至10米,将其悬停在原处5秒钟,然后在保持恒定高度的情况下向东北方向行驶。

在四旋翼飞机开始执行飞行计划的第一瞬间,高度误差为:

e(t)=r−y(t)e(t) ,= r-y(t)e(t)=ry(t)

=10m−0qquad =10m-0=10m0

=10mqquad=10m=10m

控制器感应到较大的误差,并命令电动机产生与误差成正比的垂直推力,即

u(t)=Kp∗e(t)u(t)=K_p*e(t)u(t)=Kpe(t)

当四旋翼飞机接近所需高度时,误差减小,因此控制器输入也减小。

比例增益如何放大“当前”(当前时间步长)误差,而不考虑过去或将来的误差。

许多现实世界的系统都由二阶微分方程控制,并且在设置为某个稳态值之前,会对阶跃输入表现出振荡响应。此振荡响应的主要特征如下所示:

在这里插入图片描述

  • Rise time (上升时间)TrT_rTr ,是响应从指定的低值移动到指定的高值所需的时间,通常表示为最终值的百分比。例如,其最终(稳态)值的0%到100%。

  • Peak time(峰值时间)TpT_pTp,达到第一个超调的峰值需要时间

  • Maximum percent overshoot (最大超调量):MOS=y(Tp)−y(Tss)y(Tss)×100%M_{OS}=frac{y(T_p)-y(T_{ss})}{y(T_{ss})} imes100\%MOS=y(Tss)y(Tp

    更多相关:

    • 如果你想从头学习Jmeter,可以看看这个系列的文章哦Charts 介绍包含了各种详细信息图表,比 GUI 模式的图表好看且易懂多了!做性能测试,如何发现是否有性能瓶颈?必须从结果图表中找到鸭!而 html 报告将性能测试可能需要用到的图表都加进去了,可谓是6666一共有三大模块Over TimeThroughputResponse...

    • 搞了很多年c/c++,有很多细小的东西,曾经不止一次遇到,可是一直都是放在零散的地方,要用的时候怎么也找不到,今天,我痛下决心,改掉不良习惯,把这些经验或是tips记录在这里,便于日后查找。 1.在统计网络下载信息时,如何表达文件大小? 下面是输出结果 2.打印size_t类型数据的长度,使用%lu。 下面是一个使...

    • 1,解决的问题。 2.如何实现。 面对大流量网站频繁访问数据库的一种优化,比如博客网站。不可能每个人查看都访问一次数据库。为了解决大量不必要访问的问题。 可以把第一次的内容保存为html页面。再以后定义的过期时间内都访问该静态页面。 以下是一个小的demo index.php来实现静态化的主要工作。 1

    • 什么?有个 SQL 执行了 8 秒! 哪里出了问题?臣妾不知道啊,得找 DBA 啊。 DBA 人呢?离职了!!擦!!! 程序员在无处寻求帮助时,就得想办法自救,努力让自己变成 "伪 DBA"。 索引 按页编号查看数据表信息获取查询 SELECT 语句的执行次数排名看看哪些 Ad-hoc Query 在浪费资源查看当前处于等待状态的 T...

    • 生成分析文件 命令行运行: valgrind --tool=callgrind ./palmGateMachine 检测完毕之后会生成一个文件callgrind.out.26805, 后面的数字其实是这个待测进程的pid 可视化方法 可视化方法 可视化工具 kcachegrind 1、下载地址: https://launchp...

    • MQTT 心跳和keepalive配置 内容: 正常MQTT 服务器端会配置一个超时时间,一般为60s, 在这个时间段内一个连接如果没有数据传输的话,服务端会主动断开连接以释放资源, 有两种方式可以规避这个问题: 方式1: 最为简单, 将keepalive的时间设置小于 服务端的超时时间,则客户端每隔 keepalive的时间就...

    • 概述 我们用jmeter做性能测试,必然需要学会分析测试报告。但是初学者常常因为对概念的不清晰,最后被测试报告带到沟里去。   常见的误区 分析响应时间全用平均值响应时间不和吞吐量挂钩响应时间和吞吐量不和成功率挂钩。。。。。   平均值特别不靠谱 平均值为什么不靠谱?相信大家读新闻的时候经常可以看到,平均工资,平均房价,平均支出,等等...

    • 原文: https://mp.weixin.qq.com/s/Dns-ucDwuDeR7lNSlibyAA 放假通知   今年7月1日放暑假 9月2日开学   今天,省教育厅发布通知,2019年全省中小学幼儿园暑期放假时间统一为7月1日,秋季开学时间9月2日。2020年寒假放假时间为1月18日,春季开学时间为2月10日。 刚刚...

    • 1. P117页,练习15:最高响应比 HRRF: 作业 提交时刻 运行时刻 开始时刻 完成时刻 周转时间/min 带权周转时间/min 1 10:00 2:00 10:00 12:00 120 120/120 2 10:10 1:00 12:25 13:25 195 195/60 3 1...