A real-time, cloud-connected autonomous robot fleet management system for precision agriculture.
5 rovers. Live telemetry. Firebase-driven task dispatch. Full Nav2 MPPI navigation.
| Fleet Dashboard | Live Navigation |
|---|---|
![]() |
![]() |
Rovers navigate autonomously to assigned field zones using ROS2 Nav2 MPPI controller, with real-time status streamed to a React dashboard via Firebase Firestore.
┌─────────────────────────────────────────────────────────────────┐
│ SYSTEM OVERVIEW │
│ │
│ ┌──────────────┐ ┌──────────────────────────────────────┐ │
│ │ Firebase │◄───│ React Dashboard │ │
│ │ Firestore │───►│ (Task Assignment + Live Telemetry) │ │
│ └──────┬───────┘ └──────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────┐ │
│ │ firebase_bridge (ROS2 Node) │ │
│ │ Firestore ↔ /fleet/assign_task ↔ /fleet/status │ │
│ └──────┬──────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────┐ │
│ │ fleet_manager (ROS2 Node) │ │
│ │ Task routing → NavigateToPose action → rover_N │ │
│ └──────┬──────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────┐ │
│ │ Nav2 Stack × 5 (one per rover) │ │
│ │ MPPI Controller → BT Navigator → Planner → Costmaps │ │
│ └──────┬──────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────┐ │
│ │ Gazebo Harmonic Simulation (Headless) │ │
│ │ 5× DiffDrive rovers │ LiDAR │ IMU │ Odometry │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
map ──[static]──► rover_N/odom ──[odom_to_tf]──► rover_N/base_footprint
│
[robot_state_publisher]
│
rover_N/base_link
rover_N/lidar_link
...
- 5 Autonomous Rovers — Independent Nav2 stacks with MPPI optimal trajectory following
- Real-Time Dashboard — React + TypeScript UI with live position, battery, and task status
- Firebase Integration — Firestore-driven task assignment with live telemetry streaming
- Sensor Simulation — Soil moisture, temperature, and crop health sensor simulator
- Battery Management — Automatic low-battery detection and return-to-charger navigation
- Multi-Robot TF — Fully isolated per-rover coordinate frames (
rover_N/odom,rover_N/base_footprint) - Clean WSL2 Support — Headless Gazebo, FastDDS UDP transport, staggered boot sequence
| Layer | Technology |
|---|---|
| Robot Middleware | ROS2 Jazzy |
| Simulation | Gazebo Harmonic |
| Navigation | Nav2 (MPPI Controller, NavFn Planner) |
| Robot Description | URDF / XACRO |
| Backend | Firebase Firestore + Auth Emulator |
| Frontend | React 18 + TypeScript + Vite |
| Communication | FastDDS (UDP transport) |
| OS | Ubuntu 24.04 (WSL2) |
- Windows 11 with WSL2 (Ubuntu 24.04 Noble)
- Node.js 18+ and npm
- Java 11+ (for Firebase Emulator)
# Install ROS2 Jazzy
sudo apt install ros-jazzy-desktop
# Install Nav2
sudo apt install ros-jazzy-nav2-bringup ros-jazzy-nav2-mppi-controller
# Install Gazebo Harmonic bridge
sudo apt install ros-jazzy-ros-gz-bridge ros-jazzy-ros-gz-sim
# Install additional ROS2 packages
sudo apt install ros-jazzy-slam-toolbox ros-jazzy-robot-state-publisher \
ros-jazzy-tf2-ros ros-jazzy-tf2-tools# Install globally
npm install -g firebase-tools
# Login
firebase logingit clone https://github.com/YOUR_USERNAME/agrofleet.git
cd agrofleet# Copy the ROS2 package into your workspace
mkdir -p ~/ros2_ws/src
cp -r ros2_package ~/ros2_ws/src/slam_fleet_sim
# Build
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash
colcon build --packages-select slam_fleet_sim
source install/setup.bash# Copy your Firebase credentials
cp your-firebase-credentials.json ~/ros2_ws/firebase-credentials.json
# Set up the dashboard Firebase config
cd dashboard
cp .env.example .env
# Edit .env with your Firebase project details
npm install# One command to start the entire system
bash ~/start_all.shThe script will:
- 🗄️ Start Firebase Emulator (Firestore + Auth)
- 🌍 Launch Gazebo simulation (headless)
- ⚙️ Generate per-rover Nav2 YAML configs with correct namespacing
- 🧭 Start Nav2 stacks for all 5 rovers (staggered to prevent DDS conflicts)
- 🌱 Launch sensor simulator
- 🤖 Start fleet manager
- 🔥 Connect Firebase bridge
Navigate to http://localhost:5173 in your browser.
agrofleet/
├── ros2_package/ # ROS2 package (slam_fleet_sim)
│ ├── slam_fleet_sim/ # Python nodes
│ │ ├── firebase_bridge.py # Firestore ↔ ROS2 bridge
│ │ ├── fleet_manager.py # Task routing + battery management
│ │ ├── odom_to_tf.py # Odometry → global /tf broadcaster
│ │ ├── empty_map_publisher.py # Static map for Nav2
│ │ └── sensor_simulator.py # Agricultural sensor data
│ ├── launch/
│ │ ├── simulation.launch.py # Gazebo + robot spawning + bridges
│ │ └── navigation.launch.py # Nav2 stack (per rover)
│ ├── config/
│ │ ├── nav2_params.yaml # MPPI controller + costmap config
│ │ └── slam_params.yaml # SLAM Toolbox config (legacy)
│ ├── urdf/
│ │ └── rover.urdf.xacro # Differential drive rover model
│ ├── worlds/
│ │ └── agricultural_field.sdf # 100×100m Gazebo world
│ ├── setup.py
│ └── package.xml
│
├── dashboard/ # React frontend
│ ├── src/
│ │ ├── components/ # UI components
│ │ ├── pages/ # Dashboard, Login, Register
│ │ ├── services/ # Firebase service layer
│ │ ├── hooks/ # Custom React hooks
│ │ └── contexts/ # Auth context
│ ├── firebase.json # Emulator configuration
│ └── firestore.rules # Security rules
│
├── start_all.sh # Master launch script
└── tf_tree_diagnostic.py # TF tree debugging utility
- Click on any rover in the Fleet Status panel
- Click + Task in the rover detail panel
- Select a task type (Crop Monitoring, Weeding, Soil Sampling, etc.)
- The rover will immediately begin navigating to the target coordinates
| Task | Target (x, y) |
|---|---|
| Crop Monitoring | (10, 10) |
| Weeding | (-10, 15) |
| Soil Sampling | (20, -10) |
| Irrigation | (-15, -20) |
| Pesticide Spray | (5, -25) |
- Rovers automatically return to the charging station at
(-45, -45)when battery drops below 20% - Charging rate: 0.2% per second
- Drain rate: 0.05% per second while moving
Each rover operates in its own isolated coordinate frame namespace:
rover_N/base_footprint— Robot body framerover_N/odom— Odometry frame (from Gazebo DiffDrive plugin)map— Global planning frame (shared, anchored via static transform)
The Critical Fix: TransformBroadcaster inside a namespaced ROS2 node publishes to /rover_N/tf instead of the global /tf. We bypass this by using a raw Publisher<TFMessage> on the absolute /tf topic.
Running 5 Nav2 stacks simultaneously in WSL2 causes FastDDS Shared Memory exhaustion. We enforce UDP-only transport via a custom fastdds.xml profile, eliminating "Failed init_port" SHM errors.
Each rover's Nav2 stack is launched with a 10-second delay between them. This gives FastDDS time to allocate UDP ports for the preceding rover's 10+ lifecycle nodes before the next rover attempts port allocation.
Nav2 parameters require frame IDs like robot_base_frame, global_frame, odom_topic. These are dynamically generated from the base nav2_params.yaml using sed with CRLF stripping (tr -d '\r') for Windows compatibility.
# Run the TF tree diagnostic
source /opt/ros/jazzy/setup.bash && source ~/ros2_ws/install/setup.bash
python3 ~/tf_tree_diagnostic.py rover_1Should show 🟢 TF TREE IS FULLY CONNECTED!
Nav2 lifecycle manager hasn't finished activating. Wait ~2 minutes after start_all.sh completes before assigning tasks.
# Check emulator is running
curl http://localhost:8080 # Firestore emulator
curl http://localhost:9099 # Auth emulator# Check display environment
export DISPLAY=:0
export WAYLAND_DISPLAY=wayland-0
gz sim --version# Clean shared memory on restart
rm -rf /dev/shm/*
# start_all.sh does this automatically| Topic | Type | Description |
|---|---|---|
/rover_N/odom |
nav_msgs/Odometry |
Rover odometry from Gazebo |
/rover_N/scan |
sensor_msgs/LaserScan |
LiDAR scan data |
/rover_N/cmd_vel |
geometry_msgs/Twist |
Velocity commands |
/fleet/assign_task |
std_msgs/String |
Task assignment JSON |
/fleet/status |
std_msgs/String |
Fleet telemetry JSON |
/fleet/sensor_data |
std_msgs/String |
Aggregated sensor readings |
/tf |
tf2_msgs/TFMessage |
Dynamic transforms |
/tf_static |
tf2_msgs/TFMessage |
Static transforms (map→odom) |
/clock |
rosgraph_msgs/Clock |
Simulation clock |
Built for SYNTHETIX 3.0 Hackathon @ VIT Chennai
MIT License — see LICENSE for details.

