上一篇文章《如何在gazebo中实现多机器人仿真》,介绍了如何在仿真环境gazebo中同时加载多个机器人,并且实现同时控制或单独控制。而在gazebo中加载多个机器人仅仅是多智能体协同控制研究的第一步,这次的文章将介绍如何在ROS操作系统下,gazebo仿真环境中实现基本的多机器人编队控制仿真。
1.领航者-编队者编队原理介绍
多移动机器人编队主要需要解决两个问题,即多机器人编队队形的形成和队形形成后的保持。队形形成问题是指在一个复杂环境中,多机器人随机分布,通过自身的传感器信息以及和其他机器人之间的信息交流,形成一个适合完成任务的稳定队形。常见的队形如图所示:横队形(并列行走);纵队形(跟随行走);楔形(保持V形行走)。
为了能够形成特定队形,多机器人需要确定一个队形参考点,每个机器人通过队形类型和领近机器人的相对位置,来决定自己的下一步动作。选取参考点的方法主要有:中心参考;领航者参考;邻近参考。
目前针对多机器人的编队控制,主要有以下几种方法: 1) 基于领航者-跟随者(Leader-follower) 2) 基于虚拟结构(Virtual Structure) 3) 基于人工势场(Artificial Potential Field) 4) 基于行为(Behavior) 5) 基于路径跟随(Path Following) 6) 基于信息一致性(Consensus) 本次实验采用基于领航者-跟随者(Leader-follower)的编队方法,其基本思想是将编队的所有成员指定为领航者或跟随者。通过对领航者下发运动控制命令,来控制整个编队,跟随者以相对于领航者的距离和方向信息跟随领航者,实现队形控制。 领航者-跟随者方法的优点在于编队控制结构简单易实现。在编队中,仅需要设置领航者的期望路径。这种方法的缺点是编队系统过于依赖领航者。
2. gazebo环境下编队效果展示
编队方法参考领航者-跟随者方法,队形选择为纵行编队。 运行指令: 1.启动gazebo仿真 roslaunch ares_gazebo ares_playground_gazebo.launch
2.启动编队程序 roslaunch stage_first OnYourMarkGetSetGo.launch
1、初始编队过程
2、移动小车1(领航者)
2、移动小车2
3、移动小车3
3.编队仿真程序详解
此次在gazebo下的编队方法参考领航者-跟随者方法,队形选择为纵行编队,理由有二: 1)领航者-跟随者方法较简单,纵行编队为最基础简易的队形; 2)纵行编队在复杂环境下行驶较灵活(转弯、避障等方面),有利于之后自主导航加多车编队结合的工作。
3.1 编队系统程序框架
此次在gazebo环境中进行纵行编队的仿真,下面以两个机器人为例介绍编队系统框架:
仿真环境将Robot1、Robot2的定位数据以及机器人上的激光雷达数据发送至机器人各自的节点。Robot1在编队中作为领航者,将激光数据发送至领航者节点,领航者结合激光数据做出运动及避障命令,并将运动控制命令发送至Robot1节点。跟随者节点不但接受Robot2的激光数据,还接受Robot1和Robot2的位置信息,并根据二者位置(距离和偏航角)差距,通过控制算法给出Robot2的控制命令,使二者位置差距逐渐趋近于给定值,从而达到编队效果。Robot1和Robot2的控制命令最终将发送至仿真环境中以实现。
3.2 具体程序解读
程序中将领航者、跟随者各自作为单独的节点,这样的好处是扩大机器人编队规模时直接添加节点即可。
master.cpp控制领航者,slave_tf_listener2.cpp、slave_tf_listener2.cpp分别控制两个跟随者,tf_broadcaster.cpp为小车位置tf广播节点。
3.2.1 master.cpp
首先对领航者节点master.cpp做分析:
Main函数定义节点,获取句柄,并且对领航者身份的小车ares1发布速度控制指令,接收小车ares1的激光雷达数据。当程序正常运行时,进入wander函数。
Wander函数中首先对小车是否需要避障做出判断,判断依据为激光雷达数据中的intensities[]数组,当判断周围有障碍物时,小车进入rotate程序避障。(本次设计中因小车雷达无法获取intensities[]数据,所以没用到其避障功能,这里对其不再赘述)。 当小车判断周围无障碍时,进入move程序。
在move程序中,领航者以给定的speed直线行驶。
3.2.2 slave_tf_listener.cpp
下面对跟随者节点做分析,主要对运动控制做分析,其余部分与master.cpp基本一致。 作为跟随者的小车,其运动控制命令根据与领导者的相对位置给出。
vel_msg.angular.z = 4.0 * atan2(transformSM.getOrigin().y(),transformSM.getOrigin().x())
; 跟随者小车的角速度由二者相对位置的反正切值决定 vel_msg.linear.x=0.5*sqrt(pow(transformSM.getOrigin().x(),2)+pow(transformSM.getOrigin().y(), 2))
; 跟随者小车的线速度由二者相对位置的直线距离决定 当领航者小车速度一定时,若跟随者小车与其相距较远,则给定线速度linear.x大于领航者速度;反之,相距较近时则小与领航者速度。当距离达到一定值使二者速度相同时,两者距离不变,形成稳定编队。 调整系数即可对小车形成编队速度以及编队中的相对位置进行调整,线速度控制中系数越大,编队中两车距离较远。 其中关于监听tf的具体解释可参考:tf监听关系 有关tf关系的运用与学习也可关注古月学院的《ROS入门21讲》,具体步骤如下: (1)定义监听器; tf::TransformListener listener
(2)定义存放变换关系的变量 tf::StampedTransform transformSM;
tf::StampedTransform transformMS;
(3)监听两个坐标系之间的变换
try{
listener.lookupTransform("/ares2", "/ares1",ros::Time(0), transformSM);
}
catch (tf::TransformException &ex) {
ROS_ERROR("%s",ex.what());
ros::Duration(1.0).sleep();
continue;
try{
listener.lookupTransform("/ares1", "/ares2", ros::Time(0), transformMS);
}
catch (tf::TransformException &ex) {
ROS_ERROR("%s",ex.what());
ros::Duration(1.0).sleep();
continue;
}
3.2.3 tf_broadcaster.cpp
tf_broadcaster.cpp主要接收小车的在仿真环境的位置信息,并将其转换为tf关系发布
小车发送位置信息需要在模型中添加插件。
该插件可以发送小车在仿真环境中的真实位置信息base_pose_ground_truth
,该消息类型为nav_msgs/odometry
。 编队时的rqt_graph:
4.总结与展望
本次仿真实验设计的方案参考ROS官方给出的小乌龟版“你追我赶”,以及github上的开源项目https://github.com/SantoshBanisetty/master-slave, 它是在stage平台上实现的,且不需要机器人模型,这里将其移植至gazebo中,且以具体的机器人模型使用。 本次仿真实验在ROS操作系统下,在仿真平台Gazebo中,根据领航者-跟随者的编队原理,实现了多车的纵行编队。优点在于原理简单易懂,且实验易实现,从初始编队过程以及加入人为干预后的编队恢复过程中,都可以看出系统较好的响应速度以及调整能力。不足之处在于编队队形(纵行编队)较单一,且编队控制为开环控制,并不是闭环,不能使领航者与跟随者之间的相对位置达到精确的给定距离与方位角;且领航者的运动控制为给定直线运动,并不具有实际意义,在之后的研究中,会将领航者用于自主导航,从而实现导航+编队系统的实现。 结合以上优点与不足,且程序中关于小车定位、运动控制、传感器数据获取、编队系统框架等部分已确定可实施,因此可以仅在编队控制方法处做出改进,将现有的开环编队控制换为PID闭环控制器,或运用现有编队控制论文中的编队控制策略,都可以对此系统进行优化,达到更好的多机器人编队控制效果。 多机器人协同领域作为当今机器人研究大热,本人目前也只是学其皮毛,尚存在许多不足之处,欢迎大家一起留言讨论。 “怕什么真理无穷,进一寸有一寸的欢喜”,共勉!