A lightweight, optimized ROS2 node for publishing compressed camera images from Raspberry Pi - solving the v4l2_camera dual-publishing overhead problem.
Show Image Show Image Show Image
The Issue: The standard v4l2_camera node publishes BOTH raw and compressed images simultaneously, which:
- Wastes CPU resources (double encoding)
- Consumes unnecessary bandwidth
- Causes performance bottlenecks on Raspberry Pi
- Results in dropped frames and lag
The Solution: This package publishes only compressed JPEG images , providing:
- 50% less CPU usage
- Consistent 30 FPS with no lag
- Lower memory footprint
- Optimized specifically for Raspberry Pi 4B ARM architecture
- Compressed-only publishing - no raw image overhead
- ARM Cortex-A72 optimizations - compiler flags tuned for Pi 4B
- Configurable parameters - resolution, framerate, JPEG quality
- Optional republisher - convert to raw when needed (separate launch)
- Zero frame drops - tested stable at 30 FPS
- Low latency - efficient JPEG encoding with OpenCV
- ROS2 Humble
- Raspberry Pi 4B (or compatible ARM board)
- OpenCV (libopencv-dev)
- USB Camera or Pi Camera Module (with V4L2 driver)
- Optional:
image_transportfor raw republishing
bash
# Navigate to your ROS2 workspace
cd ~/ros2_ws/src
# Clone the repository
git clone https://github.com/yourusername/rpi_camera_publisher.git camera_publisher
# Install dependencies
sudoapt-getinstall libopencv-dev ros-humble-image-transport
# Build with optimizations
cd ~/ros2_ws
colcon build --packages-select camera_publisher --cmake-args -DCMAKE_BUILD_TYPE=Release
# Source the workspace
source install/setup.bashbash
# Run with default settings (640x480 @ 30fps)
ros2 run camera_publisher camera_node
# Custom parameters
ros2 run camera_publisher camera_node --ros-args \
-p frame_rate:=30\
-p jpeg_quality:=75\
-p image_width:=1280\
-p image_height:=720\
-p camera_id:=0
# Raw camera (decompressed and can be viewed directly from Rviz2)
ros2 launch camera_publisher camera_pub.launch.pyThis launch file includes:
camera_node- Publishes compressed imagescamera_republisher- Converts compressed to raw
Tested on Raspberry Pi 4B (8GB RAM, Ubuntu 22.04 server LTS) :
Resolution FPS CPU Usage Status 640x480 30 ~12-15% ✅ No lag 1280x720 30 ~22-25% ✅ Stable 1920x1080 15 ~28-32% ✅ Smooth
Comparison with v4l2_camera_node:
- 🔴 v4l2_camera: 30-40% CPU @ 640x480 (publishes raw + compressed)
- 🟢 This package: 12-15% CPU @ 640x480 (compressed only)
Parameter Type Default Description frame_rateint 30 Frames per second camera_idint 0 Camera device ID (/dev/videoX) jpeg_qualityint 80 JPEG compression (0-100) image_widthint 640 Image width in pixels image_heightint 480 Image height in pixels frame_idstring "camera" TF frame ID
Topic Type Description /camera/image/compressedsensor_msgs/CompressedImageCompressed JPEG image
When using the republisher launch file:
Topic Type Description /camerasensor_msgs/ImageRaw image (on demand) /camera/camera_infosensor_msgs/CameraInfoCamera parameters
camera_publisher/
├── CMakeLists.txt # Build configuration with ARM optimizations
├── package.xml # ROS2 package manifest
├── LICENSE # MIT License
├── README.md # This file
├── src/
│ └── main.cpp # Camera node implementation
├── launch/
│ └── camera.launch.py # Launch file with optional republisher
└── include/
└── camera_publisher/ # (empty, reserved for headers)
The CMakeLists.txt includes ARM-specific optimizations:
-march=armv8-a+crc+simd- ARM Cortex-A72 with SIMD-mtune=cortex-a72- CPU-specific tuning-O3- Maximum optimization level-ftree-vectorize- Auto-vectorization for loops-ffast-math- Aggressive math optimizations
These flags provide ~20-30% performance improvement on Raspberry Pi 4B.
Camera not detected:
# List available cameras
ls /dev/video*
v4l2-ctl --list-devices
# Test camera with OpenCV
python3 -c "import cv2; print(cv2.VideoCapture(0).read())"Permission denied on /dev/video0:
sudousermod -a -G video $USER
# Logout and login againFor questions or suggestions, please open an issue on GitHub.