平台
操作系统:Ubuntu18.04、Windows 10
操作平台:Barrett七自由度机械臂
Web前端框架:Node.js + Vue.js + Element UI
ROS与Web开发工具:Robot Web Tools(roslibjs+ros2djs+ros3djs)
开发工具:Visual Studio Code
服务器:Tomcat8.5
环境搭建
基础环境搭建
参照基于Vue.js的ROSWeb环境搭建文档。
ROSWeb工具简介
ros-web是ros官方提供的从ros到web端的一个开源接口。其主要的功能库有3个,即roslibjs基本库,ros2djs2D库和ros3djs3D库。本项目主要用的是roslibjs和ros3djs。
roslibjs库文件
roslibjs库是ros-web中的基础库,可以实现创建ROS,订阅消息、发布话题和调用服务等功能。其中比较重要的类有ROS、Topic和Service。
ROS类
从ROS类的源码中可以看出,其底层也是基于socket协议实现的ros与web连接。ROS类在定义时,只需要提供ros端的IP和端口号即可(需要和rosbridge部分对应),如:1
2
3var ros = new ROSLIB.Ros({
url: 'ws://192.168.*.*:9090'
})
定义完该类后,可以使用ros.on()函数实时监听ros的系统状态。Ros类一共提供了3种状态,即connection、error和close,分别对应连接成功、连接错误和关闭连接状态。在对应的回调函数里面可以编写相应的逻辑功能。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
28this.ros.on('connection', () => {
this.$message({
message: '连接成功!',
type: 'success'
})
})
this.ros.on('error', (e) => {
this.$message.error('连接失败!')
})
this.ros.on('close', () => {
this.$message.error('关闭连接!')
})
```
### `Topic`类
```js
var wamPost = new ROSLIB.Topic({
ros: ros,
name: '/wam/pose',
messageType: 'geometry_msgs/PoseStamped'
})
wamPost.subscribe((message) => {
console.log(message)
wamPost.unsubscribe()
})
Topic类的构造函数需要给定3个参数,即ros类实例,话题名称name和话题的消息格式messageType。实例化类后,即可调用subscribe()函数订阅话题,并通过回调函数里面的messgage值获取话题信息,在回调函数中可以使用unsubscribe()函数取消订阅。1
2
3
4
5
6
7
8var cmdVel = new ROSLIB.Topic({
ros: ros,
name: '/turtle1/cmd_vel',
messageType: 'geometry_msgs/Twist'
})
geometryMsgsTwist.linear.x = 1
cmdVel.publish(geometryMsgsTwist)
除了可以订阅话题并获取信息,还可以发布话题。实例化话题类的方法和订阅一样,但需要提前定义好需要发布的话题消息格式和内容。1
2
3
4
5
6
7
8
9
10
11
12var geometryMsgsTwist = new ROSLIB.Message({
linear: {
x: 0.0,
y: 0.0,
z: 0.0
},
angular: {
x: 0.0,
y: 0.0,
z: 0.0
}
})
消息的定义为对象类型的键值对数据,需要根据实际话题的消息类型来具体定义。
定义好要发送的话题消息数据后,使用publich()发布话题。这里不需要订阅话题。
Service类
1 | var setPenClient = new ROSLIB.Service({ |
Service类的构造函数也需要给定3个参数,即ros类实例,服务名称name和服务的消息格式serviceType。这里同样需要先定义好服务的请求信息,格式为对象类型的键值对数据。实例化服务类后,可以通过callService()函数调用服务。
ros3djs库文件
ros3djs用于可视化3D模型相关的功能。其中比较重要的类有Viewer、TFClient和UrdfClient等。阅读底层代码可以发现,ros3djs是基于three.js 3D库实现的。
Viewer类
1 | var viewer = new ROS3D.Viewer({ |
Viewer用于创建一块用于显示3D模型的可视化区域。需要的参数为html的div区域ID divID,区域的宽度width,区域的高度heigh,是否抗锯齿antialias和背景颜色background等信息。实例化类后,即可在网页中看到一块空白区域。如需添加网格,调用ddObject(new ROS3D.Grid())函数即可。
TFClient类
1 | var tfClient = new ROSLIB.TFClient({ |
TFClient类是一个基础类,后续的一些类的参数经常需要使用它,构造函数的参数值按照官网提供的参数值即可,其中比较重要的一个参数是fixedFrame参数,这里需要和urdf模型中的基础坐标系相对应,否则会出现模型加载不完整,无法控制移动等问题。
UrdfClient类
1 | var urdfClient = new ROS3D.UrdfClient({ |
UrdfClient类可以可视化ros中的urdf模型,其主要的参数有实例化的ros,实例化的tfClient,模型存放的路径path,根对象rootObject(即urdf放在哪个区域)和模型加载器loader。这里比较重要的参数为path路径参数,这里存放的是网络或者本地的模型链接地址,本项目使用的vue.js前端框架,http://localhost:8080网址对应的即为整个项目文件夹的根目录,因此实际的模型地址位于http://localhost:8080/static中(需要将模型放在该文件夹下)。
设计思想
界面设计

整体界面分为3个部分,上面为logo显示和一些常用的功能选项。下面左侧为WAM 3D模型的可视化显示,右侧为功能逻辑部分,主要测试一些简单的基础功能。
其中WAM模型在连接成功会实时显示当前的位姿,数据也会实时更新在右下方的表格中。拖动右侧的滑动也会实时更新WAM的位姿状态。
逻辑功能
ROS中常见的功能主要有订阅消息、发布话题和调用服务。另外还需要将3D模型能够可视化显示在web网页中。因此本项目主要实现的逻辑功能包括:
- 订阅消息(
Subscribing message) - 发布话题(
publishing topic) - 调用服务(
Calling service) - 针对
urdf和xacro文件的3D模型可视化
代码模块
添加依赖文件
在vue.js的静态文件夹static中新建文件夹rosweb,用于存放所需要的第三方JavaScript文件。
其中roslib.js和ros3d.js为ros-web提供的库文件,剩余JavaScript文件为用于绘制3D可视化模型的库文件(主要为three.js框架及其依赖库)。
然后在index.html入口文件中,将这些文件添加<head>标签中。1
2
3
4
5
6<script src="./static/rosweb/three.js"></script>
<script src="./static/rosweb/ColladaLoader.js"></script>
<script src="./static/rosweb/STLLoader.js"></script>
<script src="./static/rosweb/eventemitter2.min.js"></script>
<script src="./static/rosweb/roslib.js"></script>
<script src="./static/rosweb/ros3d.js"></script>
由于ros-web的ros3d.js库文件在加载3D模型时,需要本地或者网络的模型链接,因此需要将ros中的模型部分放在static文件夹中。这里将barrett_ros中的barrett_model部分添加至static文件夹中:
主界面功能实现
代码文件位于src->components->HelloWorld.vue。基本按照ROSWeb工具简介解释的部分,更改为实际的话题/服务和消息的数据类型即可。
常见问题整理
- 在
index.html中导入完js文件,需要在.eslintrc.js中的rules.globals声明全局变量:1
2
3
4
5
6
7
8
9
10
11
12
13// add your custom rules here
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unused-vars': 'off'
},
"globals":{
"THREE": true,
"ROSLIB": true,
"ROS3D": true,
}
否则会出现无法找到该变量的定义的问题。
回调函数要改用为箭头函数,这样就可以使用使用
this对象了。解析订阅话题的接收到的值时,需要根据实际的格式对其解析。
如果遇到
ctrl+c关闭节点后,节点仍然存在的问题:在环境变量中添加export ROS_HOSTNAME=hostname(输入指令hostname即可查看自己的),且在关闭节点时不要使用ctrl+c,直接关闭窗口。连续发布多个话题或调用多个服务时,只会执行最后一个。这是
ros系统的问题,话题是异步通讯机制,发布相同消息时,只会处理最后一个,服务是同步通讯机制,可以通过判断返回的信息来实现依次调用相同的多个服务。