ROS多设备交互

ROS多设备连接同一个Master:ROS Master多设备连接-CSDN博客

在多个PC端连接同一个ROS Master后,接下来就可以实现不同设备之间的话题交流,Master主机端启动不同PC端的功能包等功能了

尽管多个PC端拥有不同的ROS工作空间,但是只要他们都连接在同一个ROS Master下,它们就能互相通信(工作空间只是存放ROS代码(功能包)的目录(如 ~/catkin_ws),它不影响ROS节点如何连接Master)

一,跨设备文件启动

要在 PC1(运行ROS Master的PC) 上启动 PC2(另一个PC) 的 ROS 功能包,你需要确保:

  1. PC2 的功能包已经编译catkin_makecolcon build)。

  2. PC1 能够访问 PC2 的 ROS 功能包(通常通过 SSH 远程执行命令)。

  3. PC2 的 ROS_MASTER_URI 指向 PC1 的 Master(确保节点注册到正确的 Master)。

一般启动方式有两种,使用ssh启动和roslaunch启动

1, SSH远程运行

最基本的就是在终端中连接到另一个PC端,然后执行终端命令

ssh <PC2_USER>@<PC2_IP> "source /opt/ros/noetic/setup.bash && source ~/catkin_ws/devel/setup.bash && rosrun <package_name> <node_name>"

例如

ssh user@192.168.1.101 "source /opt/ros/noetic/setup.bash && source ~/catkin_ws/devel/setup.bash && rosrun my_package my_node"

在文章(Python实现ssh自动连接-CSDN博客)中我们使用了Python代码进行远程ssh连接和命令执行,同样的我们也可以在这里使用Python代码执行

import paramikodef ssh_run_ros_node(host, username, password, package, node):"""通过SSH远程执行ROS节点:param host: 远程PC的IP地址:param username: 远程PC的用户名:param password: 远程PC的密码:param package: ROS包名:param node: 节点名"""# 创建SSH客户端ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())try:# 连接远程主机ssh.connect(host, username=username, password=password)# 构造ROS运行命令command = f"source /opt/ros/noetic/setup.bash && source ~/catkin_ws/devel/setup.bash && rosrun {package} {node}"# 执行命令(非阻塞方式)stdin, stdout, stderr = ssh.exec_command(command, get_pty=True)print(f"已在 {host} 上启动 {package}/{node}")# 返回SSH连接和通道,以便后续管理return ssh, stdin, stdout, stderrexcept Exception as e:print(f"SSH连接失败: {str(e)}")ssh.close()return None, None, None, None

启动bash文件,只需要将command替换一下即可。由于bash启动脚本是非交互式Shell(在上一篇文章说过),所以不会加载.bashrc配置文件,为了加载运行需要的环境,需要单独调用各条命令

def run_bash_script(ssh_client, script_path, arguments=""):"""通过SSH远程执行bash脚本:param ssh_client: 已建立的SSH连接:param script_path: 远程机器上的脚本路径(如 ~/catkin_ws/scripts/start_robot.sh):param arguments: 传递给脚本的参数"""command = f"source /opt/ros/noetic/setup.bash && source ~/catkin_ws/devel/setup.bash && bash {script_path} {arguments}"stdin, stdout, stderr = ssh_client.exec_command(command)# 读取输出(可选)print(stdout.read().decode())print(stderr.read().decode())  # 如果有错误

如果脚本依赖 ROS 环境,需要先 source

command = ("source /opt/ros/noetic/setup.bash && ""source ~/catkin_ws/devel/setup.bash && "f"bash {script_path} {arguments}"
)
ssh.exec_command(command)

启动Python文件,也是将command替换一下即可

def run_python_script(ssh_client, script_path, arguments=""):"""通过SSH远程执行Python脚本:param script_path: 远程机器上的Python脚本路径:param arguments: 传递给脚本的参数"""command = f"source ~/.bashrc && python3 {script_path} {arguments}"stdin, stdout, stderr = ssh_client.exec_command(command)print(stdout.read().decode())  # 输出print(stderr.read().decode())  # 错误

2,roslaunch远程启动

使用roslaunch启动方式可以一次性启动多个节点。

