4: Data Visualization Using ROS 2 rviz2 and Pub-Sub Communications
Simulate, publish and visualize ROS 2 LIDAR sensor data using TypeScript.
Edited 20220211 — expanded Nodejs version prerequisites to v10.22–17.x
In this tutorial we get closer to a real world scenario as we learn about ROS message interfaces, in particular the LaserScan sensor message, and how to create and publish such messages for other nodes to process. Then we will use the ROS 2 rviz2
visualization tool to render a 3D map created from the sensor data.
ROS Interfaces
In tutorial #2 we created a node that published hello world
String messages to a topic. Then in tutorial #3 we created a node that subscribed to those hello world
messages. While those were trivial examples, we gained hands-on experience in how to programmatically publish and subscribe to ROS 2 messages from a JavaScript Nodejs program. We also gleaned a little system design insights as we got an early glimpse into how ROS nodes can operate independently and coordinate between themselves through message interfaces. In addition to message interfaces, ROS supports 2 other interface types: services and actions. We will work with those interface types in future tutorials.
ROS encourages systems architectures comprised of independent, loosely coupled physical, virtual and computational components that interact through message, service and action interfaces.
ROS Common Interfaces
ROS includes a number of common interfaces that are organized into packages as shown:
- action_msgs
- builtin_interfaces
- diagnostic_msgs
- geometry_msgs
- nav_msgs
- rcl_interfaces
- rosgraph_msgs
- sensor_msgs
- shape_msgs
- srv_msgs
- stereo_msgs
- trajectory_msgs
- visualization_msgs
You are encouraged to explore the message interfaces defined in these packages. See the Resources section at the end of this tutorial for a link.
LaserScan Message
The ROS 2 sensor_msgs
package includes the LaserScan message type for communicating laser and LIDAR sensor data from a measuring device to other nodes in a ROS graph. Our program will generate and publish messages that adhere to the following LaserScan message definition..
Let’s Code
Some details about this project. The program will consist of:
- a routine that generates a data set measurements from a planar 360 LIDAR device. Data is generated once per second (1Hz)
- a ROS publisher that broadcast LIDAR sensor data (
sensor_msgs/msg/LaserScan
) to the topiclaser
when it is available - a ROS node that manages sensor data generation and the life-cycle of the publisher
- the program will run indefinitely until the process is manually terminated, e.g., Ctrl-C from shell
Prerequisites
Getting started you’ll need a dev environment with
- Nodejs v10.22 — v17.x — I’m using Node 16.13.0 (LTS)
- ROS 2 Foxy (LTS) or Galactic release
If you haven’t setup your ROS 2 JavaScript coding environment see this article.
Lastly if you would like to skip ahead and see the end result, you can find a link to a github project in the Resources section found at the end of this article.
Step-1: Project Setup
Project setup is easy as we will continue developing our code in the Nodejsros2-js-examples
project we created in Tutorial #2. From the root folder of our ros2-js-examples
project create the src/example2
folder using the following Linux commandline tools.
mkdir -p src/example3
cd src/example3
Step-2: Creating a Node and Publisher
This example will consists of 2 TypeScript files: laserscan-publisher.ts and index.ts.
laserscan-publisher.ts
Start by creating laserscan-publisher.ts
as follows:
Let’s break down the key lines of code in this file.
As in all of our tutorials we will be using the JavaScript ROS 2 client library, rclnodejs. So our 1st step is to import rclnodejs
.
import * as rclnodejs from 'rclnodejs';
Next we create the LaserScanPublisher
class.
Note how the LaserScanPublisher constructor expects an rclnodejs.Node
and an optional topic name to which messages will be published. The constructor creates a publisher instance for the default topic laser_frame
.
The start()
method creates a timer that generates a fake LaserScan message and publishes it every second. The timer runs until either the stop()
method is called or the process is killed.
The fake sensor data and messages are created by the genLaserScanMsg()
method.
lines 63,64 - Create a LaserScan message object and begin populating it.
lines 67, 68- Many of the ROS messages require a Header. The header.frame_id is important to note as it refers to the name of a reference frame. We will use the header.frame_id
property later in this rviz2 section of this tutorial.
index.ts
Next create the index.ts file.
This is the main entry point for running example-3. The main()
function does the following:
- initializes the rclnodejs library
- creates a node
- creates a LaserScanPublisher
- starts the publisher timer
Step-3: Compile TypeScript
Invoke the TypeScript compiler tsc
to transcode our *.ts files into JavaScript. The resulting JS files are created in the dist/example3
folder with the same name’s as theirsrc
TypeScript files.
npm run build
Step-4: Run
Using the Nodejs runtime, let’s run our laserscan-publisher program. In your terminal shell enter this command:
node dist/example3/index.js
You should see messages begin dribbling to stdout as shown below.
Now let’s use the ros2 topic tool to view a published LaserScan message.
ros2 topic echo /ros2_js_examples/laser_frame --no-arr
Cool! We have LaserScan messages published to the ROS node graph.
Using ROS 2 rviz2 Visualization Tool
The ROS 2 rviz2 is a data visualization tool that subscribes to topics and displays the data it receives according to the type of message, e.g., our LaserScan message. Now let’s use rviz2
tool to generate a 3D view of our LaserScan message data.
With our LaserScanPublisher still running and publishing message, launch rviz2 from a terminal shell:
rviz2
You should see the default rviz2 user interface appear similar to this screenshot from my system.
We need to configure rviz2 to subscribe to our LaserScan messages being published to the laser_frame
topic.
Start by adding a LaserScan visualization to the View as shown. Notice steps #2 and #3 in the screenshot are selecting to topic on which our laserscan data is published.
Next make the edits shown in red below:
Fixed Frame: laser_frame
Size: 0.1
BINGO! You should see the 180 degree measurements appear. You may need to zoom out to see them. Just for fun I added an Axis visualization to my view.
Note: in this scenario I’ve started example3/index.js before starting rviz2. If rviz2 is running before laserscan data is published rviz2 may not immediately rendering the data. In such cases I’ve found that by changing the LaserScan/Topic/Depth property it will force the topic subscription to reset and laserscan data will then be rendered.
Optional: Save rviz2 Display Configuration
Every time we run this example we don’t want to have to repeat these configuration steps. So our final step is to save the rviz2 display configuration for future use.
From the rviz2 user interface do the the following:
Select File > Save Config
.
Name the file laserscan.rviz
and save it to src/example3
.
The next time you run rviz2
with example3 use the following command to configure the dispaly using our new laserscan.rviz configuration info:
rviz2 -d src/example3/laserscan.rviz
Summary
Hopefully you are starting to appreciate the power and convenience of the ROS 2 platform and tools. We will continue to build on top of this experience and put the ROS 2 tools to great use in the next tutorial.
Resources
Please consider liking this tutorial and following me here and on Twitter @ros2jsguy