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,一经查实,立即删除!

相关文章

策略模式场景举例

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

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

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

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

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

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

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

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…

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服…

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

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

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

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

oracle忽略除数为0,ora-01476除数为0的解决办法,oracle中decode()的使用

执行报表查询&#xff0c;固定的一个时间点没有数据&#xff0c;应该是有数据的&#xff0c;把前一个时间节点往前调是有的&#xff0c;往后调也有bebug报错把sql放到数据库中&#xff0c;发现提示如截图解决办法&#xff0c;oracle中的decode()select decode(b,0,0,a/b*100) …

Java GridBagLayout 简单使用

这里只介绍了很基础布局构建及使用&#xff0c;主要是关于 GridBagLayout. 首先整套流程大概是&#xff0c; 声明一个 GridBagLayout 对象 private GridBagLayout gridBagLayoutFrame new GridBagLayout(); 然后把当前类的容器布局管理器设置为 GridBagLayout this.setLayout(…

Angular之简单的登录注册

使用Angular实现了一个简单的登录注册的功能........ 涉及到的Angular知识点很少 主要是这个功能的实现...(*^__^*) 嘻嘻…… 里面涉及到的知识点记录: 1.本地存储的操作 localStorage 获取本地存储的值 window.localStorage.getItem(key)-->value (得到的数据是字符串&qu…

微信扫码下载iosAPP

1.首先在应用宝上传你的安卓APP应用&#xff0c;AppStore已经有了APP 2.进入应用宝app应用管理中心&#xff0c;点击“微下载”&#xff0c;然后里面的微下载链接地址就可以用了&#xff0c;可以看到ios可以通过应用宝再跳到AppStore就可以实现下载了转载于:https://www.cnblog…

linux中的加法函数,上下文管理练习(为加法函数计时)

上下文管理(为加法函数计时)为加法函数计时使用装饰器显示该函数的执行时长使用上下文管理显示该函数的执行时长装饰器实现import timeimport datetimefrom functools import wrapsdef logger(fn):wraps(fn) # wraps(fn)(wrapper)def wrapper(*args, **kw):start datetime.dat…

07数组与接口

1、运行TextInherists.java 示例&#xff0c;观察输出&#xff0c;注意总结父类与子类之间构造方法的的调用关系&#xff0c;修改parent构造方法的代码&#xff0c;显式调用grandparent另一个构造函数。 源代码&#xff1a; class GrandParent{ public GrandParent(){ System.o…

windows 访问linux中的mongodb,MongoDB的linux系统下的安装与连接

一 安装MongoDB的服务下载Linux系统下的MongoDB安装包上传压缩包到linux服务器中&#xff0c;解压到对应的安装目录下mkdir /usr/local/mongodbtar -zxvf mongodb-linux-x86_64-4.0.10.tgzmv mongodb-linux-x86_64-4.0.10 /usr/local/mongodb新建目录&#xff0c;分别用来存储数…

linux sqlserver 管理工具,Linux连接SqlServer的图形化工具SQuirrel

SQuirrel SQL一款基于java的数据库管理工具。所以可以运行在任意平台上&#xff0c;除了界面丑一点。在windows上我绝对不会选的&#xff0c;navicat多好。安装下载地址&#xff1a;https://sourceforge.net/projects/squirrel-sql/?sourcetyp_redirect在控制台运行&#xff1…

JDK源码包结构分类

最近查看JDK源码时&#xff0c;无意间发现几个类在陌生包里&#xff1a;com.sun.*、sun.*、org.*&#xff0c;google了一把总结了下以备他人搜索&#xff0c;如内容有误欢迎指正&#xff01;Jre库包含的jar文件(jdk1.6)&#xff1a;resources.jar、rt.jar、jsse.jar、jce.jar、…

GJM :Sql 各种语句 以及函数 [转载]

版权声明&#xff1a;本文原创发表于 【请点击连接前往】 &#xff0c;未经作者同意必须保留此段声明&#xff01;如有侵权请联系我删帖处理&#xff01;1.更改数据库的名称 2.表中有数据的情况下再添加列、删除列 3.在SQLServer 中各种查询语句的使用示例 4.模糊查询的语句 5.…

linux中断处理体系结构分析(一),Linux中断处理体系结构分析(二)

1.中断处理的体系结构我们知道编写设备驱动程序一定要用到中断处理函数&#xff0c;这在驱动程序的编写中&#xff0c;占据很重要的一部分。在响应一个特定的中断的时候&#xff0c;内核会执行一个函数&#xff0c;该函数叫做中断处理程序(interrupt handler)或中断服务例程(in…

c语言作业题五六章答案,数据结构(C语言版)第五六章习题答案

数据结构(C语言版)第五六章习题答案,人民邮电出版社,答案很详细。(15)设F是一个森林&#xff0c;B是由F变换得的二叉树。若F中有n个非终端结点&#xff0c;则B中右指针域为空的结点有( )个。A&#xff0e; n-1 B&#xff0e;n C&#xff0e; n1 D&#xff0e; n22&#xff0e;应…