Enh/acceleration data to trigger parachutes
Pull Request: Add Acceleration-Based Parachute Triggers with IMU Sensor Simulation
Pull request type
- [x] Code changes (features)
- [x] Code maintenance (refactoring, tests)
Checklist
- [x] Tests for the changes have been added (if needed)
- [x] Docs have been reviewed and added / updated
- [x] Lint (
black rocketpy/ tests/) has passed locally - [x] All tests (
pytest tests -m slow --runslow) have passed locally - [ ] CHANGELOG.md has been updated (if relevant)
Current behavior
Currently, RocketPy forces users to trigger parachute deployment based on state variables (altitude z, vertical velocity vz) or pressure. This simulates "God Mode" avionics rather than realistic flight computer behavior.
Real-world rocket avionics (flight computers) trigger events based on accelerometer data (IMU):
- Liftoff detection: High positive acceleration
- Burnout detection: Sudden drop in acceleration
- Apogee detection: Zero velocity (integrated from acceleration)
Users had no way to access acceleration (u_dot) inside trigger functions, making it impossible to simulate realistic avionics algorithms.
Related Issue: RocketPy#156
New behavior
This PR introduces acceleration-based parachute triggers with the following features:
1. Acceleration Data Access in Triggers
Parachute trigger functions now optionally receive acceleration data (u_dot):
# Legacy signature (still supported)
def legacy_trigger(pressure, height, state_vector):
return state_vector[5] < 0 # vz < 0
# New signature with acceleration
def acceleration_trigger(pressure, height, state_vector, u_dot):
ax, ay, az = u_dot[3], u_dot[4], u_dot[5]
return az < -0.5 # descending with negative acceleration
2. Built-in Acceleration-Based Triggers
New triggers on rocketpy/rocket/parachute.py provides realistic avionics functions:
detect_apogee_acceleration: Detects apogee when vertical velocity ≈ 0 AND acceleration becomes negativedetect_motor_burnout: Detects motor shutdown by sudden acceleration dropdetect_freefall: Detects free-fall condition (total acceleration < 1.5 m/s²)detect_liftoff: Detects liftoff by high total acceleration (> 15 m/s²)
Usage:
from rocketpy import Parachute
main_parachute = Parachute(
name="Main",
cd_s=1.5,
trigger="apogee_acc", # Uses detect_apogee_acceleration
sampling_rate=105,
)
3. Optional IMU Sensor Noise Simulation
New parameter acceleration_noise_function in Flight.__init__ allows simulating realistic accelerometer noise:
import numpy as np
def accelerometer_noise():
"""Simulate MEMS accelerometer noise (~0.2 m/s² std dev)."""
return np.random.normal(0, 0.2, size=3)
flight = Flight(
rocket=rocket,
environment=environment,
acceleration_noise_function=accelerometer_noise,
)
4. Performance Optimization
The Flight class automatically detects trigger signatures:
- If trigger accepts
u_dotparameter → computes acceleration at event checks - If trigger only accepts state variables → skips acceleration computation (preserves performance)
5. Full Backward Compatibility
- Existing altitude-based triggers (
trigger=300) continue working - Legacy 3-parameter trigger functions remain supported
- No breaking changes to public API
Technical Details
Implementation Changes
-
rocketpy/rocket/parachute.py- Four built-in acceleration-based trigger functions
- Factory function for custom altitude triggers
- Defensive programming: checks for invalid/NaN values
__evaluate_trigger_function()now wraps triggers with signature detection- Wrapper sets
_expects_udotattribute for Flight optimization - Mapping for string triggers:
"apogee","burnout","freefall","liftoff"
-
flight.py
_evaluate_parachute_trigger()now computesu_dotwhen needed- Injects accelerometer noise before passing to trigger
- Fallback to sensors if computation fails (robustness)
- New parameter:
acceleration_noise_function
Tests Added
test_parachute_triggers.py
test_trigger_receives_u_dot_and_noise: Validates acceleration computation and noise injectiontest_trigger_with_u_dot_only: Tests acceleration-only triggerstest_legacy_trigger_does_not_compute_u_dot: Ensures performance optimization works
Trade-offs and Considerations
Performance Impact
- Trade-off: Calculating
u_dotat event points doubles physics evaluations locally - Mitigation: Only computed when trigger signature requires it (automatic detection)
- Benefit: Essential for realistic avionics simulation; minimal impact for altitude-based triggers
Coordinate System
- Acceleration components in
u_dot[3:6]follow state vector convention:[ax, ay, az] - Coordinate system matches Flight class definition (East, North, Up)
- Documented in trigger function docstrings
Breaking change
- [x] No
- [ ] Yes (describe below)
Additional information
Examples of Usage
Realistic apogee detection:
main = Parachute(
name="Main",
cd_s=1.5,
trigger="apogee_acc", # Acceleration-based apogee detection
sampling_rate=105,
)
Simulating sensor noise:
flight = Flight(
rocket=rocket,
environment=environment,
acceleration_noise_function=lambda: np.random.normal(0, 0.2, 3),
)
Custom acceleration trigger:
def my_trigger(pressure, height, state_vector, u_dot):
ax, ay, az = u_dot[3], u_dot[4], u_dot[5]
total_acc = np.linalg.norm([ax, ay, az])
return total_acc < 1.0 # Deploy when near free-fall
parachute = Parachute(name="Custom", cd_s=1.0, trigger=my_trigger)
Testing Performed
- ✅ Unit tests for all trigger functions
- ✅ Integration tests with Flight simulation
- ✅ Backward compatibility with legacy triggers
- ✅ Performance optimization validation
- ✅ Edge case handling (NaN/Inf prevention)
Documentation Notes
- All trigger functions follow NumPy docstring style
- Physical units documented (m/s², m/s, etc.)
- Examples included in function docstrings
- API documented in Flight and Parachute classes
Fixed the linting/test errors reported by the CI workflow in the latest commit.
@ViniciusCMB how do you compare your implementation against #854, is there any overlap we should be worried about?
Codecov Report
:x: Patch coverage is 75.47170% with 39 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 81.01%. Comparing base (9cf3dd4) to head (5619b3a).
:warning: Report is 24 commits behind head on develop.
| Files with missing lines | Patch % | Lines |
|---|---|---|
| rocketpy/rocket/parachute.py | 72.22% | 35 Missing :warning: |
| rocketpy/simulation/flight.py | 87.87% | 4 Missing :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## develop #911 +/- ##
===========================================
+ Coverage 80.27% 81.01% +0.74%
===========================================
Files 104 107 +3
Lines 12769 13957 +1188
===========================================
+ Hits 10250 11307 +1057
- Misses 2519 2650 +131
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
@ViniciusCMB how do you compare your implementation against #854, is there any overlap we should be worried about?
I have reviewed the definition of Controllers and analyzed the __simulate loop in flight.py.
My Conclusion: While Controllers allow for dynamic logic, the RocketPy simulation engine iterates over them in separate loops:
- Parachutes loop: Iterates over node.parachutes (where I injected u_dot).
- Controllers loop: Iterates over node._controllers (where #854 injects environment).
Impact Assessment:
- Logical Conflict: None. Standard Parachute objects are not instances of Controllers in this context, so the changes do not overlap in logic.
- Textual Conflict: Likely. Since these loops are adjacent in flight.py, git will probably flag a merge conflict, but it should be trivial to resolve.
However, since both modify the critical __simulate method and #854 involves significant changes to the Controller architecture (10 files), I cannot guarantee zero friction without running an integration test merging both branches.
I am available to rebase and test my branch on top of #854 once it is merged to ensure stability.
@ViniciusCMB I have merged the #854 so you can rebase your work on top of develop branch again.
Pls fix conflicts and linters so we can proceed with the review.