> 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.

# Using Video Capture with ROS 2

## Video with RViz 2

In this tutorial, you will learn how to configure your own RViz 2 session to see only the video data that you require.

To visualize the video stream published by the ZED node, you can use two different plugins:

* `Camera`: Displays an image from a camera, with the visualized world rendered behind it
* `Image`: Displays an image from a topic of type `sensor_msgs/Image`

### Camera

The `Camera` plugin allows you to visualize an image from a topic of type `sensor_msgs/Image`. It acts as if the source of the image is placed on its virtual frame and renders all virtual objects in front of it.

![image](/_fern-img/9c8ec5b601619719909bfa5dc058a086f416912f25435f7e805166b92f7abfb4.webp)

Key parameters:

* `Topic`: Selects the image topic to visualize from the list of available images in the combo box
* `Depth`: The depth of the incoming message queue
* `History policy`: Set the QoS history policy. `Keep Last` is suggested for performance and compatibility
* `Reliability Policy`: Set the QoS reliability policy. `Best Effort` is suggested for performance, `Reliable` is used for compatibility
* `Durability Policy`: Set the QoS durability policy. `Volatile` is suggested for compatibility

By expanding `Visibility`, you can select/deselect what will be visible in the `camera view`. Only active plugins can be selected.

### Image

The `Image` plugin allows you to visualize an image from a topic of type `sensor_msgs/Image`.

![image](/_fern-img/02d7800ef2dfff7641dcc23a55f99fd69e2c113b9b8287bb3ab88688b48f24ed.webp)

Key parameters:

* `Topic`: Selects the image topic to visualize from the list of available images in the combo box
* `Depth`: The depth of the incoming message queue
* `History policy`: Set the QoS history policy. `Keep Last` is suggested for performance and compatibility
* `Reliability Policy`: Set the QoS reliability policy. `Best Effort` is suggested for performance, `Reliable` is used for compatibility
* `Durability Policy`: Set the QoS durability policy. `Volatile` is suggested for compatibility

## Video subscribing in C++

In this tutorial, you will learn how to write a simple C++ node that subscribes to messages of type
`sensor_msgs/Image`. This lets you retrieve the Left and Right rectified images published by the ZED node.

### Introduction

Open a new console and use this command to connect the camera to the ROS 2 network:

```bash
ros2 launch zed_display_rviz2 display_zed_cam.launch.py camera_model:=<camera model>
```

> **Note**
>
> The old launch command `ros2 launch zed_display_rviz2 display_<camera model>.launch.py` is obsolete. Use the `display_zed_cam.launch.py` command above.

