β οΈ Active development β BETA. Architecture and params may change.
Anibot is a compact ROS2 differential drive robot built around a Raspberry Pi 5, capable of autonomous navigation, real-time SLAM mapping, and sensor-fused odometry using wheel encoders and LiDAR. It runs the full Nav2 stack with a calibrated EKF for reliable localization.
- Overview
- System Architecture
- Hardware
- Software Stack
- Odometry & Sensor Fusion
- Calibrated Parameters
- Workspace Structure
- Setup & Usage
- Features & Status
- Roadmap
- Known Issues & Fixes
- Contributing
- Contact
Anibot implements a complete mobile robotics stack on affordable hardware:
- Autonomous navigation with Nav2 (DWB controller)
- SLAM mapping with slam_toolbox (lifelong mode)
- Sensor-fused odometry β wheel encoders + LiDAR via EKF (
robot_localization) - AMCL localization on saved maps
- Docker-based RViz for remote visualization from a laptop
- Arduino Mega motor controller with quadrature encoder tracking at 20 Hz
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Raspberry Pi 5 β
β ββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
β β RPLIDAR A1 ββββΆβ /scan topic ββββΆβ slam_toolbox β β
β ββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
β β β
β ββββββββββββββ ββββββββββββββββ βββββββΌββββββββββ β
β βArduino MegaββββΆβ /odom (wheel)ββββΆβ robot_local. β β
β βCytron MDD3Aβ ββββββββββββββββ β (EKF fusion) β β
β ββββββββββββββ βββββββββ¬ββββββββ β
β β² β β
β ββββββ΄ββββββββ ββββββββββββββββ βββββββββΌββββββββ β
β β /cmd_vel βββββ Nav2 βββββ /odom_fused β β
β ββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SSH / ROS2 Domain 42
βββββββββββΌββββββββββ
β Laptop (Docker) β
β RViz2 + Nav2 UI β
βββββββββββββββββββββ
| Component | Model | Notes |
|---|---|---|
| Compute | Raspberry Pi 5 | Ubuntu 24.04, ROS2 Jazzy |
| Microcontroller | Arduino Mega 2560 | Motor control + encoder reading |
| Motor Driver | Cytron MDD3A | Dual channel, PWM control |
| LiDAR | RPLIDAR A1M8 | 360Β° scan, ~6m range |
| Drive | Differential Drive | 2WD with caster |
| Encoders | Quadrature (Γ4) | 28 PPR per motor, gear ratio 19.2:1 |
Arduino Pin Mapping:
| Signal | Pin |
|---|---|
| M1A (Right Motor) | 9 |
| M1B (Right Motor) | 10 |
| M2A (Left Motor) | 5 |
| M2B (Left Motor) | 6 |
| ENC_L_A | 2 (INT) |
| ENC_L_B | 3 (INT) |
| ENC_R_A | 18 (INT) |
| ENC_R_B | 19 (INT) |
| Layer | Technology |
|---|---|
| OS | Ubuntu 24.04 LTS (RPi5) |
| Middleware | ROS2 Jazzy |
| Navigation | Nav2 (DWB Local Planner) |
| Mapping | slam_toolbox (lifelong) |
| Localization | AMCL + EKF (robot_localization) |
| Sensor Fusion | robot_localization (wheel odom + laser odom) |
| Visualization | RViz2 (via Docker on laptop) |
| Serial Comm | Python pyserial @ 115200 baud |
Anibot fuses wheel odometry and laser odometry using an Extended Kalman Filter (EKF) via the robot_localization package.
/odom (wheel encoders) βββ
ββββΆ EKF βββΆ /odometry/filtered
/laser_odom (LiDAR scan match) βββ
- Wheel odom provides high-frequency velocity estimates (20 Hz) but drifts over time
- Laser odom corrects long-term drift using scan matching
- EKF output
/odometry/filteredis fed to Nav2 as the primary odometry source
π§ͺ Fusion testing in progress β actively tuning EKF covariance matrices and validating against ground truth.
These values are calibrated through physical testing (360Β° spin test, straight-line test):
# Wheel & Drive
wheel_radius: 0.041 m
wheel_base: 0.355 m # Calibrated β 360Β° spin, 1.1Β° residual error
encoder_ppr: 28 # Γ 4 quadrature = 112 counts/rev
gear_ratio: 19.2
# Scale correction (motor asymmetry compensation)
left_scale: 0.82
right_scale: 1.00
swap_motors: true # Physical L/R wiring swap β corrected in software
# PWM limits
max_pwm: 150
pwm_min: 70 # Deadband β below this motor stalls
max_linear_speed: 0.20 m/s
# Nav2 controller
desired_linear_vel: 0.18 m/s
rotate_angular_vel: 0.42 rad/s
xy_goal_tolerance: 0.20 m
yaw_goal_tolerance: 0.25 rad
# AMCL
particles_min: 1000
particles_max: 5000
z_hit: 0.95
max_beams: 180anibot_ws/
βββ src/
β βββ interface/ # Main ROS2 package
β βββ interface/ # Python nodes
β β βββ odometery.py # Wheel odometry node
β β βββ ...
β βββ launch/
β β βββ anibot_full.launch.py # Nav2 full launch
β β βββ slam_full.launch.py # SLAM launch
β βββ config/ # Nav2, EKF, AMCL params
β βββ maps/ # Saved maps (.yaml + .pgm)
β βββ CMakeLists.txt
βββ assets/ # Demo GIFs, images
βββ anibot_setup.sh # One-shot dependency installer
βββ docker_jazzy.sh # RViz2 Docker launcher (laptop)
βββ .gitignore
βββ README.md
chmod +x anibot_setup.sh
./anibot_setup.shcd ~/anibot_ws
colcon build --symlink-install
source install/setup.bashros2 launch interface slam_full.launch.pyros2 run nav2_map_server map_saver_cli -f ~/maps/my_map \
--ros-args -p save_map_timeout:=10.0ros2 launch interface anibot_full.launch.py map:=$HOME/maps/my_map.yamlros2 run teleop_twist_keyboard teleop_twist_keyboard \
--ros-args -p speed:=0.21 -p turn:=0.43# On laptop β sets up ROS2 Domain 42, software OpenGL
./docker_jazzy.shMake sure
ROS_DOMAIN_ID=42is set on both RPi and laptop.
| Feature | Status |
|---|---|
| Differential drive control | β Working |
| Quadrature encoder odometry | β Working |
| RPLIDAR A1M8 integration | β Working |
| SLAM mapping (slam_toolbox) | β Working |
| Autonomous navigation (Nav2) | β Working |
| Map saving & reloading | β Working |
| Teleoperation | β Working |
| Docker RViz (laptop) | β Working |
| Wheel + Laser odom EKF fusion | π§ͺ Testing |
| IMU integration | π Planned |
| Autonomous docking | π Planned |
| Web monitoring dashboard | π Planned |
- Basic diff drive + encoder odometry
- LiDAR scan integration
- SLAM mapping
- Nav2 autonomous navigation
- Docker RViz remote visualization
- Sensor fusion: Wheel odom + Laser odom (EKF) β in progress
- IMU integration (MPU6050 or similar)
- Full 3-source EKF (wheel + laser + IMU)
- Dynamic obstacle avoidance tuning
- Web-based robot monitoring dashboard
- Autonomous charging dock return
- Multi-floor mapping
| Issue | Fix Applied |
|---|---|
| Left motor runs faster than right | left_scale=0.82 software compensation |
| Motors physically wired L/R swapped | swap_motors=True in odometry node |
| SLAM node crashes in ROS2 Jazzy | lifecycle_manager + bond_timeout: 0.0 |
| Motors stall at low PWM | PWM_MIN=70 deadband enforced |
| Arduino resets mid-session causing odom jump | Triple reset on startup + clean encoder state |
joint_state_publisher missing causing TF errors |
Added to launch file |
| AMCL not converging | Set 2D Pose Estimate manually in RViz first |
| Wheel base drift in turns | Calibrated to 0.355m via 360Β° spin test |
Currently a solo project β contributions not open yet. Once the sensor fusion and IMU integration are stable, I'll open issues for community input. Feel free to fork and experiment!
Omkarthik Dhudu
- GitHub: @Smokey8979
- LinkedIn: Omkarthik Dhudu
- Email: sdhudu@gmail.com
- ROS2 Community
- Nav2 Developers
- slam_toolbox
- robot_localization
- Open-source robotics ecosystem π
Built with too much coffee and not enough sleep β
