告别单机调试:ROS1多机协同实战,让机器人A控制机器人B运动(基于Wheeltec底盘案例)
ROS1多机协同实战:用主机控制从机底盘运动(Wheeltec案例)
第一次看到两台机器人像跳探戈一样默契配合时,那种震撼感至今难忘。作为从单机ROS开发转向多机协同的必经之路,让主机远程控制从机底盘运动看似简单,却藏着不少"坑"。本文将手把手带你完成这个经典Demo——用一台机器人的速度指令控制另一台Wheeltec底盘的运动,同时用Rviz实时监控双机状态。
1. 多机协同的基础准备
在开始编码之前,我们需要确保硬件和网络环境就绪。不同于单机开发,多机协同对网络配置的稳定性要求更高。根据实测经验,建议使用千兆路由器组建局域网,避免使用无线中继等不稳定连接方式。
1.1 硬件连接与网络配置
两台Wheeltec机器人需要连接到同一个局域网。推荐以下检查清单:
- 物理连接:使用网线直连路由器,比Wi-Fi更稳定
- IP分配:建议为每台机器设置静态IP,避免DHCP变动导致连接中断
- 基础工具:确保每台机器安装
net-tools和openssh-server
# 检查网络接口(两台机器分别执行) ifconfig | grep "inet " # 测试双向连通性(在主机执行) ping 192.168.1.2 # 从机IP1.2 系统级配置
修改/etc/hosts文件是常被忽视的关键步骤。两台机器都需要添加对方的IP和主机名映射:
# 主机/etc/hosts添加 192.168.1.2 slave-bot # 从机/etc/hosts添加 192.168.1.1 master-bot验证配置是否生效:
# 在主机执行 ping slave-bot # 在从机执行 ping master-bot2. ROS环境搭建与Master配置
ROS1采用中心化的Master节点架构,这是多机通信的核心。我们的配置原则是:主机作为Master,从机作为Client。
2.1 主从机环境变量设置
在主机(Master)的~/.bashrc中添加:
export ROS_MASTER_URI=http://$(hostname -I | awk '{print $1}'):11311 export ROS_IP=$(hostname -I | awk '{print $1}')在从机的~/.bashrc中则指向主机的IP:
export ROS_MASTER_URI=http://192.168.1.1:11311 # 主机IP export ROS_IP=$(hostname -I | awk '{print $1}')注意:每次修改.bashrc后需要执行
source ~/.bashrc或重新打开终端
2.2 验证ROS Master状态
在主机启动roscore:
roscore在从机检查连接状态:
rostopic list # 应该能看到/rosout等默认话题常见问题排查表:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 从机无法获取话题列表 | 防火墙阻挡 | sudo ufw allow 11311 |
| 延迟高 | 网络带宽不足 | 改用有线连接或升级路由器 |
| 时断时续 | IP冲突 | 检查DHCP范围与静态IP设置 |
3. 底盘控制话题的重映射实战
Wheeltec底盘通常订阅/cmd_vel话题接收运动指令。多机控制的关键在于:让从机订阅主机发布的控制话题。
3.1 主机控制节点配置
在主机创建发布速度指令的节点:
#!/usr/bin/env python import rospy from geometry_msgs.msg import Twist def controller(): pub = rospy.Publisher('/master/cmd_vel', Twist, queue_size=10) rospy.init_node('master_controller', anonymous=True) rate = rospy.Rate(10) # 10Hz while not rospy.is_shutdown(): cmd = Twist() cmd.linear.x = 0.2 # 前进速度0.2m/s cmd.angular.z = 0.5 # 旋转速度0.5rad/s pub.publish(cmd) rate.sleep() if __name__ == '__main__': try: controller() except rospy.ROSInterruptException: pass3.2 从机启动文件修改
修改从机的bringup.launch文件,添加话题重映射:
<launch> <node pkg="turn_on_wheeltec_robot" type="wheeltec_robot_node" name="wheeltec_robot" output="screen"> <remap from="/cmd_vel" to="/master/cmd_vel"/> </node> </launch>关键参数说明:
remap:将本地/cmd_vel重映射到主机发布的/master/cmd_veloutput="screen":方便调试时查看节点输出
4. 可视化监控与调试技巧
同时观察两台机器人的状态是调试的关键。Rviz配合tf变换可以完美实现这个需求。
4.1 统一坐标系设置
在两台机器人的URDF或启动文件中,确保使用相同的全局坐标系:
<!-- 主机和从机的launch文件都添加 --> <param name="tf_prefix" value="master"/> <!-- 主机 --> <param name="tf_prefix" value="slave"/> <!-- 从机 -->4.2 Rviz多机显示配置
在主机上启动Rviz并添加以下显示项:
- RobotModel:分别添加主机和从机的描述文件路径
- TF:勾选"Show Names"查看坐标系前缀
- MarkerArray:如需显示传感器数据
调试时常用的命令组合:
# 在主机终端1:启动Master roscore # 终端2:启动主机底盘节点 roslaunch turn_on_wheeltec_robot turn_on_wheeltec_robot.launch # 终端3:启动控制节点 rosrun your_pkg master_controller.py # 在从机终端: roslaunch turn_on_wheeltec_robot bringup.launch4.3 网络延迟优化
实测中发现,当控制指令频率超过20Hz时,网络延迟会影响控制精度。推荐以下优化措施:
使用
rostopic hz /master/cmd_vel监控实际发布频率在QoS配置中启用
tcp_nodelay:pub = rospy.Publisher('/master/cmd_vel', Twist, queue_size=1, tcp_nodelay=True)考虑使用
topic_tools中的throttle节点控制带宽
5. 进阶:多机协同的扩展应用
基础Demo跑通后,可以尝试以下扩展场景:
5.1 双向通信实现
让从机将传感器数据回传给主机:
<!-- 在从机launch文件中添加 --> <node pkg="topic_tools" type="relay" name="scan_relay" args="/scan /slave/scan"/>5.2 动态参数调节
使用rqt_reconfigure动态调整控制参数:
# 在主机控制节点中添加 from dynamic_reconfigure.server import Server from your_pkg.cfg import ControllerConfig def callback(config, level): global speed_factor speed_factor = config.speed_scale return config srv = Server(ControllerConfig, callback)5.3 异常处理机制
为网络中断添加容错处理:
def check_connection(): try: rospy.wait_for_message('/master/cmd_vel', Twist, timeout=1) return True except: return False # 在控制循环中添加 if not check_connection(): emergency_stop()最后分享一个实用技巧:在长期运行的多机系统中,使用chrony同步两台机器的时间可以避免很多奇怪的时序问题。配置成功后,两台机器的时间差应小于1毫秒:
# 在两台机器上执行 sudo apt install chrony sudo service chrony restart ntpq -p