文章目录

  • 小结
  • 回顾
    • rosserial
    • ROSBridge
    • ROSBridge Client的C++实现
    • ROSBridge Client的其它实现
  • 实现及测试
    • 启动服务器端测试环境
    • 初始化ROSBridge客户端
    • ROSBridge测试/listener的topic
    • ROSBridge测试/cmd_vel的topic
    • ROSBridge测试/add_two_ints服务
    • ROSBridge测试/set_bool服务
  • 参考

小结

ROSBridge可以实现ROS系统与非ROS外部系统的通信,文档比较多比较杂,在Windows客户端的实现大多是Java, Python, JS等,这里对C++客户端使用Websockets通信进行了测试,C++ ROSBridge的客户端有轻量级,解耦合的优点。

回顾

rosserial

参考使用rosserial实现ROS与Windows的service服务通信,使用rosserial也是可以实现ROS系统与非ROS外部系统的通信。

ROSBridge

有关ROSBridge的官方文档可以参见: ROS Wiki - rosbridge_suite

ROSBridge Client的C++实现

用C++实现ROSBridge的客户端主要有两个Github,
1,Github: Sanic/rosbridge2cpp 这个实现不支持Websockets,所以没有进行测试。
2,本文主要参考了Github-C++ Rosbridge client uses Websockets and Rapidjson: ppianpak/rosbridgecpp
Rapidjson主要参考Rapidjson Tutorial。

另外也借鉴了Rosbridge的JS客户端的实现:RobotWebTools/roslibjs/examples/simple.html。

具体使用的ROSBridge的数据协议详情可以参考:Github: RobotWebTools/rosbridge_suite: rosbridge v2.0 Protocol Specification

ROSBridge Client的其它实现

Github: C# rosbridge-csharp-connection
ROSBridgeClient in Java
Github: ROSBridgeTestclient in Python

实现及测试

启动服务器端测试环境

参考ROS的roslibjs基本功能使用测试:

#启动roscore
roscore
#在/listener这个topic中发布一个"Hello, World"消息
rostopic pub /listener std_msgs/String "Hello, World"
#监听/cmd_vel的消息
rostopic echo /cmd_vel
#启动add_two_ints_server服务
rosrun rospy_tutorials add_two_ints_server
#启动rosbridge_server
roslaunch rosbridge_server rosbridge_websocket.launch

初始化ROSBridge客户端

RosbridgeWsClient rbc("192.168.238.129:9090");

这里192.168.238.129是服务器地址,端口9090。

ROSBridge测试/listener的topic

发布/listener的topic并订阅/listener的topic:

  rbc.addClient("topic_advertiser");rbc.advertise("topic_advertiser", "/listener", "std_msgs/String");rbc.addClient("topic_subscriber");rbc.subscribe("topic_subscriber", "/listener", subscriberCallback);

subscriberCallback()如下:

void subscriberCallback(std::shared_ptr<WsClient::Connection> /*connection*/, std::shared_ptr<WsClient::InMessage> in_message)
{std::cout << "subscriberCallback(): Message Received: " << in_message->string() << std::endl;
}

先前服务器已经发布了rostopic pub /listener std_msgs/String "Hello, World",客户端会有以下输出:

topic_subscriber: Sending message: {"op":"subscribe", "topic":"/listener"}
subscriberCallback(): Message Received: {"op": "publish", "topic": "/listener", "msg": {"data": "Hello, World"}}

也可以通过ROSBridge C++客户端的代码进行发布:

void publisherThread(RosbridgeWsClient& rbc, const std::future<void>& futureObj)
{rbc.addClient("topic_publisher");rapidjson::Document d;d.SetObject();d.AddMember("data", "Test message from John /listener", d.GetAllocator());while (futureObj.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout){rbc.publish("/listener", d);std::this_thread::sleep_for(std::chrono::milliseconds(1000));}std::cout << "publisherThread stops()" << std::endl;
}

也就是客户端自己发布,自己接收,ROSBridge C++客户端输出如下:

publish_client: Opened connection
publish_client: Sending message: {"op":"publish", "topic":"/listener", "msg":{"data":"Test message from John /listener"}}

有关发送消息的结构是string data如下:

john@ubuntu:~$ rostopic list
/client_count
/cmd_vel
/connected_clients
/listener
/rosout
/rosout_agg
john@ubuntu:~$ rostopic info /listener
Type: std_msgs/StringPublishers: * /rostopic_5673_1660196707336 (http://ubuntu:35063/)Subscribers: Nonejohn@ubuntu:~$ rosmsg show std_msgs/String
string datajohn@ubuntu:~$ 

ROSBridge测试/cmd_vel的topic

/cmd_vel这个消息结构比较常用但是有些复杂,需要使用好Rapidjson。
消息结构如下:

john@ubuntu:~$ rostopic info /cmd_vel
Type: geometry_msgs/TwistPublishers: * /rosbridge_websocket (http://ubuntu:38019/)Subscribers: * /rostopic_5710_1660196719502 (http://ubuntu:37659/)
john@ubuntu:~$
john@ubuntu:~$ rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linearfloat64 xfloat64 yfloat64 z
geometry_msgs/Vector3 angularfloat64 xfloat64 yfloat64 z

ROSBridge C++客户端实现代码如下:

void publisherTwist(RosbridgeWsClient& rbc)
{rbc.addClient("topic_publisher_Twist");rapidjson::Document d;d.SetObject();float x = 0.1;float y = 0.2;float z = 0.3;rapidjson::Value data(rapidjson::kObjectType);data.AddMember("x", x, d.GetAllocator());data.AddMember("y", y, d.GetAllocator());data.AddMember("z", z, d.GetAllocator());d.AddMember("linear", data, d.GetAllocator());x = -0.1;y = -0.2;z = -0.3;rapidjson::Value dataAngular(rapidjson::kObjectType);dataAngular.AddMember("x", x, d.GetAllocator());dataAngular.AddMember("y", y, d.GetAllocator());dataAngular.AddMember("z", z, d.GetAllocator());d.AddMember("angular", dataAngular, d.GetAllocator());rbc.publish("/cmd_vel", d);std::cout << "topic_publisher_Twist stops()" << std::endl;
}

ROSBridge C++客户端输出如下:

publish_client: Opened connection
publish_client: Sending message: {"op":"publish", "topic":"/cmd_vel", "msg":{"linear":{"x":0.10000000149011612,"y":0.20000000298023225,"z":0.30000001192092898},"angular":{"x":-0.10000000149011612,"y":-0.20000000298023225,"z":-0.30000001192092898}}}

发布完数据后,ROSBridge服务器端接收:

john@ubuntu:~$ rostopic echo /cmd_vel
WARNING: topic [/cmd_vel] does not appear to be published yet
linear: x: 0.10000000149011612y: 0.20000000298023224z: 0.30000001192092896
angular: x: -0.10000000149011612y: -0.20000000298023224z: -0.30000001192092896
---

ROSBridge测试/add_two_ints服务

先前在服务器端启动了add_two_ints服务
john@ubuntu:~$ rosrun rospy_tutorials add_two_ints_server

传输数据格式如下:

john@ubuntu:~$ rosservice info /add_two_ints
Node: /add_two_ints_server
URI: rosrpc://ubuntu:33809
Type: rospy_tutorials/AddTwoInts
Args: a b
john@ubuntu:~$ john@ubuntu:~$ rossrv show rospy_tutorials/AddTwoInts
int64 a
int64 b
---
int64 sumjohn@ubuntu:~$

ROSBridge C++客户端实现代码如下:

  rapidjson::Value dataTwoInts(rapidjson::kObjectType);rapidjson::Document documentAddTwoInt(rapidjson::kObjectType);int a = 5;int b = 6;documentAddTwoInt.AddMember("a", a, documentAddTwoInt.GetAllocator());documentAddTwoInt.AddMember("b", b, documentAddTwoInt.GetAllocator());rbc.callService("/add_two_ints", callServiceCallbackAddtwo, documentAddTwoInt);

callServiceCallbackAddtwo函数如下:

void callServiceCallbackAddtwo(std::shared_ptr<WsClient::Connection> connection, std::shared_ptr<WsClient::InMessage> in_message)
{std::string messagebuf = in_message->string();std::cout << "callServiceCallbackAddtwo(): Message Received: " << messagebuf << std::endl;rapidjson::Document document;if (document.Parse(messagebuf.c_str()).HasParseError()){std::cerr << "advertiseServiceCallback(): Error in parsing service request message: " << messagebuf << std::endl;return;}std::cout << "The returned sum is: " << std::to_string(document["values"]["sum"].GetInt64()) << std::endl;connection->send_close(1000);
}

ROSBridge C++客户端输出如下:

call_service_client: Opened connection
call_service_client: Sending message: {"op":"call_service", "service":"/add_two_ints", "args":{"a":5,"b":6}}
callServiceCallbackAddtwo(): Message Received: {"op": "service_response", "service": "/add_two_ints", "values": {"sum": 11}, "result": true}
The returned sum is: 11

ROSBridge服务器端输出如下:

john@ubuntu:~$ rosrun rospy_tutorials add_two_ints_server
Returning [5 + 6 = 11]

ROSBridge测试/set_bool服务

SetBool服务的数据结构如下,输入为bool data,输出为bool success string message

john@ubuntu:~$ rosservice info /set_bool
Node: /rosbridge_websocket
URI: rosrpc://ubuntu:39413
Type: std_srvs/SetBool
Args: data
john@ubuntu:~$ rossrv show std_srvs/SetBool
bool data
---
bool success
string message

ROSBridge C++客户端发布这个服务:

  rbc.addClient("service_advertiser");rbc.advertiseService("service_advertiser", "/set_bool", "std_srvs/SetBool", advertiseServiceCallback);

advertiseServiceCallback函数如下, 有返回就回调。可以看到ROSBridge C++客户端使用document["args"]["data"].GetBool()来查看ROSBridge服务器返回的SetBool的值。再返回给ROSBridge服务器bool success string message的内容。

void advertiseServiceCallback(std::shared_ptr<WsClient::Connection> /*connection*/, std::shared_ptr<WsClient::InMessage> in_message)
{// message->string() is destructive, so we have to buffer it firststd::string messagebuf = in_message->string();std::cout << "advertiseServiceCallback(): Message Received: " << messagebuf << std::endl;rapidjson::Document document;if (document.Parse(messagebuf.c_str()).HasParseError()){std::cerr << "advertiseServiceCallback(): Error in parsing service request message: " << messagebuf << std::endl;return;}bool result = document["args"]["data"].GetBool();rapidjson::Document values(rapidjson::kObjectType);rapidjson::Document::AllocatorType& allocator = values.GetAllocator();values.AddMember("success", document["args"]["data"].GetBool(), allocator);values.AddMember("message", "from advertiseServiceCallback", allocator);rbc.serviceResponse(document["service"].GetString(), document["id"].GetString(), true, values);
}

ROSBridge C++客户端调用SetBool服务:

  rapidjson::Document document(rapidjson::kObjectType);document.AddMember("data", true, document.GetAllocator());rbc.callService("/set_bool", callServiceCallback, document);

callServiceCallback的回调函数如下:

void callServiceCallback(std::shared_ptr<WsClient::Connection> connection, std::shared_ptr<WsClient::InMessage> in_message)
{std::cout << "serviceResponseCallback(): Message Received: " << in_message->string() << std::endl;connection->send_close(1000);
}

ROSBridge C++客户端自发自收的效果如下:
ROSBridge C++客户端调用/set_bool服务:

service_advertiser: Opened connection
service_advertiser: Sending message: {"op":"advertise_service", "service":"/set_bool", "type":"std_srvs/SetBool"}
call_service_client: Opened connection
call_service_client: Sending message: {"op":"call_service", "service":"/set_bool", "args":{"data":true}}

ROSBridge C++客户端接收到了/set_bool服务调用:

advertiseServiceCallback(): Message Received: {"op": "call_service", "id": "service_request:/set_bool:1", "service": "/set_bool", "args": {"data": true}}

ROSBridge C++客户端响应/set_bool调用后,进行应答rbc.serviceResponse(document["service"].GetString(), document["id"].GetString(), true, values);
结果如下:

service_response_client: Opened connection
service_response_client: Sending message: {"op":"service_response", "service":"/set_bool", "result":true, "id":"service_request:/set_bool:1", "values":{"success":true,"message":"from advertiseServiceCallback"}}

ROSBridge C++客户端接收到/set_bool调用的应答:

serviceResponseCallback(): Message Received: {"op": "service_response", "service": "/set_bool", "values": {"success": true, "message": "from advertiseServiceCallback"}, "result": true}

参考

我的AI之路(25)–ROSBridge:机器人与外部系统之间的通讯解决方案
我的AI之路(27)–用C++实现机器人与机器人后端控制系统之间的双向通讯
我的AI之路(29)–使用Boost Asio和Rapidjson实现机器人与机器人后端系统之间的自定义协议的通讯
Github: RobotWebTools/rosbridge_suite
ROS Wiki - rosbridge_suite
使用rosserial实现ROS与Windows的service服务通信
Package RosBridge——打通Ros与非Ros环境的数据壁垒
Package RosBridge——打通Ros与非Ros环境的数据壁垒 #2 C++端实现功能ppianpak / rosbridgecpp
ROSBridge简介以及理解使用(上)
ROSBridge简介以及理解使用(下)
转:使用rosbridge协议实现安卓跟ros的解耦
古月居:ROSBridge简介以及理解使用
Github: RobotWebTools/rosbridge_suite: rosbridge v2.0 Protocol Specification
ROS Wiki Rosbridge in C++
Github: Sanic/rosbridge2cpp
Request for help regarding ROS-> C++ Application (windows) communication problem for video transmission.
Github: C# rosbridge-csharp-connection
ROSBridgeClient in Java
Android使用ROSBridge与ROS通信 简单使用
Github: ROSBridgeTestclient in Python
ROS Wiki How to send data in Json format using service client in c++ code
Rapidjson Tutorial
Github-C++ Rosbridge client uses Websockets and Rapidjson: ppianpak/rosbridgecpp
RobotWebTools/roslibjs/examples/simple.html

ROSBridge - ROS系统与非ROS外部系统的通信的C++客户端实现相关推荐

  1. ORB-SLAM2环境配置以及运行详解(一):ROS与非ROS环境下的安装、编译、离线数据集测试

    系统环境:Ubuntu 16.04 LTS ROS版本:Kinetic Kame ORB-SLAM2源码的编译部分有ROS版本和非ROS版本,非ROS版本不需要安装ROS也可以运行,主要针对离线数据集 ...

  2. 树莓派装linux ros,树莓派安装Ubuntu16.04 MATE系统以及ROS(kinetic)的安装

    安装ubuntu16.04 MATE系统 1.安装Ubuntu16.04镜像 从官网下载并按照树莓派刷写系统的流程将ubuntu16.04 MATE烧写到树莓派的SD卡上 2.设置WiFi 将树莓派外 ...

  3. ROS入门-4.安装ROS系统(ubuntu20.04版本安装ros的noetic版本)

    ubuntu20.04版本安装ros的noetic版本 1.添加软件源 2.添加密钥 3.更新 4.安装ROS 5.初始化rosdep 6.设置环境变量 7.测试ROS安装是否成功 1.添加软件源 2 ...

  4. DELL戴尔Win10双硬盘安装Ubuntu20.04双系统(附带ROS安装教程)

    DELL戴尔Win10双硬盘安装Ubuntu20.04双系统(附带ROS安装教程) 1.安装场景及注意事项 1.1.确认电脑的引导方式 1.2.关闭电脑BitLocker硬盘保护 2.安装步骤 2.1 ...

  5. Windows系统下安装ROS系统

    Windows上安装ROS系统 请参照以下链接和说明,完成Windows上安装ROS系统. Installation/Windows - ROS Wiki 注意事项: Windows版本:64-bit ...

  6. [基于STM32底盘控制与ROS上层导航小车制作] 第五节 实现STM32与ubuntu系统下的ROS串口DMA通信,传输底盘速度等信息

    系列文章目录 第一节 stm32电机驱动与编码器读取反馈 第二节 stm32电机pid控制 第三节 stm32线速度标定 第四节 stm32添加mpu6050得到angle角度 第五节 实现STM32 ...

  7. Ubuntu系统下使用ROS(moveit )连接ABB实体机器人(irb120)(1.控制仿真)

    前言: 经过两天的踩坑,终于将ROS与ABB连接成功,可以通过rviz的gui界面拖动机械臂来控制实体ABB机械臂进行运动,因为网络上的教程(几位博主和ROS WIKI等)个别步骤的不完整,所以走了很 ...

  8. ROS系列——如何在ros多机系统中使用多个Velodyne VLP16

    ROS系列--如何在ros多机系统中使用多个Velodyne VLP16 说明 修改launch文件 关键点 说明 本文主要介绍ROS多机系统中如何使用多个VLP16,比如A上配备了一个VLP16,B ...

  9. 【ROS教程 001】ROS机器人系统简介及安装

    1 ROS简介 ROS(Robot Operating System)是一种得到广泛使用的机器人操作与系统软件框架,现在很多研究机构通过增加ROS支持的硬件或开放软件源代码的方式加入ROS系统的开发中 ...

  10. [转]使用rosbridge协议实现安卓跟ros的解耦

    安卓与ROS通信的现状 因为ROS官方支持的语言绑定只有C++和Python,所以目前安卓想与ROS通信,必须借助半官方的rosjava包,而Rosjava太重了,因为它跟C++/Python一样,是 ...

最新文章

  1. java cdata xml 解析,如何解析lt;![CDATA []]gt;的XML
  2. python 3.9 新特性 简介
  3. 微众WeCross 跨链平台(1)平台介绍
  4. hibernate异常之--count查询异常
  5. C++求复数的角度_人教A版高中数学必修二7.1 复数的概念优质课公开课课件、教案...
  6. python建模仿真 matlab_清华大学出版社-图书详情-《仿真建模与MATLAB实用教程》
  7. 腾讯2020校园招聘后台开发面试编程题
  8. Docker网络解决方案-Weave部署记录
  9. .Net Micro Framework移植基础(包编译通过)
  10. 天刀服务器未响应,天涯明月刀卡顿怎么办 教你如何优化游戏不在卡顿
  11. 衡量计算机储存容量的常用计量单位是,衡量存储器的单位是什么
  12. Oracle 对表空间无操作权限
  13. 九峰影业创始人_九峰百度百科
  14. 4.13nbsp;经济分析
  15. 安卓手机开机动画制作修改教程
  16. TCP的滑动窗口与拥塞窗口
  17. 【32最小系统板】pid循迹小车(铁丝循迹)
  18. css一些美化页面的方法
  19. mysql的cj是什么包_com.mysql.cj.jdbc.driver
  20. 为什么总是显示没有java_为什么总是提示错误:无法读取:HelloWorld.java

热门文章

  1. 代理服务器有问题怎么办?
  2. Http gzip 处理
  3. Wamp的介绍和配置,解决安装时一些错误和配置上的一些需要,轻轻松松搭建以为window系统的服务器
  4. 计算机isas测试,SAS硬盘测试:15,000转对决10,000转
  5. python银行账户资金交易管理_Python实现银行账户资金交易管理系统
  6. unity shader development[11]
  7. 电子数据取证-流程与技术
  8. 《千字文》 梁•周兴嗣
  9. Dreamweaver cs6运行出现错误16的解救方法
  10. VOC数据集介绍及构建自己的VOC格式目标检测数据集