6.2.1 ROS2 MIPI Camera Usage Guide
Last Version: 11/09/2025
Overview
This section introduces a camera driver and a set of ROS 2 nodes based on the JDK library for capturing and processing MIPI CSI camera data.
The JDK library provides hardware interfaces for camera access (JdkCamera
), video encoding (JdkEncoder
), decoding (JdkDecoder
), and video output (JdkVo
). ROS 2 nodes use these interfaces to publish data via custom messages.
The system architecture is as follows:
camera_node
captures camera frames and publishes them to/camera_frames
.venc_node
encodes raw frames to H.264 and publishes to/encoded_frames
.vdec_node
decodes encoded frames and publishes them to/decoded_frames
.vo_node
subscribes to camera frames and displays them on screen (with hardware acceleration).infer_node
performs object detection on camera frames (default model: YOLOv8).
Users can subscribe to the relevant topics to access frame data for further processing.
Background
Hardware Environment
This driver targets embedded systems with MIPI CSI camera support, such as Spacemit KX series development boards. The JDK SDK interfaces directly with V4L2 for efficient access to camera and video codec hardware.
System Architecture
Based on the JDK SDK’s functionalities, this toolkit defines a structure of ROS 2 packages and nodes. The main components include:
- JDK Library Components:
Provides C++ interfaces for:
- Camera capture (
JdkCamera
) - Frame encapsulation (
JdkFrame
) - Hardware encoding (
JdkEncoder
) - Decoding (
JdkDecoder
) - Video output (
JdkVo
) - DMA frame transfer (
JdkDma
)
- Camera capture (
- ROS 2 Interface Package:
The
jdk_interfaces
package defines a custom message typeJdkFrameMsg
used to transmit frame data. - FD Transfer Package:
The
jdk_fd_transmitter
package implements a zero-copy frame transfer mechanism using UNIX sockets, allowing multiple nodes to share DMA buffers and avoid memory copy overhead. - Functional Nodes:
jdk_camera_node
: Captures camera frames and publishes them to/camera_frames
jdk_venc_node
: Encodes the frames and publishes them to/encoded_frames
jdk_vdec_node
: Decodes frames and publishes them to/decoded_frames
jdk_vo_node
: Displays frames using hardware accelerationjdk_infer_node
: Performs object detection on/camera_frames
using the YOLOv8 model
The following sections will introduce the installation environment, compilation process, node startup parameters, interface definition and usage examples in detail.
Installation and Dependencies
System Requirements and Environment Setup
-
Operating System Use Bianbu 2.2 and install ROS 2 Humble (Humble Hawksbill). Follow the official guide: ROS 2 Humble Installation.
Make sure your system is up to date and install the ROS 2 desktop version:
sudo apt install ros-humble-desktop
-
Camera Driver Ensure drivers are available for MIPI CSI cameras (the Bianbu kernel supports multiple CSI interfaces by default). Check available camera devices using:
v4l2-ctl --list-devices
Example device nodes:
/dev/video0
,/dev/video50
, etc. -
Required Dependencies Install the required tools and libraries for building and running ROS 2 applications:
-
C/C++ build tools:
build-essential
,cmake
, etc. -
UUID library:
uuid-dev
(used for generating frame IDs). Reference: ROS 2 Unique Identifier Messages -
V4L2 headers (optional):
libv4l-dev
-
ROS 2 dependencies:
ament_cmake
(build tool),rclcpp
,std_msgs
,rosidl_default_generators
, and other common ROS 2 packages (these are included when installing the ROS 2 desktop version)
-
Install Required Packages (Bianbu 2.2)
Update your system and install ROS 2 Humble and build dependencies:
sudo apt update
sudo apt install -y ros-humble-desktop build-essential cmake libuuid1 uuid-dev libv4l-dev
After installation, follow the official ROS 2 instructions to set up sources and keys: ROS 2 Humble Installation Guide
Setup Workspace
Create a ROS 2 workspace (e.g., ~/ros2_ws
) and add this project’s source code (jdk
folder) into the src
directory:
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
cp -r path_to_jdk_folder ./jdk
cd ~/ros2_ws
JDK SDK Build (Optional)
If you want to install the JDK library system-wide, build it from the jdk_sdk
directory and install to /opt/jdk
:
cd jdk/jdk_ros2_ws/jdk_sdk
cmake -DCMAKE_INSTALL_PREFIX=/opt/jdk .
make install
Then set the environment variables:
export CMAKE_PREFIX_PATH=/opt/jdk:$CMAKE_PREFIX_PATH
export LD_LIBRARY_PATH=/opt/jdk/lib:$LD_LIBRARY_PATH
Allows other programs to link to the JDK library with:
find_package(jdk REQUIRED)
Verify Dependencies
Ensure that the required dependencies are installed before compiling. Common packages include:
ros-humble-rclcpp
,ros-humble-std-msgs
– ROS 2 C++ client libraryros-humble-rosidl-default-generators
– for generating custom message typesros-humble-rcl-interfaces
– usually installed with ROS 2libssl-dev
– may be required for inference plugins, encryption, or specific backends
Build and Compilation
This section explains how to build ROS 2 packages using colcon
. Ensure your source code is placed inside your ROS 2 workspace
Configure the ROS 2 Environment
Open a new terminal, load the ROS 2 environment variables:
source /opt/ros/humble/setup.bash
Navigate to the Workspace
Navigate to the root of your ROS 2 workspace (the folder containing src
):
cd ~/ros2_ws
Compile Interface and Transmission Packages
To generate message types before building other packages, compile these two packages (jdk_interfaces
and jdk_fd_transmitter
) first:
colcon build --packages-select jdk_interfaces
source install/setup.bash
colcon build --packages-select jdk_fd_transmitter
source install/setup.bash
Tip: In most cases, you can simply build all packages at once. The steps above are for clarity.
Build All Packages
To build every package in the workspace at once, run:
colcon build --symlink-install
According to the Official ROS documentation, this will build all packages together without compiling them individually.
After a successful build, you should see directories such as build/
, install/
, and log/
inside your workspace.
Source the Workspace
Before running your packages, source the newly built workspace:
source install/setup.bash
According to the Official ROS documentation, this ensures the environment can locate the compiled packages and executables.
Note:
- If you build outside of a ROS workspace (e.g., in an isolated directory), you may need to adjust
LD_LIBRARY_PATH
to include the JDK library path (/opt/jdk/lib
, if installed).- The simplest approach is to keep everything in one workspace and build with
colcon build
.
Node Launch and Parameters
The project contains several ROS 2 executable nodes. Each node can be started using ros2 run
or ros2 launch
and can be configured with parameters. The main nodes and their usage are as follows:
Camera Node (Capture)
-
Executable name:
camera_node
(package:jdk_camera_node
) -
Launch command:
ros2 run jdk_camera_node camera_node [--ros-args -p <param_name>:=<value> ...]
-
Supported parameters:
device
(string): Path to the camera device. Default:"/dev/video50"
. Adjust if needed (e.g.,"/dev/video0"
).width
(int): Image width in pixels. Default:1280
.height
(int): Image height in pixels. Default:720
.socket_path
(string): UNIX socket path for FD (file descriptor) transfer. Default:"/tmp/jdk_fd_socket"
. Used for passing frame buffers.
-
Description:
-
The camera node opens the V4L2 device specified by
device
, captures NV12 frames, and periodically publishes them to the/camera_frames
topic. -
At the same time, starts a UNIX socket service (at
socket_path
) for DMA-based frame buffer transfer. -
Custom settings can be applied using
-p device:=/dev/video0 -p width:=1280 -p height:=720
-
Hardware Encoder Node (VENC)
-
Executable name:
venc_node
(package:jdk_venc_node
) -
Launch command:
ros2 run jdk_venc_node venc_node [--ros-args -p <param_name>:=<value> ...]
-
Supported Parameters:
width
(int): Input frame width. Default:1920
.height
(int): Input frame height. Default:1080
.payload
(int): Encoding format. Default:CODING_H264
(H.264).format
(int): Pixel format. Default:PIXEL_FORMAT_NV12
(NV12).use_dma
(bool): Use DMA for transfer. Default:true
.venc_fd_socket
(string): Socket path for encoded frame output. Default:"/tmp/jdk_fd_enc2out.sock"
. (Note: There is also an internal subscription socket, defaulting to"/tmp/jdk_fd_socket"
, which usually does not need to be modified.)
-
Description:
- The encoder node subscribes to the
/camera_frames
topic (using SensorData QoS). - It receives raw frames and performs H.264 encoding in an internal thread.
- Encoded frames are then published to the
/encoded_frames
topic using the customJdkFrameMsg
message type. - To use a different encoding format, adjust the
payload
parameter (for example, set it toCODING_H265
). - The
use_dma
parameter controls whether DMA is used for frame transfer.
- The encoder node subscribes to the
Hardware Decoder Node (VDEC)
-
Executable name:
venc_node
(package:jdk_venc_node
) -
Launch command:
ros2 run jdk_venc_node venc_node [--ros-args -p <param_name>:=<value> ...]
-
Supported Parameters:
width
(int): Input frame width. Default:1920
.height
(int): Input frame height. Default:1080
.payload
(int): Encoding format. Default:CODING_H264
(H.264).format
(int): Pixel format. Default:PIXEL_FORMAT_NV12
(NV12).use_dma
(bool): Use DMA for transfer. Default:true
.dec_fd_socket
(string): UNIX socket path for decoded frame output. Default:"/tmp/jdk_fd_dec2out.sock"
.venc_fd_socket
(string): UNIX socket path for encoded output. Default:"/tmp/jdk_fd_enc2out.sock"
(matches the encoder node’svenc_fd_socket
).
-
Description:
- The VDEC node subscribes to the
/encoded_frames
topic and decodes incoming encoded frames. - It then publishes the decoded raw frames to the
/decoded_frames
topic. - In most cases,
venc_fd_socket
should match the encoder node’s output path for getting the encoded data (The default parameters already match the encoder node’s output socket path, so manual changes are usually unnecessary).
- The VDEC node subscribes to the
Video Output Node (VO)
-
Executable name:
vo_node
(package:jdk_vo_node
) -
Launch command:
ros2 run jdk_vo_node vo_node [--ros-args -p <param_name>:=<value> ...]
-
Supported parameters:
width
(int): Frame width. Default:1920
.height
(int): Frame height. Default:1080
.format
(int): Pixel format. Default:PIXEL_FORMAT_NV12
.use_dma
(bool): Use DMA for transfer. Default:true
.cam_fd_socket
(string): Camera frame FD socket path. Default:"/tmp/jdk_fd_socket"
.
-
Description:
- The VO node subscribes to the
/camera_frames
topic. - It uses the hardware video output (
JdkVo
) to display frames directly on the screen (overlay output). - This node is typically used to verify camera capture.
- If display functionality is not needed, this node can be skipped.
- The VO node subscribes to the
Inference Node (Infer)
-
Executable name:
infer_node
(package:jdk_infer_node
) -
Launch command:
ros2 run jdk_infer_node infer_node [--ros-args -p <param_name>:=<value> ...]
-
Supported parameters:
socket_path
(string): FD socket path. Default:"/tmp/jdk_fd_socket"
(same ascamera_node
).
-
Description:
- The Infer node subscribes to the
/camera_frames
topic. - It uses the built-in YOLOv8 ONNX model (
yolov8n.q.onnx
) to perform object detection on camera frames. - Detection results are printed in the terminal.
- Frame data is obtained via FD transfer, so no display functionality is required.
- Users can refere to the sample in
yolov8n.q.onnx
to replace the default model with their own ONNX model if desired.
- The Infer node subscribes to the
Parameter Summary Table
Node | Parameter | Type | Default | Description |
---|---|---|---|---|
camera_node | device | string | "/dev/video50" | Camera device path (V4L2) |
width | int | 1280 | Frame width in pixels | |
height | int | 720 | Frame height in pixels | |
socket_path | string | "/tmp/jdk_fd_socket" | FD transfer socket path | |
venc_node | width | int | 1920 | Input frame width |
height | int | 1080 | Input frame height | |
payload | int | CODING_H264 (H.264) | Encoding format | |
format | int | PIXEL_FORMAT_NV12 | Pixel format (FourCC) | |
use_dma | bool | true | Use DMA transfer | |
venc_fd_socket | string | "/tmp/jdk_fd_enc2out.sock" | Output socket for encoded frames | |
vdec_node | width , height | int | 1920 , 1080 | Output frame size after decoding |
payload | int | CODING_H264 | Encoding format | |
format | int | PIXEL_FORMAT_NV12 | Pixel format | |
use_dma | bool | true | Use DMA transfer | |
dec_fd_socket | string | "/tmp/jdk_fd_dec2out.sock" | Socket for decoded output | |
venc_fd_socket | string | "/tmp/jdk_fd_enc2out.sock" | Socket from encoder node | |
vo_node | width , height | int | 1920 , 1080 | Frame display dimensions |
format | int | PIXEL_FORMAT_NV12 | Pixel format | |
use_dma | bool | true | Use DMA | |
cam_fd_socket | string | "/tmp/jdk_fd_socket" | Input socket from camera | |
infer_node | socket_path | string | "/tmp/jdk_fd_socket" | FD socket path for inference |
Use
--ros-args -p param:=value
to override parameters, for example:-p device:=/dev/video0
5. Node Interface Descriptions
The system mainly uses a custom message type jdk_interfaces/msg/JdkFrameMsg
to transmit image frames between nodes. Typical topic interfaces are as follows:
/camera_frames
-
Message Type:
jdk_interfaces/JdkFrameMsg
-
Publisher:
camera_node
-
Each message contains raw camera data (default in NV12 format). The message fields include:
stamp
: Timestampframe_id
: UUID-based Frame IDwidth
andheight
: Frame dimensionsstride
: Image row size in bytessize
: Frame data sizepix_format
: V4L2 FourCC pixel formatis_dma
: Whether the frame uses DMA transferdma_fd
: DMA file descriptor (used ifis_dma = true
)data
: Byte array of image data (used ifis_dma = false
; NV12 layout)
Note:
- When
is_dma=true
, actual image data is stored in the buffer pointed to bydma_fd
, and thedata
field is empty. - When
is_dma=false
, image bytes are stored indata
with NV12 layout.
/encoded_frames
-
Message Type:
jdk_interfaces/JdkFrameMsg
-
Publisher:
venc_node
-
This topic contains encoded frame data, typically H.264 stream data.
pix_format
: Corresponds to the encoding type (e.g., H264 or H265)data
: Data is stored either in data or transferred viadma_fd
.
/decoded_frames
-
Message Type:
jdk_interfaces/JdkFrameMsg
-
Publisher:
vdec_node
-
This topic contains decoded raw image frames in NV12 format. These can be used for further processing or displayed using the VO node.
Notes
- Currently, no ROS services or actions are defined in this system. All inter-node communication is handled through the above topics.
- Users can subscribe to
/camera_frames
or other topics and retrieve theJdkFrameMsg
in callbacks, and convert NV12 data to a viewable format (e.g., RGB using OpenCV) for processing or visualization.
Usage Example
The following examples demonstrate a typical workflow from compilation to running the system and obtaining camera frame data.
Compile the Workspace
Assuming your workspace is located at ~/ros2_ws
, build all packages using the steps below:
cd ~/ros2_ws
source /opt/ros/humble/setup.bash
colcon build --symlink-install
source install/setup.bash
At this point, all nodes are compiled and ready to run. Please refer to the ROS2 Official Document for more details.
Run the Camera Node
In a terminal, launch the camera capture node:
ros2 run jdk_camera_node camera_node --ros-args \
-p device:=/dev/video50 -p width:=1280 -p height:=720
- This command opens
/dev/video50
(or other specified device) and starts publishing frames to/camera_frames
. - For Customization
- Change
device
to match your camera (e.g.,/dev/video0
) - Adjust
width
andheight
to set the frame size
- Change
Run Other Nodes
Launch other nodes in separate terminals as needed:
ros2 run jdk_venc_node venc_node
ros2 run jdk_vdec_node vdec_node
ros2 run jdk_vo_node vo_node
ros2 run jdk_infer_node infer_node
What each node does:
- The encoder node encodes
/camera_frames
to H.264 and publishes to/encoded_frames
- The decoder node decodes and publishes to
/decoded_frames
- The display node renders frames directly on the screen
- The inference node prints object detection results in the terminal
View Topic Data
After launching the nodes, use ROS 2 CLI tools to inspect the topics:
ros2 topic list | grep jdk
ros2 topic echo /camera_frames
Using ros2 topic echo
, you can view the metadata of JdkFrameMsg
.
Note: The image data is transmitted in binary format, so you cannot view it directly in the terminal.
You can also write a subscriber node to:
- Receive
JdkFrameMsg
messages. - Extract the NV12 image data.
- Convert it to a displayable format (e.g., RGB with OpenCV).
- Save or show the images as needed.
Subscriber Example (Python)
The following example shows how to subscribe to camera frames in a custom ROS 2 node and convert NV12 data to an OpenCV image:
import rclpy
from rclpy.node import Node
from jdk_interfaces.msg import JdkFrameMsg
import numpy as np
import cv2
class CameraListener(Node):
def **init**(self):
super().**init**('cam_listener')
self.sub = self.create_subscription(
JdkFrameMsg, 'camera_frames', self.callback, 10)
def callback(self, msg):
# If data is not using DMA (is_dma=False), read the data array
if not msg.is_dma:
width, height = msg.width, msg.height
# NV12 data is stored in msg.data
nv12 = np.frombuffer(msg.data, dtype=np.uint8)
yuv = nv12.reshape((height * 3 // 2, width)) # NV12 total length = height*1.5*width
# Convert NV12 to BGR image for OpenCV
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV12)
cv2.imshow('Camera', bgr)
cv2.waitKey(1)
def main():
rclpy.init()
node = CameraListener()
rclpy.spin(node)
rclpy.shutdown()
if **name** == '**main**':
main()
- This example subscribes to
/camera_frames
. - In the callback, it reads
msg.data
(assumingis_dma=False
) and converts the NV12 frame into a BGR image that can be displayed using OpenCV. - If DMA mode is used (
is_dma=True
), you would access the frame buffer viadma_fd
(not shown in this example).
Summary
-
These examples demonstrate a full workflow, from building the workspace to processing real-time camera frames.
-
Users can customize launch parameters, subscribe to topics, or create their own nodes for more advanced image processing and analysis.
-
This toolkit allows efficient access to MIPI CSI camera data in a ROS 2 environment, while providing encoding, decoding, and inference capabilities for downstream development.