0
点赞
收藏
分享

微信扫一扫

《DMF407电机控制专题教程》第9章 PID参数整定

第9章 PID参数整定​


本章我们主要来学习PID算法的参数整定,在上一章节中我们有提到,每一个系统的PID系数并不是通用的,在不同的系统中运用同样的PID系数,其最终所体现的效果可能是相差甚远的,因此,我们需要根据实际的系统进行PID的参数整定(调参)

本章分为如下几个小节:

9.1 采样周期选择

9.2 PID参数整定

9.3正点原子PID上位机介绍


9.1 采样周期选择

采样周期指的是PID控制中实际值的采样时间间隔,其越短,效果越趋于连续,但对硬件资源的占用也越高。在实际的应用中,我们可以使用理论或者经验方法来确定采样周期:

① 理论方法:香农采样定理。这个定理可以用来确定采样周期可选择的最大值,当采样周期超出了这个最大的允许范围,我们所得到的信号就会失真,也就无法较好地还原信号了。香农采样定理的具体原理我们不展开介绍,感兴趣的朋友可以去查找相关的资料,我们这里重点关注经验方法。

② 经验方法:根据控制对象突变能力选择。假设电机当前转速为20RPM,我们需要提高它的转速到30RPM,此电机的转速在1s之内最大可以突变10RPM(即电机速度的突变能力),如果我们每1ms采集一次电机转速,那么每一次采集到的速度变化量最大为10RPM / 1000 = 0.01RPM,很明显,此时最大的变化量远远小于当前的速度,这对于我们的PID控制效果并没有明显的提升,但是却占用了很多的硬件资源,因此,我们需要根据控制对象的突变能力来选择采样周期。

9.2 PID参数整定方法

PID参数整定的方法很多,概括起来有两大类,如表9.2.1所示:

理论计算整定法

工程整定法

数学模型

试凑法、临界比例法、一般调节法

9.2.1 PID参数整定方法

理论计算整定法依据系统的数学模型,经过理论计算确定PID参数。这种方法是建立在理想化条件下的,其得到的参数不一定能够直接使用,需要结合经验以及实际的系统进行调整。

工程整定法工程经验,直接在控制系统的试验中进行整定方法易于掌握,在实际调参中被广泛采用。工程整定法包括:试凑法、临界比例法和一般调节法。

注意无论采用哪一种方法所得到的PID参数,都需要在实际运行中进行最后调整与完善,因此,在PID参数整定中,最重要的就是经验的积累

接下来我们了解一下PID各个系数调节的效果,这样才能做到在PID调参中有的放矢。

比例系数:调节作用快,系统一出现偏差,调节器立即将偏差放大输出。

积分系数:积分系数的调节会改变输入偏差对于系统输出的影响程度。积分系数越大,消除静差的时间越短,但是过大的积分系数则会导致系统出现超调现象,这在具有惯性的系统中尤为明显。

③ 微分系数:微分系数的调节是偏差变化量对于系统输出的影响程度。微分系数越大,系统对于偏差量的变化越敏感,越能提前响应,进而抑制超调,但是过大的微分系数则会让整个系统出现振荡。

9.2.1 试凑法

1)内容:结合系统的具体情况以及经验,先试凑几组合理的PID系数,同时需要观察系统的曲线变化,确定每一个系数对于整个系统曲线的大致影响,然后再根据具体的曲线进行调整。

2)调节思路

先是比例(P),再积分(I),最后是微分(D);

按纯比例系统整定比例系数,使其得到比较理想的调节过程曲线,然后再把比例系数缩小1.2倍左右,将积分系数从小到大改变,使其得到较好的调节过程曲线;

在这个积分系数下重新改变比例系数,再看调节过程曲线有无改善;

如有改善,可将原整定的比例系数减少,改变积分系数,这样多次的反复,就可得到合适的比例系数和积分系数;

如果存在外界的干扰,系统的稳定性不好,可把比例、积分系数适当减小,使系统足够稳定;

