Skip to main content

Overview

Deployment is the process of preparing your robot for reliable autonomous operation in the target environment. This includes startup procedures, safety protocols, and operational guidelines.
Goal: Ensure robot operates safely, reliably, and effectively in real-world conditions without constant supervision.

Pre-Deployment Checklist

Hardware Readiness

  • Mechanical:
    • All screws tight (check regularly for vibration loosening)
    • No rattling or loose components
    • Wheels spin freely
    • Weight distribution balanced
    • Cable management secure (no dangling wires)
  • Electrical:
    • Battery fully charged (12.6V for 3S LiPo)
    • All connections secure
    • Emergency stop tested and functional
    • No exposed wiring
    • Fuse installed (10A recommended)
  • Sensors:
    • LiDAR lens clean
    • IMU securely mounted
    • Camera (if used) focused
    • All sensors powered and publishing

Software Readiness

  • System:
    • ROS2 packages built (no errors)
    • Launch files tested
    • Configuration files verified
    • Map(s) loaded correctly
  • Testing:
    • Teleoperation working
    • Autonomous navigation successful (>90%)
    • Obstacle avoidance tested
    • Recovery behaviors validated
    • Continuous operation >30 minutes
  • Safety:
    • Emergency stop kills motors immediately
    • Software watchdogs implemented
    • Velocity limits set appropriately
    • Collision detection active

Environment Preparation

  • Map:
    • Environment mapped completely
    • Map saved and backed up
    • No large unknown areas
    • Dynamic objects (chairs) noted
  • Safety:
    • Emergency stop accessible
    • Clear operating area (no trip hazards)
    • Good lighting (avoid direct sunlight on LiDAR)
    • Spectators at safe distance
  • Communication:
    • WiFi network stable
    • SSH access tested
    • Development PC connected
    • Monitoring tools ready

Startup Procedure

Standard Startup Sequence

1

Pre-Start Inspection

Visual check (30 seconds):
  1. Battery charged (check voltage: 11.5V - 12.6V)
  2. No loose wires or components
  3. LiDAR rotates freely (no obstructions)
  4. Wheels turn freely
  5. Emergency stop released (if has latch)
2

Power On

Power sequence:
  1. ESP32 first (or both simultaneously if single switch)
    • Power LED on ESP32 should illuminate
    • Wait 2 seconds for boot
  2. Raspberry Pi
    • Connect power
    • Wait 30-45 seconds for boot
    • Green LED activity indicates booting
Verify:
# SSH into Raspberry Pi
ssh ubuntu@192.168.1.100
# (adjust IP as needed)
3

Launch Robot System

Terminal 1: Launch complete robot stack
cd ~/ros2_ws
source install/setup.bash

# Launch everything (sensors + navigation)
ros2 launch mecanum_description robot_navigation.launch.py \
  map:=/home/ubuntu/ros2_ws/src/mecanum_description/maps/demo_map.yaml
Wait for all nodes to start (15-20 seconds)Expected output:
[INFO] [controller_manager]: Loaded controller 'mecanum_drive_controller'
[INFO] [rplidar_node]: RPLIDAR running at 5.5 Hz
[INFO] [amcl]: Initializing AMCL
[INFO] [bt_navigator]: Behavior tree navigator started
...
4

Verify System Status

Check all nodes running:
# Terminal 2: Check nodes
ros2 node list

# Should see:
# /controller_manager
# /mecanum_drive_controller
# /robot_state_publisher
# /imu_publisher
# /ekf_filter_node
# /rplidar_node
# /map_server
# /amcl
# /planner_server
# /controller_server
# /bt_navigator
# ...
Check sensor data:
# LiDAR
ros2 topic hz /scan
# Expected: ~5.5 Hz

# Odometry
ros2 topic hz /odometry/filtered
# Expected: ~50 Hz

# IMU
ros2 topic hz /imu/data
# Expected: ~100 Hz
Check for errors:
# Look for ERROR or WARN messages
ros2 topic echo /rosout | grep -E "ERROR|WARN"
Success criteria: All sensors publishing, no critical errors
5

Localize Robot

Launch RViz (on development PC):
# On development PC
export ROS_DOMAIN_ID=0
rviz2 -d ~/ros2_ws/src/mecanum_description/rviz/navigation.rviz
Set initial pose (AMCL):
  1. Click “2D Pose Estimate” button
  2. Click robot’s actual position on map
  3. Drag to set orientation
  4. Watch particle cloud converge (5-10 seconds)
Verify localization:
  • Particle cloud tight cluster
  • Robot model aligned with physical position
  • TF mapbase_link correct
Success criteria: Localization error <10cm
6

