RocketPy supports advanced parachute deployment logic using acceleration data from simulated IMU (Inertial Measurement Unit) sensors. This enables realistic avionics algorithms that mimic real-world flight computers.
Traditional parachute triggers rely on altitude and velocity. Acceleration-based triggers provide additional capabilities:
- Motor burnout detection: Detect thrust termination via sudden deceleration
- Apogee detection: Use acceleration and velocity together for precise apogee
- Freefall detection: Identify ballistic coasting phases
- Liftoff detection: Confirm motor ignition via high acceleration
These triggers can optionally include sensor noise to simulate realistic IMU behavior, making simulations more representative of actual flight conditions.
RocketPy provides four built-in acceleration-based triggers:
Detects when the motor stops producing thrust by monitoring sudden drops in acceleration magnitude.
from rocketpy import Parachute
drogue = Parachute(
name="Drogue",
cd_s=1.0,
trigger="burnout", # Built-in trigger
sampling_rate=100,
lag=1.5
)Detection criteria: - Vertical acceleration < -8.0 m/s² (end of thrust phase), OR - Total acceleration magnitude < 2.0 m/s² (coasting detected) - Rocket must be above 5m altitude and ascending (prevents false triggers at launch)
Detects apogee using both near-zero vertical velocity and negative vertical acceleration.
main = Parachute(
name="Main",
cd_s=10.0,
trigger="apogee_acc", # Acceleration-based apogee
sampling_rate=100,
lag=0.5
)Detection criteria: - Absolute vertical velocity < 1.0 m/s - Vertical acceleration < -0.1 m/s² (downward)
Detects free-fall by monitoring very low total acceleration (near gravitational acceleration only).
drogue = Parachute(
name="Drogue",
cd_s=1.0,
trigger="freefall",
sampling_rate=100,
lag=1.0
)Detection criteria: - Total acceleration magnitude < 11.5 m/s² - Rocket descending (vz < -0.2 m/s) - Altitude > 5m (prevents ground-level false triggers)
Detects motor ignition via high total acceleration.
test_parachute = Parachute(
name="Test",
cd_s=0.5,
trigger="liftoff",
sampling_rate=100,
lag=0.0
)Detection criteria: - Total acceleration magnitude > 15.0 m/s²
You can create custom triggers that use acceleration data:
def custom_trigger(pressure, height, state_vector, u_dot):
"""
Custom trigger using acceleration data.
Parameters
----------
pressure : float
Atmospheric pressure in Pa (with optional noise)
height : float
Height above ground level in meters (with optional noise)
state_vector : array
[x, y, z, vx, vy, vz, e0, e1, e2, e3, wx, wy, wz]
u_dot : array
Derivative: [vx, vy, vz, ax, ay, az, e0_dot, ...]
Accelerations are at indices [3:6]
Returns
-------
bool
True to trigger parachute deployment
"""
# Extract acceleration components (m/s²)
ax = u_dot[3]
ay = u_dot[4]
az = u_dot[5]
# Calculate total acceleration magnitude
total_acc = (ax**2 + ay**2 + az**2)**0.5
# Custom logic: deploy if total acceleration < 5 m/s² while descending
vz = state_vector[5]
return total_acc < 5.0 and vz < -10.0
# Use custom trigger
parachute = Parachute(
name="Custom",
cd_s=2.0,
trigger=custom_trigger,
sampling_rate=100,
lag=1.0
)Triggers can also accept sensor data alongside acceleration:
def advanced_trigger(pressure, height, state_vector, sensors, u_dot):
"""
Advanced trigger using both sensors and acceleration.
Parameters
----------
sensors : list
List of sensor objects attached to the rocket
u_dot : array
State derivative including accelerations
Returns
-------
bool
"""
# Access sensor measurements
if len(sensors) > 0:
imu_reading = sensors[0].measurement
# Use acceleration data
az = u_dot[5]
# Combine sensor and acceleration logic
return az < -5.0 and imu_reading > threshold
parachute = Parachute(
name="Advanced",
cd_s=1.5,
trigger=advanced_trigger,
sampling_rate=100
)To simulate realistic IMU behavior, you can add noise to acceleration data:
from rocketpy import Flight
flight = Flight(
rocket=my_rocket,
environment=env,
rail_length=5.2,
inclination=85,
heading=0,
acceleration_noise_function=lambda: np.random.normal(0, 0.5, 3)
)The acceleration_noise_function returns a 3-element array [noise_x, noise_y, noise_z]
that is added to the acceleration components before passing to the trigger function.
Example with time-correlated noise:
class NoiseGenerator:
def __init__(self, stddev=0.5, correlation=0.9):
self.stddev = stddev
self.correlation = correlation
self.last_noise = np.zeros(3)
def __call__(self):
# Time-correlated noise (AR(1) process)
white_noise = np.random.normal(0, self.stddev, 3)
self.last_noise = (self.correlation * self.last_noise +
np.sqrt(1 - self.correlation**2) * white_noise)
return self.last_noise
flight = Flight(
rocket=my_rocket,
environment=env,
rail_length=5.2,
inclination=85,
heading=0,
acceleration_noise_function=NoiseGenerator(stddev=0.3, correlation=0.95)
)Computing acceleration (u_dot) requires evaluating the equations of motion,
which adds computational cost. RocketPy optimizes this by:
- Lazy evaluation:
u_dotis only computed if the trigger actually needs it - Metadata detection: The wrapper inspects trigger signatures to determine requirements
- Caching: Derivative evaluations are reused when possible
Trigger signature detection:
- 3 parameters
(p, h, y): Legacy trigger, nou_dotcomputed - 4 parameters with
u_dot: Only acceleration computed - 4 parameters with
sensors: Only sensors passed - 5 parameters: Both sensors and acceleration provided
- Choose appropriate sampling rates: 50-200 Hz is typical for flight computers
- Add realistic noise: Real IMUs have noise; simulate it for validation
- Test edge cases: Verify triggers work at low altitudes, high speeds, etc.
- Use built-in triggers: They handle edge cases (NaN, Inf) automatically
- Document custom triggers: Include detection criteria in docstrings
from rocketpy import Rocket, Parachute, Flight, Environment
import numpy as np
# Environment and rocket setup
env = Environment(latitude=32.99, longitude=-106.97, elevation=1400)
env.set_atmospheric_model(type="standard_atmosphere")
my_rocket = Rocket(...) # Define your rocket
# Drogue parachute: Deploy at motor burnout
drogue = Parachute(
name="Drogue",
cd_s=1.0,
trigger="burnout",
sampling_rate=100,
lag=1.5,
noise=(0, 8.3, 0.5) # Pressure sensor noise
)
my_rocket.add_parachute(drogue)
# Main parachute: Deploy at 800m using custom trigger
def main_deploy_trigger(pressure, height, state_vector, u_dot):
"""Deploy main at 800m while descending with positive vertical acceleration."""
vz = state_vector[5]
az = u_dot[5]
return height < 800 and vz < -5 and az > -15
main = Parachute(
name="Main",
cd_s=10.0,
trigger=main_deploy_trigger,
sampling_rate=100,
lag=0.5,
noise=(0, 8.3, 0.5)
)
my_rocket.add_parachute(main)
# Flight with IMU noise simulation
flight = Flight(
rocket=my_rocket,
environment=env,
rail_length=5.2,
inclination=85,
heading=0,
acceleration_noise_function=lambda: np.random.normal(0, 0.3, 3)
)
flight.all_info()