一、背景
从我构思圆梦小车的第一天起,我就把实现小车速度PID控制作为目标之一,也许是我出身于自动控制专业的情结吧。
在我写的第一组关于智能小车的文章中(“寻迹小车 FollowMe”),就期望能实现小车 PID 调速,并且参照《电动机的单片机控制》一书写了相应的测速和控制程序,但不幸的是,没有实现 ,当初以为是测速的分辨率过低(只有10个脉冲/轮子转一圈)。
后来将小车升级,用开模具方式大大提高了测速的精度,推出了圆梦小车第一代。测速精度达到了每转50个脉冲(如果用前后沿检测,可以达到100个脉冲),但略作尝试后还是没有实现,似乎没有找到问题的根源。
准确的说应该是我没有掌握PID控制程序,我虽是学习自动控制出身,但毕业后从未实际应用过PID控制,所有知识局限于当初学校的实验,这也是我一直想在小车上实现PID的动机之一:一个学自控的居然没有在现实中运用PID的能力,汗颜啊!
因为无力而为,所以在“圆梦小车StepByStep”系列文章中,就跳过了这一段内容。但心未死,想借助小车客户中的高手之力完成之,为我打破这个僵局,可小车倒是送出去几套,PID调速还是杳无音讯,无语!
随着小车进化至第三代(轮式驱动单元)、第四代(FIRA小车),将PID调速的梦想实现的愿望越加强烈!为此,还找了朋友介绍个熟人帮忙,本来信心满满,因为朋友说这个人参加了 Freescale 智能车大赛,其中就用到了PID调速。为此我又送出了一套第四代圆梦小车,更令我失望,连回音都没有,郁闷!
这一切迫使我自己去尝试!看来这种没有多少经济利益的事少有人问津,但愿是这个原因,而不是由于无能。
转机缘于一个买了“轮式驱动单元”的客户(现在是朋友了),他告诉我,参考 Arduino 所提供的 PID 库函数实现了“轮式驱动单元”的调速,而且效果不错。(Arduino 是一个基于AVR单片机的开源平台,经过几年发展,目前资源十分丰富)
我急切的下载了 Arduino 的PID 库函数 ,发现很有价值,就着手尝试了,以下便是实施的过程。
二、PID库函数的消化和移植
下载了 Arduino的PID函数库后发现,函数是按 C++ 的类方式编写的,相当专业,可我的小车程序是用 C 写的,不支持类,所以需要移植。
以下便是其函数定义:(两个构建函数,还用了面向对象的重载)
因为看到其算法中大量使用了浮点运算,担心轮式驱动单元的MCU(STC12C5206AD)难以承担,所以先在四代小车的STM32控制器上移植。
以下是其部分变量定义:
(注:后来才知道,上面的 double 就是32位浮点,我开始以为是64位浮点呢。)
之所以看了这个程序很感兴趣,是因为它将各个量值的概念理的比较清晰,尤其是周期、积分常数、微分常数,这是我以往一直糊里糊涂的内容。
就是下面这个参数调整函数,使我确切的知道了PID参数所对应的物理含义:
将这个库函数移植到STM32控制器上后,略作测试,发现有效果了,大喜!
但由于STM32的控制程序是基于 uCOS的,有些复杂,所以决定先搞定第三代小车:轮式驱动单元,正好第三代的第二版:内置MCU的智能车轮硬件完成了,所以就决定先将PID程序移植到“第三代小车第二版”上。
因为轮式驱动单元内部空间较小,故选择SOP16封装的STC12C5206AD单片机,只有6k FlashROM ,所以必须优化PID库函数,否则代码空间不够。
为此,简化了库中的一些函数,同时能不用浮点的地方就不用浮点,一是减少代码,二是提高速度,8位机不能和Cortex-M3比,速度低多了。
首先,简化变量,只保留影响计算精度的变量为浮点:
用全局变量代替标准类函数的输入输出接口:
取消那些标准的类输入输出接口函数,只保留必须的初始化和PID计算:
注意:因为空间不够,连带前馈控制的初始化函数都封掉了。
为了便于整定PID参数,根据小车的特性,将原来定义为浮点的PID参数简化为用一字节无符号数表示,且利用STC12C5206AD的Flash可以作为EEPROM的特性,将三个参数置于CODE区中,程序中设置内存写功能,通过串口通讯实现随时调整:
用以下函数将设置的PID参数转换为计算所需的浮点数,因为直接设置浮点数有些困难:
在PID计算中尽量减少浮点计算:
至此,PID库函数的移植完成了,下一步是做嵌入程序前的准备。
三、嵌入程序前的准备
要实现PID调速,首先得解决测速,有了速度才能实现反馈,从而和设定值比较,得到偏差,根据偏差,调用 PID 计算,得到输出控制值:
因为PID控制的基础是以周期T测量,计算出偏差后修正输出。而测量周期不能太长,那样响应将滞后;但过短也没有意义,因为对象的惯性特征,导致极小的时间间隔中不会有变化。
根据小车电机的驱动特性,100ms左右的周期比较合适。
但小车的测速码盘是直接设计在轮毂上的,虽说每转有100个脉冲(轮式驱动单元),但相对于那些设计在电机输出轴上的高级编码器而言,分辨率远远不够。按目前小车的减速箱设计,对于1:48减速箱,最快时100ms 约34个脉冲,而1:120减速箱才不到14个脉冲,如果调速范围设置为50% 到 100% ,则脉冲数更少,分辨率无法满足控制的要求,如果再降低周期,则更无法得到可靠的控制反馈了。
为此,首先得解决测速的分辨率问题,因为控制速度属于运转稳态时的任务,在起、停过程通常不需要。而正常运转时,相邻2个脉冲的周期不会变化很大,故可以据此利用前一周期的数值作为倍频的依据,详细算法此处不再赘述,有兴趣者可以到我在GoogleCode上设立的开源项目:http://code.google.com/p/fira-mirosot-robot/中下载:
http://code.google.com/p/fira-mirosot-robot/downloads/detail?name=Introduction%20B%20-%20Hardware%20of%20the%20Smart%20Car.pdf&can=2&q=
其原理示意如下图:
为了具备提高PID计算周期的可能,将测速周期提高到20ms。而为了减小计算量,将倍频数设定为 256倍,实际没有太大意义,只是为了便于计算。有效的倍频数应该在50到100倍即可。
程序目前所用的PID计算周期为100ms,即5次测速计算一次,输出一次修正值。如果需要,很容易减小周期以改善响应。
因为倍频处理较复杂,要应付的请况比较多,且由于计算时中断的打扰,很容易出现粗大误差,为此调试时耗费了不少精力。现在的效果应该算是比较满意了。
以下就是测速用的变量:
从变量数可以看出处理之麻烦,是不是我想的太复杂?不知是否有高人能写出更简洁的计算方式?
四、将PID计算嵌入程序
有了可靠的速度,PID计算的引入还是很方便的。
首先,设置一个激活PID计算的机制,本程序是通过串口命令,也可以根据程序的需要或者其它触发机制。因为第二版轮式驱动单元是作为执行机构,只有一个控制通道UART,所以就由通讯命令激活:
激活后在每5次计算速度后触发一次PID控制,如下:
至此,从功能角度看,这个轮式驱动单元已具备PID调速功能,但还不能说实现了PID调速,因为PID参数整定在PID控制中十分重要,且要将一个具备PID调节功能的系统整定好也是件巧活。
因为我并不具备这方面的经验,所以想借助程序的灵活性设计一些辅助的手段,以方便参数的整定,从而降低难度,使小车的PID调速成为易事。
五、PID参数整定前的准备
从搜集的PID参数整定方法的资料看,多数需要能记录速度变化的趋势,也就是所谓的“对象动态特性”测量,或者说是“冲击响应”测量。
既然小车内部已经实现了数字化的速度检测,且有通讯接口,为何不将速度送到PC机上,利用PC机显示速度变化曲线,从而得到整定参数的依据。
可我PC机上的图形编程能力太菜,亏得有个好友帮忙,为我写了一个图形显示程序,使速度显示成为现实。(由衷表示感谢!)
为了配合这个功能,在小车控制程序中增加了速度输出,每次测量(20ms)都将速度结果送出,PC机根据这些速度数据绘出速度随时间的变化曲线:
六、参数整定过程
轮式驱动单元第二版驱动很方便,用串口可以容易的控制,为了简化操作,是空载方式测试的,我用无线方式试验过,有载(装在小车上)效果更好。下图为空载调试方式:
从各类参数整定方式中,我感觉那个“齐格勒—尼克尔斯经验法”比较容易实施,就按那个进行了参数调整,先关闭积分和微分作用,只保留P,在电机可以工作的下限速度进行整定(因为我试过,如果在偏高的速度整定,则在低速工作时会振荡,还无能力解释),逐渐加大P使速度发生振荡,如下图:
此时得到临界比例系数Pd,从图上得到振荡周期T ,根据“齐格勒—尼克尔斯经验法”:
Kp Ki Kd
P 控制: 0.5Pd
PI控制: 0.45Pd 0.83T
PID控制: 0.6Pd 0.5T 0.125T
计算出PID系数,Pd = 22 ,T = 300ms ,按PID控制计算,得到:
Kp = 1.3, Ki = 0.15秒 Kd = 0.03秒
设置到程序中后,基本可以了,只是微分系数需要略作调整(降低到0.02秒,否则有些振荡),设置后的速度曲线为:
七、结语
当时得到这个结果时,我倍感很神奇!
因为早期的一件事让我对PID系数的配比感到神秘莫测:曾经按照老外的示例做了个LEGO的两轮平衡车,他也是用的PID控制,区区几行程序,小车就站起来了。可是我将他的三个系数随便一改,哪怕是略作调整,小车就趴下了,很是灵验。
那时我就对PID系数的整定心存敬畏,同时也一直想尝试利用程序使其变得不那么神秘。
这次尝试总算了结了我的心愿,爽!
借助这个工具,应该可以解决许多需要PID控制的问题,如两轮平衡、差分驱动小车走直线等,只要程序中能测出偏差;而这是必须的,否则PID控制也无从谈起。
但愿此尝试能起到抛砖引玉作用,使我们的爱好者们、多数大学生们所做的小车也能像那个外国人做的绕着茶杯转的小车那样流畅:
而不是只有参加FreeScale智能车大赛的同学才能做到。