Bug2算法的实现(RobotBASIC环境中仿真)

  移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求——避障。之前简单介绍过Bug避障算法,但仅仅了解大致理论而不亲自动手实现一遍很难有深刻的印象,只能说似懂非懂。我不是天才,不能看几遍就理解理论中的奥妙,只能在别人大谈XX理论XX算法的时候,自己一个人苦逼的面对错误的程序问为什么...

  下面开始动手来实现一下简单的Bug2避障算法。由于算法中涉及到机器人与外界环境的交互,因此需要选择一个仿真软件。常用的移动机器人仿真软件主要有Gazebo、V-rep、Webots、MRDS(microsoft robotics developer studio)等,这些软件基本都是三维环境下的模拟仿真,而目前大多数移动机器人均采用轮式结构,一般只在平面上运动。为了简化建模和编程方便,选择了一个平面环境下的机器人仿真软件——RobotBASIC。RobotBASIC的使用方法很简单,语法与标准的BASIC语言相似,它能使你简单、迅速地模拟多种类型的环境和情况。

  在Bug2算法中机器人围绕障碍物行走需要机器人能感知到障碍物的存在,可以通过碰撞传感器或红外接近开关实现。RobotBASIC中的机器人身体上装有5个红外传感器,分别间隔45°安装,如下图所示。通过函数rFeel()可获得表示红外传感器状态的编码数字,如果该方向检测到障碍则对应的位置1。即如果只在正前方检测到障碍则rFeel()返回 0b00100 = 4. 与一般碰撞传感器相比,红外传感器探测物体效果更好,因为最好不与环境接触发生碰撞,哪怕是很小的碰撞也可能会对机器人造成影响。

  RobotBASIC中的碰撞传感器有4个,分布在机身周围。前后的碰撞传感器分别形成130°圆弧,侧面两个形成50°圆弧。分布情况如下图所示:

有时机器人有必要对某物体的轮廓进行跟踪:

  1. 当机器人沿预期路径运动时遇到障碍物,它可能会通过在障碍物周边移动,绕过这个障碍物。
  2. 在办公室环境中,用于递送文件的机器人肯能会沿着墙壁在走廊里行走,依次拜访每个房间。
  3. 一种使机器人在错综复杂的走廊中在一个方向(左或右)沿墙壁运动的策略。

  机器人在遇到一个障碍物前一直向前运动。当遇到障碍物时,机器人将停止向前运动,并对墙面进行跟踪。为了理解机器人怎么对墙壁进行跟踪,想象你被蒙上眼睛时,站在离墙壁很近的地方,并沿着墙壁行走到达目的地。你可能会伸出一只手(如果墙在你的右边,伸出右手)来帮助你确定墙壁的位置。随着你和墙壁之间的距离增大,你的手最终将不能触摸到墙壁。然后你需要右转并向前运动以再次靠近墙壁。如果你发现自己与墙壁越来越近,则需要弯曲手臂。为了维持伸出手臂,你必须向远离墙壁的方向旋转,以避免撞到墙上。

  下面根据Bug避障算法简介中的伪代码实现机器人在未知环境中的避障行走。可以在程序中设定不同的目标位置,并用鼠标在屏幕上选好一个机器人初始位置之后按下左键确定(为了模拟更加动态的未知环境,还可以在机器人移动过程中随时加入一个障碍物,但下面的程序还没有实现这一功能,有待优化)。

