Guide to Building an Indoor Delivery Rover: ROS2 Humble on a 4WD Acrylic Smart Chassis with Raspberry Pi 5

Building an Indoor Delivery Rover: ROS 2 Humble on a 4WD Acrylic Smart Chassis with Raspberry Pi 5

This step‑by‑step tutorial shows you how to turn a 4‑wheel‑drive acrylic smart chassis into a fully‑functional indoor delivery robot powered by ROS 2 Humble Hawksbill and a Raspberry Pi 5. We cover hardware assembly, wiring, software installation, ROS 2 node development, and real‑world testing—all written in present tense for easy follow‑along.

1️⃣ Parts & Tools

Item Quantity Notes
Acrylic Smart Chassis (4WD, 300 mm × 300 mm) 1 Includes motor mounts & caster
DC Gear Motors (12 V, 30 RPM) 4 Compatible with motor driver board
Motor Driver (DRV8833 Dual H‑Bridge) 1 Handles up to 1.5 A per channel
Raspberry Pi 5 (4 GB) with 32 GB microSD 1 Latest SBC, 2.4 GHz/5 GHz Wi‑Fi
Power Distribution Board (5 V / 12 V buck‑boost) 1 Provides stable 5 V for Pi & sensors
Li‑Po Battery (2S 7.4 V, 4000 mAh) 1 Mounted on chassis rear
Jumper Wires, Heat‑Shrink, Screwdriver Set Essential for wiring
Optional Sensors (Lidar, IMU, Camera) Add later for navigation

2️⃣ Chassis Assembly & Wiring

Mount the Motors

Secure each motor into the pre‑drilled holes using M3×8 mm screws. Align the motor shafts toward the chassis center to keep the robot balanced.

Attach the Motor Driver

Place the DRV8833 board on the chassis mounting plate. Connect each motor’s two wires to the driver’s A1/A2 and B1/B2 terminals. Remember to keep the polarity consistent for forward motion.

Power Distribution

Connect the Li‑Po battery to the 12 V input of the distribution board. From the board, feed 12 V to the motor driver and 5 V to the Raspberry Pi 5 via the buck‑converter module.

Run the wiring neatly along the chassis channels. Use heat‑shrink tubing on all exposed solder joints to avoid short circuits. Finally, mount the Raspberry Pi 5 on the top side of the chassis using the included standoff kit.

Tip: Verify motor polarity before plugging the battery in. A quick test of ros2 topic echo /cmd_vel (once ROS is up) tells you if the wheels spin in the expected direction.

3️⃣ Raspberry Pi 5 & ROS 2 Installation

3.1 Flash Ubuntu 22.04 (Jammy)

ROS 2 Humble officially supports Ubuntu 22.04. Use Balena Etcher to flash the .img file onto the 32 GB microSD.

# Download Ubuntu Server
wget https://cdimage.ubuntu.com/releases/22.04/release/ubuntu-22.04-live-server-arm64.iso

# Burn with Etcher (GUI) or dd (CLI)
sudo dd if=ubuntu-22.04-live-server-arm64.iso of=/dev/sdX bs=4M status=progress conv=fsync

3.2 First‑Boot Configuration

  1. Log in with the default ubuntu user (password ubuntu).
  2. When prompted, change the password.
  3. Run sudo apt update && sudo apt upgrade -y to bring the system up‑to‑date.
  4. Enable SSH: sudo systemctl enable ssh && sudo systemctl start ssh.

3.3 Install ROS 2 Humble

Follow the official ROS 2 installation steps, trimmed for Raspberry Pi 5.

# Setup sources
sudo apt update && sudo apt install -y curl gnupg lsb-release
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=arm64 signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

# Install ROS 2 packages
sudo apt update
sudo apt install -y ros-humble-ros-base ros-humble-rclcpp ros-humble-geometry-msgs

# Source the setup script automatically
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc

3.4 Install Additional Packages

For motor control we use the ros2_control and ros2_controllers packages.

sudo apt install -y ros-humble-ros2-control ros-humble-ros2-controllers

Optional: ros-humble-rplidar-ros for later SLAM integration.

4️⃣ Writing ROS 2 Nodes for Mobility

4.1 Create a Workspace

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build
source install/setup.bash

4.2 Motor Driver Python Node

This node subscribes to /cmd_vel (geometry_msgs/Twist) and converts linear/angular velocity into PWM signals for the DRV8833 board using the pigpio library.

# ~/ros2_ws/src/rover_motor/rover_motor/motor_node.py
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import pigpio

class MotorNode(Node):
    def __init__(self):
        super().__init__('motor_node')
        self.sub = self.create_subscription(Twist, 'cmd_vel', self.cmd_callback, 10)

        # GPIO pins (BCM numbering)
        self.IN1 = 17  # Motor A forward
        self.IN2 = 27  # Motor A reverse
        self.IN3 = 22  # Motor B forward
        self.IN4 = 23  # Motor B reverse
        self.PWM_FREQ = 20000  # 20 kHz PWM

        self.pi = pigpio.pi()
        for pin in [self.IN1, self.IN2, self.IN3, self.IN4]:
            self.pi.set_mode(pin, pigpio.OUTPUT)

        self.max_pwm = 255   # 8‑bit duty cycle

    def cmd_callback(self, msg):
        # Simple differential drive conversion
        linear = msg.linear.x     # m/s
        angular = msg.angular.z   # rad/s
        wheel_base = 0.15         # meters (distance between wheels)
        wheel_radius = 0.035      # meters

        # Desired wheel speeds (rad/s)
        v_left  = (linear - angular * wheel_base / 2.0) / wheel_radius
        v_right = (linear + angular * wheel_base / 2.0) / wheel_radius

        # Convert to PWM (clamp to [-max_pwm, max_pwm])
        left_pwm  = int(max(min(v_left * 20, self.max_pwm), -self.max_pwm))
        right_pwm = int(max(min(v_right * 20, self.max_pwm), -self.max_pwm))

        self.set_motor(self.IN1, self.IN2, left_pwm)
        self.set_motor(self.IN3, self.IN4, right_pwm)

    def set_motor(self, pin_fwd, pin_rev, pwm):
        if pwm > 0:
            self.pi.set_PWM_dutycycle(pin_fwd, pwm)
            self.pi.set_PWM_dutycycle(pin_rev, 0)
        elif pwm < 0:
            self.pi.set_PWM_dutycycle(pin_fwd, 0)
            self.pi.set_PWM_dutycycle(pin_rev, -pwm)
        else:
            self.pi.set_PWM_dutycycle(pin_fwd, 0)
            self.pi.set_PWM_dutycycle(pin_rev, 0)

def main(args=None):
    rclpy.init(args=args)

Comments

Popular posts from this blog

Guide to Low-Cost Agricultural Surveying: Designing an Outdoor Rover via APM Rover Firmware and 3D Printed Chassis

Guide to Simulating and Building a Mecanum-Wheel Omnidirectional Robot using FreeRTOS and ESP32