Contents
- Overview and scope
- Repository layout
- System architecture
- Quick start (env, install, run)
- Full simulation workflow
- SCRBE static pipeline
- Fuzzer and visual analytics
- Data products and locations
- Tests and quality checks
- Intentional bug: emergency deployment gated by altitude
- Creating missions
This project implements:
- A modular drone simulation with PyBullet dynamics, mission execution, telemetry logging, and Matplotlib-based visualization.
- A structure- and component-preserving reduced pipeline (SCRBE) for fast, static-state analyses of emergency deployment logic.
- An STL-guided, Hypothesis-powered fuzzer that explores battery/altitude and controller parameters to falsify a safety property.
The systems are intentionally instrumented for message logging and trace capture to enable reproducible experiments and visual analysis.
- core/: Drone internals
- messaging.py: topic-based in-process message bus with CSV logging
- physics_engine.py: PyBullet wrapper
- drone.py: integrates physics, controllers, and state publication
- controllers/: flight, mission, parachute, emergency, sensors, actuators
- sensors/: battery, GPS, IMU models
- actuators/: parachute actuator
- simulation/: Orchestration, logging, and interactive visualizer
- simulator.py, flight_logger.py, visualizer.py
- scrbe/: Reduced pipeline (static state), CLI, and docs
- src/pipeline.py, run_simulation.py, config/scrbe_config.json
- scrbe_fuzzer/: Fuzzer, harness, oracle, metrics, and visualization suite
- run_fuzz.py, results/, visualize/**
- config/: Simulation configs (drone, battery, gps, imu, physics, simulation)
- missions/: Example mission JSONs
- data/: Default full-simulation flight log (CSV)
- tests/: Unit/integration tests
The simulation system composes the simulator, the drone and its controllers/sensors/actuators, a message broker, and output components (logger and visualizer).
flowchart LR
%% Styling
classDef simulator fill:#d4f1f9,stroke:#05728f,stroke-width:1px,color:#05728f,rounded
classDef logger fill:#d5e8d4,stroke:#82b366,stroke-width:1px,color:#3d602e,rounded
classDef controller fill:#fff2cc,stroke:#d6b656,stroke-width:1px,color:#7d5f15,rounded
classDef sensor fill:#e1d5e7,stroke:#9673a6,stroke-width:1px,color:#5e3973,rounded
classDef actuator fill:#ffcccc,stroke:#cc6666,stroke-width:1px,color:#994c4c,rounded
classDef drone fill:#f8cecc,stroke:#b85450,stroke-width:1px,color:#8a2b23,rounded
classDef broker fill:#dae8fc,stroke:#6c8ebf,stroke-width:1px,color:#314b73,rounded
%% Main components
Simulator[Simulator]:::simulator
subgraph OutputComponents["Output Components"]
FlightLogger[Flight Logger]:::logger
Visualizer[Visualizer]:::logger
end
subgraph DroneSystem["Drone System"]
Drone[Drone]:::drone
subgraph Controllers["Controllers"]
MissionController[Mission Controller]:::controller
FlightController[Flight Controller]:::controller
SensorController[Sensor Controller]:::controller
ActuatorController[Actuator Controller]:::controller
ParachuteController[Parachute Controller]:::controller
EmergencyController[Emergency Controller]:::controller
end
subgraph Sensors["Sensors"]
GPS[GPS]:::sensor
IMU[IMU]:::sensor
Battery[Battery]:::sensor
end
subgraph Actuators["Actuators"]
ParachuteActuator[Parachute Actuator]:::actuator
end
MessageBroker[Message Broker]:::broker
end
%% Connections
Simulator --> Drone
Simulator --> FlightLogger
Simulator --> Visualizer
Drone --> MissionController
Drone --> FlightController
Drone --> SensorController
Drone --> ActuatorController
Drone --> ParachuteController
Drone --> EmergencyController
SensorController --> GPS
SensorController --> IMU
SensorController --> Battery
ParachuteController --> ParachuteActuator
%% All components connect to message broker
MessageBroker <--> Drone
MessageBroker <--> MissionController
MessageBroker <--> FlightController
MessageBroker <--> SensorController
MessageBroker <--> ActuatorController
MessageBroker <--> ParachuteController
MessageBroker <--> EmergencyController
MessageBroker <--> FlightLogger
%% Add description
style OutputComponents fill:none,stroke:none
style DroneSystem fill:none,stroke:none
style Controllers fill:none,stroke:none
style Sensors fill:none,stroke:none
style Actuators fill:none,stroke:none
Code pointers:
- Simulator, logger, visualizer: simulation/ (
simulator.py,flight_logger.py,visualizer.py) - Drone and message broker: core/ (
drone.py,messaging.py) - Controllers: core/controllers/
- Sensors: core/sensors/
- Actuators: core/actuators/
The commands below assume macOS/Linux with zsh; adapt to your shell as needed.
# 1) Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 2) Install base requirements (simulation + visualizer)
pip install -r requirements.txt
# 3) (Optional, for fuzzing) Install fuzzer extras
pip install -r scrbe_fuzzer/requirements.txtRun a mission end-to-end (physics + controllers + logging + interactive viz):
source .venv/bin/activate
python run_simulation.py --mission missions/sample_mission.jsonArtifacts:
- Flight log:
data/flight_log.csv - Interactive plots open automatically at the end.
Visualize an existing log without re-running physics:
source .venv/bin/activate
python run_simulation.py --visualize-only --log-file data/flight_log.csvRun a reduced, static-state analysis at a fixed battery and altitude:
source .venv/bin/activate
python run_scrbe_simulation.py --battery 10.0 --altitude 70.0 --logOutputs (example):
- Message bus log:
log/scrbe_run_YYYYMMDD_HHMMSS/message_bus.csv - Flight trace:
scrbe/flight_record/scrbe_run_YYYYMMDD_HHMMSS.csv
The CLI validates inputs and config schema (scrbe/config/scrbe_config.json).
See also: scrbe/README.md and scrbe/docs/message_logging.md.
The fuzzer explores battery/altitude and (optionally) controller parameters to falsify an STL safety property.
Run a bounded session and generate figures:
source .venv/bin/activate
python scrbe_fuzzer/run_fuzz.py --runs 20 --visualResults go to a timestamped directory, e.g. scrbe_fuzzer/results/session_20251029_124816/:
violations.csv: tabular summary of runsviolations/: per-run JSONs for violationssummary.json: counts and ratesvisual/: publication-ready figures (PNG/SVG)
Re-generate visuals for an existing session:
source .venv/bin/activate
python -m scrbe_fuzzer.visualize --input scrbe_fuzzer/results/session_20250421_002920/violations.csvExample figure (state vs limits) from a real session:
See also: scrbe_fuzzer/README.md and scrbe_fuzzer/visualize/README.md.
- Full simulation
data/flight_log.csv(wide CSV: state, targets, battery, modes)
- SCRBE
log/<log_id>/message_bus.csv(origin, topic, payload)scrbe/flight_record/<log_id>.csv(battery, altitude, mode, deployed flags)
- Fuzzer
scrbe_fuzzer/results/session_*/violations.csvscrbe_fuzzer/results/session_*/violations/*.jsonscrbe_fuzzer/results/session_*/visual/*.png|*.svg
source .venv/bin/activate
pytest -qKey tests include sensors/physics/controller behavior and the intentional emergency-controller constraint.
There are two parachute deployment paths in this repository:
- Manual deploy via mission command
- Trigger: mission action
DEPLOY_PARACHUTE(or publishing toparachute/deploy). - Flow: MissionController → ParachuteController → ParachuteActuator.
- Behavior: The actuator’s
deploy()currently deploys at any altitude and does not enforcemin_deploy_altitude/max_deploy_altitude(keys exist in config but aren’t checked incore/actuators/parachute_actuator.py).
- Emergency deploy on low battery (intentional flaw)
- Trigger: Battery status becomes LOW at or below the configured threshold.
- Flow: EmergencyController monitors battery and altitude; if LOW, it is supposed to deploy.
- Intentional bug: The EmergencyController requires altitude ≥
min_deploy_altitudebefore publishing a deploy command, withholding deployment at low altitudes even in an emergency. Seecore/controllers/emergency_controller.py.
Property under test and expected violations
- Intended safety property (used by the SCRBE checker and fuzzer): “If battery is low while airborne, deploy the parachute within Δ.”
- Because of the intentional gating, runs where the battery becomes LOW below
min_deploy_altitudewill violate this property. The visualization suite highlights this region.
References and code pointers
- Formal statement and rationale: formalization.md
- Emergency controller notes: core/controllers/README_emergency_controller.md
- Manual deployment path: core/controllers/parachute_controller.py, core/actuators/parachute_actuator.py
Missions are JSON arrays of steps. Each step includes an action and, when relevant, a waypoint as [x, y, z] in meters.
Example:
[
{"action": "TAKE_OFF", "waypoint": [0, 0, 10]},
{"action": "GOTO", "waypoint": [10, 0, 10]},
{"action": "GOTO", "waypoint": [10, 10, 10]},
{"action": "LAND"}
]Supported actions:
TAKE_OFF: ascend to the specifiedwaypointaltitude (x/y used as target as well)GOTO: move to the specifiedwaypoint[x, y, z]LAND: land at the current x/y position (z will be set to 0 internally)DEPLOY_PARACHUTE: request parachute deployment at the current position
Notes:
- Unknown actions are logged and skipped. See
core/controllers/mission_controller.pyfor exact behavior.
For emergency deployment behavior, see Intentional bug: emergency deployment gated by altitude.
See also:
- Example missions in
missions/includingsample_mission.jsonandparachute_test_mission.json