System Ready

Robot is now ready for operation!Indicators:
  • ✓ All nodes running
  • ✓ Sensors publishing
  • ✓ Robot localized correctly
  • ✓ No errors in logs
Next: Send navigation goals or start waypoint mission

Quick Start Script

Create automated startup script:
#!/bin/bash
# File: ~/start_robot.sh

echo "=== Mecanum Robot Startup ==="
echo

# Navigate to workspace
cd ~/ros2_ws
source install/setup.bash

# Check battery voltage (optional: requires voltage sensor)
# ./scripts/check_battery.sh

echo "Starting robot system..."
echo "Press Ctrl+C to stop"
echo

# Launch complete system
ros2 launch mecanum_description robot_navigation.launch.py \
  map:=/home/ubuntu/ros2_ws/src/mecanum_description/maps/demo_map.yaml
Make executable:
chmod +x ~/start_robot.sh
Usage:
./start_robot.sh

Auto-Start on Boot (Optional)

Create systemd service for auto-start:
# File: /etc/systemd/system/mecanum-robot.service

[Unit]
Description=Mecanum Robot Navigation System
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/ros2_ws
Environment="ROS_DOMAIN_ID=0"
ExecStart=/bin/bash -c 'source /home/ubuntu/ros2_ws/install/setup.bash && ros2 launch mecanum_description robot_navigation.launch.py map:=/home/ubuntu/ros2_ws/src/mecanum_description/maps/demo_map.yaml'
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
Enable service:
sudo systemctl daemon-reload
sudo systemctl enable mecanum-robot.service
sudo systemctl start mecanum-robot.service

# Check status
sudo systemctl status mecanum-robot.service
Disable auto-start:
sudo systemctl disable mecanum-robot.service

Operation Procedures

Manual Navigation (RViz)

For interactive goal selection:
1

Launch RViz

# On development PC
rviz2 -d ~/ros2_ws/src/mecanum_description/rviz/navigation.rviz
2

Send Navigation Goal

  1. Click “2D Nav Goal” in toolbar
  2. Click goal position on map
  3. Drag to set orientation
  4. Release mouse
  5. Watch robot navigate
3

Monitor Progress

Watch in RViz:
  • Green line: Global path
  • Red path: Local trajectory
  • Robot moving smoothly
  • Costmaps updating
Check status:
ros2 topic echo /behavior_tree_log | grep -i "goal"
4

Stop Navigation

Cancel goal if needed:
ros2 action send_goal /navigate_to_pose \
  nav2_msgs/action/NavigateToPose \
  "{}" --feedback --cancel
Or emergency stop:
  • Press physical emergency stop button
  • Or publish zero velocity:
    ros2 topic pub --once /mecanum_drive_controller/cmd_vel \
      geometry_msgs/msg/Twist \
      "{linear: {x: 0}, angular: {z: 0}}"
    

Waypoint Mission

For autonomous patrol or delivery missions: Method 1: Waypoint Follower Node
# Launch robot (if not already running)
ros2 launch mecanum_description robot_navigation.launch.py

# Define waypoints (x, y, yaw in map frame)
ros2 run mecanum_description waypoint_follower \
  --waypoints "[[2.0, 1.0, 0.0], [4.0, 2.0, 1.57], [3.0, 3.0, 3.14], [0.0, 0.0, 0.0]]" \
  --loop false
Method 2: Custom Python Script
#!/usr/bin/env python3
# File: ~/missions/patrol_mission.py

import rclpy
from rclpy.node import Node
from geometry_msgs.msg import PoseStamped
from nav2_msgs.action import NavigateToPose
from rclpy.action import ActionClient
import math

