ROS是一个强大的机器人操作系统,它提供了许多方便的功能来让机器人更容易开发和使用。但每当我需要查看某个话题内容的时候,我就需要在一堆终端中找到显示话题内容的那个终端,或者新开一个。这实在是不够优雅,本着遇见彩虹(bushi吃定困难的精神!能不能使用一个第三方设备,比如说ipad或者手机来实时显示话题内容或者显示更多东西?当然这个第三方设备一定不会是和主机有线连接的,也最好不需要在设备上安装什么软件。那什么方案能解决以上问题捏?当然是web服务!
一、系统架构
系统架构主要包括以下几个部分:
-
-
ROS(Robot Operating System):ROS 是你的机器人应用程序的核心,负责处理如导航、感知、控制等任务,并通过 ROS 主题发布消息。在我们的案例中,我们关注的是 ROS 主题
your_topic
,它发布
std_msgs/String
类型的消息。
-
Flask 应用:Flask 应用是你的 Web 服务器,它提供了一个 Web 界面可以让用户通过浏览器进行交互。它还运行了一个 ROS 节点,订阅了
your_topic
主题,然后将收到的消息通过 WebSocket 连接发送给客户端。
-
Flask-SocketIO:Flask-SocketIO 是 Flask 应用的一个扩展,它提供了 WebSocket 功能。在 Flask 应用中,当接收到来自 ROS 主题的消息时,Flask-SocketIO 会将消息转发给所有连接的 WebSocket 客户端。
-
Web 客户端:Web 客户端是用户的浏览器,它加载了一个包含 JavaScript 代码的 HTML 页面。这个 JavaScript 代码创建了一个 WebSocket 连接到 Flask 应用,并监听来自服务器的消息。当接收到消息时,它将消息内容打印到浏览器的控制台。
-
这个系统的工作流程如下:
-
- Flask 应用启动,创建一个 ROS 节点并订阅
your_topic
主题。 - 用户在浏览器中打开 Flask 应用的 URL,浏览器加载 HTML 页面并运行 JavaScript 代码。
- JavaScript 代码创建一个 WebSocket 连接到 Flask 应用。
- 当 ROS 通过
your_topic
主题发布消息时,Flask 应用的 ROS 节点会接收到消息。 - Flask 应用通过 WebSocket 连接将消息发送给浏览器。
- 浏览器接收到 WebSocket 消息,并将消息内容打印到网页。
- Flask 应用启动,创建一个 ROS 节点并订阅
二、环境安装
-
安装rosbridge-server
ROS Bridge是一个ROS包,可以让非ROS应用通过网络接口访问ROS服务。安装如下:
sudo apt-get install ros-<rosdistro>-rosbridge-server 其中`<rosdistro>`应被替换为你的ROS版本,例如`melodic`,`noetic`或`kinetic`。
- 安装并设置Flask
Flask是一个轻量级的Web服务器框架,可以用来构建你的web服务。首先,你需要安装Flask和Flask-SocketIO,可以通过pip来安装:
pip install flask flask_socketio
小tips:安装失败的大部分原因都是pip没有换源捏
-
使用roslibjs或者roslibpy连接到rosbridge的示例(本博客不使用这个方法)
roslibjs是一个JavaScript库,可以在网页中使用,用于连接到rosbridge并订阅ROS话题。以下是一个基本的示例:
var ROSLIB = require('roslib');
var ros = new ROSLIB.Ros({
url : 'ws://localhost:9090'
});
var topic = new ROSLIB.Topic({
ros : ros,
name : '/your_topic',
messageType : 'std_msgs/String'
});
topic.subscribe(function(message) {
console.log('Received message on ' + topic.name + ': ' + message.data);
topic.unsubscribe();
});
```
在这个例子中,你需要替换`/your_topic`为你想要订阅的话题的名称,`std_msgs/String`为你的话题的消息类型。
你可以在Flask应用中集成这段JavaScript代码,然后当你访问你的IP地址时,你的浏览器将会连接到rosbridge,订阅你指定的话题,并在控制台打印出接收到的消息。
- 三、功能实现
- 创建一个简单的Flask服务器,如下所示:
from flask import Flask, render_template from flask_socketio import SocketIO app = Flask(__name__) socketio = SocketIO(app) @app.route('/') def sessions(): return render_template('session.html') if __name__ == '__main__': socketio.run(app, host='0.0.0.0', port=5000)
- 创建一个简单的Flask服务器,如下所示:
这将创建一个在0.0.0.0:5000上运行的服务器,并在访问时返回一个名为session.html
的页面。我们需要创建这个HTML文件,以便Flask能找到它。
-
-
创建一个WebSocket连接
WebSocket连接将用于实时传输ROS主题的信息。你需要在Flask服务器中添加一些代码来处理WebSocket连接。
在Flask服务器代码中添加以下代码:
@socketio.on('connect') def connect(): print('Client connected')
- 将ROS节点和WebSocket连接
- 新建一个ROS节点订阅指定的话题,并将ROS节点和WebSocket连接。你可以通过在
callback
函数中添加一行代码来实现这一点,该函数将消息发送到WebSocket。#!/usr/bin/env python import rospy from std_msgs.msg import String from flask import Flask, render_template from flask_socketio import SocketIO, emit from threading import Thread # 创建 Flask 应用 app = Flask(__name__) app.debug = True socketio = SocketIO(app) @app.route('/') def sessions(): return render_template('session.html') @socketio.on('connect') def connect(): print('Client connected') # 全局变量,用于存储 ROS 节点是否已经初始化 ros_initialized = False # 定义 ROS 回调函数 def callback(data): rospy.loginfo(rospy.get_caller_id() + " I heard %s", data.data) # 当收到 ROS 消息时,通过 WebSocket 广播消息 socketio.emit('message', {'data': data.data}) # 定义 ROS 监听器 def listener(): global ros_initialized if not ros_initialized: rospy.init_node('listener', anonymous=True) ros_initialized = True rospy.Subscriber("your_topic", String, callback) rospy.spin() # 定义 Flask 应用线程 def flask_thread(): socketio.run(app, host='0.0.0.0', port=5000, use_reloader=False) if __name__ == '__main__': rospy.init_node('listener', anonymous=True) Thread(target=listener).start() Thread(target=flask_thread).start()
- 在HTML页面中显示消息
最后,你需要在HTML页面中显示这些消息。你可以使用JavaScript和Socket.IO客户端库来实现这一点。
在你的
session.html
文件中,添加以下代码:
<!DOCTYPE html> <html> <head> <title>ROS Topic Viewer</title> <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script type="text/javascript"> var socket = io.connect('http://' + document.domain + ':' + location.port); socket.on('message', function(msg) { $('#log').append('<p>' + msg.data + '</p>'); }); </script> </head> <body> <div id="log"></div> </body> </html>
-
四、功能测试
- 运行ROS节点
- 手动发布测试话题
- 通过第三方设备访问端口大功告成!我们已经成功实现了从web页面查看指定的话题内容的基础功能。但也许可以开发一个功能包使我们能够在web页面优雅的查看整个ros中的话题、话题内容、消息格式、以及节点与节点直接的话题订阅关系?
评论(0)
您还未登录,请登录后发表或查看评论