多虚拟机下实现ROS2通讯

  1. 首先两台电脑win下,都连接在同一局域网(WiFi)下,且在虚拟机Ubuntu 22.04 中安装ROS2。在ROS2中,理想情况是,多个机器上的不同节点只要在同一个ROS_DOMAIN_ID、同一个局域网下,既可以进行多机通讯,即在设备1上运行节点,在设备2上的命令行输入如下指令即可查看运行于设备1中的节点名称。但是我经过多次测试,设置虚拟机网络桥接等办法,最终结果是虚拟机1,电脑1,电脑2,虚拟机2,四个环境下可以相互ping通。(具体操作流程我参考了这位博主的内容,最终失败了ROS2多机通讯,基于两台VM虚拟机的多机通讯,通讯失败解决办法(适用于多台虚拟机或物理机间的互PING)_ros2 node 局域网-CSDN博客
  2. 接下来我将把我设置的具体流程和大家一起交流分享一下,有些专业术语可能用词不当,还请大家一起交流。

一. 配置环境

1. 配置两台虚拟机的网络环境。点击虚拟机--->设置,进行下面设置。

2. 点击编辑--->虚拟网络编辑器,进行下面设置。

上面操作完成后,若没有弹出下面这个界面,请看一下任务栏,点击出来即可,接着进行下面操作。

安装上面操作后,两台虚拟机即可完成桥接模式,则相当于直接连接主机的物理端口,虚拟机使用独立的IP,虚拟机和主机在局域网中属于平级关系。

3. 查看两台虚拟机的ip,并检测是否可以相互ping通。

首先两台虚拟机进行网络重启

sudo systemctl restart NetworkManager.service

查看两台虚拟机的ip,其中 ens33 为虚拟机网口名称,192.168.1.59是为虚拟机设置的静态IP。

ifconfig

此时检测两台虚拟机是否可以相互ping通。此过程不需要关闭win防火墙,也不需要在 “网络和internet->状态->高级网络设置->网络和共享中心->更改高级共享设置”中启用网络发现和打印机共享(反正我没有设置也可以正常通信)。

ping 192.168.1.72

二.两台虚拟机通过ROS2进行通信

注意:下面指令中运行包含运行ROS2节点时,都需要加载文件,我没有加是因为把下面指令加入了 .bashrc 中!!!

source /home/df/ROS2/ws00_hell0world/install/setup.bash
source /home/df/ROS2/ws01_plumbing/install/setup.bash

电脑1 VMware下(.bashrc文件中包含 export ROS_DOMAIN_ID=6)

新终端1输入:

fastdds discovery --server-id 0 --ip-address 192.168.1.59 --port 14520

新建终端2:

export ROS_DISCOVERY_SERVER="192.168.1.59:14520"
export ROS_DOMAIN_ID=23
ros2 run cpp01_topic demo01_talker_str --ros-args --remap __node:=demo01_talker_remap_14520

电脑2 VMware下(.bashrc文件中包含 export ROS_DOMAIN_ID=5)

新终端1输入:

export ROS_DISCOVERY_SERVER="192.168.1.59:14520"
export ROS_DOMAIN_ID=23
ros2 run cpp01_topic demo02_listener_str --ros-args --remap __node:=demo02_listener_remap_14520

新建终端2:

export ROS_DISCOVERY_SERVER="192.168.1.59:14520"
rqt_graph

最终结果显示:

实验结果一(1):

验证 export ROS_DOMAIN_ID=23 对结果是否有影响?

将上述方法中的指令 export ROS_DOMAIN_ID=23 全部删除后,电脑1 VMware中默认(.bashrc文件中包含 export ROS_DOMAIN_ID=6),而电脑2 VMware中默认((.bashrc文件中包含 export ROS_DOMAIN_ID=5),但实验最终结果和实验一相同,都可以进行通信。实验结果表明ROS_DOMAIN_ID 是否相同对此方法无影响。这个我也不太了解希望知道的朋友可以一起讨论一下。

实验结果一(2):

通过实验结果rqt_graph可以看出,两个节点demo01_talker_remap_14520 ,demo02_listener_remap_14520 中间并没有显示话题 chatter。一开始猜测两节点通信是否和话题无关。但是最终测试发现两节点正常通信,仍然需要具有相同的话题!

  1. 单机下默认环境(终端开始未执行此指令 export ROS_DISCOVERY_SERVER="192.168.1.59:14520")下结果:
  1. 单机下更改talker_node_cpp中话题名称为 chatter_1后
  1. 更改talker_node_cpp中话题名称为 chatter_1后,双机联调后运行结果:电脑2 VMware下并未收到电脑1VMware 的数据,但是执行 rqt_graph 后发现和两虚拟机正常通信的图一样

下图为电脑2VMware

电脑1VMware有数据发送

三.总结

电脑通过wifi在局域网里连接,虽然udp可以联通,但组播的方式仍收到限制,最后通过集中式的发现协议成功联通。

通过Wi-Fi连接的局域网环境可能会存在一些网络配置限制,特别是在使用UDP多播时。局域网的路由器和防火墙设置可能会影响多播通信的有效性,因此在某些情况下,您可能需要使用其他方法来确保通信的可靠性。

使用集中式的发现协议,例如通过配置发现服务器,是一种有效的方法,可以帮助确保节点之间的连接和通信。这种方式通过中央服务器来管理节点的注册和发现,从而克服了多播可能面临的限制。这种方法特别适用于复杂的网络环境,其中多播可能受到限制或不可靠。

在ROS 2中,Fast DDS的发现服务可以配置为使用中央发现服务器,以帮助节点在具有网络限制的环境中进行通信。这种方法提供了更高的可靠性,使节点能够轻松地找到和连接到其他节点,无论它们在网络中的位置如何。

总之,根据特定的网络环境和需求,可以选择适当的通信方式,包括UDP多播、中央发现服务器或其他方法,以确保ROS节点之间的可靠通信。

关于实验的节点代码是赵虚左老师视频教程的程序,感谢感谢!!!

demo01_talker_str.cpp

/* 
  需求: 以某个固定频率发送文本“helloworld!”,文本后缀编号,每发布一条,编号+1。
  流程:
      1.包含头文件;
      2.初始化ROS2客户端;
      3.自定义节点类;
        3-1.创建发布方;
        3-2.创建定时器;
        3-3.组织并发布信息。
      4.调用spin函数,传入自定义类对象指针;
      5.释放资源;

 */

// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using namespace std::chrono_literals;

// 3.自定义节点类;
class Talker: public rclcpp::Node{
public:
  Talker():Node("talker_node_cpp"),count(0)
  {
    RCLCPP_INFO(this->get_logger(),"发布节点创建!");
    // 3-1.创建发布方;
    /* 
      模板:被发布的消息类型;
      参数:
        1.话题名称;
        2.QOS(消息队列长度)。
      返回值:发布对象指针。
     */
    publisher_ = this->create_publisher<std_msgs::msg::String>("chatter",10);
    // 3-2.创建定时器;
    /* 
      参数:
        1.时间间隔;
        2.回调函数;
      返回值:定时器对象指针。
     */
    timer_ = this->create_wall_timer(1s, std::bind(&Talker::on_timer, this));

  }
private:
  void on_timer()
  {
    // 3-3.组织并发布信息。
    auto message = std_msgs::msg::String();
    message.data = "hello world!" + std::to_string(count++);
    RCLCPP_INFO(this->get_logger(), "发布方发布的消息:%s", message.data.c_str());
    publisher_->publish(message);
  }
  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
  rclcpp::TimerBase::SharedPtr timer_;
  size_t count;
};
 




int main(int argc, char ** argv)
{
  // 2.初始化ROS2客户端;
  rclcpp::init(argc, argv);
  // 4.调用spin函数,传入自定义类对象指针;
  rclcpp::spin(std::make_shared<Talker>());
  // 5.释放资源;
  rclcpp::shutdown();

  return 0;
}

demo02_listener_str.cpp

/* 
    需求:订阅发布方发布的消息,并在终端输出。
    流程:
        1.包含头文件;
        2.初始化ROS2 客户端;
        3.自定义节点类;
            3-1.创建订阅方;
            3-2.解析并输出数据。
        4.调用spin函数,并传入节点对象指针;
        5.资源释放;
 */
// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

// 3.自定义节点类;
class Listener: public rclcpp::Node{
public:
    Listener():Node("listener_node_cpp")
    {
        RCLCPP_INFO(this->get_logger(), "订阅方创建!");
        // 3-1.创建订阅方;
        /* 
            模板:消息类型;(发布使用什么消息类型,接收就用什么消息类型)
            参数:
                1.话题名称;(和发布方保持一致)
                2.QQS,队列长度;
                3.绑定一个回调函数。
            返回值:订阅对象指针。
         */
        Subscription_ = this->create_subscription<std_msgs::msg::String>("chatter", 10, std::bind(&Listener::do_cb, this, std::placeholders::_1));

               
    }
private:
    void do_cb(const std_msgs::msg::String &msg)
    {
        // 3-2.解析并输出数据。 
        RCLCPP_INFO(this->get_logger(), "订阅到的消息是:%s", msg.data.c_str());

    }
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr Subscription_;

};

int main(int argc, char const *argv[])
{
    // 2.初始化ROS2 客户端;
    rclcpp::init(argc, argv);
    //  4.调用spin函数,并传入节点对象指针;
    rclcpp::spin(std::make_shared<Listener>());

    //  5.资源释放;
    rclcpp::shutdown();
    return 0;
}  

参考资料:ROS2.0 简单的多机通讯 | 鱼香ROS

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值