⑥ 如果系统存在小幅度超调,可以将整定好的比例系数和积分系数适当减小,增大微分系数,以得到超调量最小、调节作用时间最短的系统曲线;

9.2.2 临界比例法

1)内容:在闭环的控制系统里,将调节器置于纯比例作用下,从小到大逐渐调节比例系数,直到系统曲线出现等幅振荡,再根据经验公式计算参数。

2)调节思路:

① 将积分、微分系数置零,比例度取适当值,平衡操作一段时间,使控制系统按纯比例作用的方式投入运行。

② 慢慢地增大比例系数,细心观察曲线的变化情况。如果控制过程的曲线波动是衰减的,则把比例系数继续增大;如果曲线波动是发散的,则应把比例系数减小,直至曲线波动呈等幅振荡,此时记下临界比例系数δK和临界振荡周期Tk的值。

③ 根据记下的比例系数和周期,采用经验公式,计算调节器的参数。

参与控制的环节

Kp

Ki

Kd

P

δK/2

0

0

PI

δK/2.2

Kp/(0.833·Tk)

0

PID

δK/1.7

Kp/(0.5·Tk)

0.125·TKp

9.2.2.1 临界比例法参数表

9.2.3 一般调节法​

1)内容:这种方法针对一般的 PID 控制系统所以称之为一般调节法。

2)调节思路

① 首先将积分、微分系数置零,使系统为纯比例控制。控制对象的值设定为系统允许的最大值的60%~70%,接着逐渐增大比例系数,直至系统出现振荡;此时再逐渐减小比例系数,直至系统振荡消失,然后记录此时的比例系数,并设定系统的比例系数为当前值的 60%~70%。

确定比例系数后,设定一个较小的积分系数,然后逐渐增大积分系数,直至系统出现振荡;此时在逐渐减小积分系数,直至系统振荡消失,然后记录此时的积分系数,并设定系统的积分系数为当前值的55%~65%。

③ 微分系数一般不用设定,为 0 即可。若系统出现小幅度振荡,并且通过PI环节无法优化,这可以采用与确定比例、积分系数相同的方法,微分系数取系统不振荡时的30%左右。

④ 系统空载、带载联调,再对 PID 参数进行微调,直至满足要求。

9.2.4实际调参演示

接下来我们将从实际的PID系统曲线来理解PID各个系数的调节效果,大家一定要注意经验的积累。我们调节PID系数的思路如下:

先调整比例系数,积分、微分系数设置为0,此时的系统只有比例环节参与控制。

如果此时系统的曲线出现大幅振荡,如图9.2.4.1所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上位机


9.2.4.1 PID曲线出现大幅振荡

首先确定硬件上是否出现了故障,例如电压不稳定、电机堵转等,排除了这些之后,那就说明比例系数调节的过大了,这个时候我们可以把比例系数慢慢地减小,并同时观察曲线的变化。

② 当我们调小比例系数之后,曲线的大幅度振荡现象消失,但是曲线依旧存在小幅度的超调现象,并且此时通过调节比例系数已经无法优化曲线,如图9.2.4.2所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上位机_02


9.2.4.2 PID曲线存在小幅度超调

此时,我们可以慢慢地增大微分系数,并同时观察曲线的变化,从而找到最合适的参数。增大微分系数之后,如果系统的曲线已经较为理想,则说明这个系统只需要比例和微分环节的控制。

如果在纯比例环节的控制下,系统的实际值始终达不到目标值,存在静态误差,如图9.2.4.3所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上位机_03


9.2.4.3 系统存在静态误差

此时,我们可以逐渐增大积分系数,并同时观察曲线的变化,如果消除静差的时间过长,则可以再适当增大积分系数,但是需要注意兼顾系统的超调量。经过调整之后,如果系统的曲线已经较为理想,则说明这个系统只需要比例和积分环节的控制。

如果系统在比例和积分环节的控制下出现小幅度的超调现象,此时,我们可以慢慢地增大微分系数,并同时观察曲线的变化,从而找到最合适的参数。

