Only released in EOL distros:
Package Summary
A declarative widget library based on ros.js
- Author: Benoit Lescot and Stéphane Magnenat
- License: BSD
- Source: git https://github.com/ethz-asl/websocket_gui.git (branch: None)
Package Summary
A declarative widget library based on ros.js
- Author: Benoit Lescot and Stéphane Magnenat
- License: BSD
- Source: git https://github.com/ethz-asl/websocket_gui.git (branch: None)
Overview
Using a robot, you want to display information provided by the platform and its sensors. Some tools like webui and QGroundControl already exist but own dependencies with ROS and/or others plug-in. This implicates to install additional software on your visualization computer which could be constraining.
In order to avoid that problem, the remote lab project developed a robot web application wviz based on the websocket protocol. However, this API is still low level and requires some ROS and JavaScript backgrounds.To make things easier for the user, we developed the websocket_gui stack.
websocket_gui furnishes several widgets to display information from ROS messages in a web browser based on rosjs. Its low level communication protocol is managed by the rosbridge node.
List of widgets :
Architecture
Overall
To run this stack, you need the following infrastructure which is quite simple. On the left side, you have your robot with ROS. Rosbridge is a necessary node to create the interface between ROS and your web browser from the client side. When the connection is opened and data are received by the client side, they are displayed calling widgets based on web libraries like JavaScript, HTML5 and CSS3.
Widget concepts
With these widgets, you can display several information, and/or data in the same screen with different types of display. To make things easier for the user, the HTML structure of your page also called Document Object Model is built automatically. If you are familiar with this concept, you can jump to the Widgets section. Otherwise take a look to the next section.
HTML5 and CSS3
HTML and CSS are programming languages used to create web pages. They have been invented by Tim Berners-Lee and Håkon Wium Lie in the 90's. Few years later, the first one created the World Web Consortium W3C which is the reference website (I hope your future Holly Bible) in this field.
- HTML handles and organizes the content of your web page. It describes what must be display on the page using tags (title, header, footer, paragraph ....).
A web page is divided in several elements. The document's body is defined by the <body> tag. It contains all the content of an HTML document such as text, picture, video ..... In the body, you can insert <div> tag. They define a division or a section in a HTML document. In our case, each widget defines its own <div> element. You just have to add the widget to the <body> of you HTML page. That's an example of four widgets display in a web browser.
- CSS manages appearance of elements composing your web page. For example, their position, colour-background, font-size, height, width ...
JavaScript
JavaScript is the programming language of scripts for the Web. It has been developed in Netscape, by Brendan Eich. It has to be directly included in the web page and make a HTML page more dynamic for the user. Using this stack, you will be confronted to two JavaScript functions:
innertHTML
This property returns the inner HTML of an HTMLObject element. You need to call this function on the body element to add a widget in your HTML page. The following example displays "/topic_name" on your entire page each 300 milliseconds:1 document.body.innerHTML+=DisplayTopic("width:100%;height:100%;","/topic_name",300)
For further details, take a look to innerHTML.
dictionary
This object contains keys on which values are associated. It looks like to a dictionary in Python or C++. This object will be given as argument to some widgets. Following examples show two differents syntax to create the same dictionary:
Example 1:This notation will be taken as "convention" in this wiki.
Example 2:For further details, take a look to dictionary.
Widgets
This section lists available widgets.
Altimeter
This widget looks like to a plane altimeter. A needle rotates according the value of the parameter specified in option. At the bottom of this widget, a counter displays the current value.
1 document.body.innerHTML+=Altimeter(style,topic_name,delay_ms,dictionary)
style : CSS style (width and height in % or px are wished). string
topic_name : ROS topic name (example "/imu_node") string
delay_ms : Period in milliseconds to update altimeter. -1 can be chosen and will update the widget each time a new message is received by ROS. integer
dictionary : Some parameters are required for this widget because it can not have in advance the range of value to display. To create a dictionary in JavaScript take a look to .5 keys are required, 1 is optional. Two angles are necessary. They delineate the area on which the needle will move. By convention, clockwise rotation is defined positive. The origin is defined as theta equal zero on a unit circle.
"theta_start" : angle in radian starting the scale_division. integer or float
"theta_end" : angle in radian ending the scale_division. integer or float
"value_start" : first value of the scale division. integer or float
"value_end" : last value of the scale division. integer or float
"value_inc" : increment for the scale division. integer or float
"key"(OPTIONAL) : By default, the widget will search for "height" or "altitude" in messages published on the topic given in topic_name. If you need an other key, give it here. string
This widget resizes itself according the height and the width of the body element. It finds the optimal scale to keep its ratio. Moreover the altimeter is centred in its div.
DisplayImage
This widget display images from a ROS image topic. Two modes are available. Firstly, you can stream video as another message type from ROS using rosjs (included in rosbridge). In order to increase performance benefits mjeg_server has been developed. It's a streaming server that subscribes to a ROS image topic, publishes data as MJPEG streams via HTTP and displays it in your browser.
1 document.body.innerHTML+=DisplayImage(style,topic_name,period_ms,port_opt)
style : CSS style (width and height in % or px are wished). string
topic_name : topic name in ros (example "/cam"). string
period_ms : Period in milliseconds to update image. -1 can be chosen and will update the widget each time a new message is received by ROS. integer
port_opt (OPTIONAL) : If you give a port, the mjpeg_server mode will be used. The period_ms is not used because the streaming server adapts its period following the publishing period of the ros topic. integer It requires to launch the mjpeg_server node manually.
This widget resizes itself according the height and the width of the body element. It finds the optimal scale to keep the image ratio.
DisplayTopic
This widget displays a topic like the rostopic echo command in ROS.
1 document.body.innerHTML+=DisplayTopic(style,topic_name,period_ms)
style : CSS style (width and height in % or px are wished). string
topic_name : topic name in ros (example "/cam"). string
period_ms : Period in milliseconds to update image. -1 can be chosen and will update the widget each time a new message is received by ROS. integer
The size of the font is defined by default.
Plot
It plots one or several data from a topic according the timestamps contained in the message header. If the message does not own timestamps, a pseudo time is automatically created.This widget uses a JavaScript library flot.
1 document.body.innerHTML+=Graph(style,topic_name,period_ms,dictionary)
style : CSS style (width and height in % or px are wished). string
topic_name : topic name in ROS (example "/imu_node") string
period_ms : Period in milliseconds to update altimeter. -1 can be chosen and will update the widget each time a new message is received by ROS. integer
dictionary : Some parameters are required for this widget in order to allowed the user to custom its graph. To create a dictionary in JavaScript take a look here.3 keys are required. Let's take a ros message in example.
"key" : array containing names of value to plot. array of string Example 1 : Plot the height
Example 2 : Plot the secs
Example 3 : Plot the first parameter of the angular_velocity_covariance
Example 4 : Plot angular_velocity vector
"color" : array containing color for each value. array of string You must have as much colors as key elements. You can define a color using three different ways (name, hexadecimal or RGB notations). For all color references, visit w3schools.com.
The following code colors vector components from the last example respectively in red, green and blue."nb_pt" : maximal number of points to plot simultaneously . integer or float
This widget adapts its scale division for a proper display and resizes itself automatically.
Log
This widget displays a console showing main steps of the process. A color code is established to display information, warning and error. Two sources can provide messages, ROS (as rxconsole) and JavaScript.
1 document.body.innerHTML+=Log(style,topic_name,bool_rxconsole,bool_js)
style : CSS style (width and height in % or px are wished). string
topic_name : topic name in ros (example "/imu_node") string
bool_rxconsole : Bool for rx_console information. bool
bool_js : Bool for JavaScript information. bool
RosTurtle
This widget displays a turtle drawing a square and its trajectory like turtlesim
1 document.body.innerHTML+=RosTurtle(style,teleop_turtle)
style : CSS style (width and height in % or px are wished). string
teleop_turtle : display arrows panel to control the turtle. (bool, default:false)
Display the turtle and its trajectory sensed from /turtle1/pose . If teleop_turtle set to true you can control the turtle clicking on arrow or using arrows on your keyboard. When the webbrowser is resized the trajectory is clear.
Battery
This widget displays a battery and the battery_voltage.
1 document.body.innerHTML+=Battery(style,topic_name,period_ms,dict)
style : CSS style (width and height in % or px are wished). string
topic_name : topic name in ros (example "/imu_node") string
period_ms : Period in milliseconds to update altimeter. -1 can be chosen and will update the widget each time a new message is received by ROS. integer
dictionary : Some parameters are required for this widget in order to allowed the user to custom its battery display. To create a dictionary in JavaScript take a look to . 3 keys are required, 1 is optionnal
"value_min" : Lower value reachable by the battery. (integer or flot, default:0)
"value_max" : Higher value reachable by the battery. (integer or flot , default:12)
"safety_threshold" : Threshold value delimiting the green range and the orange/red range. (integer or flot , default:("value_max"-"value_min")/2)
The green color is selected for value contained in [threshold;value_max[
The orange color is selected for value contained in [value_min+50%*(threshold-value_min),threshold[
The red color is selected for value contained between [value_min;value_min+50%*(threshold-value_min)[
"display_value" : Display battery voltage under the battery (bool, default:false)
"key" (OPTIONAL) : Key associated to the battery value in your ros message. (String,default keys:"battery","battery_voltage", "battery_lvl")
If no key "key" is present in the dictionary, the widget searches for default key iteratively. If no key is found, an error message is written in the Log widget.
Installation
To use the websocket_gui, you will need the trunk of the websocket_gui stack: and one additional package such as rosbridge.
In order to download and build the websocket_gui stack, open a terminal and follow these steps:
Show EOL distros:
1 #Go to your working ros directory
2 cd somewhere/in/my/ros/folder
3
4 #Clone the brown_remotelab stack containing rosbridge package in this directory
5 git clone --recursive https://brown-ros-pkg.googlecode.com/svn/trunk/distribution/brown_remotelab
6 #Build rosbridge
7 cd brown_remotelab/rosbridge
8 make
9
10 #Clone the websocket_gui stack in this directory
11 git clone --recursive https://github.com/ethz-asl/websocket_gui
12 #Build it
13 cd websocket_gui
14 make
15
16 #Install dependencies for the Map widget
17 #gdal library (http://www.gdal.org/)
18 sudo apt-get install gdal-bin python-gdal libgdal-doc
19 #Mapserver library (http://mapserver.org/)
20 sudo apt-get install cgi-mapserver mapserver-doc mapserver-bin python-mapscript php5-mapscript
21 #Test mapserv for cgi by typing in your favorite browser:
22 http://localhost/cgi-bin/mapserv
23 #You should obtain the following answer:
24 "No query information to decode. QUERY_STRING is set, but empty."
25
26 #Now your installation is successful, let's play with some widgets
1 #This installation supposed you have set your ros environment and created a ros workspace.
2
3 #Add the brown_remotelab stack containing rosbridge package to the overlay
4 roslocate info brown_remotelab | rosws merge
5
6 #Add the websocket_gui package to the overlay
7 roslocate info websocket_gui | rosws merge
8
9 #Update repositories in the overlay
10 rosws update
11
12 #Build packages
13 rosmake websocket_gui
14 rosmake rosbridge
15
16 #Install dependencies for the Map widget
17 #gdal library (http://www.gdal.org/)
18 sudo apt-get install gdal-bin python-gdal libgdal-doc
19 #Mapserver library (http://mapserver.org/)
20 sudo apt-get install cgi-mapserver mapserver-doc mapserver-bin python-mapscript php5-mapscript apache2
21 #Test mapserv for cgi by typing in your favorite browser:
22 http://localhost/cgi-bin/mapserv
23 #You should obtain the following answer:
24 "No query information to decode. QUERY_STRING is set, but empty."
25
26 #Now your installation is successful, let's play with some widgets
TOtest.
Quick start
First example with a well known turtle ...
This example works with the [[http://wiki/turtlesim|turtlesim] node used in the ros_tutorial. A turtle pops and draws a rectangle. The altimeter displays the turtle angle.
Open you favourite terminal and write the following commands:
roslaunch websocket_gui turtle_draw_rectangle.launch
This launch file starts the turtlesim and the draw_square nodes.
Then open in firefox or google chrome somewhere/in/my/ros/folder/websocket_gui/examples/html/turtle_drawing_rectangle.html.
Well this is a really basic example, it would be more funny if we could teleop the turtle... Okay, so let's do it
Second example to teleop the turtle
Let's take the first example and improve it in order to control the turtle's movements.
If you ran the first example, you can stop the last launch file.
Open you favourite terminal and write the following commands:
roslaunch websocket_gui turtle_teleop.launch
It's the same launch file compared to the previous except that the draw_square node has been removed.
A turtle pops and does not move but don't be too sad,.
Open in firefox or google chrome somewhere/in/my/ros/folder/websocket_gui/examples/html/turtle_teleop.html.
You can teleop the turtle pressing your keyboard arrays or clicking on the arrays drawn into the page.
Turtle examples were fun but quite simplistic. Now let's talk about a more practical example.
Third example with a micro-helicopter
For this example we will not use the turtlesim package. Our inputs will be provided by a rosbag which is a sample of a dataset. It was acquired on a micro-helicopter platform by a team from the ETHZ. To run this example properly, you need to install the following packages for the rosbag: - ethzasl_sensor_fusion - asctec_mav_framework Open you favourite terminal and write the following commands:
1 #Go to your working ros directory
2 cd somewhere/in/my/ros/folder
3 #Download ethzasl_sensor_fusion
4 git clone git://github.com/ethz-asl/ethzasl_sensor_fusion
5 #Download asctec_mav_framework
6 git clone https://github.com/ethz-asl/asctec_mav_framework
7 #Build packages
8 rosmake ethzasl_sensor_fusion
9 rosmake asctec_mav_framework
10 #It's done! Now you just have to start the launch file
11 roslaunch websocket_gui helicopter.launch
12 #It launches the rosbridge node and plays the rosbag in loop.
Open in firefox or google chrome somewhere/in/my/ros/folder/websocket_gui/examples/html/helicopter.html.
In this example the map uses maps.google API and is online which could present difficulties if you don't have access on your experiment place.
A tool has been developed to download tiles from the internet and create your own local map. It will be present in the next example.
Forth example with a micro-helicopter and an offline map
In order to process the tiles downloaded and create the "map" server, some packages must be installed.
Open you favourite terminal and write the following commands:
1 #Install mapserver packages http://mapserver.org/
2 sudo apt-get install mapserver-bin mapserver-doc cgi-mapserver python-mapscript php5-mapscript
3 #Install gdal libraries http://www.gdal.org/
4 sudo apt-get install gdal-bin
5 #go to the script directory
6 cd somewhere/in/my/ros/folder/websocket_gui/tools/Map/script
7 #Execute script
8 python GetMap.py 47.418912 8.566297 1123 674 -z 0.25 -s 256 -a
9 # Open in firefox or google chrome ''somewhere/in/my/ros/folder/websocket_gui/examples/html/helicopter2.html
10
Files and Organization
This part parses the websocket_gui directory and details all files purpose. If you want to create your own widget, it will help you to find out how this API works.
In your terminal, write the following command
cd websocket_gui ls
You obtain:
Let's make a review of the main files and directories.
build |
Contains websocket_gui.js generated from the Makefile and grouping all the JavaScript API. |
examples |
css
Contains style.css defining some css properties for the body and the widget class elements of the html pages.html
Contains a list of html pages for each widgets.launch
Contains the launch file necessary to run the turtle_example.htmlpictures
Contains several pictures necessary for some widgets like RosTurtle
js |
Contains all the JavaScript API. |
flot
Contains the flot API. It's a pure JavaScript plotting library for jQuery.process.js
This file is the spine of the API.- Firstly, it instantiates the WebSocketGui class function.
- Then, it creates the websocket connection and manages it. When the connection is open, 4 tasks are run.1 function WebSocketGui() 2 { 3 //ROS 4 this.topics=[]; //array of ros topic 5 this.types=[]; //types associated to topics 6 // Socket server 7 if (window.location.protocol == "file:") 8 { 9 this.address="localhost"; 10 } 11 else 12 { 13 this.address=window.location.hostname; 14 } 15 this.port="9090"; 16 this.connection=""; //connection object from rosjs (rosbridge) 17 //list of handlers 18 this.handlers=[]; //array containing Handlers objects 19 this.widgets=[]; //array containing WidgetWithTask objects 20 this.resize_tasks=[]; //array containing all resize tasks 21 //process_state 22 this.ros_topics_available=false; 23 this.RosJsHdl_created=[]; 24 this.widget_handler_created=false; 25 //current widget_id 26 this.id_widget=0; 27 //Verbose for log 28 this.verbose=false; 29 }
1 initialize_ros //Stores list of ros topics and types in websocket_gui_obj 2 create_widget_handlers //Creates or updates '''Handler''' obj for each element in websocket_gui.widgets 3 create_rosbridge_handlers //Creates "callback" for all topics contained in websocket_gui.handlers 4 call_rosbridge_services // Subscribes to all topics contained in websocket_gui.handlers 5
process_factory.js
Contains functions used in process.js like:Handler()
Each instance of this class is associated to only one ROS topic. It stores tasks of all widgets and the current ros_msg.1 function Handler(topic_name,period_ms) 2 { 3 this.topic=topic_name; //one topic per handler object 4 this.period_ms=period_ms; //one period to get messages from "this.topic" 5 this.tasks=[]; //array of tasks for each widgets related to "this.topic" 6 this.rsp=""; //current ros message published on "this.topic" 7 this.add_task=function (task) // push a new task in "this.tasks" 8 { 9 this.tasks.push(task); 10 }; 11 this.run_tasks=function() //execute list of tasks contained in "this.tasks" 12 { 13 for (var id_task in this.tasks) 14 { 15 this.tasks[id_task](); 16 } 17 }; 18 }
resize_widgets()
Resizes all widgets contained in the html page owning a resize task.
rosbridge_wsview_v2.js
Contains rosbridge_wsview functions.They have been upgraded to handle more image format for the DisplayImage widget.websocket_gui.js
Contain the load script function to add some additional JavaScript source to your html5 page. It's an alternative version to the MakeFile.widgets
All this JavaScript widgets files are build on the same scheme. There are 4 functions to underline:WidgetClass()
This function contains all parameters required to ensure the good functioning of the widget.Widget()
This function must be called and added dynamically to a part a your HTML5 document. It's general running is detailed in the next part.widget_ref
This variable contains an anonymous function defining task(s) to execute when new messages from ROS related to this widget are received. These tasks can be compared to actions contained in a ROS callback function.resize_widget_task()
This function will re-size the widget when the document's body of your HTML page is re-sized.
widgets_factory.js
Contains functions called by the widgets like :
WidgetWithTask()
Each widget is associated to a ros topic,1 function WidgetWithTask(topic,period_ms,div_id,task,task_name,resize_task_function) 2 { 3 this.topic=topic; //topic related to this widget 4 this.period_ms=period_ms; //period related to this widget 5 this.task=task; //create or update handler for this topic 6 this.task_name=task_name; // Name of the widget 7 this.div_id=div_id; //"widget_i" with i the number-1 of widget present in your page 8 this.run_task=function() //Execute this.task with the proper parameters 9 { 10 his.task(this.topic,this.period_ms,this.div_id); 11 } 12 if (resize_task_function) //define a resize_task 13 { 14 this.resizetask=function() 15 { 16 resize_task_function(this.div_id); 17 } 18 } 19 }
create_task_for_widget(topic_name)
It return a task (function) which will be stored in the WidgetWithTask object. This function checks if the topic_name exists. If it does, this function creates or updates the Handler object associated to this topic.create_resize_task_for_widget()
It returns a task(function) which will be stored in the WidgetWithTask object. This function will resize the widget.
API functioning
Opening a html page, two process will be executed in parallel. The first one is link to your widget: Firstly the widget function creates a WidgetWithTask Object. A widget_task and a resize_widget_task functions are store in this object. Then the WidgetWithTask object is added the websocket_gui_obj which is a instance of WebSocketGui. Finaly the <div> element associated to the widget is returned.
During this time,
Report a Bug
You can use our issue tracker