11. Custom Message

The python environment in Omniverse Isaac Sim comes with a built-in ROS environment based on ROS Noetic that contains rospy. This makes most of the core ROS packages and messages available, as well as publishing/receiving custom messages.

11.1. Learning Objectives

  • Publishing and receiving ROS messages in standalone python scripts.

  • Using custom ROS message that contains contact sensor information.

  • Publishing ROS messages in extension scripts.

11.2. Getting Started


This tutorial assumes that you have


Always make sure roscore is running, and that ros_workspace is in your environment’s $ROS_PACKAGE_PATH before running any of the following scripts.

11.3. Publishing A Custom Message in Standalone Python

We will use data from our contact sensor to demonstrate how to publish a customized ROS message. To start, make a ROS message with the fields corresponding to the contact sensor data fields. The message definition file can be found in ros_workspace/src/isaac_tutorials/msg/ContactSensor.msg

Header header
float64 time
float64 value
bool in_contact

There are modifications that are necessary in the CMakeLists.txt and package.xml to enable building custom messages. This is already done for you in the workspace provided. Go to ROS custom messages for more information on building custom messages in your own workspace.

Build and source the workspace with the custom message definition.

$ cd ros_workspace
$ catkin_make
$ source devel/setup.bash
$ cd ../

Now the custom message is ready to be used, and you can run the provided contact sensor publisher example

$ ./python.sh standalone_examples/api/omni.isaac.ros_bridge/contact.py

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

The code provided is putting a cube on the ground and reporting the force experienced on the cube. It is meant to run in headless mode, so no images will be rendered. The contact information will be first printed in the terminal where the contact.py is running, and the same message is also published to a rostopic named /contact_report. To check the raw published messages, open a new ROS-sourced terminal:

$ cd ros_workspace
$ source devel/setup.bash
$ rostopic echo /contact_report

11.4. Publishing in Extension Scripting

If you wish to publish messages in the Extension workflow, you must use asyncio (or similar modules). It allows the thread running rospy commands to not block the main Omniverse Isaac Sim thread. Its necessary when running rospy in an extension or in the script editor.

The following script can be executed in the Window -> Script Editor Window.

import asyncio
import rospy

    rospy.init_node("hello", anonymous=True, disable_signals=True, log_level=rospy.ERROR)
except rospy.exceptions.ROSException as e:
    print("Node has already been initialized, do nothing")

async def my_task():
    from std_msgs.msg import String
    pub = rospy.Publisher("/hello_topic", String, queue_size=10)

    for frame in range(10):
        pub.publish("hello world " + str(frame))
        await asyncio.sleep(1.0)
    pub = None


You can monitor the received message in another ROS-sourced terminal. Note that the above code will publish 10 times and stops, so make sure to run the following command before running the publishing script. The first message might not print out as it takes time for the rostopic echo command to initialize the ROS subscription to the topic

$ rostopic echo /hello_topic

11.4.1. Publishing Custom Messages in Extension Scripting

To publish custom messages in extension scripting, you would need to provide the full path to your custom message Python module.

The following code snippet is used to import the ContactSensor message (from Publishing A Custom Message in Standalone Python tutorial).

Change <PYTHON_VERSION> to python3 if using ROS Noetic or python2.X if using ROS Melodic:

import sys


from _ContactSensor import ContactSensor

contact_msg = ContactSensor()

11.5. Receiving ROS Messages

We also provide a simple subscriber example where upon receiving an empty ROS message, a cube in the scene teleport 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.ros_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.

$ rostopic pub -r 1 /move_cube std_msgs/Empty

11.6. Summary

This tutorial covered

  • Publishing and receiving ROS messages in standalone and extension scripting

  • Using custom ROS message that contains contact sensor information.

11.6.1. Next Steps

Continue on to the next tutorial in our ROS Tutorials series, ROS Bridge in Standalone Workflow to learn how to run the ROS Bridge in the standalone workflow.

11.6.2. Further Reading

  • See Isaac Sensor for additional information about the contact sensor extension