class PatrolMission(Node):
    def __init__(self):
        super().__init__('patrol_mission')
        self.nav_client = ActionClient(self, NavigateToPose, 'navigate_to_pose')

        # Define patrol waypoints (x, y, yaw)
        self.waypoints = [
            (2.0, 1.0, 0.0),
            (4.0, 2.0, math.pi/2),
            (3.0, 3.0, math.pi),
            (1.0, 2.5, -math.pi/2),
            (0.0, 0.0, 0.0)  # Return to start
        ]

    def run_patrol(self):
        for i, (x, y, yaw) in enumerate(self.waypoints):
            self.get_logger().info(f'Navigating to waypoint {i+1}/{len(self.waypoints)}: ({x}, {y}, {yaw})')
            success = self.navigate_to_pose(x, y, yaw)

            if not success:
                self.get_logger().error(f'Failed to reach waypoint {i+1}. Aborting mission.')
                return False

            self.get_logger().info(f'Reached waypoint {i+1}')

        self.get_logger().info('Patrol mission completed successfully!')
        return True

    def navigate_to_pose(self, x, y, yaw):
        goal_msg = NavigateToPose.Goal()
        goal_msg.pose.header.frame_id = 'map'
        goal_msg.pose.header.stamp = self.get_clock().now().to_msg()
        goal_msg.pose.pose.position.x = x
        goal_msg.pose.pose.position.y = y
        goal_msg.pose.pose.orientation.z = math.sin(yaw / 2.0)
        goal_msg.pose.pose.orientation.w = math.cos(yaw / 2.0)

        self.nav_client.wait_for_server()
        send_goal_future = self.nav_client.send_goal_async(goal_msg)
        rclpy.spin_until_future_complete(self, send_goal_future)

        goal_handle = send_goal_future.result()
        if not goal_handle.accepted:
            return False

        result_future = goal_handle.get_result_async()
        rclpy.spin_until_future_complete(self, result_future)

        return result_future.result().status == 4  # SUCCEEDED

def main():
    rclpy.init()
    mission = PatrolMission()
    mission.run_patrol()
    rclpy.shutdown()

if __name__ == '__main__':
    main()
Run mission:
python3 ~/missions/patrol_mission.py

Teleoperation Backup

Manual control if autonomous navigation fails:
# Keyboard teleop
ros2 run teleop_twist_keyboard teleop_twist_keyboard \
  --ros-args -r /cmd_vel:=/mecanum_drive_controller/cmd_vel

# Or joystick (if available)
ros2 run joy joy_node
ros2 run teleop_twist_joy teleop_node

Safety Protocols

Emergency Stop Procedures

Emergency Stop Priority:
  1. Physical E-Stop button (immediate motor power cut)
  2. Software stop command
  3. Kill navigation node
  4. Power off robot
1. Physical Emergency Stop
Press red emergency stop button
→ Motors power disconnected immediately
→ Robot stops instantly
→ Raspberry Pi remains on (safe shutdown)
2. Software Emergency Stop
# Stop all motion
ros2 topic pub --once /mecanum_drive_controller/cmd_vel \
  geometry_msgs/msg/Twist \
  "{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"

# Cancel navigation goal
ros2 action send_goal /navigate_to_pose \
  nav2_msgs/action/NavigateToPose \
  "{}" --cancel
3. Kill Navigation
# If software stop doesn't work, kill navigation nodes
ros2 lifecycle set /planner_server shutdown
ros2 lifecycle set /controller_server shutdown
ros2 lifecycle set /bt_navigator shutdown
4. Full System Shutdown
# Graceful shutdown
ros2 launch mecanum_description robot_navigation.launch.py --shutdown

# Or force kill
pkill -9 -f ros2

# Power off Raspberry Pi
sudo shutdown now

Safety Limits

Configure conservative safety limits:
# config/nav2_params.yaml

controller_server:
  ros__parameters:
    # Velocity limits (conservative for safety)
    max_vel_x: 0.4        # Reduce from 0.5 m/s
    max_vel_y: 0.4
    max_vel_theta: 0.8    # Reduce from 1.0 rad/s

    # Acceleration limits
    acc_lim_x: 2.0        # Reduce from 2.5 m/s²
    acc_lim_y: 2.0
    acc_lim_theta: 2.5    # Reduce from 3.2 rad/s²

local_costmap:
  local_costmap:
    ros__parameters:
      # Larger safety buffer
      robot_radius: 0.25   # Increase from 0.22 m (inflate robot size)
      inflation_radius: 0.60  # Increase from 0.55 m

Collision Detection

Monitor for collisions:
# Watch for unexpected forces (IMU acceleration spikes)
ros2 topic echo /imu/data --field linear_acceleration

# If accel > 20 m/s² → likely collision, stop robot
Add collision detection node (optional):
class CollisionDetector(Node):
    def __init__(self):
        super().__init__('collision_detector')
        self.subscription = self.create_subscription(
            Imu, '/imu/data', self.imu_callback, 10)
        self.cmd_pub = self.create_publisher(
            Twist, '/mecanum_drive_controller/cmd_vel', 10)

    def imu_callback(self, msg):
        accel_magnitude = math.sqrt(
            msg.linear_acceleration.x**2 +
            msg.linear_acceleration.y**2 +
            msg.linear_acceleration.z**2
        )

        if accel_magnitude > 20.0:  # Collision threshold
            self.get_logger().error('COLLISION DETECTED! Stopping robot.')
            # Stop robot
            stop_msg = Twist()
            self.cmd_pub.publish(stop_msg)

Monitoring & Diagnostics

