Node-RED ROS 2 Plugin
This project is part of DIH^2. The main goal is provide Node-RED interoperability with ROS2 and FIWARE. The plugin introduces in the Node-RED palette new nodes dealing with:
Type definition
In order to transmit information it is necessary to precisely define the composition of the data delivered.
Node-RED approach is based on JSON which is versatile and user friendly but cannot be used to interoperate with industrial protocols that require language-independent type Description.
In order to provide this interoperability ROS2 introduced IDL. Which is a data type and interfaces descriptive language customary in industrial applications.
The new nodes make both: IDL type descriptions and well known ROS2 types available.
ROS2 Publisher-Subscriber interface
Publisher and Subscriber nodes are provided to directly access its ROS2 counterparts.
Different topics and QoS can be selected. Also a global configuration node allows to select the ROS domain to enforce.
FIWARE Context Broker Publisher-Subscriber interface
The Context Broker doesn't provide a Publisher-Subscriber interface (works more like a database) but a translation can be easily performed if:
- Entities are understood as topics.
- Creating or setting an entry is understood as publishing.
- Notification callbacks on an entity are understood as subscribtion callbacks.
Contents
Background
The interoperability between the plugin and the ROS2 and FIWARE Broker environments is achieved using WebSocket bridges to them. This was the natural choice given that Node-RED relies on WebSocket for front-end/back-end communication.
These bridges are generated using Integration-Service an eProsima open-source tool.
Using Integration-Service directly from the plugin was possible, but it was considered a better choice to create another Node.js library (is-web-api, to abstract the bridge operation. This way:
- The plugin can rely on any other bridge technology.
- Development is simplified by enforcing separation of concerns.
- Any other Node.js project (besides the plugin) can profit from the bridge library.
Install
A Dockerfile is provided to exemplify the set up on an argument provided ROS2 distro.
Dependencies
Some of the following installation steps can be skipped if the target system already fulfils some of the requirements:
-
ROS2 installation. Follow the official ROS2 installation guide for the distro of choice. The Dockerfile is based on a ROS2 image, so this is not exemplified.
-
Install Node.js. The usual OS package managers (like
apt
on Ubuntu orwinget/chocolatey
on windows) provide it. An exhaustive list is available here. Some package managers constrain the user to a specific version of Node.js. The Node.js site hints on how to install specific versions.For example, in
apt
is possible to add via location configuration file a new remote repository where all Node.js versions are available. This is the strategy that the Dockerfile uses:$ curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh $ chmod +x nodesource_setup.sh && sudo sh -c ./nodesource_setup.sh $ sudo apt-get install -y nodejs
-
Install Node-RED. Follow the official Node-RED installation guide. The Dockerfile favors the easiest procedure which relies on
npm
(default Node.js package manager) which is available after Node.js installation step:$ npm install -g node-red
-
Install Integration-Service. Follow the Integration-Service installation manual. This is exemplified in the Dockerfile, basically it is build from sources downloaded from github. Dependencies associated with the build and bridge environments are required:
$ apt-get update $ apt-get install -y libyaml-cpp-dev libboost-program-options-dev libwebsocketpp-dev \ libboost-system-dev libboost-dev libssl-dev libcurlpp-dev \ libasio-dev libcurl4-openssl-dev git $ mkdir -p /is_ws/src && cd "$_" $ git clone https://github.com/eProsima/Integration-Service.git is $ git clone https://github.com/eProsima/WebSocket-SH.git $ git clone https://github.com/eProsima/ROS2-SH.git $ git clone https://github.com/eProsima/FIWARE-SH.git $ . /opt/ros/humble/setup.sh # customize the ROS2 distro: foxy, galactic, humble ... $ colcon build --cmake-args -DIS_ROS2_SH_MODE=DYNAMIC --install-base /opt/is
Note that it uses the ROS2 build tool: colcon As ROS2 it is necessary to source and overlay. In order to simplify sourcing
/opt/is
was chosen as deployment dir. The overlay can be then sourced as:$ . /opt/is/setup.bash
It will automatically load the ROS2 overlay too. After the overlay is sourced it must be possible to access the integration-service help as:
$ integration-service --help
Plugin installation
Once all the dependencies are available we can deploy the plugin via npm:
-
From npm repo:
$ npm install -g node-red-ros2-plugin
-
From sources.
npm
allows direct deployment from github repo:$ npm install -g https://github.com/eProsima/node-red-ros2-plugin
Or, as in the Dockerfile, from a local sources directory. The docker favors this approach to allow tampering with the sources.
$ git clone https://github.com/eProsima/node-red-ros2-plugin.git plugin_sources $ npm install -g ./plugin_sources
Usage
In order to test the plugin there are two options: follow the installation steps above or run the test container provided here.
Node-RED palette
The main concepts associated with Node-RED operation are explained here. The plugin nodes are displayed on the Node-RED palette as shown in the image. From there, they can be dragged into the workspace.
The palette is the pane on the left where all available nodes are classified by sections. Plugin ones appear under ROS2
and FIWARE
(figure's red frame). The worksplace is the central pane where different flows are associated to the upper tabs.
Note: the text that labels the node, changes from palette to workspace, and may change depending on the node configuration.
Definining a type
In order the publish or subscribe data we need first to specify the associated type. The plugin provides two options:
Choosing a predefined ROS2 type
Defining a new type via IDL
Injecting a type instance into the pipeline
Node-RED pipelines start in source nodes. The most popular one is the inject node which requires the user to manually defined each field associated to the type. In order to simplify this a specific node is introduced:
This node mimics the inject node behaviour but automatically populates the input dialog with the fields associated with
any type node linked to it. For example, if we wire together a ROS Inject
and a ROS Type
or IDL Type
nodes as
shown in the figure:
The associated dialogs are populated with the linked type fields and types.
ROS2 nodes usage
In order to interact with a ROS2 environment we must specify the same domain id in use for that environment.
The domain id is a number in the range [0, 166]
that provides isolation for ROS2 nodes.
It defaults to 0 and its main advantage is reduce the incomming traffic for each ROS2 node, discharging them and
speeding things up.
Another key concepts in the ROS2 environment are:
- topic one. A topic is a text string ROS2 nodes use to notify all other nodes in which data they are interested. When a ROS2 node wants to send or receive data it must specify:
- Which type is the data they want receive. For example the
geometry_msgs/Pose
we introduced above. - Topic associated with the data. For example
/marker_pose
, but in ROS2 topics are often decorated using namespaces to simplify identification, as in/eProsima/buildings/E3g1/room/F2h3/marker/4Rg1/pose
.
-
Quality of Service (QoS). Those are
policies that allow fine tunning of the communication between nodes. For example:
- History QoS allows to discard messages if only the most recent one is meaningful for our purposes.
- Reliable QoS enforces message reception by resending it until the receiver acknowledges it.
- Durability QoS assures messages published before the receiver node creation would be delivered.
Note: ROS2 nodes can only communicate if their respective QoS are compatible. Information on QoS compatibility is available here.
ROS2 configuration node
A Node-RED config node is provided to set up the domain ID, which is a global selection:
Note: The ROS2 default domain value is 0
ROS2 Publisher
This node represents a ROS2 publisher. It is able to publish messages on a specific topic with specific QoS | |
The dialog provides controls to configure:
|
ROS2 Subscriber
This node represents a ROS2 subscriber. It is able to subscribe on a specific topic and receive all messages published for it. | |
The dialog provides controls to configure:
|
ROS2 Examples
ROS2 Basic Publication Example
Let's show how to use a custom type.
-
Launch docker compose as explained here.
-
Create and wire the following nodes:
- An
IDL Type
node. Open the associated dialog and introduce the following idl:
module custom_msgs { module msg { struct Message { string text; uint64 value; }; }; };
-
A
ROS Publisher
node. Open the associated dialog and set up the publisher:Topic
: hopeDomain
: 42 -
A
ROS Inject
node. Open the associated dialog and fill in the fields:text
: Hello World!value
: 42
- An
-
Deploy the flow pressing the corresponding button. Once deployed, the custom type has been registered in the ROS2 distro.
-
Let's launch a subscriber from the ROS2 cli.
$ docker exec -ti --env ROS_DOMAIN_ID=42 docker-visual-ros-1 /ros_entrypoint.sh ros2 topic echo /hope custom_msgs/msg/Message
- Now click on the inject node button within the editor and see how the terminal receives the data.
Note: In the example the ROS2 domain value selected is 42, different from the default value of 0.
ROS2 Basic Subscription Example
In this case, a builtin ROS2 type (geometry_msgs/Point
) will be used.
-
Launch docker compose as explained here.
-
Create and wire the following nodes:
-
A
ROS2 Type
node. Open the associated dialog and select:Package
: geometry_msgsMessage
: Point -
A
ROS2 Subscriber
node. Open the associated dialog and set up the subscriber:Topic
: hopeDomain
: 17 -
A
debug
node from thecommon
palette section. Open the associated dialog and set it up to show the x coordinate of the point:Output
:msg.x
-
-
Deploy the flow pressing the corresponding button.
-
Publish a message on that topic from the ROS2 cli. In this example we launch a new container connected to the same network using the standard
ros:humble
image.
$ docker run --rm -ti --env ROS_DOMAIN_ID=17 --network docker_visualros ros:humble \
ros2 topic pub /hope geometry_msgs/msg/Point "{ x: 42, y: 0, z: 0 }"
ROS2 Mandatory Turtlesim Example
Turtlesim is an ad hoc package that ROS2 provides as GUI node example.
Set up
Unlike the previous examples turtlesim cannot work on terminal mode. There are several ways to workaround this:
- Run GUI application in a docker container as shown here.
- Share the container network stack with the host.
- Run Node-RED backend directly in your host (see installation steps).
Here we favour the second option as the most simple. This only requires:
- A ROS2 installation in the host. Follow the official ROS2 installation guide for the distro of choice.
- Launch the Visual-ROS container sharing host network stack:
node-red-ros2-plugin/docker$ docker build --build-arg ROS_DISTRO=humble -t visualros:humble .
$ docker run -ti --name turtledemo --network host --ipc host visualros:humble /node_entrypoint.sh node-red
Demo steps
- Launch
turtlesim
on the host by doing:
$ . /opt/ros/humble/setup.sh
$ ros2 run turtlesim turtlesim_node
A window should appear with a turtle in the middle.
-
Open a web browser on http://localhost:1880.
-
Create and wire the following nodes:
- A
ROS2 Type
node. In the associated dialog set up the turtlesim pose type:geometry_msgs/Twist
. - A couple of
ROS2 Inject
nodes: one to move the turtle forward and another to spin it. Wire both nodes to theROS2 Type
. Open the associated dialogs and take into account that:- mover forward means
linear.x = 1
- spin means
angular.z = 1
- mover forward means
- A
ROS2 Publisher
node. Wire it to theROS2 Type
node. Open the associated dialog and set up as:- Topic the
turtle/cmd_vel
. - Use the default ROS2 domain 0.
- Topic the
- A
-
Click the
Deploy
button.
Now click on the inject nodes buttons within the editor and see how the turtle moves.
This json file can be imported to Node-RED in order to reproduce the flow.
FIWARE nodes usage
The FIWARE Context Broker uses a REST API to provide information. This interface do not exactly follows a Publisher/Subscriber model but can be adapted to do so:
- Broker entities are mapped as Publisher/Subscriber topics.
- Types are described using IDL which works as a subset of the NGSI type system.
FIWARE configuration node
A Node-RED config node is provided to set up the FIWARE Context Broker IPv4 address which is a global selection.
FIWARE Publisher
FIWARE Subscriber
FIWARE Examples
FIWARE Basic Publication Example
Let's use a custom type.
-
Launch docker compose as explained here.
-
Create and wire the following nodes:
- An
IDL Type
node. Open the associated dialog and introduce the following idl:
module custom_msgs { module msg { struct Message { string text; uint64 value; }; }; };
-
A
FIWARE Publisher
node. Open the associated dialog and set up the publisher:Topic
: hopeContext Broker
:192.168.42.14:1026
Note the address and port of the Context Broker was specified in the
compose.yaml
file. -
A
ROS Inject
node. Open the associated dialog and fill in the fields:text
: Hello World!value
: 42
- An
-
Deploy the flow pressing the corresponding button.
-
Once deployed, click on the inject node button within the editor. The Context Broker should have created an entity associated to the topic (
hope
) with the values provided in the inject node.
In order to check it, the FIWARE Context Broker can be directly queried using its REST API (note that in the
compose.yaml
file the Context Broker port 1026 is mapped to the host machine). Open a console on the host and type:
$ curl -G -X GET "http://localhost:1026/v2/entities" -d "type=custom_msgs::msg::Message" -d "id=hope"
It should return the following json:
[
{
"id": "hope",
"type": "custom_msgs::msg::Message",
"text": {
"type": "Text",
"value": "Hello World!",
"metadata": {}
},
"value": {
"type": "Number",
"value": 42,
"metadata": {}
}
}
]
FIWARE Basic Subscription Example
In this case, a builtin ROS2 type (geometry_msgs/Point
) will be used.
-
Launch docker compose as explained here.
-
Create and wire the following nodes:
-
A
ROS2 Type
node. Open the associated dialog and select:Package
: geometry_msgsMessage
: Point -
A
FIWARE Subscriber
node. Open the associated dialog and set up the subscriber:Topic
: positionContext Broker
:192.168.42.14:1026
-
A
debug
node from thecommon
palette section. Open the associated dialog and set it up to show the x coordinate of the point:Output
:msg.x
-
-
Deploy the flow pressing the corresponding button.
-
Publish a message on that topic from the FIWARE REST API. Because the
compose.yaml
maps the FIWARE Context Broker port to a host one (1026) is possible to reach it from the host machine. Open a console on the host and type:
$ curl http://localhost:1026/v2/entities -H 'Content-Type: application/json' -d @- <<EOF
{
"id": "position",
"type": "geometry_msgs::msg::Point",
"x": {"value": 42, "type":"Text"},
"y": {"value": 4, "type":"Text"},
"z": {"value": 2, "type":"Text"}
}
EOF
The debug pan should log an output. In order to update the entity value, further http queries should follow:
$ curl -X PUT http://localhost:1026/v2/entities/position/attrs?type=geometry_msgs::msg::Point \
-H 'Content-Type: application/json' -d @- <<EOF
{
"x": {"value": 3, "type":"Text"},
"y": {"value": 2, "type":"Text"},
"z": {"value": 1, "type":"Text"}
}
EOF
This project (DIH² - A Pan‐European Network of Robotics DIHs for Agile Production) has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 824964