以上就是在实际调参中经常遇到的一些问题以及解决方法。然而,在实际应用中,控制系统是多样且复杂的,上述方法只能作为参考,并不是通用的,因此在PID调参过程中,大家一定要注意经验的积累。

9.3 正点原子PID上位机介绍

为了方便大家调试PID参数以及控制电机,我们开发了PID调试助手上位机,其采用串口通信,支持多种波特率,具有以下功能:

16路波形实时显示;设备状态以及故障显示。

总里程、设备位置、电机类型显示。

③ 支持10组PID参数调节,可以自定义参数调节范围。

  1. 支持多种电机控制指令。大家可以打开PID调试助手来查看它的界面,软件的路径:A盘à6,软件资料à1,软件à6,PID调试助手àATK_PID.exe。

9.3.1 上位机通信协议

上位机和下位机(开发板)之间使用整帧传输的方式进行通信,数据帧采用CRC16的校验方式,下面我们简单介绍一下数据帧的格式,如下表9.3.1.1所示:

帧头

数据类别

数据域

校验和

帧尾

0xC5

1字节

0~32字节

2字节

0x5C

9.3.1.1 数据帧格式

帧头:一包数据的头部,固定为0xC5,长度为1个字节。

② 数据类别:数据的属性,例如电机速度,温度等,长度为1个字节。

③ 数据域:某个数据类别的值,长度为0~32个字节。

④ 校验和:采用CRC16-MODBUS校验,校验范围包括帧头、数据类别和数据域,长度为2个字节。

  1. 帧尾:一包数据的尾部,固定为0x5C,长度为1个字节。

具体的协议内容可查阅《PID调试助手通信协议.pdf》这个文档,路径:A盘à6,软件资料à1,软件à6,PID调试助手à《PID调试助手通信协议.pdf》

注意通信协议的内容不要求熟记,大家只需要了解数据帧的格式即可,当我们需要用到某个功能的时候,再去查阅相关的协议说明。

9.3.2 上位机使用方法​

① 双击ATK_PID.exe即可打开上位机,上位机主界面如图9.3.2.1所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上传_04


图9.3.2.1 上位机主界面

设备连接处选择下位机对应的COM口、波特率,点击“打开”按钮,如果没有显示COM口,可以尝试点击蓝色的刷新图标进行刷新,界面如图9.3.2.2所示:

《DMF407电机控制专题教程》第9章 PID参数整定_数据_05


图9.3.2.2 设备连接

③ 按需选择波形显示通道和缩放方式,点击“开始”即可显示波形,如图9.3.2.3所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上传_06


图9.3.2.3 波形显示设置

④ 观察设备的状态及故障指示,如图9.3.2.4所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上位机_07


图9.3.2.4 设备状态及故障指示

⑤ 右侧界面可设置、获取参数,下发控制指令及显示系统数据,如图9.3.2.5所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上传_08


图9.3.2.5 右侧界面功能

⑥ 上图9.3.2.5中,点击右侧的“参数调整”按钮,即可进入PID系数及多种参数设置的界面,如图9.3.2.6所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上传_09


图9.3.2.6 PID系数及其他参数设置

进入到图9.3.2.6这个界面之后,我们可以在区域①选择所需的PID参数组别(1~10)以及设置相应的PID系数。PID系数可以在输入框手动输入或者拉动横条来选择所需数值,数值确定完后点击“设置PID”按钮即可设置PID系数,如果选择了自动发送指令,当我们拉动完横条之后,上位机就会自动设置对应的参数,其他的参数设置方法同理。

注意:参数的设置是有默认范围的,如果上位机默认的范围不适用,可以点击上图区域③的“参数范围设置”按钮,即可改变参数设置范围,如图9.3.2.7所示:

《DMF407电机控制专题教程》第9章 PID参数整定_上位机_10


图9.3.2.7 参数范围设置

关于PID上位机调试助手的简单使用就介绍到这里,其他的功能大家可以亲自去上手体验,这只是一个非常简单的工具。