MainProgram://-------------define variables here-----------target_x =  400target_y =  150HitPoint_x = 0HitPoint_y = 0dx0 = 0dy0 = 0RobotSize = 10delayTime = 2 TurnDir = 1  isFirstHit = falseisReachTarget = falseisAbleToTarget = truegosub DrawScenegosub InitializeRobotrInvisible Red,GrayLineWidth 2rPen Down,Redrepeat readmouse x,y,buntil b = 2  //Click the right button to start movement//----------------while loop---------------while truegosub MoveLineToTarget if isReachTarget then breakgosub FollowWallif isReachTarget then breakif (not isAbleToTarget) then break    wend           
End
//==========================================================
DrawScene:ClearScrLineWidth 3 Data Wall_1; -100,450,  500,450,  500,360,  100,360,  100,450,  150,-400Data Wall_2; -250,250,  500,250,  500,50,   450,50,  450,200,  250,200, 250,250, 260,-240MPolygon Wall_1, Gray             //Draw obstaclesMPolygon Wall_2, GrayCircle  600,400, 700,200, Black, Gray Circle (target_x - 5),(target_y + 5), (target_x + 5),(target_y - 5), Red, Red  //Draw target
Return    
//==========================================================
InitializeRobot:repeat readmouse x, y, buntil b = 1  //Click the left button to locate the robot//Calculate the initial angle for robot to face the targetdx0 = target_x - xdy0 = target_y - y if dx0 = 0 AND dy0 = 0theta = 0elsetheta = PolarA(dx0, dy0) * 180 / pi() + 90 if theta > 180 then theta = theta - 360 if theta < -180 then theta = theta + 360rLocate x, y, theta, RobotSize          //InitializationGotoXY x,ylineto target_x, target_y, 1, Gray      //Draw m-line  
Return  
//==========================================================
MoveLineToTarget:dx = target_x - rGpsX()dy = target_y - rGpsY()if dx = 0 AND dy = 0  then returntheta = PolarA(dx, dy) * 180 / pi() + 90 - rCompass()  if theta > 180 then theta = theta - 360 if theta < -180 then theta = theta + 360rTurn thetadistance = Round(polarR(dx, dy))for i = 1 to distanceif rBumper() & 4isFirstHit = trueHitPoint_x = rGpsX()      //record the hit point positionHitPoint_y = rGpsY()breakendifif PolarR(target_x-rGpsX(),target_y-rGpsY()) < 5isReachTarget = truexyString 2,2,"Get to the target!"breakendifrForward 1                  //move forward one pixeldelay delayTimenext
Return
//==========================================================
FollowWall:  TurnAmount = 5If TurnDir > 0 FN = 6     //right and right frontElseFN  = 12   //front and left frontEndifwhile true// reach the goal ? condition1 = PolarR(target_x - rGpsX(),target_y - rGpsY()) < 5 if condition1 isReachTarget = truexyString 2, 2, "Get to the target!"breakendif// re-encounter the hit point ? condition2 = (PolarR(rGpsX()-HitPoint_x,rGpsY()-HitPoint_y) < 5) and (not isFirstHit)    if condition2        isAbleToTarget = falsexyString 2, 2, "Cannot reach the target!"breakelsetemp = rGpsY() - (dy0 / dx0 * (rGpsX() - target_x) + target_y)// re-counter the m-line ?condition3 = ((temp * temp) < 12) and (not isFirstHit)// closer to the goal?condition4 =  PolarR(target_x-rGpsX(),target_y-rGpsY()) < PolarR(target_x-HitPoint_x,target_y-HitPoint_y)if (condition3 and condition4) then  break          endif    While (rFeel() & FN) or (rBumper() & 4)rTurn -TurnDirWendrForward 1  // forward always to prevent stallif PolarR(rGpsX()-HitPoint_x,rGpsY()-HitPoint_y) > 5isFirstHit = falseendifWhile not rFeel()// turn back quickly to find wall againrTurn TurnAmount*TurnDirrForward 1Wenddelay delayTimewend
Return
//==========================================================

  由于真实的环境是动态的、未知的、复杂的,可能随时出现一个障碍物挡在机器人面前,也可能存在形状复杂的障碍物(如Bug避障算法简介中出现的螺旋形障碍物),或者一开始机器人就被封闭在障碍物的内部。因此,算法的鲁棒性非常重要,需要设计出一个合理地规则解决上述问题。上述算法的实现过程在大体上是对的,但在细节上还存在诸多问题有待优化。下面几幅图给出了不同位置和不同转向时的情况,假如算法考虑的不够全面就可能会出现在某些初始位置或者换个转向就失效的情况。

  初始时刻机器人被封闭在障碍物内部,无法到达目标,此时算法应该做出合理地判断,停止循环,避免一直在内部转圈:

  如下图所示,机器人跟踪墙壁时换了一个转向。之前设定的是靠右行走,现在靠左行走。如果算法鲁棒性不好,就可能会出现换个转向就失效的情况。

   编写这个程序的时候遇到了很多问题:

  1. 在RobotBASIC软件中机器人移动的距离最小为1个像素点,因此很多情况下会出现舍入误差。比如判断点是否在直线上,两点是否重合的时候就不能用"=",而需要设定一个合理的阈值用"<"或">"判断,阈值过大过小都不好。

  2. 直线检测时对公式 y=dy/dx*(x-x0)+y0进行变形(考虑到有可能机器人和目标点处于一条竖直线上,此时斜率为无穷大),判断y*dx - dy(x-x0)+y0*dx = 0?  理论上如果点在直线上该等式的值就为0,我想当然的以为当点接近直线时,该式子的值也会很小,因此设了一个不大的阈值来检测点是否在直线上。而一般情况下dx的值都会有好几百,两边同乘dx后误差被放的很大,远远超出了阈值。最后还是用y=dy/dx*(x-x0)+y0来进行判断了,一偷懒没有写if dx=0的情况,毕竟用鼠标去定位机器人的时候很难使其正好与目标处于一条铅垂线上...我又不严谨了O__O "…

  3. 当机器人沿着直线撞到障碍物时,切换到FollowWall程序。在FollowWall中需要不断检测机器人是否再次遇到hit point,如果再次遇到则说明无路可走,要退出主程序。因此设置一个标识变量isFirstHit,在MoveLineToTarget子程序中碰到障碍物时,isFirstHit设为true,然后程序跳入FollowWall中。while循环中检测是否为再次碰到hit point,如果是第一次则机器人继续绕墙行走,理论上执行rForward 1之后就可以直接将变量isFirstHit设为false了。但实际上这样在机器人第一次撞墙后就停止不动,并跳出了主程序!仔细分析走一个像素点之后就立马将标志取反将会在第二次进入while循环的时候造成判断错误。因为我们比较当前点是否为hit point的时候使用了一个距离阈值:(PolarR(rGpsX()-HitPoint_x,rGpsY()-HitPoint_y) < 5) ,即当前点距hit point在5个像素范围内就认为这两个点重合。因此还没等机器人走出这一范围,if语句的条件就成立为真,接着就执行了break语句跳出了循环。为了解决这一问题,可以让机器人多走一段距离之后再对isFirstTrue赋值false。问题又来了,走多远再对其赋值?检测两点重合的阈值设多大?(有时设小了机器人会直接越过该点,导致其完全停不下来...)这些问题都需要仔细琢磨。

