2021.2.21 RoboCupRescue
作者:互联网
问题
先说一下这段时间对AStarPathPlanning和BuildingDetector的研究。
对于这两个文件的研究起源于消防agent面对障碍物静止不动的现象,这个现象在hfutengine十分普遍,成为了消防效果很差的重大原因。
一个消防agent在程序运行的300个周期中不断重复着以下的几个活动步骤(在Tactics中写明):
1.试图接收中心智能体或其它agent发来的消息并确定目标,若成功接收,跳过步骤2;
2.自己的detector确定一个目标;
3.ExtAction根据目标提取出一个动作,如动作为移动,则由PathPlanning规划路径返回给ExtAction,再提取出这个路径对应的移动动作;
4.执行动作。
其中步骤1里中心智能体的消息为allocator确定的目标,而消防站在当前的代码中完全没有作用(如下图),警察和消防之间的沟通经良良提醒得知,其也未完全建立。
所以步骤1无效,所有目标均由detector确定。
假设
而经由上次的集中实验,我暂时没有发现目标选择上的明确问题,于是针对“消防面对障碍物不动”这个问题提出了三个假设:
1.PathPlanning总是得出一个其上包含障碍物的路径作为结果,导致不能通过;
2.在执行整个Tactics的过程中,某个步骤在某种情境下出现bug导致了某种意义上的程序中断;
3.在我们跑过的几个地图中,碰巧detector首先给出了一个不可能到达的目标,而能否到达无法检测出,导致该静止不动的消防卡在当前任务。
初步研究
在初始的验证中,我想当然地认为既然警察、救护和消防共用PathPlanning,而其它两种agent并没有出现如此明显的路径规划异常,便直接排除了第1种假设(这是一个很大的误区)。不过我还是复习了A*算法并详细查看了AStarPathPlanning文件,重新通读tactics等文件,深入研究了detector和firefighting,并针对目标选取提供了两种改进思路:
1.在detector的calcTarget()函数中,对边建筑(着火建筑凸包的边缘)列表进行遍历,删除其中到达路径不可通过的所有目标,然后再进行基于火势的排序(基于火势的排序已经实现);
2.在BuildingSorter(基于火势排序的排序器)的compare()方法里添加有关路径上障碍物是否存在的排序;
寻找方法
要实现上面的两种思路,都需要一个共同的方法,那就是判断路是否被障碍物阻断(部分阻断并不是阻断)。我花了很长时间寻找一个判断路通的方法未果,便想自己写一个方法,但这至少也需要搞清楚障碍物存在的形式。我又陷入没有头绪的境地。直到昨天良良在研究警察的代码时发现了其detector中的一个方法isGetCross(),我才注意到Road和hfutRoad以及一些其它相关的东西,由此揭开了障碍物的面纱,看清了其真实的面目——Road对象的getBlockeds()方法。
另外,pathplanning中的getDistance()方法被频繁用到:
取整条路径中每一个Road对象的location(找不到具体是何物,只知道是一个类似Piar对象的东西,推测是一个坐标,具有first和second两个可以访问的值),然后求首尾间的欧氏长度。
走出误区
直至昨天良良提醒我,警察的目标选取才是重要的,而路径规划并没有意义——他的清障动作是在附近有障碍物时便执行,走到何处,清到何处,且救护车的动作情况实际上并没有被仔细观察。
由此我想到,当下的AStarPathPlanning很可能忽略了障碍物的存在——是专为警察设计的。于是我重新仔细考虑了AStarPathPlanning算法里图的构建方式(原本令我十分费解):
LazyMap是一种初始时未知键值和值的Map(未知但确实存在,是一对对的泛型引用),它的键值在访问时才实际赋值。如此处的neihbours.get(xxx),本来没有xxx这一键值,可是却要访问它,此时便会直接创建一个xxx键用来使用。
总之,此处构建出的图应该是一个理解为邻接表的映射,键值为每个Area,值为每个Area的所有相邻Area。
完全忽略了障碍物的存在。
而后我对此进行了实验验证。
实验评估
上图是test地图第103周期的截图。消防最初的位置就在警察现在的位置,但因为第一个着火建筑是最下方那个(id:248),其一直未出现在视线中,所以消防在扑灭自己身旁的火后(左蓝色建筑,id:905)目标一直为空。
直到49周期,警察清障到达右上角的道路,发现了此时已经深红色的建筑着火后,消防才找到了新的目标。
此时注意,路径规划给出了一条最佳路径——[256, 271, 278, 263, 270, 257, 280, 262, 974, 975, 919]。我逐个对照地图,发现这个路径数组指示的正是下图的道路:
这条路被障碍物堵死,但又恰好是到达火场的最短路径,符合上述“消防面对障碍物不动的原因是路径规划完全忽略了障碍物的存在”这一假设。继续进行相似的实验,得出结论一样。
至此,我们基本可以推测得部分消防静止不动这一现象在代码尺度上的原因就是路径规划忽略了障碍物,导致原本应该奔赴目标的消防被卡在原地。这一点非常致命,几乎导致了半数消防在半数时间内在原地罚站!
进一步的做法
可想而知,消防的路径规划与警察的路径规划完全是两码事,为此我们应该保留原有的A*作为警察的路径规划,重写一个规避障碍物的路径规划用于消防。
在此记录以下pathplanning的格式:
写一个结点类Node,在init()中完成图的构建。在calc()中得到result,类型是一个ArrayList<EntityID>,实际上是一个元素为Road对象的数组。访问时用getResult()。
标签:障碍物,2021.2,21,RoboCupRescue,消防,路径,目标,detector,警察 来源: https://blog.csdn.net/JasperSong/article/details/113914646