Introduction
-
Using ROS bridge server and a web page built with roslibjs on LAN to build a ros Interface.
-
Rosbridge server provides a websocket to connect the ros system and the web page.
-
Nginx, the local server, is used to host the web page locally.
-
The ports
There are two ports in this system, one is the port of rosbridge server, the other is the port of local server.
- The port of rosbridge server is set to 9090 by default. The setting is in the HTML file and the launch file of rosbridge server, we can change it, but remember to change the port in the HTML file and the launch file at the same time.
- The port of local server is set to 90 by default. The setting is in the nginx config file. This port is used to host the web page locally, and for the user to access the web page.
Setup
-
Install rosbridge server and nginx
sudo apt-get install ros-$ROS_DISTRO-rosbridge-server sudo apt-get install nginx
-
Generate ssl certificate and key file using openssl (cd to the directory you want to store the files first)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt
-
Edit the nginx config in
/etc/nginx/nginx.conf
3.1. Change the default user name www-data to hoster user name (the first line of the file, see example 3.3.)
3.2. Add the server config session in the config file.
http { ... server { # Put your server config here } }
3.3. Here is an example of the config file
user alfonso; # change to local server name worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; server { listen 90; # change 90 to local server port listen [::]:90; # change 90 to local server port listen 443 ssl; # ssl config ssl_certificate /home/alfonso/Documents/gui/localhost.crt; # change to file path on local server ssl_certificate_key /home/alfonso/Documents/gui/localhost.key; # change to file path on local server ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:'; ssl_prefer_server_ciphers on; server_name localhost; # Change to the directory of the web page on local server # This will be the root directory of the web page # Any inlude file in the web page should be in this directory root /home/alfonso/Documents/gui; index index.html; } include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; # gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
-
The example web page, using a virtual joystick to publish the cmd_vel topic.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/nipplejs/0.7.3/nipplejs.js"></script> <script type="text/javascript"> var ros = new ROSLIB.Ros({ // change to robot ip address // 9090 is the default port of rosbridge server url: 'ws://192.168.120.148:9090' }); ros.on('connection', function () { document.getElementById("status").innerHTML = "Connected"; }); ros.on('error', function (error) { document.getElementById("status").innerHTML = "Error"; }); ros.on('close', function () { document.getElementById("status").innerHTML = "Closed"; }); var txt_listener = new ROSLIB.Topic({ ros: ros, name: '/txt_msg', messageType: 'std_msgs/String' }); txt_listener.subscribe(function (m) { document.getElementById("msg").innerHTML = m.data; move(1, 0); }); cmd_vel_listener = new ROSLIB.Topic({ ros: ros, name: "/cmd_vel", messageType: 'geometry_msgs/Twist' }); move = function (linear, angular) { var twist = new ROSLIB.Message({ linear: { x: linear, y: 0, z: 0 }, angular: { x: 0, y: 0, z: angular } }); cmd_vel_listener.publish(twist); } createJoystick = function () { var options = { zone: document.getElementById('zone_joystick'), threshold: 0.1, position: { left: 50 + '%' }, mode: 'static', size: 150, color: '#000000', }; manager = nipplejs.create(options); linear_speed = 0; angular_speed = 0; manager.on('start', function (event, nipple) { timer = setInterval(function () { move(linear_speed, angular_speed); }, 25); }); manager.on('move', function (event, nipple) { max_linear = 5.0; // m/s max_angular = 2.0; // rad/s max_distance = 75.0; // pixels; linear_speed = Math.sin(nipple.angle.radian) * max_linear * nipple.distance/max_distance; angular_speed = -Math.cos(nipple.angle.radian) * max_angular * nipple.distance/max_distance; }); manager.on('end', function () { if (timer) { clearInterval(timer); } self.move(0, 0); }); } window.onload = function () { createJoystick(); } </script> </head> <body> <h1>Simple ROS User Interface</h1> <p>Connection status: <span id="status"></span></p> <p>Last message on /txt_msg: <span id="msg"></span></p> <div id="zone_joystick" style="position: relative;"></div> </body> </html>
Startup
On robot side
-
Start rosbridge server
roslaunch rosbridge_server rosbridge_websocket.launch
-
After the user side is connected, check if the data is received.
rostopic echo /cmd_vel
On local server side
- Start local server
sudo service nginx start
On user side
- Open the web page
https://<ip address of the local server>:90
Bug fixes
-
Error :
The web page shows 403 Forbidden
- Solution :
- Instruction - 解决Nginx出现403 forbidden
- check users
ps aux | grep "nginx: worker process" | awk '{print $1}'
- Edit the user name in /etc/nginx/nginx.conf, default is www-data change to your user name
- Solution :
-
Error :
The web page shows ERR_SSL_PROTOCOL_ERROR
- Solution :
-
Add the ssl config session in /etc/nginx/nginx.conf
server { listen 90; listen [::]:90; listen 443 ssl; root /home/alfonso/Documents/gui; index index.html; # ssl config ssl_certificate /home/alfonso/Documents/gui/localhost.crt; ssl_certificate_key /home/alfonso/Documents/gui/localhost.key; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:'; ssl_prefer_server_ciphers on; server_name localhost; }
-
Restart nginx
sudo service nginx restart
- Solution :
Reference
Websocket
- Instruction - ROS package#1 ROS Bridge 跨平台溝通
- Github - roslibjs
- CSDN - ROS进阶——Websocket
- 古月居 - 利用Websocket实现ROS与Web的交互
- Instruction - ROS web tutorial part 1 - rosbridge server and roslibjs
- Instruction - HTTPS站点使用WebSocket的错误及解决方案