使用launch文件启动有两种方式:第一种是先要使用ssh连接后再运行command命令执行,实际上相当于在被连接端使用roslaunch命令。第二种直接使用<machine>标签实现多机协同,无需手动调用ssh(无需手动编写 SSH 代码,ROS 内部自动处理远程连接)。

第一种

import paramikodef remote_roslaunch(host, username, password, package, launch_file, args=""):"""远程执行roslaunch:param host: 远程PC的IP:param username: 远程PC的用户名:param password: 远程PC的密码:param package: ROS包名:param launch_file: launch文件名(不含.launch后缀):param args: 传递给launch文件的参数(如 "arg1:=value1 arg2:=value2")"""ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())try:ssh.connect(host, username=username, password=password)# 构造roslaunch命令command = (f"source /opt/ros/noetic/setup.bash && "f"source ~/catkin_ws/devel/setup.bash && "f"roslaunch {package} {launch_file}.launch {args}")# 执行命令(非阻塞)stdin, stdout, stderr = ssh.exec_command(command, get_pty=True)print(f"已在 {host} 上启动 {package}/{launch_file}.launch")return ssh  # 返回SSH连接,用于后续管理except Exception as e:print(f"SSH执行失败: {str(e)}")ssh.close()return None

如果希望 roslaunch 在 SSH 断开后继续运行,使用 nohup: 

command = ("nohup roslaunch {package} {launch_file}.launch {args} ""> /dev/null 2>&1 &"
)

第二种 

 <machine> 标签:定义远程计算机的配置(IP、用户名、密码、环境加载脚本等)。ROS 的 roslaunch 工具会自动通过 SSH 在指定机器上启动节点。但第一次使用时需要手动ssh连接一次你要连接的主机,连接后主机会将其自动添加到~/.ssh/kown_hosts,之后再退出ssh后,<machine>即可正常工作

<launch><!-- 定义远程机器 pc1 --><machine name="pc1"                   <!-- 逻辑名称(用于node的machine属性) -->address="192.168.1.101"      <!-- 远程IP -->user="user"                  <!-- 用户名 -->password="pass"              <!-- 密码(可选,建议用密钥替代) -->env-loader="/opt/ros/noetic/env.sh"  <!-- 环境加载脚本 -->/><!-- 定义远程机器 pc2 --><machine name="pc2" address="192.168.1.102" user="user" password="pass" env-loader="/opt/ros/noetic/env.sh" /><!-- 在 pc1 上启动 node1 --><node machine="pc1" name="node1" pkg="your_pkg" type="node1"/><!-- 在 pc2 上启动 node2 --><node machine="pc2" name="node2" pkg="your_pkg" type="node2"/>
</launch>

env-loader:当启动节点时,该脚本会在指定的机器上被执行,从而设置环境变量。这意味着在启动节点前,此脚本里的环境变量设置会生效。其主要用途是为特定节点或者一组节点设定所需的环境变量,像 ROS 工作空间的路径、依赖库的路径等。 其一般内容如下

#!/bin/bash
source /opt/ros/noetic/setup.bash
source /home/ubuntu20_04/gazebo_ws/devel/setup.bash
export ROS_MASTER_URI=http://<CAR_IP_ADDRESS>:11311  # 小车IP
export ROS_HOSTNAME=<PC_IP_ADDRESS>                  # PC端IP

 

复用机器定义:用于模块化地定义和复用远程机器配置,并启动对应的节点。假设你有两台机器人(robot1 和 robot2),需要分别在它们上面启动相同的节点组(如导航、感知等),通过将主launch文件中定义机器配置,并引用子launch文件(定义节点逻辑),就可以实现同一个节点在不同机器上复用

<!-- 定义机器模板 -->
<group><!-- 定义一个名为robot1的远程机器 --><machine name="robot1"                <!-- 逻辑名称(用于后续引用) -->address="192.168.1.101"      <!-- 远程机器的IP地址 -->user="user"                  <!-- SSH登录用户名 -->env-loader="~/env.sh"        <!-- 远程机器的环境加载脚本 -->/><!-- 包含另一个launch文件,并传递参数 --><include file="$(find your_pkg)/launch/robot_nodes.launch"><arg name="machine" value="robot1"/>  <!-- 将machine名称传递给子launch文件 --></include>
</group>

 子launch文件内容示例如下:

<launch><!-- 接收从主文件传递的machine名称 --><arg name="machine"/><!-- 在指定的远程机器上启动节点 --><node machine="$(arg machine)" name="nav_node" pkg="your_pkg" type="nav.py"/><node machine="$(arg machine)" name="sensor_node" pkg="your_pkg" type="sensor.py"/>
</launch>

比如下面的多机器并行启动,均使用同样的节点 

<!-- main.launch -->
<launch><!-- 启动robot1 --><group><machine name="robot1" address="192.168.1.101" .../><include file="robot_nodes.launch"><arg name="machine" value="robot1"/></include></group><!-- 同时启动robot2 --><group><machine name="robot2" address="192.168.1.102" .../><include file="robot_nodes.launch"><arg name="machine" value="robot2"/></include></group>
</launch>

3,命名冲突问题

有时在不同的PC端可能需要启动同一个功能包来分别完成对应的功能,这些功能包会发布同一个话题,但是所有设备都只有一个ROS Master,这时就会出现话题名冲突的问题和节点名冲突的问题,这时就要进行命名空间的隔离

通过为每台PC的节点分配独立命名空间,避免话题和节点冲突。如下所示

group结构加命名空间

<launch><!-- PC1节点放入 /PC1 命名空间 --><group ns="PC1"><node pkg="navigation_pkg" name="nav" type="nav_node" output="screen"></node></group>
</launch>
<launch><!-- PC2节点放入 /PC2 命名空间 --><group ns="PC2"><node pkg="sim_navigation_pkg" name="nav" type="nav_node" output="screen"></node></group>
</launch>

node加命名空间 

<launch><!-- 定义 PC2 --><machine name="pc2" address="192.168.1.102" user="user" password="pass"  env-loader="/opt/ros/noetic/env.sh"  <!-- PC2 的环境脚本 -->/><!-- 定义 PC3 --><machine name="pc3" address="192.168.1.103" user="user" env-loader="/opt/ros/noetic/env.sh" /><!-- 在 PC2 上运行 PC1 的节点 --><node machine="pc2" name="nav_node" pkg="navigation_pkg" type="nav_node" ns="pc2"/><!-- 在 PC3 上运行同一节点(通过命名空间隔离) --><node machine="pc3" name="nav_node" pkg="navigation_pkg" type="nav_node" ns="pc3"/>
</launch>

这样输出话题时就会加一个前缀,如下所示

/pc2/cmd_vel
/pc3/cmd_vel
/pc2/odom
/pc3/odom

 如果无法修改命名空间,也可以重映射话题名称,但是话题如果很多的话这种方式就比较麻烦

<!-- PC1的Launch文件 -->
<node pkg="navigation_pkg" name="nav" type="nav_node"><remap from="cmd_vel" to="PC1_cmd_vel"/>  <!-- PC1的控制话题 -->
</node><!-- PC2的Launch文件 -->
<node pkg="sim_navigation_pkg" name="nav" type="nav_node"><remap from="cmd_vel" to="PC2_cmd_vel"/>   <!-- PC2的控制话题 -->
</node>

二,跨设备通信

我们将各PC端连接到同一个ROS Master下之后,它们的话题服务等就都是一样的了,设备之间就可以同步发布话题,订阅话题等进行数据之间的交换,与一个PC端各节点之间订阅话题是一样的

以话题为例(服务一样)

PC1发布话题/cmd_vel

# PC1的节点
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)

PC2订阅同一话题

# PC2的节点
rospy.Subscriber('/cmd_vel', Twist, callback)

 三,工作空间同步

通过 rsync 将 PC1 的工作空间完整拷贝到 PC2。注意PC2 需安装与 PC1 相同版本的 ROS 和系统依赖(如 Ubuntu 20.04 + ROS Noetic)。

# 在 PC1 上执行(同步到 PC2)
rsync -avz ~/catkin_ws/ user@192.168.1.101:~/catkin_ws/

rsync 会将 PC1 的 ~/catkin_ws/ 目录(包括源代码、编译生成的节点和消息)同步到 PC2 的相同路径下。PC2 的工作空间内容与 PC1 完全一致(包括编译后的可执行文件)。PC2 可以直接运行 功能包中的节点,无需重新编译。

