Getting Sensor Data in ROS

Sensor Data visualization with PlotJuggler

In this tutorial, you will learn in detail how to configure the PlotJuggler tool to display data values in multiple dynamic live plots.

The package provides two launch files:

  • plot_sensors_zedm.launch: launches the ZED node preconfigured for the ZED-M and PlotJuggler preconfigured to show ZED-M sensor data
  • plot_sensors_zed2.launch: launches the ZED node preconfigured for the ZED-M and PlotJuggler preconfigured to show ZED-M sensor data

ZED-M

Start the ZED-M sensor data plotting with the command:

$ roslaunch zed_sensors_sub_tutorial plot_sensors_zedm.launch

PlotJuggler will start asking about “ROS Topic Subscriber”, click OK to start subscribing to the sensor topics.

ROS Topic Subscriber

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

Topic list

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

ZED-M Plots

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 top left
  • orientation in quaternion form on bottom left

ZED 2

Start the ZED 2 sensor data plotting with the command:

$ roslaunch zed_sensors_sub_tutorial plot_sensors_zed2.launch

PlotJuggler will start asking about “ROS Topic Subscriber”, click OK to start subscribing to the sensor topics.

ROS Topic Subscriber

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

Topic list

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

ZED 2 Plots

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 top left
  • orientation in quaternion form on middle left
  • magnetometer data on middle right
  • barometer data on bottom left
  • temperature data on 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 ZED2 camera.

Note: the tutorial is valid also for a ZED-M camera, but only topics of type sensor_msgs/Imu will be available.

Introduction

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

$ roslaunch zed_wrapper zed2.launch

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

Running the tutorial

If you properly followed the ROS Installation Guide, the executable of this tutorial has been compiled and you can run the subscriber node using this command:

$ rosrun zed_sensors_sub_tutorial zed_sensors_sub

If the ZED node is running, and a ZED 2 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 image topics (with a ZED Mini you will receive only the IMU data):

[ INFO] [1576844361.799432833]: Accel: 0.517,-0.146,9.749 [m/s^2] - Ang. vel: -0.002,-0.000,-0.001 [deg/sec] - 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 [deg/sec] - 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 [deg/sec] - 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 [deg/sec] - 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 [deg/sec] - 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 [deg/sec] - 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 [deg/sec] - 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_obj_det_sub_tutorial.cpp:


#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 [deg/sec] - 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*1e-6, msg->magnetic_field.y*1e-6, msg->magnetic_field.z*1e-6);
}

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/imu/temperature", 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 about the above source code:

void imuCallback(const sensor_msgs::Imu::ConstPtr& msg) {
    ROS_INFO( "Accel: %.3f,%.3f,%.3f [m/s^2] - Ang. vel: %.3f,%.3f,%.3f [deg/sec] - 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*1e-6, msg->magnetic_field.y*1e-6, msg->magnetic_field.z*1e-6);
}

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

This is a list of callbacks functions that handles the receiving of the different types of message topics bringing sensor data information. Each callback has a boost::shared_ptr to the received message as 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 relative message, printing the sensor data information to screen.

The main function is very standard and is explained in details in the “Talker/Listener” ROS tutorial.

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

    // Subscriber
    ros::Subscriber subImu = n.subscribe("/zed/zed_node/imu/data", 10, imuCallback);
    ros::Subscriber subImuTemp = n.subscribe("/zed/zed_node/imu/temperature", 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 sub-package. Along with the node source code are the package.xml and CMakeLists.txt files that complete the tutorial package.