9.3.3 下位机协议代码实现​

下位机的协议代码包括三个部分:CRC16校验函数、底层数据解析及上传函数、应用层数据接收及上传函数。这里我们只讲解应用层代码,详细的源码请大家参考《实验6-5直流有刷电机-速度环PID控制实验》里的debug.cdebug.h源码。

1)初始化调试函数

/**​
初始化调试​
无​
无​
*/​
void debug_init(void)​
{​
debug_obj_init(&g_debug); /* 初始化所需内存 */​
}

该函数调用了debug_obj_init这个底层函数,从结构体g_debug的首地址开始,把该结构体所需要使用的空间清零,我们在执行其他的协议代码之前,要先调用该代码进行内存的初始化。

2)目标值范围设置函数

/**​
设置目标值范围​
:最大值​
:最小值(反转时最大速度)​
: 最大突变值​
无​
*/​
void debug_set_point_range(float max_limit, float min_limit, float step_max)​
{​
static float step_temp = 0.0;​

/* 判断目标值突变是否超过允许范围 */​
if (abs((int)(*debug_rev.speed - step_temp)) > step_max) ​
{​
*debug_rev.speed = step_temp; /* 超过最大突变值,保持原来数值 */​
}​

step_temp = *debug_rev.speed; /* 保存本次数值 */​

if (*debug_rev.speed >= max_limit) /* 超过限制 */​
{​
*debug_rev.speed = max_limit; /* 配置为最大允许值 */​
}​

if (*debug_rev.speed <= min_limit) /* 超过限制 */​
{​
*debug_rev.speed = min_limit; /* 配置为最大允许值 */​
}​
}

该函数可以限制PID系统的目标值范围,进而避免不合理目标值所带来的积分饱和问题,与此同时,它还可以限制目标值的突变范围,这对于具有惯性的系统尤为重要。

3)PID数据上传函数

/**​
数据上传​
:PID组(1~10)​
:目标速度地址​
、I、D :PID参数​
无​
*/​
void debug_send_initdata(upload_type PIDx, float *SetPoint, float P, float I, float D)​
{​
/* 开发板和上位机共用一个PID目标值的内存地址,数据同步更方便 */​
debug_rev.speed = (float *)(SetPoint); ​

g_debug.pid[PIDx - TYPE_PID1].pid.pidf[0] = P; /* 传入P值 */​
g_debug.pid[PIDx - TYPE_PID1].pid.pidf[1] = I; /* 传入I值 */​
g_debug.pid[PIDx - TYPE_PID1].pid.pidf[2] = D; /* 传入D值 */​
debug_upload_data(&g_debug, PIDx); /* 发送PID参数 */​
}

该函数用于上传PID系数到上位机,第一个入口参数PIDx传入的是PID参数的组别;第二个入口参数传入的是目标值的地址,这里我们将目标值的上传和下发地址设置为同一个,这样同步目标值数据会更加方便;最后三个入口参数传入的分别是P、ID三个系数的值。

4)参数上传函数

/**​
电流数据上传​
、V_I、W_I :三相电流数据​
如果只有单相,习惯用U_I上传​
无​
*/​
void debug_send_current(float U_I, float V_I, float W_I)​
{​
g_debug.amp[0] = U_I; 传入U相电流值 */​
g_debug.amp[1] = V_I; /* 传入V相电流值 */​
g_debug.amp[2] = W_I; /* 传入W相电流值 */​
debug_upload_data(&g_debug, TYPE_AMP); /* 发送电流数据 */​
}​

/**​
电压数据上传​
:电压数据​
无​
*/​
void debug_send_valtage(float valtage)​
{​
g_debug.bus_vol = valtage; /* 传入电压值 */​
debug_upload_data(&g_debug, TYPE_VBUS); /* 发送电压数据 */​
}​

/**​
功率数据上传​
:功率数据​
无​
*/​
void debug_send_power(float power)​
{​
g_debug.power = power; 传入功率值 */​
debug_upload_data(&g_debug, TYPE_POWER); /* 发送功率数据 */​
}​

