搜索
bottom↓
回复: 1

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

[复制链接]

出0入234汤圆

发表于 2022-8-15 15:24:11 | 显示全部楼层 |阅读模式
1)实验平台:正点原子DMF407电机开发板
2)平台购买地址: https://detail.tmall.com/item.htm?&id=677230699323
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/stm32dj/ATK-DMF407.html
4)对正点原子电机开发板感兴趣的同学可以加群讨论: 592929122 lQLPJxaFi2zaB4UWWrDAMgIsFEW2pwLb3abnwDMA_90_22.png
lQDPJxaFi2nfFizMjM0CbLCPlxn_FVheIQLb3aGrwFQA_620_140.jpg

lQLPJxaFi2nfFhLMkM0BXrDNvOUyeU_FPgLb3aGvQNIA_350_144.png


第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所示:
lQLPJxaXwdqr1TU3zQH_sLZbvSgWsh8qAvm0k0dABgA_511_55.png
表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的值。
③ 根据记下的比例系数和周期,采用经验公式,计算调节器的参数。
lQLPJxaXwecwK7tvzQH8sJjrQ_7rczK3Avm0p1_AJwA_508_111.png
表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所示:
image002.jpg
图9.2.4.1 PID曲线出现大幅振荡

        首先确定硬件上是否出现了故障,例如电压不稳定、电机堵转等,排除了这些之后,那就说明比例系数调节的过大了,这个时候我们可以把比例系数慢慢地减小,并同时观察曲线的变化。
        ② 当我们调小比例系数之后,曲线的大幅度振荡现象消失,但是曲线依旧存在小幅度的超调现象,并且此时通过调节比例系数已经无法优化曲线,如图9.2.4.2所示:
image004.jpg
图9.2.4.2 PID曲线存在小幅度超调

        此时,我们可以慢慢地增大微分系数,并同时观察曲线的变化,从而找到最合适的参数。增大微分系数之后,如果系统的曲线已经较为理想,则说明这个系统只需要比例和微分环节的控制。
        ③ 如果在纯比例环节的控制下,系统的实际值始终达不到目标值,存在静态误差,如图9.2.4.3所示:
image006.jpg
图9.2.4.3 系统存在静态误差

        此时,我们可以逐渐增大积分系数,并同时观察曲线的变化,如果消除静差的时间过长,则可以再适当增大积分系数,但是需要注意兼顾系统的超调量。经过调整之后,如果系统的曲线已经较为理想,则说明这个系统只需要比例和积分环节的控制。
        ④ 如果系统在比例和积分环节的控制下出现小幅度的超调现象,此时,我们可以慢慢地增大微分系数,并同时观察曲线的变化,从而找到最合适的参数。
        以上就是在实际调参中经常遇到的一些问题以及解决方法。然而,在实际应用中,控制系统是多样且复杂的,上述方法只能作为参考,并不是通用的,因此在PID调参过程中,大家一定要注意经验的积累。
9.3 正点原子PID上位机介绍
为了方便大家调试PID参数以及控制电机,我们开发了PID调试助手上位机,其采用串口通信,支持多种波特率,具有以下功能:
① 16路波形实时显示;设备状态以及故障显示。
② 总里程、设备位置、电机类型显示。
③ 支持10组PID参数调节,可以自定义参数调节范围。
①         支持多种电机控制指令。
        大家可以打开PID调试助手来查看它的界面,软件的路径:A盘6,软件资料1,软件6,PID调试助手ATK_PID.exe。
9.3.1 上位机通信协议
上位机和下位机(开发板)之间使用整帧传输的方式进行通信,数据帧采用CRC16的校验方式,下面我们简单介绍一下数据帧的格式,如下表9.3.1.1所示:
lQLPJxaXwfKDW6o3zQH2sNnSbsBF96EAAvm0uuVA0gA_502_55.png
表9.3.1.1 数据帧格式

① 帧头:一包数据的头部,固定为0xC5,长度为1个字节。
② 数据类别:数据的属性,例如电机速度,温度等,长度为1个字节。
③ 数据域:某个数据类别的值,长度为0~32个字节。
④ 校验和:采用CRC16-MODBUS校验,校验范围包括帧头、数据类别和数据域,长度为2个字节。
②         帧尾:一包数据的尾部,固定为0x5C,长度为1个字节。
        具体的协议内容可查阅《PID调试助手通信协议.pdf》这个文档,路径:A盘6,软件资料1,软件6,PID调试助手《PID调试助手通信协议.pdf》。
注意:通信协议的内容不要求熟记,大家只需要了解数据帧的格式即可,当我们需要用到某个功能的时候,再去查阅相关的协议说明。
9.3.2 上位机使用方法
① 双击ATK_PID.exe即可打开上位机,上位机主界面如图9.3.2.1所示:
image008.jpg
图9.3.2.1 上位机主界面

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

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

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

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

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

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

        关于PID上位机调试助手的简单使用就介绍到这里,其他的功能大家可以亲自去上手体验,这只是一个非常简单的工具。
9.3.3 下位机协议代码实现
下位机的协议代码包括三个部分:CRC16校验函数、底层数据解析及上传函数、应用层数据接收及上传函数。这里我们只讲解应用层代码,详细的源码请大家参考《实验6-5直流有刷电机-速度环PID控制实验》里的debug.c和debug.h源码。
1)初始化调试函数
/**
* @brief       初始化调试
* @param       无
* @retval      无
*/
void debug_init(void)
{
    debug_obj_init(&g_debug);            /* 初始化所需内存 */
}
该函数调用了debug_obj_init这个底层函数,从结构体g_debug的首地址开始,把该结构体所需要使用的空间清零,我们在执行其他的协议代码之前,要先调用该代码进行内存的初始化。
2)目标值范围设置函数
/**
* @brief       设置目标值范围
* @param       max_limit:最大值
* @param       min_limit:最小值(反转时最大速度)
* @param       step_max : 最大突变值
* @retval      无
*/
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数据上传函数
/**
* @brief       PID数据上传
* @param       PIDx      :PID组(1~10)
* @param       *SetPoint :目标速度地址
* @param       P、I、D   :PID参数
* @retval      无
*/
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、I、D三个系数的值。
          4)参数上传函数
/**
* @brief       电流数据上传
* @param       U_I、V_I、W_I :三相电流数据
* @note        如果只有单相,习惯用U_I上传
* @retval      无
*/
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);       /* 发送电流数据 */
}

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

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

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

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

/**
* @brief       温度数据上传
* @param       motor_temp :电机温度
* @param       board_temp :驱动板温度
* @retval      无
*/
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);         /* 发送温度数据 */
}

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

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

/**
* @brief       波形数据上传
* @param       chx :通道,取值1~16
* @param       wave:数据
* @retval      无
*/
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参数接收函数
/**
* @brief       上位机PID参数接收
* @param       PIDx    :PID组(1~10)
* @param       P、I、D :PID参数
* @retval      无
*/
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)上位机命令接收函数
/**
* @brief       上位机命令接收
* @param       无
* @retval      0:无效,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源码。 


阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2022-8-15 19:28:50 | 显示全部楼层
从正点原子的stm32开始入的门,这么多年了,教程还是这么完整,点个赞!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 06:14

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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