> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.stereolabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.stereolabs.com/_mcp/server.

# Getting IMU and Sensor Data in ROS

> **Warning**
>
> **The ZED ROS Wrapper packages are no longer maintained** because ROS 1 reached [end-of-life (EOL) on 2025-05-31](https://www.ros.org/blog/noetic-eol/) with the final Noetic release.
>
> We recommend upgrading to [ROS 2](/docs/integrations/ros-2) to take advantage of the latest ZED SDK features for robotics applications.

In this tutorial, you will learn how to display ZED cameras' sensor data using PlotJuggler and subscribe to the sensors' data streams.

## Sensor Data visualization with PlotJuggler

In this tutorial, you will learn in detail how to configure the [PlotJuggler](https://wiki.ros.org/plotjuggler) tool to display data values in multiple dynamic live plots.

The `zed_sensors_sub_tutorial` package of the `zed-ros-examples` repository provides three launch files:

* `plot_sensors_zedm.launch`: launches the ZED node preconfigured for the ZED Mini and PlotJuggler preconfigured to show ZED Mini sensor data
* `plot_sensors_zed2.launch`: launches the ZED node preconfigured for the ZED 2 and PlotJuggler preconfigured to show ZED 2 sensor data
* `plot_sensors_zed2i.launch`: launches the ZED node preconfigured for the ZED 2i and PlotJuggler preconfigured to show ZED 2i sensor data

### ZED Mini

Start the ZED Mini sensor data plotting with the command:

```bash
roslaunch zed_sensors_sub_tutorial plot_sensors_zedm.launch
```

PlotJuggler will start by prompting about the "ROS Topic Subscriber"; click OK to start subscribing to the sensor topics.

![ROS Topic Subscriber](/_fern-img/d00978557667083d80e13990430fb2b5af4e8acc3f580528dff968629c16e1eb.webp)

The next window will show all the available topics. Press OK to choose the pre-selected ones:

![Topic list](/_fern-img/5d51dcd85edd970504862faf541970a66e0fb9f6e5bbf899ac37e8d2fc7d7185.webp)

Finally, PlotJuggler will start showing the sensor data published by the ZED node:

![ZED Mini Plots](/_fern-img/b25c3df9980e758650f70b3b930a8050b1d6e87eddc5bcf19f7f5404dd0bc31d.webp)

On the left, you can find the list of all the available subscribed topics, on the right the live plots:

* *accelerometer* data on the top right
* *gyroscope* data on the top left
* *orientation* in quaternion form on the bottom left

### ZED 2 / ZED 2i

Start the ZED 2 sensor data plotting with the command:

```bash
roslaunch zed_sensors_sub_tutorial plot_sensors_zed2.launch
```

Start the ZED 2i sensor data plotting with the command:

```bash
roslaunch zed_sensors_sub_tutorial plot_sensors_zed2i.launch
```

PlotJuggler will start by prompting about the "ROS Topic Subscriber"; click OK to start subscribing to the sensor topics.

![ROS Topic Subscriber](/_fern-img/d00978557667083d80e13990430fb2b5af4e8acc3f580528dff968629c16e1eb.webp)

The next window will show all the available topics. Press OK to choose the pre-selected ones:

![Topic list](/_fern-img/5d51dcd85edd970504862faf541970a66e0fb9f6e5bbf899ac37e8d2fc7d7185.webp)

Finally, PlotJuggler will start showing the sensor data published by the ZED node:

![ZED 2 Plots](/_fern-img/4e556c3a6b6a8d4974a7ae6c0b334646d98aad7b3c0520eaab6222715b07ae57.webp)

On the left, you can find the list of all the available subscribed topics, on the right the live plots:

* *accelerometer* data on the top right
* *gyroscope* data on the top left
* *orientation* in quaternion form on the middle left
* *magnetometer* data on the middle right
* *barometer* data on the bottom left
* *temperature* data on the bottom right

## Sensor Data subscribing in C++

In this tutorial, you will learn how to write a simple C++ node that subscribes to messages of type
`sensor_msgs/Imu`, `sensor_msgs/Temperature`, `sensor_msgs/MagneticField` and `sensor_msgs/FluidPressure`.
This lets you retrieve the data from all the sensors available in the ZED 2 and ZED 2i cameras.

> **Note**
>
> The tutorial is also valid for the ZED Mini, ZED X and ZED X Mini cameras, but only the IMU data (and the IMU temperature for the ZED X and ZED X Mini) will be available.

### Introduction

Use this command to connect the ZED 2 camera to the ROS network:

```bash
roslaunch zed_wrapper zed2.launch
```

or this command if you are using a ZED 2i:

```bash
roslaunch zed_wrapper zed2i.launch
```

The ZED node will start to publish sensor data in the network only if there is another node that subscribes to the corresponding topic.

> **Note**
>
> The code below subscribes to topics in the `/zed/zed_node` namespace used by `zed.launch`. With `zed2.launch` or `zed2i.launch`, the namespace is `/zed2/zed_node` or `/zed2i/zed_node`: change the topic names in the code or remap them when running the node.

### Running the tutorial

If you properly followed the [ROS Installation Guide](/docs/integrations/ros/#installation), the executable of this tutorial has been compiled and you can run the subscriber node using this command:

```bash
rosrun zed_sensors_sub_tutorial zed_sensors_sub
```

If the ZED node is running, and a **ZED 2** or a **ZED 2i** is connected or you have loaded an SVO file, you will receive
the following stream of messages confirming that you have correctly subscribed to the ZED sensor topics (with a **ZED Mini** you will receive only the IMU data):

```bash
[ INFO] [1576844361.799432833]: Accel: 0.517,-0.146,9.749 [m/s^2] - Ang. vel: -0.002,-0.000,-0.001 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.799457532]: Mag. Field: -0.000,0.000,0.000 [uT]
[ INFO] [1576844361.799474450]: IMU temperature: 34.09 [C]
[ INFO] [1576844361.802636040]: Accel: 0.529,-0.161,9.758 [m/s^2] - Ang. vel: 0.000,0.002,-0.001 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.802658603]: IMU temperature: 34.09 [C]
[ INFO] [1576844361.804891549]: Accel: 0.529,-0.161,9.758 [m/s^2] - Ang. vel: 0.000,0.002,-0.001 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.804913269]: IMU temperature: 34.09 [C]
[ INFO] [1576844361.807097286]: Accel: 0.531,-0.163,9.765 [m/s^2] - Ang. vel: 0.003,-0.002,0.003 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.807119117]: IMU temperature: 34.11 [C]
[ INFO] [1576844361.809285372]: Accel: 0.531,-0.168,9.770 [m/s^2] - Ang. vel: 0.000,0.001,-0.000 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.809305127]: IMU temperature: 34.11 [C]
[ INFO] [1576844361.812520685]: Accel: 0.529,-0.168,9.775 [m/s^2] - Ang. vel: 0.001,0.001,-0.001 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.812557808]: IMU temperature: 34.11 [C]
[ INFO] [1576844361.814767190]: Accel: 0.521,-0.165,9.770 [m/s^2] - Ang. vel: 0.001,0.001,-0.000 [rad/s] - Orient. Quat: -0.008,-0.027,-0.001,1.000
[ INFO] [1576844361.814793950]: IMU temperature: 34.11 [C]
[ INFO] [1576844361.814813679]: Atmospheric Pressure: 1010.30 [hPa]
[ INFO] [1576844361.814827208]: Left CMOS temperature: 33.18 [C]
[ INFO] [1576844361.814842668]: Right CMOS temperature: 33.56 [C]
```

### The code

The source code of the subscriber node `zed_sensors_sub_tutorial.cpp`:

```C

#include <ros/ros.h>
#include <sensor_msgs/Imu.h>
#include <sensor_msgs/MagneticField.h>
#include <sensor_msgs/FluidPressure.h>
#include <sensor_msgs/Temperature.h>

/**
 * Subscriber callbacks
 */

void imuCallback(const sensor_msgs::Imu::ConstPtr& msg) {
    ROS_INFO( "Accel: %.3f,%.3f,%.3f [m/s^2] - Ang. vel: %.3f,%.3f,%.3f [rad/s] - Orient. Quat: %.3f,%.3f,%.3f,%.3f",
              msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z,
              msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z,
              msg->orientation.x, msg->orientation.y, msg->orientation.z, msg->orientation.w);
}

void imuTempCallback(const sensor_msgs::Temperature::ConstPtr& msg) {
    ROS_INFO( "IMU temperature: %.2f [C]",
              msg->temperature);
}

void leftTempCallback(const sensor_msgs::Temperature::ConstPtr& msg) {
    ROS_INFO( "Left CMOS temperature: %.2f [C]",
              msg->temperature);
}

void rightTempCallback(const sensor_msgs::Temperature::ConstPtr& msg) {
    ROS_INFO( "Right CMOS temperature: %.2f [C]",
              msg->temperature);
}

void magCallback(const sensor_msgs::MagneticField::ConstPtr& msg) {
    ROS_INFO( "Mag. Field: %.3f,%.3f,%.3f [uT]",
              msg->magnetic_field.x*1e6, msg->magnetic_field.y*1e6, msg->magnetic_field.z*1e6);
}

void pressureCallback(const sensor_msgs::FluidPressure::ConstPtr& msg) {
    ROS_INFO( "Atmospheric Pressure: %.2f [hPa]",
              msg->fluid_pressure*100.f);
}

/**
 * Node main function
 */
int main(int argc, char** argv) {
    ros::init(argc, argv, "zed_sensors_subscriber");
    ros::NodeHandle n;

    ros::Subscriber subImu = n.subscribe("/zed/zed_node/imu/data", 10, imuCallback);
    ros::Subscriber subImuTemp = n.subscribe("/zed/zed_node/temperature/imu", 10, imuTempCallback);
    ros::Subscriber subLeftTemp = n.subscribe("/zed/zed_node/temperature/left", 10, leftTempCallback);
    ros::Subscriber subRightTemp = n.subscribe("/zed/zed_node/temperature/right", 10, rightTempCallback);
    ros::Subscriber subPress = n.subscribe("/zed/zed_node/atm_press", 10, pressureCallback);
    ros::Subscriber subMag = n.subscribe("/zed/zed_node/imu/mag", 10, magCallback);

    ros::spin();

    return 0;
}
```

### The code explained

The following is a brief explanation of the source code above:

```C
void imuCallback(const sensor_msgs::Imu::ConstPtr& msg) {
    ROS_INFO( "Accel: %.3f,%.3f,%.3f [m/s^2] - Ang. vel: %.3f,%.3f,%.3f [rad/s] - Orient. Quat: %.3f,%.3f,%.3f,%.3f",
              msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z,
              msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z,
              msg->orientation.x, msg->orientation.y, msg->orientation.z, msg->orientation.w);
}

void imuTempCallback(const sensor_msgs::Temperature::ConstPtr& msg) {
    ROS_INFO( "IMU temperature: %.2f [C]",
              msg->temperature);
}

void leftTempCallback(const sensor_msgs::Temperature::ConstPtr& msg) {
    ROS_INFO( "Left CMOS temperature: %.2f [C]",
              msg->temperature);
}

void rightTempCallback(const sensor_msgs::Temperature::ConstPtr& msg) {
    ROS_INFO( "Right CMOS temperature: %.2f [C]",
              msg->temperature);
}

void magCallback(const sensor_msgs::MagneticField::ConstPtr& msg) {
    ROS_INFO( "Mag. Field: %.3f,%.3f,%.3f [uT]",
              msg->magnetic_field.x*1e6, msg->magnetic_field.y*1e6, msg->magnetic_field.z*1e6);
}

void pressureCallback(const sensor_msgs::FluidPressure::ConstPtr& msg) {
    ROS_INFO( "Atmospheric Pressure: %.2f [hPa]",
              msg->fluid_pressure*100.f);
}
```

This is a list of callback functions that handle the different types of messages carrying sensor data.
Each callback has a `boost::shared_ptr` to the received message as a parameter, this means you don't have to worry about memory management.
The code of each callback is very simple and demonstrates how to access the fields of the corresponding message, printing the sensor data information to the screen.

The `main` function is very standard and is explained in detail in the ["Talker/Listener" ROS tutorial](http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29).

The most important lesson of the above code is how the subscribers are defined:

```C
    // Subscriber
    ros::Subscriber subImu = n.subscribe("/zed/zed_node/imu/data", 10, imuCallback);
    ros::Subscriber subImuTemp = n.subscribe("/zed/zed_node/temperature/imu", 10, imuTempCallback);
    ros::Subscriber subLeftTemp = n.subscribe("/zed/zed_node/temperature/left", 10, leftTempCallback);
    ros::Subscriber subRightTemp = n.subscribe("/zed/zed_node/temperature/right", 10, rightTempCallback);
    ros::Subscriber subPress = n.subscribe("/zed/zed_node/atm_press", 10, pressureCallback);
    ros::Subscriber subMag = n.subscribe("/zed/zed_node/imu/mag", 10, magCallback);
```

A `ros::Subscriber` is a ROS object that listens on the network and waits for its own topic message to be available.
When a message is received, it executes the callback assigned to it.

We declared a subscriber for each of the callback functions that we defined above, taking care to use the correct topic name, e.g. `/zed/zed_node/imu/data` for IMU data.

### Conclusion

The full source code of this tutorial is available on GitHub in the [zed\_sensors\_sub\_tutorial](https://github.com/stereolabs/zed-ros-examples/tree/master/tutorials/zed_sensors_sub_tutorial) sub-package.
Along with the node source code are the `package.xml` and `CMakeLists.txt` files that complete the tutorial package.

> **Note**
>
> The code on this page differs from the GitHub version: it subscribes to the IMU temperature on the `temperature/imu` topic published by the ZED node, prints the angular velocity in rad/s, and converts the magnetic field from Tesla to µT with a `1e6` factor.