关于AGV车PID控制及其惯性讨论
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_553982.JPGAGV车运行中…… (原文件名:AGV运行.JPG)
上图是前段时间和公司做的AGV车,功能都实现了,不过运行状况一般,有较大晃动,特别是载满货以后过弯道时经常出轨。
描述如下:
正常行驶时速度1~2M/S。这里我们只做到了1M/S。当速度再加快时,载上货物运行正常,但是空车运行时不太稳定,停止时易出轨。而在过弯道时,空车正常,载货时易出轨,所以这里我们采用了直道和弯道分开的策略,让弯道时减速。但由于载货对车体本身影响较大,过弯道有时还是不太稳定。
以下是系统中用到的PID循迹算法。虽然循迹功能实现了,但是当载货较重时,车身还是存在较大的晃动,感觉和机械机构也有关,因为通过挂钩拉货,挂钩摩擦力对车体由较大影响,当然这里和算法本身及其参数设计也有较大关系。
/********************
* 结构体定义区 *
********************/
typedef struct PID
{
int16_t pConst; //比例常数 Proportional Const
int16_t iConst; //积分常数 Integral Const
int16_t dConst; //微分常数 Derivative Const
int16_t position;
int16_t hisPosition;
int16_t lastPosition;
}PID;
/***********************************************************
* 函数名称:PID参数初始化
* 功能描述:初始化PID参数,并实现P、I、D三个参数的整定
* 参数列表:
* 返回结果:无
***********************************************************/
voidPIDInit(PID *iPID)
{
memset(iPID, 0, sizeof(iPID));//将所有值清零
iPID->pConst = 2; //比例常数 Proportional Const
iPID->iConst = 0; //积分常数 Integral Const
iPID->dConst = 8; //微分常数 Derivative Const
}
/***********************************************************
* 函数名称:PID控制程序
* 功能描述:
* 参数列表:
* 返回结果:无
***********************************************************/
void PIDCalc( PID *cPID)
{
int16_t pGain; //P增益
int16_t iGain; //I增益
int16_t dGain; //D增益
int16_t pidGain; //控制量
cPID->position = Discretized(PIN_RED & 0X1F); //对采集的循迹信号进行离散化处理得到位置信息
cPID->hisPosition += cPID->position; //记录偏差之和
cPID->lastPosition = cPID->lastPosition;
cPID->lastPosition = cPID->lastPosition; //
cPID->lastPosition = cPID->lastPosition; //
cPID->lastPosition = cPID->position; //
pGain = (cPID->pConst) * (cPID->position); //计算比例分量(P)=比例系数*本次位置差
iGain = (cPID->iConst) * (cPID->hisPosition); //计算积分分量(I)=积分系数*偏差之和
dGain = (cPID->dConst) * ((cPID->position) - (cPID->lastPosition)); //计算微分分量(D)=微分系数*(本次位置差-前3次的位置差)
//由于采样比较快,用本次位置-前3次位置才有足够大的控制 pidGain = pGain + iGain + dGain; //P分量和D分量相加,得到控制量。
if (pidGain > 320)pidGain = 320; //模糊化处理,防止增量溢出
if (pidGain < -320) pidGain = -320;
pidGain = pidGain/10;
SetMotors(pidGain); //将控制量传入电机控制函数进行控制
}
/***********************************************************
* 函数名称:电机调速
* 功能描述:通过得到的pidValue来改变占空比大小
* 参数列表:
* 返回结果:
***********************************************************/
void SetMotors(int16_t pidValue)
{
// PWM_CON =_BV(ENA) | _BV(ENB) |_BV(CTRL0) |!_BV(CTRL1) | _BV(CTRL2) |!_BV(CTRL3); //left
// PWM_CON =_BV(ENA) | _BV(ENB) | !_BV(CTRL0) | _BV(CTRL1) |!_BV(CTRL2) | _BV(CTRL3); //right
// PWM_CON =_BV(ENA) | _BV(ENB) |_BV(CTRL0) |!_BV(CTRL1) |!_BV(CTRL2) | _BV(CTRL3); //back
PWM_CON =_BV(ENA) | _BV(ENB) | !_BV(CTRL0) | _BV(CTRL1) | _BV(CTRL2) |!_BV(CTRL3); //forward
g_dutyL = 36 + pidValue; //改变PWM值
g_dutyR = 36 - pidValue;
}
/***********************************************************
* 函数名称:Discretized
* 功能描述:对从循迹板采集的数据进行离散化处理
* 参数列表:
*
* 返回结果:
*
***********************************************************/
int16_t Discretized(uint8_t temp)
{
switch (temp) //将位置信号进行离散化
{
case 0x1b: g_position = 0;
break;
case 0x1d: g_position = 10; //正,左加右减,向右转
break;
case 0x17: g_position = -10; //负,左加右减,右转
break;
case 0x1e: g_position = 20; //正,左减右加,极左转
break;
case 0x0f: g_position = -20; //负,左加右减,极右转
break;
case 0x1c: g_position = 40 ; //正,左减右加,极左转
break;
case 0x07: g_position = -40 ; //负,左加右减,极右转
break;
default: g_position = 0;
break;
}
return g_position;
}
这上面的参数中10、20、40以及pConst、iConst、dConst都是先定了个大致范围,然后根据实际效果更改而得到的。不知道大家对这个算法和其参数的设定有什么想法? 难道大家都这么惜字如金,不肯发表下见解…… Mark.
菜鸟学习。 项目不错,但是整体架构不现实。大系统要考虑扩展性,集中式控制并不能把这个项目做到底,建议采用分布式模块化设计。
如CAN驱动器,CAN传感器,pc104主控,多路104CAN卡。
最后建议使用陀螺仪+红外坐标。 回复【3楼】real_sugar
-----------------------------------------------------------------------
3楼讲的好深奥啊,呵呵。
请问能给介绍一下什么是集中式控制和分布式模块化设计吗?举个例子。不懂,嘿嘿。 我是这么理解的找一片ARM把电机都接过来接过来高层规划和底层控制都一起搞了算集中式。
每个电机都用独立ARM控制,再和高层PC104通信算是分布式控制。 有史以来第一次完整的看一遍pid的整个计算代码,mark了,原来pid没想象中那么吓人。 int16_t Discretized(uint8_t temp)
{
switch (temp) //将位置信号进行离散化
{
case 0x1b: g_position = 0;
break;
case 0x1d: g_position = 10; //正,左加右减,向右转
break;
case 0x17: g_position = -10; //负,左加右减,右转
break;
case 0x1e: g_position = 20; //正,左减右加,极左转
break;
case 0x0f: g_position = -20; //负,左加右减,极右转
break;
case 0x1c: g_position = 40 ; //正,左减右加,极左转
break;
case 0x07: g_position = -40 ; //负,左加右减,极右转
break;
default: g_position = 0;
break;
}
return g_position;
}
这个离散的太离谱了吧就几个档,微分又大,每次position变化的时候不会很响么? MARK一下。 不会帮顶! 回复【7楼】real_sugar
-----------------------------------------------------------------------
嗯,我感觉这里问题也很大。但是下面循迹板传过来的只有5个信号,分别是中、左、右、极左、极右,感觉太少了,不好处理。至于数值,我是通通过实践改的数值,似乎也没有什么实际的理论依据吧。本来想用傻孩子那个贴里面的类质心算法获取当前机器人偏离轨迹线的量的,但是感觉原理差不多吧…… 关注.. 可以前后双排循迹板的~容易求质心,也容易求角度差。ROBOCON典型应用~ 回复【12楼】real_sugar
-----------------------------------------------------------------------
呃。这个想法不错,不过估计会用到一大堆数学公式吧……不知道谁有这方面的资料!! 我们公司也做AGV小车,调试中也出现类似问题,小车速度较高时,转向就回出现问题,这和小车转向机构以及色带宽度有关系 我在楼主的另一篇和这个一样的帖子里,回复过, 回复【15楼】hailongwang 阳光灿烂
-----------------------------------------------------------------------
货物是在车子后面的,通过挂钩连接。看过别的公司做的车,一般直接用绳连接,或者用直接用个钩子插在后面的车上,反正他们做的AGV后面的货物对前面的车子影响很小。不过我们做的这个后面的货车是他们提供的,得按他们要求的来,所以使用了挂钩……他,他们的想法是希望通过程序控制,使即使货物对车影响较大的情况下车子还是能平稳运行……有点难弄。不知道谁有更好的控制算法…… 回复【14楼】DLPIC
-----------------------------------------------------------------------
看过你那个车的视频了,效果挺不错的。不知道算法是怎么设计的。
不过你们这个视频里面车子和后面货车连接好像是直接用钢绳是吧,这样感觉应该还行,货物对车子本身影响小点。不过不知道载满货物后效果怎样。
还有几个问题:你们的电机是选择东方马达的是吧,这个性能怎么样啊。我们那个是选的上海的一个公司的,可以用PWM去控制转速。不过一直觉得效果一般,特别是停止的时候向前会有较大的移动,简言之就是不能立刻停下来。后来我们在停止的时候给它一个反转信号,才基本满足要求,但是感觉这样对电机本身伤害较大。 还有几个问题:你们的电机是选择东方马达的是吧,这个性能怎么样啊。我们那个是选的上海的一个公司的,可以用pwm去控制转速。不过一直觉得效果一般,特别是停止的时候向前会有较大的移动,简言之就是不能立刻停下来。后来我们在停止的时候给它一个反转信号,才基本满足要求,但是感觉这样对电机本身伤害较大。
-----------------------------------------------------------------------
直接用伺服电机就可以改善性能了,我一直以为你的车电机是闭环的呢~ 回复【18楼】real_sugar
-----------------------------------------------------------------------
我们用的是无刷直流伺服电机。 回复【16楼】shaw
回复【15楼】hailongwang 阳光灿烂
-----------------------------------------------------------------------
货物是在车子后面的,通过挂钩连接。看过别的公司做的车,一般直接用绳连接,或者用直接用个钩子插在后面的车上,反正他们做的agv后面的货物对前面的车子影响很小。不过我们做的这个后面的货车是他们提供的,得按他们要求的来,所以使用了挂钩……他,他们的想法是希望通过程序控制,使即使货物对车影响较大的情况下车子还是能平稳运行……有点难弄。不知道谁有更好的控制算法……
-----------------------------------------------------------------------
回复【17楼】shaw
回复【14楼】dlpic
-----------------------------------------------------------------------
看过你那个车的视频了,效果挺不错的。不知道算法是怎么设计的。
不过你们这个视频里面车子和后面货车连接好像是直接用钢绳是吧,这样感觉应该还行,货物对车子本身影响小点。不过不知道载满货物后效果怎样。
还有几个问题:你们的电机是选择东方马达的是吧,这个性能怎么样啊。我们那个是选的上海的一个公司的,可以用pwm去控制转速。不过一直觉得效果一般,特别是停止的时候向前会有较大的移动,简言之就是不能立刻停下来。后来我们在停止的时候给它一个反转信号,才基本满足要求,但是感觉这样对电机本身伤害较大。
-----------------------------------------------------------------------
我感觉小车和后面货物最好采用带有弹簧的硬连接。弹簧可以起到缓冲作用,我视频里的连接方式是我随便找个绳子连的,
停止时向前移动,是因为没有做刹车系统吧,可以考虑加入机械刹车,根据电机拖动书上讲,反转信号刹车是可以的,对电机肯定有一定影响, 突然发现跑题了。其实最想知道的还是对这个算法的研究…… 回复【楼主位】shaw
-----------------------------------------------------------------------
说点不着边的:
“memset(iPID, 0, sizeof(iPID));//将所有值清零”
这句话中
iPID是个指针,要将所有值清零是否需写成sizeof(PID)? 回复【22楼】un_wi
-----------------------------------------------------------------------
嗯,这个问题还是挺着边的,这里的确应该用PID,楼上眼力真好,呵呵。
我仿真了一下,将0换成了其他数测试,发现用iPID时只操作了一个数,用PID才对所有内内容都操作了,和书上讲的一样,呵呵。当然,幸运的是,在这句话操作之前,里面的参数默认已经清零了,所以对后面没有太大影响。
不过又出现了一个新的问题,是关于memset的,我用5测试,发现将里面内容改成char时正确,但会出现一个方框,当为int时得到的是1285(1为257,4为1028……),不知道是怎么回事……问题如下图。
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_557986.JPG
(原文件名:调试.JPG) 回复【23楼】shaw
-----------------------------------------------------------------------
我认为memset函数会从ipid地址开始把sizeof(pid)个字节全部写为5,当取值类型为int16时,它的值是0x0505=1285。 回复【24楼】un_wi
-----------------------------------------------------------------------
嗯,明白什么意思了,呵呵,受教啦…… TMD
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_558818.png
(原文件名:QQ截图未命名.png)
这个我找啦很久啊 回复【26楼】5irmb 李_志伟
-----------------------------------------------------------------------
请问你也在做AGV车的吗,还是…… 回复【27楼】shaw
回复【26楼】5irmb 李_志伟
-----------------------------------------------------------------------
请问你也在做agv车的吗,还是……
-----------------------------------------------------------------------
200%的初学者 shaw 你好!对你的小车我十分感兴趣!我6月10日-15日都会在北京。不知道shaw是否方便,登门造访? 对楼主的AGV很感兴趣,不知楼主的AGV是采用什么寻迹方式,红外,还是磁,通读全文感觉是一种开关量的寻迹方式?? mark 回复【30楼】williamhoa
---------------------------------------------------------------------
首先这个不是我的AGV吧,是我们公司做的,呵呵。
我们采用的是红外的方式,在车的最下面安装了16个红外对管,用于采集位置信息,将采集到的信号通过一块MEGA16进行处理,然后转化成左、中、右、极左、极右等开关信号传递给主控芯片处理。二者之间通过五个IO口相连。
不过个人感觉红外对环境要求还是比较高的,我们那个运行环境灯光条件并不是特别好,有些地方亮有些地方暗,所以有时会偶尔影响循迹。想过用磁引导,但是一般做磁引导轨迹条和控制器都得进口,昆山有家是从日本丰田进口的,效果挺好。 谢谢。 路过。 mark mark 去掉微分 学习啦,高手很多,很强大! 不过个人感觉红外对环境要求还是比较高的,我们那个运行环境灯光条件并不是特别好,有些地方亮有些地方暗,所以有时会偶尔影响循迹。想过用磁引导,但是一般做磁引导轨迹条和控制器都得进口,昆山有家是从日本丰田进口的,效果挺好。
这个 比较容易解决 在 循迹板 下面 增加照明设施 就可以了 !!!! 小弟 也刚刚入门,对 PID控制还不太了解 ,有什么 好的资料指点 一下 谢谢了!! 建议改变传感器的位置,比如将传感器位置适当前放,可以有一定的预示作用,同时增大传感器的分辨率,也可由提高可靠性
并不需要更改太多的东西就可以做到 我也在做AGV,用的也是传感器,算法采用模糊PI放积分饱和增量式算法!
货物对AGV的影响相当大,我们做的是300KG的拖车,问题的本质其实还是力学和机构配合的问题! 再次马克。 回复【楼主位】shaw
-----------------------------------------------------------------------
LZ既然有16个红外对管,那干嘛不多搞几个偏差等级呢? 我做飞思卡尔智能车的经验,偏差至少要有8-9挡,也就是每边至少4挡才能保证运行稳定,而且要采用非线性的排列方式,中间附近的管子多,两边的管子少,这样可以保证探测范围大并且保证中线附近不会抖。 做两轮平衡车时意识到,这种惯性控制小车,不同的负载所需要的PID控制参数是不同,写死的一套PID是不能包打天下的 MARK 学习学习 回复【42楼】jay404823000
-----------------------------------------------------------------------
这种方法效果不错,不过在多轨道时不太好控制,容易走错路。 {:handshake:}[mark一下 还有这种车呢 不错不错 之前有接触过AGV小车 ,现在在做自平衡 感觉有改进的地方 LZ这个PID 作为教程 很不错。。。哦。 其实车子的速度有30米/分就可以了,太快不安全。在工厂里运行容易撞到人。 MARK{:lol:} 8位AGV传感器理论上是不是应该有0-255中数值?那这些数值是不是该建立一个简单的模型?望楼主赐教
页:
[1]