• ros2与web通信实例


    ros2与web通信实例

    最近需要进行ros2与web端进行通信操作,目标是ros2发送的消息web端能够显示在界面,并且前端能够发布数据,最终实例如下:
    ros2与web交互
    然而网上查的的资料如古月居的:

    利用Websocket实现ROS与Web的交互
    https://www.guyuehome.com/5386

    包括ros官网上以及目前网上绝大部分资料都是ros1与web交互的
    http://wiki.ros.org/roslibjs/Tutorials/BasicRosFunctionality

    使用它们的资料将会出现非常多的麻烦,本人经过艰难的查找和验证终于成功实现ros2与web交互,记录如何在前人ros1的基础上进行修改,实现ros2与web交互

    1、下载rosbridge-suite

    介绍以下所需要的工具包:rosbridge_suite功能包,roslibjs,ros2djs,ros3djs。
    rosbridge_suite:实现Web浏览器与ROS之间的数据交互;

    roslibjs:实现了ROS中的部分功能,如Topic,Service,URDF等;

    ros2djs:提供了二维可视化的管理工具,可以用来在Web浏览器中显示二维地图;

    ros3djs:提供了三维可视化的管理工具,可以在Web端显示三维模型。

    在这几个功能包中,rosbridge_suite是最重要的,它是Web和ROS沟通的桥梁,roslibjs也是必须的,它能实现ROS中最基本的功能,下面的例程就是用它来实现的,至于ros2djs和ros3djs是后期开发所需要的,对于新手来说可以暂时不用下载。它们的下载安装方法如下,在终端中分别输入以下指令:

    请注意第一句的:

    sudo apt-get install ros-kinetic-rosbridge-suite

    kinetic是ros的不同版本,请换成自己的ros版本,本人使用的是humble版本的

    sudo apt-get install ros-kinetic-rosbridge-suite
    git clone https://github.com/RobotWebTools/roslibjs.git
    git clone https://github.com/RobotWebTools/ros2djs
    git clone https://github.com/RobotWebTools/ros3djs
    
    • 1
    • 2
    • 3
    • 4

    2、再运行launch文件

    ros1的命令如下
    roslaunch rosbridge_server rosbridge_websocket.launch

    但是rosbridge是经过更新的,没有rosbridge_websocket.launch
    ros2的命令应该改成如下形式:

    ros2 launch rosbridge_server rosbridge_websocket_launch.xml
    
    • 1

    3、打开example.html

    运行了这个launch文件后,只需要在浏览器中打开我们设计的html文件就能够实现Web端与ROS的交互了。下面来看一个简单的example.html的例子。

     DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    
    <script type="text/javascript" src="http://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js">script>
    <script type="text/javascript" src="http://static.robotwebtools.org/roslibjs/current/roslib.min.js">script>
    
    <script type="text/javascript" type="text/javascript">
      // Connecting to ROS
      var ros = new ROSLIB.Ros({
        url : 'ws://localhost:9090'
      });
    
      //判断是否连接成功并输出相应的提示消息到web控制台
      ros.on('connection', function() {
        console.log('Connected to websocket server.');
      });
    
      ros.on('error', function(error) {
        console.log('Error connecting to websocket server: ', error);
      });
    
      ros.on('close', function() {
        console.log('Connection to websocket server closed.');
      });
    
      // Publishing a Topic
      var cmdVel = new ROSLIB.Topic({
        ros : ros,
        name : '/cmd_vel',
        messageType : 'geometry_msgs/Twist'
      });//创建一个topic,它的名字是'/cmd_vel',,消息类型是'geometry_msgs/Twist'
    
      var twist = new ROSLIB.Message({
        linear : {
          x : 0.1,
          y : 0.2,
          z : 0.3
        },
        angular : {
          x : -0.1,
          y : -0.2,
          z : -0.3
        }
      });//创建一个message
    
      function func()//在点击”Publish”按钮后发布消息,并对消息进行更改
      {
        cmdVel.publish(twist);//发布twist消息
        twist.linear.x = twist.linear.x + 0.1;
        twist.linear.y = twist.linear.y + 0.1;
        twist.linear.z = twist.linear.z + 0.1;
        twist.angular.x = twist.angular.x + 0.1;
        twist.angular.y = twist.angular.y + 0.1;
        twist.angular.z = twist.angular.z + 0.1;
      }
    
      // Subscribing to a Topic
      var listener = new ROSLIB.Topic({
        ros : ros,
        name : '/chatter',
        messageType : 'std_msgs/String'
      });//创建一个topic,它的名字是'/chatter',,消息类型是'std_msgs/String'
    
      function subscribe()//在点击”Subscribe”按钮后订阅'/chatter'的消息,并将其显示到网页中
      {
         listener.subscribe(function(message) {
           document.getElementById("output").innerHTML = ('Received message on ' + listener.name + ': ' + message.data);
         });
      }
    
      function unsubscribe()//在点击”Unsubscribe”按钮后取消订阅'/chatter'的消息
      {
         listener.unsubscribe();
      }
    
    script>
    head>
    
    <body>
      <h1>Simple roslib Exampleh1>
      <p>Check your Web Console for output.p>
      <p id = "output">p>
      <button onclick = "func()">Publishbutton>
      <button onclick = "subscribe()">Subscribebutton>
      <button onclick = "unsubscribe()">Unsubscribebutton><br />
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    请注意上面这两个 .js 链接已经失效了,需要自己换成新的连接或下载到本地下面是最新的地址,本人是直接下载到本地的

    http://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js
    http://static.robotwebtools.org/roslibjs/current/roslib.min.js

    最新的两个.js下载地址如下:

    https://github.com/RobotWebTools/roslibjs
    https://github.com/EventEmitter2/EventEmitter2

    这是本人下载到本地后调用的修改,注意改成自己的地址

    <script type="text/javascript" src="/root/myjs/EventEmitter2-master/lib/eventemitter2.js">script>
    <script type="text/javascript" src="/root/myjs/roslibjs-develop/build/roslib.min.js">script>
    
    • 1
    • 2

    4、启动talker

    原文的这一步也有问题,建议修改成自己编写的talker

    rosrun  roscpp_tutorials  talker
    
    • 1

    本人自己写的talker如下:

    /*
      send "hello wordl!" with a fixed-frequency and add 1 to the number for each data sent
    */
    // 1.include header files
    #include "rclcpp/rclcpp.hpp"
    #include "std_msgs/msg/string.hpp"
    
    using namespace std::chrono_literals;
    // 3.define node class
    class MinimalPublisher: public rclcpp:: Node{
      
      public:
        MinimalPublisher(): Node("minimal_publisher"),count(0)
        {
          RCLCPP_INFO(this->get_logger(),"create the publish node!");
          // 3-1 create a publisher
          /*
            template:the type of messages published
            parameter:
              1.topic name
              2.QOS(Quality of Service) message queue length
            return:publish object pointer
          */
          publisher_ = this->create_publisher<std_msgs::msg::String>("/chatter",10);
          // 3-2 create a timer
          /*
            parameter:
              1.time interval
              2.callback function
            return:timer object pointer
          
          */
          
          timer_ = this->create_wall_timer(1s, std::bind(&MinimalPublisher::timer_callback,this));
        }
      private:
        void timer_callback()
        {
          // 3-3 organize messages and publish them
          auto message = std_msgs::msg::String();
          message.data = "Hello world!" + std::to_string(count++);
          RCLCPP_INFO(this->get_logger(), "Published message: '%s'",message.data.c_str());
          publisher_->publish(message);
        }
        rclcpp::TimerBase::SharedPtr timer_;
        rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
        size_t count;
    };
    int main(int argc,char const *argv[]){
        // 2.initialize ROS2 client
        rclcpp::init(argc,argv);
        // 4.call the spin function and pass in the node object pointer
        rclcpp::spin(std::make_shared<MinimalPublisher>());
        // 5.release resources
        rclcpp::shutdown();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    点击web上的Subscribe后可以看到web的订阅话题,自己对着这个话题编写ros2发布方程序就可以了

    在这里插入图片描述

    5、启动listener

    先运行

    ros2 topic list
    
    • 1

    然后点击web端的Publish就可以从web端发送信息到ros2
    在这里插入图片描述
    参考链接:

    古月居的利用Websocket实现ROS与Web的交互
    https://www.guyuehome.com/5386

    ros官网
    http://wiki.ros.org/roslibjs/Tutorials/BasicRosFunctionality

  • 相关阅读:
    uni-app:通过循环处理数据,通过filter方法查询满足条件的项,通过map方法查询每条数据的具体一项
    安卓APP源码和报告——学生信息管理系统
    Linux C语言开发(续)
    JAVA编程规范之异常处理
    C语言 编译和链接
    chatgpt赋能python:Python文件夹的使用和优化
    Redis第十二讲:如何保证数据一致性、缓存设计模式、缓存穿透问题解决
    38.基于TCP协议的通信程序
    verilog 并行块实现
    Python3-批量重命名指定目录中的一组文件,更改其扩展名
  • 原文地址:https://blog.csdn.net/weixin_43254438/article/details/133080053