The ZED node will start to publish image 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 2 Examples Installation Guide](https://github.com/stereolabs/zed-ros2-examples#build-the-package), the executable of this tutorial has been compiled and you can run the subscriber node using this command:

```bash
ros2 run zed_tutorial_video zed_tutorial_video
```

The tutorial node subscribes to generic `left_image` and `right_image` topics, so a remapping is required to connect to the correct topics published by the ZED node:

```bash
ros2 run zed_tutorial_video zed_tutorial_video --ros-args -r left_image:=/zed/zed_node/left/color/rect/image -r right_image:=/zed/zed_node/right/color/rect/image
```

If the ZED node is running and a camera 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:

```bash
[INFO] [zed_video_tutorial]: Left  Rectified image received from ZED	Size: 1280x720 - Timestamp: 1602576933.791896880 sec 
[INFO] [zed_video_tutorial]: Right Rectified image received from ZED	Size: 1280x720 - Timestamp: 1602576933.891931106 sec 
[INFO] [zed_video_tutorial]: Left  Rectified image received from ZED	Size: 1280x720 - Timestamp: 1602576934.91928857 sec 
[INFO] [zed_video_tutorial]: Right Rectified image received from ZED	Size: 1280x720 - Timestamp: 1602576934.91928857 sec 
[INFO] [zed_video_tutorial]: Left  Rectified image received from ZED	Size: 1280x720 - Timestamp: 1602576934.191911460 sec 
[INFO] [zed_video_tutorial]: Right Rectified image received from ZED	Size: 1280x720 - Timestamp: 1602576934.191911460 sec

[...]
```

### The code

The source code of the subscriber node [zed\_video\_sub\_tutorial.cpp](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_video_tutorial/src):

**`C++`**

```cpp C++
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/qos.hpp>
#include <sensor_msgs/msg/image.hpp>

rclcpp::Node::SharedPtr g_node = nullptr;

/**
 * Subscriber callbacks. The argument of the callback is a constant pointer to the received message
 */


void imageRightRectifiedCallback(const sensor_msgs::msg::Image::SharedPtr msg) {
    RCLCPP_INFO(g_node->get_logger(),
                "Right Rectified image received from ZED\tSize: %dx%d - Timestamp: %u.%u sec ",
                msg->width, msg->height,
                msg->header.stamp.sec,msg->header.stamp.nanosec);
}

void imageLeftRectifiedCallback(const sensor_msgs::msg::Image::SharedPtr msg) {
    RCLCPP_INFO(g_node->get_logger(),
                "Left  Rectified image received from ZED\tSize: %dx%d - Timestamp: %u.%u sec ",
                msg->width, msg->height,
                msg->header.stamp.sec,msg->header.stamp.nanosec);
}

int main(int argc, char* argv[]) {
    rclcpp::init(argc, argv);

    // Create the node
    g_node = rclcpp::Node::make_shared("zed_video_tutorial");

    /* Note: it is very important to use a QOS profile for the subscriber that is compatible
     * with the QOS profile of the publisher.
     * The ZED component node uses a default QoS profile with reliability set as "RELIABLE"
     * and durability set as "VOLATILE".
     * To be able to receive the subscribed topic the subscriber must use compatible
     * parameters.
     */

    // https://github.com/ros2/ros2/wiki/About-Quality-of-Service-Settings

    rclcpp::QoS video_qos(10);
    video_qos.keep_last(10);
    video_qos.best_effort();
    video_qos.durability_volatile();

    // Create right image subscriber
    auto right_sub = g_node->create_subscription<sensor_msgs::msg::Image>(
                "right_image", video_qos, imageRightRectifiedCallback );

    // Create left image subscriber
    auto left_sub = g_node->create_subscription<sensor_msgs::msg::Image>
            ("left_image", video_qos, imageLeftRectifiedCallback );

    // Let the node run
    rclcpp::spin(g_node);

    // Shutdown when the node is stopped using Ctrl+C
    rclcpp::shutdown();

    return 0;
}
```

### The code explained

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

**`C++`**

```cpp C++
void imageRightRectifiedCallback(const sensor_msgs::msg::Image::SharedPtr msg) {
    RCLCPP_INFO(g_node->get_logger(),
                "Right Rectified image received from ZED\tSize: %dx%d - Timestamp: %u.%u sec ",
                msg->width, msg->height,
                msg->header.stamp.sec,msg->header.stamp.nanosec);
}

void imageLeftRectifiedCallback(const sensor_msgs::msg::Image::SharedPtr msg) {
    RCLCPP_INFO(g_node->get_logger(),
                "Left  Rectified image received from ZED\tSize: %dx%d - Timestamp: %u.%u sec ",
                msg->width, msg->height,
                msg->header.stamp.sec,msg->header.stamp.nanosec);
}
```

These callbacks are executed when the subscriber node receives a message of type `sensor_msgs/Image` that matches the subscribed topic.
The parameter of the callback is a `std::shared_ptr` to the received message. This means you don't have to worry
about memory management.
The callback code is very simple and demonstrates how to access the fields in a message;
in this case, the `height` and `width` of the image and the topic timestamp.

The `main` function is divided into two main parts:

Node declaration:

**`C++`**

```cpp C++
    rclcpp::init(argc, argv);

    // Create the node
    g_node = rclcpp::Node::make_shared("zed_video_tutorial");
```

First, the ROS 2 environment is initialized with the `rclcpp::init` command. Then, the `zed_video_tutorial` node is created and a shared pointer `g_node` to it is initialized.

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

**`C++`**

```cpp C++
    rclcpp::QoS video_qos(10);
    video_qos.keep_last(10);
    video_qos.best_effort();
    video_qos.durability_volatile();

    // Create right image subscriber
    auto right_sub = g_node->create_subscription<sensor_msgs::msg::Image>(
                "right_image", video_qos, imageRightRectifiedCallback );

    // Create left image subscriber
    auto left_sub = g_node->create_subscription<sensor_msgs::msg::Image>(
                "left_image", video_qos, imageLeftRectifiedCallback );
```

The two `auto` variables `right_sub` and `left_sub` are two `rclcpp::Subscription` objects.

A `rclcpp::Subscription` is a ROS object that listens to 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 two subscribers: one for the left rectified image and one for the right rectified image.

* The subscriber to the `right_image` topic calls the `imageRightRectifiedCallback` function when it receives a message of type
  `sensor_msgs/Image` that matches that topic
* The subscriber to the `left_image` topic calls the `imageLeftRectifiedCallback` function when it receives a message of type
  `sensor_msgs/Image` that matches that topic

It is important that the two subscriptions use a QoS profile compatible with the QoS profile of the publisher of the topics.

In this case, the QoS profile is configured to keep the last received 10 messages with "best effort" reliability and "volatile" durability. This configuration is highly compatible with many possible publisher configurations.

For more information about QoS compatibility, refer to the [ZED node guide](/docs/integrations/ros-2/zed-stereo-node/#qos-profiles).

> **Note**
>
> The code of this tutorial instantiates a `rclcpp::Node` without **subclassing** it. This was the typical usage model in the original ROS, but unfortunately, this style of coding is not compatible with composing multiple nodes into a single process. Thus, it is no longer the recommended style for ROS 2.
> Please refer to the "[Depth sensing](/docs/integrations/ros-2/depth-sensing/#depth-subscribing-in-c)" tutorial for C++ tutorials written with a coding style more targeted to ROS 2.

### Conclusion

The full source code of this tutorial is available on GitHub in the [zed\_video\_tutorial](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_video_tutorial) sub-package.

Along with the node source code are the `package.xml` and `CMakeLists.txt` files that complete the tutorial package.