9. ROS2 Bridge in Standalone Workflow

9.1. Learning Objectives

Prerequisite

9.2. Manually Stepping ROS2 Components

One major usage for standalone scripting is to manually control the simulation steps. An OnImpulseEvent Omnigraph node can be connected to any ROS2 Omnigraph node so that the frequency of the publishers and subscribers can be carefully controlled.

An example of how a new action graph with a ROS2 Publish Clock node can be setup to be precisely controlled with a ROS2 Domain ID of 1:

import omni.graph.core as og
# Create a new graph with the path /ActionGraph
og.Controller.edit(
    {"graph_path": "/ActionGraph", "evaluator_name": "execution"},
    {
        og.Controller.Keys.CREATE_NODES: [
            ("ReadSimTime", "omni.isaac.core_nodes.IsaacReadSimulationTime"),
            ("Context", "omni.isaac.ros2_bridge.ROS2Context"),
            ("PublishClock", "omni.isaac.ros2_bridge.ROS2PublishClock"),
            ("OnImpulseEvent", "omni.graph.action.OnImpulseEvent"),
        ],
        og.Controller.Keys.CONNECT: [
            # Connecting execution of OnImpulseEvent node to PublishClock so it will only publish when an impulse event is triggered
            ("OnImpulseEvent.outputs:execOut", "PublishClock.inputs:execIn"),
            # Connecting simulationTime data of ReadSimTime to the clock publisher node
            ("ReadSimTime.outputs:simulationTime", "PublishClock.inputs:timeStamp"),
            # Connecting the ROS2 Context to the clock publisher node so it will run under the specified ROS2 Domain ID
            ("Context.outputs:context", "PublishClock.inputs:context"),
        ],
        og.Controller.Keys.SET_VALUES: [
            # Assigning topic name to clock publisher
            ("PublishClock.inputs:topicName", "/clock"),
            # Assigning a Domain ID of 1 to Context node
            ("Context.inputs:domain_id", 1),
        ],
    },
)

On any frame, run the following to set an impulse event which will tick the clock publisher once:

og.Controller.set(og.Controller.attribute("/ActionGraph/OnImpulseEvent.state:enableImpulse"), True)

9.3. Examples

We converted a few of the tutorial examples into standalone python examples. Here are the instructions for running them.

9.3.1. ROS2 clock

This sample demonstrates how to create a action graph with ROS2 component nodes and then tick them at different rates.

The sample can be executed by running the following:

./python.sh standalone_examples/api/omni.isaac.ros2_bridge/clock.py

9.3.2. Carter Stereo

This sample demonstrates how to take an existing USD stage with an action graph containing ROS2 component nodes and modifying the default settings. The stereo camera pair is automatically enabled and the second viewport window is docked in the UI.

  • On each frame:

    • The ROS2 clock is published

    • Lidar message is published

    • Oometry is published

    • The Twist subscriber is spun

    • TF messages are published

    • Left and right cameras are published

  • Every Two Frames:

    • The Twist command message is published

The sample can be executed by running the following:

./python.sh standalone_examples/api/omni.isaac.ros2_bridge/carter_stereo.py

To exit the sample you can terminate via the terminal with CTRL-C

To visualize the result:

In a new terminal, run the following command to load Rviz2:

ros2 run rviz2 rviz2 -d ros2_workspace/src/isaac_tutorials/rviz2/carter_stereo.rviz

Make sure Left Camera - Depth, Right Camera - Depth, Right Camera - RGB and Left Camera - RGB within the Displays are enabled to visualize RGB and Depth images.

Note

If some of the images don’t show up on RViz2, press Stop and Play in the simulator for the images to show up.

9.3.3. Multiple Robot ROS2 Navigation

This sample shows how to run an existing USD stage.

To visualize the output see the interactive version of the sample:

  • On each frame:

    • The ROS clock component is published

    • Lidar messages are published

    • Oometry is published

    • The Twist subscriber is spun

    • TF messages are published

The sample can be executed with both the hospital and office environments. Run either of the following commands to run the sample with the specified environment:

./python.sh standalone_examples/api/omni.isaac.ros2_bridge/carter_multiple_robot_navigation.py hospital

OR

./python.sh standalone_examples/api/omni.isaac.ros2_bridge/carter_multiple_robot_navigation.py office

To exit the sample you can terminate via the terminal with CTRL-C

9.3.4. MoveIt2

This sample shows how to add multiple USD stages. It also demonstrates how to manually create a action graph with ROS2 component nodes and then manually tick them.

To visualize the output see the interactive version of the sample:

  • On each frame:

    • The ROS clock is published

    • Joint State messages are published

    • Joint State subscriber is spun

    • TF messages are published

The sample can be executed by running the following:

./python.sh standalone_examples/api/omni.isaac.ros2_bridge/moveit.py

To exit the sample you can terminate via the terminal with CTRL-C

9.3.5. Receiving ROS2 Messages

This is a simple subscriber example where upon receiving an empty ROS2 message, a cube in the scene teleports to a random location. This one is running with rendering enabled, so you should be able to see the scene and the cube moving. To run this example

./python.sh standalone_examples/api/omni.isaac.ros2_bridge/subscriber.py

To exit the sample you can terminate via the terminal with CTRL-C

Once the scene with cube is loaded, you can publish the empty message manually from another terminal. We’ll do it at rate of 1Hz.

ros2 topic pub -r 1 /move_cube std_msgs/msg/Empty

9.4. Summary

In this tutorial we learned how to manually step ROS2 components and run standalone ROS2 python examples.

9.4.1. Next Steps

Continue on to the next tutorial in our ROS2 Tutorials series, The Ignition-Omniverse connector with Gazebo.