Run Edge Impulse Vision on a JetBot with Rubik Pi
This tutorial runs an Edge Impulse object-detection model on a JetBot-class robot using a Qualcomm Rubik Pi, Ubuntu 24.04, and ROS 2 Jazzy. It combines the robot-specific jetbot_ros package with edgeimpulse_ros.
edgeimpulse_ros subscribes to a sensor_msgs/Image topic and publishes detections; the JetBot launch file starts a v4l2_camera driver to supply those frames. jetbot_ros provides motor control, teleoperation, navigation, and launch integration. Keeping these roles separate makes the same perception node reusable across different robot platforms.
What you will build
You will run local object detection on the robot’s camera feed, publish the results into ROS 2, and keep the mobile base control path available for robot-specific behavior nodes.
Prerequisites
- A Rubik Pi running Ubuntu 24.04 and ROS 2 Jazzy.
- A SparkFun JetBot AI Kit v2.0 or compatible JetBot-class chassis with a SparkFun or Waveshare motor controller.
- A USB camera connected to the Rubik Pi.
- A Linux
.eim object-detection model exported from Edge Impulse Studio.
- Local copies of ei_jetbot_ros_rubikpi and edgeimpulse-ros.
Read Run Edge Impulse Object Detection with ROS 2 first for the shared model export, runtime, and topic details.
1. Provision the Rubik Pi
On the Rubik Pi, run the repository’s provisioner:
cd ~/jetbot_ros_rubikpi
sudo bash scripts/rubikpi_provision.sh
It installs the ROS 2 Jazzy base packages, V4L2 camera support, vision_msgs, diagnostic_msgs, OpenCV, NumPy, PortAudio (for the SDK’s pyaudio dependency), and the JetBot hardware dependencies. For the SparkFun hardware path, confirm the Qwiic driver is available:
python3 -c "import qwiic; print(qwiic.__file__)"
2. Build a shared ROS 2 workspace
The JetBot helper links both packages into the same workspace:
cd ~/jetbot_ros_rubikpi
bash scripts/setup_edge_impulse_workspace.sh ~/jetbot_edgeimpulse_ws ~/jetbot_ros_rubikpi ~/edgeimpulse-ros
cd ~/jetbot_edgeimpulse_ws
source /opt/ros/jazzy/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build --symlink-install
source install/setup.bash
Install the Edge Impulse Linux SDK and the JetBot runtime requirements:
sudo apt install -y ros-jazzy-vision-msgs ros-jazzy-diagnostic-msgs \
ros-jazzy-v4l2-camera python3-opencv python3-numpy portaudio19-dev
sudo python3 -m pip install --break-system-packages \
-r ~/jetbot_ros_rubikpi/requirements-edge-impulse.txt
The repository currently installs the Edge Impulse runtime into the system Python on Ubuntu 24.04 by using —break-system-packages. That matches the repo, but treat it as a dedicated robot-image or disposable development-machine workflow rather than a general-purpose Python setup.
3. Start motor control and object detection
The integrated launch file starts the motor node, a v4l2_camera driver, and the edgeimpulse_ros detector. Give it the model path and the camera device:
cd ~/jetbot_edgeimpulse_ws
source /opt/ros/jazzy/setup.bash
source install/setup.bash
ros2 launch jetbot_ros jetbot_edge_impulse.launch.py \
motor_controller:=motors_sparkfun \
model_path:=/home/$USER/models/jetbot-detector.eim \
video_device:=/dev/video0
For a Waveshare motor board, install the required motor-driver package first:
pip install Adafruit-MotorHAT
Then replace the motor executable:
ros2 launch jetbot_ros jetbot_edge_impulse.launch.py \
motor_controller:=motors_waveshare \
model_path:=/home/$USER/models/jetbot-detector.eim \
video_device:=/dev/video0
The launch file already starts a v4l2_camera driver on video_device. Do not start a second camera driver on the same /dev/video* device at the same time. On the validated Rubik Pi camera path, use YUYV if MJPG causes an empty encoding or a cv_bridge exception.
4. Inspect inference output
The detector publishes these topics:
source ~/jetbot_edgeimpulse_ws/install/setup.bash
ros2 topic echo /edgeimpulse_detector/detections
ros2 run rqt_robot_monitor rqt_robot_monitor
| Topic | Purpose |
|---|
/edgeimpulse_detector/detections | vision_msgs/Detection2DArray messages containing accepted bounding boxes. |
/edgeimpulse_detector/debug_image | Annotated sensor_msgs/Image when publish_debug_image:=true. |
/diagnostics | diagnostic_msgs/DiagnosticArray with FPS, latency, and model health. |
Keep the vision pipeline observational until detections are stable. A downstream behavior node should gate any autonomous action on confidence, label, and robot state rather than acting on every frame.
Motor and camera checks
Before connecting detection output to autonomy, verify the base robot path independently.
Start normal hardware control:
source ~/jetbot_edgeimpulse_ws/install/setup.bash
ros2 launch jetbot_ros jetbot_cpu.launch.py motor_controller:=motors_sparkfun
Then publish a short forward command and a stop:
ros2 topic pub -1 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.05}, angular: {z: 0.0}}"
ros2 topic pub -1 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.0}, angular: {z: 0.0}}"
Simulation notes
The repository includes Gazebo Classic worlds for navigation and data collection. Use them on an Ubuntu or WSL development machine where Gazebo Classic is available:
ros2 launch jetbot_ros gazebo_world.launch.py
The current edgeimpulse_ros package subscribes to a sensor_msgs/Image topic, so it can in principle consume the Gazebo camera stream by pointing image_topic at it. This repo validates the detector against the real V4L2 camera path, so treat the Gazebo integration as unvalidated.
Troubleshooting
| Symptom | Resolution |
|---|
package 'jetbot_ros' not found | Source /opt/ros/jazzy/setup.bash and ~/jetbot_edgeimpulse_ws/install/setup.bash. |
| Camera device is busy | Stop any other camera client using the same /dev/video* device before starting the launch. |
| Qwiic module cannot be imported | Re-run the provisioner, or install the SparkFun Qwiic packages into the system Python ROS 2 uses. |
| Waveshare motor import fails | Install Adafruit-MotorHAT in the Python environment used by the motor node. |
| No detections | Verify the .eim path, video_device, model labels, and confidence_threshold; confirm the camera is publishing with ros2 topic hz /jetbot/camera/image_raw and inspect /diagnostics for inference activity. |
| Robot moves but vision is unstable | Keep autonomy disabled, collect images from the mounted camera, retrain or tune the model, and raise confidence_threshold before enabling behavior logic. |
Next steps
- Add a behavior node that subscribes to
/edgeimpulse_detector/detections and publishes guarded /cmd_vel commands.
- Watch
/diagnostics (FPS and latency) under load to understand the inference budget.
- Collect additional training data from the final camera position.
- Validate any autonomous behavior at low speed before increasing robot velocity.