[古董贴][原创]循线算法原理与实践
[说在前面的话]看了OURAVR机器人板块的很多文章,仍然停留在Show图片,Show代码,大家“喊一下牛”的程度。真真做机器人的,却又像是做进度报告似的……实在看不过,本人最爱显示小聪明,所以,斗胆,鲁班门前弄大斧,各位大虾面前抢先说说——“循线算法原理与实践”。
还是那句老话:没时间的捧个人场哈!
[硬件基本构架]
对于机器人的循线,为了获得场地上白线(黑线)的信息,硬件结构一般有如下几种种类。
1、红外对管阵列。采取这种方式的机器人比较多,尤其在各种机器人竞赛中,几乎是标准配置。但是这种技术有一个致命的弱点,就是对于场地光线的干扰特别敏感,而且也很难把红色和白线区别开来,所以使用受到一定的限制。一般解决这类问题的方法是在红外光上加载一个调制波,通过检测这个调制波来消除场地光线的干扰,至于如何解决红色和白色的区别问题,那就几乎是五花八门了。
2、光纤传感器阵列。采用这种传感器阵列的原因是,光纤非常细,在单位面积内可以安装更多的传感器,从而获得更精确地场地信息。当然,钱也也花得更多。
3、线性CCD。这种硬件方法几乎是一种对场地信息分辨率的BT追求,如果说红外对管阵列还是离散信息的话,那么线性CCD就是线性的连续数据。当然驱动它也不是一件容易的事情,对于单片机也有更高的速度要求。
4、视觉。废话少说——否则明天我都别想吃饭。
[基本原理]
所谓循线,就是通过一定的传感器探测地面色调迥异的两种色彩从而获得引导线位置,修正机器人运动路径的一种技术。——说的太拗口了。不说太多理论的东西,我们就从基于红外对管阵列的循线技术来说起。
假设,我们使用的是黑底白线的场地。红外对管阵列由3个红外对管1字摆开组成。白线的宽度略小于或等于红外对管阵列的宽度。
1、数据的采集。
对于机器人来说,通过传感器感知周围事物的信息,利用这些信息并不作太多智能上的计算而直接通过一定的转换,指导机器人的运动——这种形式在人工智能学上叫做机器人的“反应范式”。所以,我们要想让我们的机器人能够寻着我们给定的轨迹线运动,第一步就必须让他感知到轨迹线的存在。一般的做法就是通过AD采样,获得红外对管(传感器)反馈回来的电压信息。然而,这样获得的电压值信息是无法直接指导运动的,必须把他们转化为二值的(也就是二进制信息,1表示线存在,0表示线不存在)信息,然后通过处理每一个管子反馈回来的二值信息获得白线的位置信息。
>>技术点AAD信号的阀值化。(你可以参考其它的算法,获得比较详尽的技术,我这里只是举例一二)
所谓阀值化,就是通过一定的范围把握,从而把线性的数据转化为离散数据的一种变换。简单的说,就是通过分段函数的方法,将数据分类。在我们这个应用中,就是想方设法使AD采集回来的电压值变化为一个恰恰能够准确表示白线位置信息的二进制信息,1代表白线存在,0代表白线不存在。由于白色和黑色在电压差异上非常之巨大,所以可以简单的通过一个标志线来区分它们,当电压值高于这个标志线了,就把他标志为1,否则就标志为0,算法描述为:
if (AdValue > MarkLing)
{
LineInfor = 1;
}
else
{
LineInfor = 0;
}
这样做非常简单,适合于比较标准的场地,然而对于那些模糊了的场地或者是非标准场地,虽然人的肉眼能够看出来,但是对于机器人来说,可能看到的就是花白的一片或者是黑色的夜幕。当标志线值过高时,机器人能看到的只是那些特别明显的白线,其他则是黑色的夜幕,很容易丢失轨迹线;当标志线值过低时,机器人眼中就是白茫茫的一片毛刺。总而言之,对场地的适应性非常差。解决方法是,通过设定两个标志线来标定轨迹线信息,当AD值高于某一值时,标志1;当AD值低于另外某一值时,则标定0。算法描述为:
if (AdValue > High_MarkLine)
{
LineInfor = 1;
}
else if (AdValue < Low_MarkLine)
{
LineInfor = 0;
}
else
{
LineInfor = NoInfor;
}
>>技术点 B 动态预值。(你可以参考其它的算法,获得比较详尽的技术,我这里只是举例一二)
当然,这种算法在简单的机器人循线中不是很常用。比较常见,适应性强的方法是,首先从AD值中找到一个中间值作为MarkLine,(或者可以从AD值中找那些比较接近最大值和最小值之差的0.618倍的数值),然后再使用第一种方法标记,这样的算法叫做动态预值。如果把这种算法应用于第二种当然也不多啦。
2、数据的简单加工——第一个循线程序。
到目前为止,我们已经把AD的值的数组转变为了一个表示白线位置的二进制位的数组——我们不妨直接把他用一个字节表示哈。那么,这个字节的状态就表示了当前白线的位置信息。再假设,我们已经写好了几个函数用来分别控制小车的左右运动。那么我们就可以通过以下的简单方式来实现循线了。
//用字节的高三位表示三个管子检测到的白线信息。
switch (LineInforByte)
{
case 0b11100000: //全部在白线上
Motor_Left_GoFront(FullSpeed);
Motor_Right_GoFront(FullSpeed);
break;
case 0b01100000: //明显车子向左偏了哈
Motor_Left_GoFront(FullSpeed);
Motor_Right_GoFront(NormalSpeed);
break;
case 0b00100000:
Motor_Left_GoFront(FullSpeed);
Motor_Right_GoFront(LowSpeed);
break;
……
//其他情况仿照上面自己写了哈。
default:
Motor_Left_GoFront(StopNow);
Motor_Right_GoFront(StopNow);
break
}
呵呵,这样就完成了一个循线小车的程序了哈。简单吧。
顺便说明一下下,Motor_Left_GoFront()函数是一个控制电机PWM输出的函数。FullSpeed NormalSpeed LowSpeed StopNow StopFree 是一些控制PWM的宏定义,你可以修改这些宏定义的值来实现以上的功能。我想,你看了这个程序应该已经对循线的基本原理了然于胸了吧。哈哈哈哈哈哈哈哈。
3、数据的高级加工——复杂地面情况的模糊识别算法。
(肚子饿了,吃饭后、约会完毕后、发现人气高后……再说,哈哈哈哈哈哈)
-----此内容被Gorgon Meducer于2005-10-23,11:50:58编辑过 我觉得关键是这三个问题
一个是识别再一个是控制算法在一个是控制输出
识别上可以采用多点光学采集、线阵视觉或面阵视觉,然后要做一些处理
对于点阵的就是阈值判断,面阵的就是边沿提取等,复杂一点可以上升到图像处理
然后就是控制算法了,最好是还有一些别的传感器,譬如电子罗盘(检测方向)、陀螺仪(检测偏航角速度)然后使用PID或者模糊控制算法
在然后就是控制输出了,要实现对电动机的精确控制并不容易,尤其是差速转弯的小车更麻烦,舵机转向轮得到还好一些,但是又不适合原地转弯。 支持~!
长期以来 大家都 在 show ~! 呵呵,人工智能方面的东西我以后会有介绍拉。
不久我就会写一些关于伺服电机控制的文章,保证解决你说的这些问题啦。
当然,主要是面向学生类的爱好者,没有必要那么专业的啦。 3、数据的高级加工——复杂地面情况的模糊识别算法。
以上的算法的确可以应付规范场地下的情况了,但是由于其类似查表式的数据处理方式,一旦出现真值表中没有的情况——哪怕是很明显的直线存在——机器人都没有办法处理了。典型的就是在地上有大块的白色斑点,导致机器人对白线视而不见。
解决以上问题的方法还要从人眼识别白线的原理上说起。在破坏严重的场地上,人类的眼睛仍然可以识别出原先的白线,这是为什么呢?通过重心。人类的眼睛通过捕捉白线的重心确立白线的大体轨迹,从而辨认出白线的位置。从概率的角度上说,在破坏严重的场地上,出现在白线两边的浅色干扰的概率是一样的,即使不同,由于白线本身的存在,其重心至少是不会偏离白线很远的,所以,只要简单的获得地面浅色标志的重心,就可以大体确立白线的所在。我们可以利用物理学上质心的算法获得这一信息。忘了说一点,要想机器人增强对环境的适应力,就需要增加传感器的数目。我们不妨用8个红外管作为传感器。这样通过处理后获得的场地信息就整整1个字节了。假设1个光电管的1拥有1单位的重量,八个光电管的坐标分别为 -7 -5 -3 -11 3 5 7,其间距都是2个单位,通过置信公式很容易计算出质心的坐标,通过这个坐标和0的绝对值,就可以知道当前机器人偏离白线的多少,而这个偏离值则可以通过简单的比例直接指导运动函数。典型实例如下:
/********************************************************
*函数说明:电机动作调速函数 *
*说明: 该函数放在定时器或者主循环里面用于产生软PWM*
********************************************************/
void SpeedPWM(char PWMLine)
{
char PWMLine_L = PWMLine;
char PWMLine_R = PWMLine;
static char PWMCount_L = 0;
static char PWMCount_R = 0;
char Temp = 0;
if (FollowLineEnable == True)
{
Temp = (char)fabs((float)CG_X);
if (AdcValueFlag == 0)
{
Temp = 0;
}
else
{
if (CG_X <0)
{
if ((Temp<<4) <= PWMLine_R)
{
PWMLine_R -= ((Temp<<5)+Temp<<2);
}
else
{
PWMLine_R = 0;
}
}
else
{
if ((Temp<<4) <= PWMLine_L)
{
PWMLine_L -= (Temp<<5);
}
else
{
PWMLine_L = 0;
}
}
}
}
PWMCount_L ++;
PWMCount_R ++;
if (PWMCount_L > Fastest)
{
PWMCount_L = Stop;
}
if (PWMCount_R > Fastest)
{
PWMCount_R = Stop;
}
if (PWMCount_L < PWMLine_L)
{
switch (GoDirection)
{
case Front:
Motor_Left_GoFront;
break;
case Back:
Motor_Left_GoBack;
break;
case Left:
Motor_Left_GoFront;
break;
case Right:
Motor_Left_GoBack;
break;
case Stop:
Motor_Left_Stop_Free;
break;
}
}
else
{
Motor_Left_Stop_Free;
}
if (PWMCount_R < PWMLine_R)
{
switch (GoDirection)
{
case Front:
Motor_Right_GoFront;
break;
case Back:
Motor_Right_GoBack;
break;
case Left:
Motor_Right_GoBack;
break;
case Right:
Motor_Right_GoFront;
break;
case Stop:
Motor_Right_Stop_Free;
break;
}
}
else
{
Motor_Right_Stop_Free;
}
}
/********************************************************
*函数说明:获取偏离轨迹线的数值 *
*输入: 表明寻线状态的字节 *
*[说明] *
* 通过类质心算法获取当前机器人偏离轨迹线的量*
* - 表示偏左 + 表示偏右 *
********************************************************/
signed char GetCG_X(unsigned char AdcValues)
{
signed char a = 0;
signed char Temp = 0;
signed char Totals = 0;
for (a = 0;a<8;a++)
{
if ((AdcValues <<a)>>7)
{
Temp += ((-7)+ (a<<1));
Totals++;
}
}
if (Totals ==0)
{
return0;
}
return(Temp / Totals);
}
函数调用GetCG_X函数,用来获取CG_X,CG_X直接在PWM输出函数里面指导机器人的运动。
以上方法的好处是,提供了一个比例调节循线动作的可能。支持多传感器的情况,尤其适合线性CCD类的线性数据的处理。为机器人提供了一个相对完整的视觉,不可能出现无法识别的情况,而且,这种情况可以使机器人在不加修改程序的情况下直接在在白线循线和黑线循线状态下切换。 好文章. hao 4、循线位置闭环控制中的PD算法
从上面各章中,我们已经初步掌握了获取机器人位置信息的方法,并且利用简单的P调解来指导机器人运动——不知不觉间,我们已经进入了控制学中关于位置环的闭环控制的问题了。
我们通过传感器获得白线的位置信息,并且通过计算获得了白线的质心距离车体中心的偏移量。控制车体中心位于白线的质心——这就是循线中位置环所要控制的东西。
首先,我们来说说如果不用PD算法,我们会如何控制这一位置环。我们可以简单的利用如果质心偏左就向左边全速运动,质心偏右就向右边全速运动来实现。这样的确可以完成循线的操作,但是效果显而易见,车子就像喝醉了酒一样,走着蛇形的路线。如果我们通过偏移量的多少乘上一个比例K来指导向左或者向右运动的幅度,那么我们的s形运动的幅度就会越来越小,最终到达水平运动。
这就是P算法。在P算法中k值的确立非常关键,如果K值过大,仍然会出现明显的S形运动——这个被称为超调;如果K值过小,那么就不能有效地指导循线,机器人就像对白线没有反应一样,很容易就超出了合理的运动范围;如果K值不合适,那么至少也会导致机器人不能以最快的速度到达位置环的平衡位置甚至是震荡。如何获得一个合适的K值理论上是可以通过计算获得的,但往往经验值和测试得来的数值会比较有效。
当使用P算法时,到达平衡位置中心后由于场地的原因,机器人出现频繁的调节位置的动作,就会大大限制住机器人移动的平均速度。这个时候,就需要一个和回复位置环速度有关系的量,这个就是我们通常称之为D的量,通常这个也称之为和动量有关的修正量——大家可以查阅相关的书籍获得D调节的详细内容。一般情况下,循线中仅仅是P调节就已经足够了满足一般要求了。 好文章,收下来慢慢学习……谢谢Gorgon Meducer! 好东东!!!!!!
没时间的捧个人场! 作者这么辛苦给我贡献了一篇好文章,不顶都不行啊~~~哈哈 ding 捧场~~~~~ 好啊,不愧搞机器人出来的啊。 我是高中搞机器人的,你的这些算法我们在实践中用到了,但就是没有上升到你这样的理论水平,现在看到了,有豁然开朗的感觉 谢谢。COOL! 谢谢。 05年的,还想听一听,不知道还有没有了。 对1楼的补充:差速转弯的小车 + 与车轮同步的光码盘计数反馈 ,在车轮不打滑的情况下,可以实现较精确的转弯,还可用来计算路程
-----------------------------------------------------------------------------------
【1楼】 violit
我觉得关键是这三个问题
一个是识别再一个是控制算法在一个是控制输出
识别上可以采用多点光学采集、线阵视觉或面阵视觉,然后要做一些处理
对于点阵的就是阈值判断,面阵的就是边沿提取等,复杂一点可以上升到图像处理
然后就是控制算法了,最好是还有一些别的传感器,譬如电子罗盘(检测方向)、陀螺仪(检测偏航角速度)然后使用PID或者模糊控制算法
在然后就是控制输出了,要实现对电动机的精确控制并不容易,尤其是差速转弯的小车更麻烦,舵机转向轮得到还好一些,但是又不适合原地转弯。 标记 网上搜的太杂,进了论坛才发现了好东东 刚刚看了,孩子发帖的时间,三年前。。。牛啊,孩子 本人刚学AVR没有多久,其实Gorgon Meducer 傻孩子的贴.我多数是看不懂的,但我从他的贴中看我应该向他学习的东西,治学要严谨.乐观面对.
真的相当感谢. 学习 重见天日,坚决顶~ mark,希望增加些智能算法方面的。。 请问怎么收藏呢? 我用CCD寻线,但是有强光干扰,如何处理比较好? 有点类似机器视觉,但是比那个好实现和好弄哦 mark! 循线平滑 很关键 to 【30楼】 highnose
楼上不要挖坟…… ===================
=挖坟无罪,盗墓有理=
=================== 我参加过的智能车比赛中就是使用这类方法。 mark 受益良多 学习 好东西还是得顶的啊!学习 我也来挖。。。哈哈。。。回头看看自己吧。。。
现在比以前还傻。。。哈哈。。 学习啦 好东西。用光电管的话,一体的是不是会好点? good; 打印慢慢学 确实不错,有前途~! 寻线方法应用场合较多。楼主在这方面有研究。 学习 学习了,^_^ 很好 我在比赛时用了其中的几个算法,现在想问问版主 能不能介绍一下私服电机的控制,如果有研究了可以跟我联系 。qq77167898 察看另外一个帖子……关于2007电子设计大赛驱动的…… 专看老帖!顶! mark有空自己做一个 好文章 坐下来慢慢看 不错! 收藏 学习 学习 顶,是必须的! 好文章,mark出来慢慢看 看看 mark 爱!!!!!!!!!! 05年的帖子现在看了还有用,哈哈,谢谢傻孩子
页:
[1]