Real-Time Monitoring

Dashboard view (RViz):
rviz2 -d ~/ros2_ws/src/mecanum_description/rviz/monitoring.rviz
Configure RViz displays:
  • Map + costmaps
  • LaserScan
  • Robot model with TF
  • Odometry path trail
  • Navigation paths (global + local)
  • Camera feed (if available)

System Health Checks

Create monitoring script:
#!/bin/bash
# File: ~/scripts/health_check.sh

echo "=== System Health Check ==="
echo

# Check nodes
echo "Checking critical nodes..."
NODES="controller_manager mecanum_drive_controller rplidar_node planner_server controller_server bt_navigator"
for node in $NODES; do
  if ros2 node list | grep -q $node; then
    echo "✓ $node running"
  else
    echo "✗ $node NOT running"
  fi
done

echo
echo "Checking sensor rates..."
# LiDAR
echo -n "LiDAR (/scan): "
timeout 5 ros2 topic hz /scan 2>&1 | grep "average rate" || echo "NOT publishing"

# Odometry
echo -n "Odometry (/odometry/filtered): "
timeout 5 ros2 topic hz /odometry/filtered 2>&1 | grep "average rate" || echo "NOT publishing"

echo
echo "Checking TF tree..."
ros2 run tf2_ros tf2_echo map base_link 2>&1 | head -n 5

echo
echo "=== Health Check Complete ==="
Run periodically:
./scripts/health_check.sh

Logging

Enable detailed logging:
# Set log level
export RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity}] [{name}]: {message}"
export RCUTILS_COLORIZED_OUTPUT=1

# Launch with logging
ros2 launch mecanum_description robot_navigation.launch.py \
  --log-level DEBUG

# Or per-node logging
ros2 run --log-level INFO <package> <node>
Save logs:
# Record all topics
ros2 bag record -a -o robot_session_$(date +%Y%m%d_%H%M%S)

# Or specific topics
ros2 bag record /scan /odom/filtered /cmd_vel /plan

Shutdown Procedure

1

Stop Navigation

Cancel any active goals:
  1. Cancel goals in RViz or via command line
  2. Wait for robot to stop moving
  3. Verify robot stationary:
    ros2 topic echo /cmd_vel
    # Should show all zeros
    
2

Shutdown Software

Graceful shutdown:
# In terminal where robot was launched, press Ctrl+C
# Wait for all nodes to shutdown (~5 seconds)
Verify all nodes stopped:
ros2 node list
# Should show minimal/no nodes
3

Power Off Raspberry Pi

Safe shutdown to prevent SD card corruption:
sudo shutdown now
Wait for:
  • Green LED stops blinking (~10 seconds)
  • No disk activity
Then: Disconnect power
4

Power Off ESP32 & Motors

Disconnect main power:
  1. Ensure robot is stationary
  2. Flip power switch OFF
  3. Verify all LEDs off
  4. Store robot safely
5

Battery Maintenance

LiPo battery care:
  • If using soon: Leave charged
  • If storing >1 week: Discharge to storage voltage (3.8V/cell = 11.4V total for 3S)
  • Store in fireproof LiPo bag
  • Check voltage weekly

Troubleshooting Deployment Issues

Checklist:
  1. Check controllers active:
    ros2 control list_controllers
    
  2. Check serial connection to ESP32:
    ls /dev/ttyUSB*
    
  3. Check /cmd_vel published:
    ros2 topic echo /mecanum_drive_controller/cmd_vel
    
  4. Manually test motors (upload test firmware)
Common cause: Serial communication between Pi and ESP32 broken
Causes:
  • High motor current (aggressive acceleration)
  • Raspberry Pi CPU maxed out
  • Old/degraded battery
Solutions:
  • Reduce velocity/acceleration limits
  • Optimize CPU usage (lower rates)
  • Replace battery
  • Use larger capacity battery (e.g., 10000mAh instead of 5000mAh)
Debug:
  1. Check Raspberry Pi temperature:
    vcgencmd measure_temp
    # Should be <75°C
    
  2. Check memory usage:
    free -h
    
  3. Check logs for errors:
    journalctl -u mecanum-robot.service
    
Solutions:
  • Add heatsink/fan to Raspberry Pi
  • Reduce costmap sizes
  • Lower update rates
  • Kill unnecessary processes

Next Steps

References

[1] ROS2 Lifecycle Nodes: https://design.ros2.org/articles/node_lifecycle.html [2] Nav2 Monitoring: https://docs.nav2.org/tutorials/docs/monitoring_nav2.html [3] LiPo Battery Safety: https://rogershobbycenter.com/lipoguide