/**​
速度数据上传​
:速度数据​
无​
*/​
void debug_send_speed(float speed)​
{​
g_debug.speed = (int16_t)(speed); /* 传入速度值 */​
debug_upload_data(&g_debug, TYPE_SPEED); /* 发送速度数据 */​
}​

/**​
总里程数据上传​
:总里程数据​
无​
*/​
void debug_send_distance(uint64_t len)​
{​
g_debug.sum_len = len; /* 传入总里程值 */​
debug_upload_data(&g_debug, TYPE_SUM_LEN); /* 发送总里程数据 */​
}​

/**​
温度数据上传​
:电机温度​
:驱动板温度​
无​
*/​
void debug_send_temp(float motor_temp, float board_temp)​
{​
g_debug.temp[0] = board_temp; /* 传入驱动板温度值 */​
g_debug.temp[1] = motor_temp; /* 传入电机温度值 */​
debug_upload_data(&g_debug, TYPE_TEMP); /* 发送温度数据 */​
}​

/**​
电机状态上传​
:电机状态​
无​
*/​
void debug_send_motorstate(motor_state motor_codestae)​
{​
g_debug.status = motor_codestae; /* 传入电机状态 */​
debug_upload_data(&g_debug, TYPE_STATUS); /* 发送电机状态 */​
}​

/**​
电机类型上传​
:电机类型​
无​
*/​
void debug_send_motorcode(motor_code motorcode)​
{​
g_debug.motor_code = motorcode; /* 传入电机类型 */​
debug_upload_data(&g_debug, TYPE_MOTOR_CODE); /* 发送电机类型 */​
}​

/**​
波形数据上传​
:通道,取值1~16​
:数据​
无​
*/​
void debug_send_wave_data(uint8_t chx, int16_t wave)​
{​
g_debug.user_data[chx - 1] = wave; /* 选择通道,传入数据 */​
debug_upload_data(&g_debug, TYPE_USER_DATA); /* 发送波形数据 */​
}

这一系列的函数都调用了debug_upload_data这个底层函数,它们的作用就是上传相应的参数到上位机,我们只要根据需求调用即可。

5)PID参数接收函数

/**​
上位机PID参数接收​
:PID组(1~10)​
、I、D :PID参数​
无​
*/​
void debug_receive_pid(upload_type PIDx, float *P, float *I, float *D)​
{​
*P = g_debug.pid[PIDx - TYPE_PID1].pid.pidf[0]; /* 接收P参数 */​
*I = g_debug.pid[PIDx - TYPE_PID1].pid.pidf[1]; /* 接收I参数 */​
*D = g_debug.pid[PIDx - TYPE_PID1].pid.pidf[2]; /* 接收D参数 */​
}

该函数用于接收上位机下发的PID系数,第一个入口参数PIDx传入的是PID参数的组别;后面的三个入口参数传入的分别是P、I、D三个系数的接收地址。

6)上位机命令接收函数

/**​
上位机命令接收​
无​
:无效,1:停机,2:运行,3:刹车​
*/​
uint8_t debug_receive_ctrl_code(void)​
{​
static uint8_t rec_r = 0;​

/* 判断命令范围是否正确 */​
if (debug_rev.Ctrl_code >= 0x01 && debug_rev.Ctrl_code <= 0x03) ​
{​
rec_r++;​
if (rec_r >= 2)​
{​
rec_r = 0;​
debug_rev.Ctrl_code = 0;​
}​
return debug_rev.Ctrl_code; /* 返回命令 */​
}​
return 0;​
}

该函数用于解析上位机下发的命令,它的返回值如下:0(无效);1(停机);2(运行);3(刹车)。

上述的就是下位机应用层代码,关于底层代码的实现方法,大家可以参考《实验6-5直流有刷电机-速度环PID控制实验》里的debug.c和debug.h源码。

举报

相关推荐

0 条评论