# 在 PC1 上执行(将工作空间同步到 PC2)
rsync -avz --delete ~/catkin_ws/ user@192.168.1.101:~/catkin_ws/
  • 参数说明

    • -a:归档模式(保留权限、符号链接等)。

    • -v:显示同步详情。

    • -z:压缩传输数据。

    • --delete:删除 PC2 上多余的文件(保持严格一致)。

如果 PC1 修改了代码,需重新运行 rsync 同步到 PC2,可以搭配 inotifywait 工具实现自动同步。

 除此之外,也可以仅同步必要的功能包,如下:

rsync -avz ~/catkin_ws/src/navigation_pkg/ user@192.168.1.101:~/catkin_ws/src/navigation_pkg/
# 在 PC2 上单独编译该包:
cd ~/catkin_ws/ && catkin_make --pkg navigation_pkg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/75125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于国内环境 在Ubuntu 上安装 Docker 指南

前言 在容器化技术主导云原生时代的今天&#xff0c;Docker 凭借其轻量化、高移植性和秒级部署能力&#xff0c;已成为开发与运维的必备工具。然而&#xff0c;国内用户在 Ubuntu 系统上安装 Docker 时&#xff0c;常因 ​官方镜像源访问受限、网络延迟高、依赖包安装失败 等问…

数据结构:二叉树(三)·(重点)

二叉树的存储结构 ⼆叉树⼀般可以使⽤两种结构存储&#xff0c;⼀种顺序结构&#xff0c;⼀种链式结构。 顺序结构 顺序结构存储就是使⽤数组来存储&#xff0c;⼀般使⽤数组只适合表⽰完全⼆叉树&#xff0c;因为不是完全⼆叉树会有 空间的浪费&#xff0c;完全⼆叉树更适合…

EasyExcel实现图片导出功能(记录)

背景&#xff1a;在旧系统的基础上&#xff0c;导出一些工单信息时&#xff0c;现需要新添加处理人的签名或者签章&#xff0c;这就涉及图片的上传、下载、写入等几个操作。 1、EasyExcel工具类 &#xff08;1&#xff09;支持下拉框的导出。 import com.alibaba.excel.Easy…

Android Material Design 3 主题配色终极指南:XML 与 Compose 全解析

最小必要颜色配置 <!-- res/values/themes.xml --> <style name"Theme.MyApp" parent"Theme.Material3.DayNight"><!-- 基础三原色 --><item name"colorPrimary">color/purple_500</item><item name"col…

【Git】“warning: LF will be replaced by CRLF”的解决办法

一、原因分析 不同操作系统的换行符标准不同&#xff1a; • Windows&#xff1a;使用 CRLF&#xff08;\r\n&#xff09;表示换行&#xff1b; • Linux/Mac&#xff1a;使用 LF&#xff08;\n&#xff09;表示换行 Git 检测到本地文件的换行符与仓库设置或目标平台不兼容时…

PyTorch 深度学习实战(33):联邦学习与隐私保护

在上一篇文章中,我们探讨了多模态学习与CLIP模型的应用。本文将深入介绍联邦学习(Federated Learning)这一新兴的分布式机器学习范式,它能够在保护数据隐私的前提下实现多方协作的模型训练。我们将使用PyTorch实现一个基础的联邦学习框架,并在图像分类任务上进行验证。 一…

蓝桥杯 web 展开你的扇子(css3)

普通答案&#xff1a; #box:hover #item1{transform: rotate(-60deg); } #box:hover #item2{transform: rotate(-50deg); } #box:hover #item3{transform: rotate(-40deg); } #box:hover #item4{transform: rotate(-30deg); } #box:hover #item5{transform: rotate(-20deg); }…

LLM驱动的智能体:基于GPT的对话智能体开发指南

前言 大语言模型&#xff08;LLM, Large Language Model&#xff09;正在彻底改变智能体&#xff08;Agent&#xff09;的设计和实现方式。从简单的聊天机器人到复杂的自动化助手&#xff0c;基于GPT等LLM的对话智能体已经在客服、教育、办公自动化、编程助手等领域得到了广泛…

深度解析 C# 中介者模式:设计与实战应用

中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;其核心思想是将多个对象之间的交互集中到一个中介者对象中&#xff0c;从而减少对象之间的直接交互&#xff0c;降低耦合度。在实现复杂系统时&#xff0c;中介者模式有助于提高系统的可维…

每日算法-250408

