What ROS2 actually is
ROS2 (Robot Operating System 2) is a middleware for robot software. It solves the messaging problem: how do you get your LIDAR, camera, motor driver, and navigation algorithm to talk to each other without writing custom serial protocols for every connection? ROS2 provides a publish/subscribe message bus, a standardized message format library, and a huge ecosystem of ready-to-use drivers.
On the Room-Nav kit, ROS2 connects: rplidar_ros2 (LIDAR driver) → slam_toolbox (mapping) → nav2 (navigation) → cmd_vel (motor commands) → your motor driver node → Cytron MDD10A. Each component is a “node” publishing and subscribing to “topics”.
Core concepts in 5 minutes
Minimal motor driver node (Python)
This is the simplest possible motor driver node — subscribes to /cmd_vel and maps it to PWM signals for the Cytron MDD10A. Based on the Room-Nav kit wiring.
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import RPi.GPIO as GPIO # or Jetson.GPIO on Orin
PWM_L, PWM_R = 33, 35 # GPIO pin numbers (BOARD mode)
DIR_L, DIR_R = 31, 37
class MotorDriver(Node):
def __init__(self):
super().__init__('motor_driver')
self.sub = self.create_subscription(
Twist, '/cmd_vel', self.cmd_callback, 10)
# setup PWM at 1kHz
GPIO.setmode(GPIO.BOARD)
for pin in [PWM_L, PWM_R, DIR_L, DIR_R]:
GPIO.setup(pin, GPIO.OUT)
self.pwm_l = GPIO.PWM(PWM_L, 1000)
self.pwm_r = GPIO.PWM(PWM_R, 1000)
self.pwm_l.start(0)
self.pwm_r.start(0)
def cmd_callback(self, msg: Twist):
linear = msg.linear.x # m/s forward
angular = msg.angular.z # rad/s rotation
# differential drive mixing
left = (linear - angular * 0.165) / 0.5 # 165mm track, 0.5 m/s max
right = (linear + angular * 0.165) / 0.5
self._set_motor(self.pwm_l, DIR_L, left)
self._set_motor(self.pwm_r, DIR_R, right)
def _set_motor(self, pwm, dir_pin, val):
GPIO.output(dir_pin, GPIO.HIGH if val >= 0 else GPIO.LOW)
pwm.ChangeDutyCycle(min(abs(val) * 100, 100))
def main():
rclpy.init()
rclpy.spin(MotorDriver())
Minimal launch file
# soohoo_robot/launch/bringup.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
# LIDAR
Node(package='rplidar_ros', executable='rplidar_composition',
parameters=[{'serial_port': '/dev/ttyUSB0', 'frame_id': 'laser'}]),
# OAK-D (depth + AI)
Node(package='depthai_ros_driver', executable='camera',
parameters=[{'i_nn_type': 'mobilenet'}]),
# Motor driver (custom node above)
Node(package='soohoo_robot', executable='motor_driver'),
# nav2 bringup (uses nav2_params.yaml)
Node(package='nav2_bringup', executable='bringup_launch.py'),
])
Run with: ros2 launch soohoo_robot bringup.launch.py
The 5 commands you'll use daily
# List running nodes
ros2 node list
# See what topics are active
ros2 topic list
# Stream a topic (see real sensor data)
ros2 topic echo /scan
# Check topic bandwidth (LIDAR should be ~2kB/s at 2000 samples)
ros2 topic hz /scan
# Send a manual velocity command (test motors without nav2)
ros2 topic pub /cmd_vel geometry_msgs/Twist \
"{linear: {x: 0.2}, angular: {z: 0.0}}"
# Install ROS2 Humble on JetPack 6 (Jetson Orin Nano)
# Takes ~20 min from fresh flash
sudo apt update && sudo apt install -y curl gnupg lsb-release
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
| sudo apt-key add -
echo "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/ros2.list
sudo apt update
sudo apt install -y ros-humble-desktop ros-humble-nav2-bringup \
ros-humble-slam-toolbox ros-humble-rplidar-ros
source /opt/ros/humble/setup.bash
You now have the fundamentals: power budgets, motor control, sensors, and ROS2. The Room-Nav kit is the reference platform this module was written for.
View Room-Nav BOM →