MoveLineToTarget:...isFirstHit = true....
ReturnFollowWall:while true...if (PolarR(rGpsX()-HitPoint_x,rGpsY()-HitPoint_y) < 5) and (not isFirstHit)     breakrForward 1  // move forwardif PolarR(rGpsX()-HitPoint_x,rGpsY()-HitPoint_y) > 5isFirstHit = false...wend
Return
经验与总结:

  调试往往需要花费远远超过你想象的时间——有时比编写代码时间还要长得多,因此一定要有耐心。在调试期间获得的信息无论对于修改程序中的错误,还是进一步开发这个或其他程序,甚至对提高你解决问题的能力,都是非常有价值的。随着经验的积累,你会发现在细心进行系统设计和谨慎编写代码的过程中多花一些时间,能够大大节省调试的时间。

  对一台真实的机器人,我们很难设想各种问题产生的原因,所以也就很难对算法进行综合测试。一台能在几种有限环境中运行良好的机器人,往往面对不可测的情况时就会失败。有了机器人模拟器就能构建多种不同的环境,这有助于实现算法,减少失败的可能性。不过仅仅依靠调试器查找错误并不能代替全面的分析推理。

 

 

参考:

John Blankenship, Samuel Mishal. 《机器人编程设计与实现》 科学出版社

Robotics, vision and control fundamental algorithms in MATLAB.  Chapter 5 · Navigation  pp.90-91