记录今天解决的两道 LeetCode 算法题&#xff0c;主要涉及二分查找的应用。 1283. 使结果不超过阈值的最小除数 题目描述 思路 核心思路是 二分查找。 解题过程 为什么可以使用二分&#xff1f; 关键在于单调性。对于一个固定的数组 nums&#xff0c;当除数 divisor 增大时&…

MySQL的子查询

一、前言 MySQL 子查询是指嵌套在其他 SQL 语句&#xff08;如 SELECT、WHERE、FROM 等&#xff09;内部的查询。用于辅助主查询完成复杂的数据筛选或计算。 二、子查询分类 标量子查询 描述&#xff1a;返回 单行单列&#xff08;一个值&#xff09;&#xff0c;常用于比较运…

Linux 基础入门操作 前言 VIM的基本操作 2

1 VIM的背景介绍 Vi 的诞生与1976年&#xff0c;Vim 的前身是 Vi&#xff08;Visual Editor&#xff09;&#xff0c;由 Bill Joy 在 BSD Unix 系统上开发&#xff0c;作为 ed&#xff08;行编辑器&#xff09;的改进版本&#xff0c;提供全屏编辑功能&#xff0c;成为 Unix/L…

Java:Set操作

目录 Set 转 List Set 转 List Set<String>set new HashSet<String>(); set.add("c"); set.add("d"); set.add("a"); set.add("a");//方法一&#xff1a; List<String>list new ArrayList<String>(set);//…

算力驱动未来:从边缘计算到高阶AI的算力革命

算力驱动未来&#xff1a;从边缘计算到高阶AI的算力革命 摘要 本文深入探讨了不同算力水平&#xff08;20TOPS至160TOPS&#xff09;在人工智能领域的多样化应用场景。从边缘计算的实时目标检测到自动驾驶的多传感器融合&#xff0c;从自然语言处理的大模型应用到AI for Scie…

虚拟机上安装openEuler和openGauss数据库

1.虚拟机版本选择VM 16 PRO 2.openEuler版本选择openEuler-22.03-LTS-SP4-x86_64 下载地址&#xff1a;https://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS-SP4/ISO/x86_64/openEuler-22.03-LTS-SP4-x86_64-dvd.iso 3.虚拟机安装openEuler过程&#xff1a; 4.安装ope…

0_Pytorch中的张量操作

[引言]张量的概念 1.基本概念 张量是一个通用的多维数组&#xff0c;可以表示标量&#xff08;0 维&#xff09;、向量&#xff08;1 维&#xff09;、矩阵&#xff08;2 维&#xff09;以及更高维度的数据。张量是 PyTorch 中的核心数据结构&#xff0c;用于表示和操作数据。…

LS-LINUX-002 简易创建SSH

LS-LINUX-002 简易创建SSH 1. CentOS 8 创建和配置SSH服务 1.1 安装SSH服务 CentOS 8 默认已经安装了OpenSSH服务。如果没有安装&#xff0c;可以使用以下命令安装&#xff1a; sudo dnf install -y openssh-server1.2 启动SSH服务 安装完成后&#xff0c;需要启动SSH服务…

计算机专业求职面试的常见题目分类整理

以下是计算机专业求职面试的常见题目分类整理&#xff0c;每个大类精选20道高频问题&#xff0c;结合参考内容进行解析与扩展&#xff0c;帮助系统化备考&#xff1a; 一、数据结构与算法 解释时间复杂度和空间复杂度 时间复杂度衡量算法执行时间随输入规模的增长趋势&#xf…

脚本启动 Java 程序

如果你想在后台启动一个 Java 程序&#xff0c;并在终端窗口中显示一个自定义的名字&#xff0c;可以通过编写一个简单的脚本来实现。以下是一个基于 Linux/macOS 的解决方案&#xff0c;使用 Bash 脚本启动 Java 程序&#xff0c;并在终端窗口中显示自定义标题。 示例脚本 创建…

CentOS禁用nouveau驱动

1、验证 nouveau 是否在运行 lsmod | grep nouveau如果命令返回结果&#xff0c;说明 nouveau 驱动正在运行。 2、编辑黑名单文件 通过编辑黑名单配置文件来禁用 nouveau 驱动&#xff0c;这样在系统启动时不会加载它。 vi /etc/modprobe.d/blacklist-nouveau.conf修改以下…