Multi-purpose quadcopter control stack with:
- ROS 2 control + safety pipeline (hardware + Gazebo Sim / fast sim)
- Standalone Python simulator (no ROS) for fast iteration on planners/controllers
- ESP32 TX/RX link for manual flight + autonomous command relay
- Controllers
- ROS 2: PID / LQR / MPC (work-in-progress depending on package)
- Python-only (
sim_py): PID / LQR / MPC position controllers + Matplotlib teleop
- Path planning (Python-only): straight / A* / RRT planners
- Terrain generation: forest / mountains / plains (shared between ROS and Python sim)
- Safety: validation, limiting, watchdog (
safety_gate) - Hardware link: CRSF adapter + ESP-NOW based TX/RX + protocol bridging
Manual Flight
TX (IMU+Joystick) -> ESP-NOW -> RX -> Protocol Bridge -> Flight Controller
(CRSF/SBUS/PPM/iBus/FrSky)
Autonomous (Hardware-in-the-loop)
ROS Controllers -> Safety Gate -> CRSF Adapter -> UDP -> TX -> ESP-NOW -> RX -> Protocol -> FC
Simulation
- ROS 2 (Gazebo / fast sim):
Ground Station / Air Unit -> sim_bridge -> Gazebo Sim (or sim_fast)
- Python-only (no ROS):
Planner -> Controller -> Dynamics backend (pointmass/rotorpy) -> Matplotlib 3D
./scripts/setup_sim_py_venv.sh
source sim_py/.venv/bin/activate
python -m sim_py.run_simOptional RotorPy backend:
./scripts/setup_sim_py_venv.sh --with-rotorpy
source sim_py/.venv/bin/activate
python -m sim_py.run_sim --backend rotorpyUseful overrides:
# Switch controller
python -m sim_py.run_sim --controller mpc
# Change terrain type (still uses the terrain config YAML unless overridden)
python -m sim_py.run_sim --terrain forest
# Override sim time / dt (if you pass these, they override sim_config.yaml)
python -m sim_py.run_sim --sim-time 240 --dt 0.01
# Use a different terrain config file
python -m sim_py.run_sim --terrain-config ros2_ws/src/terrain_generator/config/terrain_params.yaml
# Select dynamics backend (default: pointmass)
python -m sim_py.run_sim --backend rotorpy
# Interactive teleop (Matplotlib, best with RotorPy backend)
python -m sim_py.run_sim --controller teleop --backend rotorpy --terrain forestsim_py now includes an interactive teleop mode for quick manual flying in the Matplotlib 3D viewer.
- Launch:
python -m sim_py.run_sim --controller teleop --backend rotorpy - Controls (focus the plot window first):
W/S: +/- XA/D: +/- YR/F: +/- ZP: pause/resumeEsc: close
Teleop is acceleration-command based and works best with the RotorPy backend.
-
Main config:
sim_py/sim_config.yaml- Start/goal:
path.start_relative_*,path.end_relative_*end_relative_z: "auto"picks a random goal altitude in ([0, \text{tallest tree}])
- Planner:
path.planner_type=straight|astar|rrt|rrt* - Runtime:
controller.sim_time,controller.dt - Backend:
simulation.backend=pointmass|rotorpy(CLI--backendoverrides) - Terrain appearance / scaling:
visual.forest_density_scale: scales forest density (clamped to 1.0)visual.tree_height_scale: scales sampled tree heightsvisual.height_ratio: sets map height asheight_ratio * tallest_treevisual.tree_radius_ref: reference radius for drawing thicker/thinner trunks
- Start/goal:
-
Terrain config (shared with ROS):
ros2_ws/src/terrain_generator/config/terrain_params.yaml- Forest obstacle count is mainly set by:
forest.grid_sizeandforest.density- expected trees ~= (grid_size^2 \cdot density)
The rebuilt Gazebo + ground-station / air-unit stack now lives in ros2_ws.
- Workspace docs / runbook:
ros2_ws/README.md - Primary sim bringup:
ros2 launch sim_gazebo bringup.launch.py - Ground station bringup:
ros2 launch ground_station ground.launch.py
cd ros2_ws
colcon build --symlink-install
source install/setup.bashros2 launch sim_gazebo bringup.launch.py
ros2 launch ground_station ground.launch.py
# Fast headless backend
ros2 launch sim_fast bringup.launch.pyFor the current tested Gazebo + terrain + planner demo commands (including dense forest and path visualization), use:
ros2_ws/README.md->Recommended Test Flows (Current)
The old RViz/controller prototype workspace was replaced during consolidation.
If you still need the legacy PID/LQR/MPC ROS2 stack, recover it from git history.
Current ROS2 workflows are documented in ros2_ws/README.md.
Dockerfiles are split by workflow:
- ROS 2 Humble:
docker/Dockerfile.humble - Python simulator/tools:
docker/Dockerfile.sim - Firmware tooling (PlatformIO):
docker/Dockerfile.firmware
Build and run:
# ROS 2 image
docker build -f docker/Dockerfile.humble --target ros-dev -t uav-controller:ros-humble .
docker run --rm -it --network=host --privileged -v "$PWD":/workspace uav-controller:ros-humble
# sim_py + Python tools image
docker build -f docker/Dockerfile.sim -t uav-controller:sim .
docker run --rm -it -v "$PWD":/workspace uav-controller:sim
# firmware / PlatformIO image
docker build -f docker/Dockerfile.firmware -t uav-controller:firmware .
docker run --rm -it -v "$PWD":/workspace uav-controller:firmwareMore details: docker/README.md.
The gps/ project is an ESP32 GPS bring-up/telemetry module using Adafruit_GPS.
- Supports PMTK/NMEA modules (Adafruit Ultimate GPS / MTK33xx style)
- Supports u-blox modules with UBX configuration (while parsing NMEA output)
- Auto-probes common UART baud rates (9600/38400/115200), parses fix/satellite/SNR metrics, and prints diagnostics over serial
- Build/flash protocol options:
pio run -d gps -e gps_auto -t upload(AUTO detect PMTK vs UBLOX)pio run -d gps -e gps_pmtk -t upload(force PMTK mode)pio run -d gps -e gps_ublox -t upload(force UBLOX mode)
| Path | Type | Purpose |
|---|---|---|
ros2_ws/src/air_unit |
Python | Air-side command manager / mission executor / telemetry adapter |
ros2_ws/src/ground_station |
Python | CLI, monitor, and demo mission tools |
ros2_ws/src/planner |
Python | ROS2 planner service wrapper for sim_py planners |
ros2_ws/src/sim_bridge |
Python | Backend adapters (Gazebo / fast sim) |
ros2_ws/src/sim_fast |
Python | Headless simulation bringup |
ros2_ws/src/sim_gazebo |
Python | Gazebo Sim bringup and assets |
ros2_ws/src/px4_bridge |
Python | PX4 bridge scaffolding |
ros2_ws/src/uav_algorithms |
Python | Shared algorithms / planning API helpers |
ros2_ws/src/drone_msgs |
ROS msgs/srvs | Command, telemetry, mission, planner interfaces |
ros2_ws/src/terrain_generator |
Python | Terrain + obstacles (forest/mountains/plains) |
sim_py |
Python | Standalone planner/controller/dynamics/visualization |
ESPNOW_TX |
ESP32 | ESP-NOW based TX/RX firmware |
LoRa_TX |
ESP32 | LoRa TX experiments |
gps |
ESP32 | GPS telemetry module (Adafruit_GPS / NMEA + PMTK + UBX support) |
Utils |
Python | Protocol decoder/monitor + tools |
The current ROS2 Gazebo/fast-sim stack uses the /uav/... namespace by default.
/uav/command(drone_msgs/msg/Command)/uav/mission(drone_msgs/msg/Trajectory)/uav/telemetry(drone_msgs/msg/Telemetry)/uav/mission_status(drone_msgs/msg/MissionStatus)/uav/backend/cmd_twist(geometry_msgs/msg/Twist)/uav/backend/enable(std_msgs/msg/Bool)/uav/backend/odom(nav_msgs/msg/Odometry)/uav/backend/telemetry_raw(drone_msgs/msg/Telemetry)
Gazebo bridged topics:
/model/x3/odometry/X3/gazebo/command/twist/X3/enable
See ros2_ws/README.md for the full topic/node diagram and troubleshooting notes.
- docs/SOFTWARE_GUIDE.md: software guide (start here)
- docs/EXAMPLE_USAGE.md: terrain + controller examples
sim_py/INFO.md: standalone simulator architecture + usagedocker/README.md: Docker build/run commands by workflowdocs/HARDWARE.md: TX integration for autonomous modeESPNOW_TX/README.md: TX/RX firmware detailsgps/DASHBOARD.md: GPS serial dashboard usageUtils/README.md: protocol monitor / decoder tooling
- ROS 2 Humble is required for ROS-based control + RViz simulation
- The Python-only sim (
sim_py) is designed for fast iteration (no ROS needed)
Test brushed quad with the custom TX/RX.