转载于:https://www.cnblogs.com/21207-iHome/p/5998630.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469970.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php l方法,ThinkPHP的L方法使用简介

thinkPHP的L方法用于启用多语言的情况下&#xff0c;设置和获取当前的语言定义。其调用格式为&#xff1a;L(语言变量[,语言值])1.设置语言变量除了使用语言包定义语言变量之外&#xff0c;我们可以用L方法动态设置语言变量&#xff0c;例如&#xff1a;L(LANG_VAR,语言定义);语…

linux-pcap 抓包程序框架

转&#xff1a;http://blog.chinaunix.net/uid-21556133-id-120228.html libpcap详解2010-12-01 22:07libpcap&#xff08;Packet Capture Library&#xff09;&#xff0c;即数据包捕获函数库&#xff0c;是Unix/Linux平台下的网络数据包捕获函数库。它是一个独立于系统的用户…

策略模式场景举例

容错恢复机制 容错恢复机制是应用程序开发中非常常见的功能。那么什么是容错恢复呢&#xff1f;简单点说就是&#xff1a;程序运行的时候&#xff0c;正常情况下应该按照某种方式来做&#xff0c;如果按照某种方式来做发生错误的话&#xff0c;系统并不会崩溃&#xff0…

php写抢票脚本,火车票抢票python代码公开揭秘!

市场上很多火车票抢票软件大家应该非常熟悉&#xff0c;但很少有人研究具体是怎么实现的&#xff0c;所以觉得很神秘&#xff0c;其实很简单。下面使用Python模拟抢票程序&#xff0c;给大家揭秘抢票到底是怎么回事。该代码仅供参考&#xff0c;主要用于大家沟通交流&#xff0…

python不用加号实现加法

问题: Calculate the sum of two integers a and b, but you are not allowed to use the operator and -.Example:Given a 1 and b 2, return 3. class Solution(object):def getSum(self, a, b):""":type a: int:type b: int:rtype: int"""…

.net与mysql,ASP.NET与MySql的连接

ASP.NET与MySql的连接1.数据连接方式ASP.NET本身的数据访问ADO.NET不支持对于MySql的连接和查询&#xff0c;但是MySQL官网上均提供了多种ASP.NET连接到MySQL的方式&#xff1a;(1)ODBC驱动的访问方式&#xff1a;mysql-connector-odbc-5.1.5-win32.msi&#xff0c;ODBC(2)ADO.…

php 反射 视频教程,php 实现反射

