本帖最后由 digeyes 于 2013-4-4 05:22 PM 编辑
4月4号更新在4楼
在下灵鹫宫新手刚500k,换服务器这几天都在折腾机器人。现在还有不少地方的秘密地点不知道怎么去,路径也还没录完,不过基本框架倒是完工大半了。这个机器人旨在制作一个通用的行走、搜索工具以辅助任务机器人的实现。 本文包含4部分: 1、路径的录制和遍历及指令的衔接 2、通过遍历自动记录和使用房间信息 3、遍历错位后如何重新定位 4、在1、2、3的基础上实现全球定位
路径的录制和遍历及指令的衔接
这方面的内容论坛里有不少文章,不过还是老生常谈下吧。在进入正题之前介绍3个重要变量,后面经常会用到。 @nesw : n|e|s|w|ne|se|sw|nw|nu|eu|su|wu|nd|ed|sd|wd|u|d|enter|out @reversenesw: s|w|n|e|sw|nw|ne|se|sd|wd|nd|ed|su|wu|nu|eu|d|u|out|enter @fullnesw: north|east|south|west|northeast|southeast|southwest|northwest|northup|eastup|southup|westup|northdown|eastdown|southdown|westdown|up|down|enter|out 分别是基本方向、逆向、方向全名的list,老手一看就知道。 关于录制遍历用的路径,最好是起点和终点为同一个地方。逆向行走会有很多麻烦。 #alias recordpath { #var recordingpath #loo 1,%numitems( @nesw) { #alias @{nesw.%i} { @{fullnesw.%i} #var %1 %additem( @{nesw.%i}, @{%1}) _nodef path } } #unalias enter #unalias out } 这是我用来录制路径的alias,输入recordpath 名称 ,然后像平时那样走路就会自动记录下路径了,比如recordpath yangzhou,就会把你之后的行走路线记录到变量@yangzhou里。最后两行删掉了enter 和out,呵呵,因为某些原因...... 第二行的@recordingpath作为临时变量用于储存区域名称,其实应该叫做recordingarea的,无所谓了。 #alias addp {#var @recordingpath %additem( %1, @{@recordingpath}) _nodef path} addp 用来在路径中添加enter、out和基本路径以外的指令。比如:addp {open door;e} 。指令有空格的或多个命令要用{}括起来。 #alias recordingfin
{#loo 1,%numitems(@nesw) {#unalias @{nesw.%i}}} 用这个来结束录制。 路径录制好了,该说下使用方法了。我定义了两3种用法,goto、walk和bianli。 goto就是很单纯的把一个路径从头走到尾: #alias goto { #loo 1,%numitems( @{%1}) { #wa 70 #exe @{%1.%i} } #alias gotofin { #unalias gotofin #exe %2 } tell @myid gotofin } goto本身没什么好说的,每步的延迟70ms,一口气走到路径结束。最后的#alias gotofin和tell @myid的用处是方便和其它指令衔接。在复杂机器人的行进过程中遇到任务模块衔接时,单纯的用”;”分割指令很容易产生触发冲突和busy、等待的处理上的难题,为了确保在一段指令切实完成后再执行下一部分的指令,最好的办法就是在指令末尾tell自己,通过触发的方式执行下一段指令。goto在走完路径后会告诉自己指令结束,然后通过trigger执行gotofin指令。gotofin在执行goto时定义,运行一次自动删除,非常方便。用于配合的trigger: #trigger {^你告诉*:gotofin$} {gotofin} goto使用方法: goto 路径名 {结束后要执行的指令} 例:goto yangzhou {#wa 3000;dance;laugh;haha;hehe;cry} goto可以嵌套,如:goto a {goto b {goto c}} 下一个是walk: #alias walk { #if (%1=null) {#var walkcount 0 _nodef path} #if (@walkcount=%eval( %numitems( @{%1})+1)) { tell @myid 行走结束 #add walkcount 1 } #if (@walkcount<=%numitems( @{%1})) { #exe %item( @{%1}, @walkcount) #add walkcount 1 } } 其实zmud是没有null的,呵呵,不过这个alias的使用没有问题,懒得改。直接输入walk会重置相关参数,然后一直输入walk 路径名 就可以一步一步走了。手动遍历,方便测试。走完后tell自己行走结束,触发执行bianlifin #alias bianli { #var currentpath @{%1} walk look #alias bianlifin { #unalias bianlifin #exe %2 } } #trigger {^%s这里*的出口是*} { #t+ walktrig #cr } #trigger walktrig {^> *$} { #t- walktrig walk currentpath } 触发式遍历指令用于搜索,格式: bianli 路径名 {完成后指令},需要和两个trigger配合使用。如果把出口信息直接当做走下一步的trigger,会出现找到人时多走一步的问题,需要逆向行走一步,这会产生很多麻烦,比如目标刚好处于路径不可逆的位置,真的很麻烦...... 而用以上两个trigger就绝不会出现这样的问题。可以和goto配合使用。 例如:goto a {bianli b {goto c {bianli d}} } 这样就可以很方便的实现一个指令走完路径a再遍历路径b再到c再遍历d。 当然也可以 bianli a {bianli b {bianli c {bianli d}}},如果goto路上有什么障碍就这么做。 触发式遍历在使用时需要配合应对busy及拦路的的trigger,形如: #trigger {谁拦住了你} {#add walkcount -1;kill who} #trigger {那谁死了} {walk currentpath} #trigger {正忙不能移动} {#wa 1000;#add walkcount -1;walk currentpath} 注:currentpath是使用bianli指令时赋值的一个临时变量,储存了要走的路径。
呃,开始直接在浏览器里写写了一半崩溃了,我那个郁闷啊。然后word里写了粘贴过来全是乱的,编辑了半天,完了都1点半了...... 剩下的明天再写吧。 |