定义一个人类class person{public $name;public $gender;public function say(){//echo $this->name."say".$this->gender;}public function __set($name,$value){$this->name$value;}public function __get($name){if(!isset($name)){echo "未设置&qu…

代理模式——HeadFirst设计模式学习笔记

代理模式&#xff1a;为另一个对象提供一个替身或占位符控制这个对象的访问 特点&#xff1a; 让代理对象控制对象的访问&#xff0c;被代理对象可以是远程对象&#xff08;远程代理&#xff09;&#xff0c;创建开销较大对象&#xff08;虚拟代理&#xff09;&#xff0c;或需…

cursor用法java,Cursor的基本使用方法

Cursor的基本使用方法今天在用到Cursor的时候发现&#xff0c;有很多游标相关的知识还是有欠缺&#xff0c;在网上搜了篇基础讲解的文&#xff0c;觉得还不错&#xff0c;自己整理了一下发上来。虽然很基础&#xff0c;但是有一些内容之前确实没有很扎实得掌握&#xff0c;所以…

$(document).ready()与window.onload的区别

1、执行时间&#xff1a; window.onload要等到页面所有元素加载完毕才执行&#xff0c;包括&#xff08;图片、flash等&#xff09; $(document).ready()在DOM结构绘制完毕后就执行&#xff0c;不必等到加载完毕。 2、执行个数&#xff1a; 如果有多个window.onload&#xff0c…

mongo java 日期,Java 8日期/时间(JSR-310)类型与Spring Data MongoDB的映射

我有Java 8日期/时间字段的简单文档Documentpublic class Token {private Instant createdAt;...}我希望坚持使用Spring Data MongoDB 1.5版.但java.time.Instant类型的字段无法正确反序列化,因为MappingMongoConverter缺少java.time类的转换器.在Spring 4中,我找到了带有不同转…

win7(64位)php5.5-Apache2.4-mysql5.6环境安装

win7&#xff08;64位&#xff09;安装搭建 php-5.5.10 apache2.4.7 mysql-5.6.16 环境 工具/原料 php-5.5.10-Win32-VC11-x64.zip 下载地址: http://windows.php.net/download/ httpd-2.4.7-win64-VC11.zip 下载地址: http://www.apachelounge.com/download/ mysql-5.6.16-win…

matlab中计算不等式的解,大神们,求个解多元一次不等式的代码,要所有整数解...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼用lingo做的&#xff0c;我lingo特烂328*a1470*b1300*c570*d3750*e2080*f3900*g3070*h<9000;gin(a) ;gin(b) ;gin(c) ;gin(d) ;gin(e) ;gin(f) ;gin(g) ;gin(h) ;结果&#xff1a;Feasible solution found.Infeasibilities: 0.0…

14.5.5.1 An InnoDB Deadlock Example 一个InnoDB 死锁实例

14.5.5.1 An InnoDB Deadlock Example 一个InnoDB 死锁实例下面的例子演示了一个错误可以发生当一个lock 请求会导致一个死锁,例子设计2个客户端&#xff0c;A和B:Jekins:/root# mysql -uroot -p1234567 -e"SHOW ENGINE INNODB STATUS\G;" | grep -i dead Warning: …

php开发环境 ubuntu,Ubuntu配置PHP开发环境

开发环境安装目前web服务器有很多&#xff0c;本文安装Apache服务器&#xff1b;本文使用的服务器是Mysql服务器。sudo apt install apache2常用命令重启Apache&#xff1a;sudo /etc/init.d/apache2 restart重启php&#xff1a;sudo /etc/init.d/php-fapm restart配置apache服…

Jmeter java.lang.OutOfMemoryError: GC overhead limit exceeded

使用这个jmeter工具测试时&#xff0c;遇到这么个gc错误&#xff0c;网上找到了解决方案。原因是jmeter默认分配内存的参数很小&#xff0c;好像是256M吧。故而解决方法&#xff0c;就是增加内存&#xff1a; set HEAP-Xms4g -Xmx4gset NEW-XX:NewSize1g -XX:MaxNewSize1g 注意…

php基础知识总结大全,php基础知识回顾 —— 常量

您现在的位置是&#xff1a;网站首页>>PHP>>phpphp基础知识回顾 —— 常量发布时间&#xff1a;2019-01-23 17:23:08作者&#xff1a;wangjian浏览量&#xff1a;489点赞量&#xff1a;0在PHP中有这样一类变量&#xff0c;当变量值被定义之后&#xff0c;它的值就不…

Java 配置maven及阿里云镜像

一&#xff1a;配置maven 1.下载maven&#xff0c;选择Binary tar.gz&#xff0c;解压拷贝到目录/usr/local/ https://maven.apache.org/download.cgi2.配置系统默认maven路径&#xff0c;打开配置文件 $ open ~/.bash_profile写入路径信息 export M2_HOME/usr/local/apache-ma…

php中get_featured_posts()是什么意思,WordPress的Get_Posts()函数详解

WP中获取POST有两个主要函数&#xff0c;Get_post()和Get_Posts()。一个是获取单文章&#xff0c;另外一个是获取多文章&#xff0c;其中&#xff0c;官网对Get_posts()函数的描述很简单。但有的时候描述越简单的函数&#xff0c;使用起来却并没有那么简单。下面我通过一个案例…

Android Studio 下使用git -- 个人,本地版本控制

第一步&#xff1a;下载安装git 下载地址 : https://git-scm.com/downloads 第二步&#xff1a;Android Studio 下配置git路径。 配置之后&#xff0c;Test弹出如下成功的提示即可。 第三步&#xff1a;创建版本库 选择项目的根目录比较适合。 第四步&#xff1a;添加需要版本控…