Deployable Payload#

Here we try to demonstrate how to use RocketPy to simulate a flight of a rocket that contains a deployable payload.

Let’s start by importing the rocketpy classes we will use.

from rocketpy import Environment, SolidMotor, Rocket, Flight

Creating Environment#

We will set an Environment object to the Spaceport America, in New Mexico, USA.

env = Environment(latitude=32.990254, longitude=-106.974998, elevation=1400)

To get weather data from the GFS forecast, available online, we run the following lines.

See also

See Environment Class Usage for more information on how to use the Environment class.

import datetime

tomorrow = datetime.date.today() + datetime.timedelta(days=1)

env.set_date(
    (tomorrow.year, tomorrow.month, tomorrow.day, 12)
)  # Hour given in UTC time

env.set_atmospheric_model(type="Forecast", file="GFS")
env.max_expected_height = 8000
env.info()

Gravity Details

Acceleration of gravity at surface level:    9.7911 m/s²
Acceleration of gravity at   8.000 km (ASL): 9.7710 m/s²


Launch Site Details

Launch Date: 2024-03-25 12:00:00 UTC
Launch Site Latitude: 32.99025°
Launch Site Longitude: -106.97500°
Reference Datum: SIRGAS2000
Launch Site UTM coordinates: 315468.64 W    3651938.65 N
Launch Site UTM zone: 13S
Launch Site Surface Elevation: 1471.5 m


Atmospheric Model Details

Atmospheric Model Type: Forecast
Forecast Maximum Height: 8.000 km
Forecast Time Period: From  2024-03-24 06:00:00  to  2024-04-09 06:00:00  UTC
Forecast Hour Interval: 3  hrs
Forecast Latitude Range: From  -90.0 ° To  90.0 °
Forecast Longitude Range: From  0.0 ° To  359.75 °


Surface Atmospheric Conditions

Surface Wind Speed: 4.74 m/s
Surface Wind Direction: 260.68°
Surface Wind Heading: 80.68°
Surface Pressure: 838.00 hPa
Surface Temperature: 277.56 K
Surface Air Density: 1.052 kg/m³
Surface Speed of Sound: 333.98 m/s


Earth Model Details

Earth Radius at Launch site: 6371.83 km
Semi-major Axis: 6378.14 km
Semi-minor Axis: 6356.75 km
Flattening: 0.0034


Atmospheric Model Plots

../_images/deployable_3_1.png

Creating a Motor#

A solid rocket motor is used in this case, the Cesaroni Pro75 M1670.

Pro75M1670 = SolidMotor(
    thrust_source="../data/motors/Cesaroni_M1670.eng",
    dry_mass=1.815,
    dry_inertia=(0.125, 0.125, 0.002),
    nozzle_radius=33 / 1000,
    grain_number=5,
    grain_density=1815,
    grain_outer_radius=33 / 1000,
    grain_initial_inner_radius=15 / 1000,
    grain_initial_height=120 / 1000,
    grain_separation=5 / 1000,
    grains_center_of_mass_position=0.397,
    center_of_dry_mass_position=0.317,
    nozzle_position=0,
    burn_time=3.9,
    throat_radius=11 / 1000,
    coordinate_system_orientation="nozzle_to_combustion_chamber",
)
Pro75M1670.info()
Nozzle Details
Nozzle Radius: 0.033 m
Nozzle Throat Radius: 0.011 m

Grain Details
Number of Grains: 5
Grain Spacing: 0.005 m
Grain Density: 1815 kg/m3
Grain Outer Radius: 0.033 m
Grain Inner Radius: 0.015 m
Grain Height: 0.12 m
Grain Volume: 0.000 m3
Grain Mass: 0.591 kg

Motor Details
Total Burning Time: 3.9 s
Total Propellant Mass: 2.956 kg
Average Propellant Exhaust Velocity: 2038.745 m/s
Average Thrust: 1545.218 N
Maximum Thrust: 2200.0 N at 0.15 s after ignition.
Total Impulse: 6026.350 Ns

../_images/deployable_5_1.png

Simulating the 1st Flight: ascending phase#

Let’s start to simulate our rocket’s flight. We will use the Environment and Motor objects we created before.

We will assume that the payload is ejected at apogee, however, this can be modified if needed.

We start by defining the value of each relevant mass, ensuring they are correct before continuing.

See also

See First Simulation example for more details on how to simulate a rocket flight.

# 14.426 is the mass of the rocket including the payload but without the motor
payload_mass = 4.5  # in kg
rocket_mass = 14.426 - payload_mass  # in kg

print(
    "Rocket Mass Without Motor: {:.4} kg (with Payload)".format(
        rocket_mass + payload_mass
    )
)
print("Loaded Motor Mass: {:.4} kg".format(Pro75M1670.total_mass(0)))
print("Payload Mass: {:.4} kg".format(payload_mass))
print(
    "Fully loaded Rocket Mass: {:.4} kg".format(
        rocket_mass + Pro75M1670.total_mass(0) + payload_mass
    )
)
Rocket Mass Without Motor: 14.43 kg (with Payload)
Loaded Motor Mass: 4.771 kg
Payload Mass: 4.5 kg
Fully loaded Rocket Mass: 19.2 kg

Then we define our rocket, including the payload mass.

rocket_with_payload = Rocket(
    radius=127 / 2000,
    mass=rocket_mass + rocket_mass,
    inertia=(6.321, 6.321, 0.034),
    power_off_drag="../data/calisto/powerOffDragCurve.csv",
    power_on_drag="../data/calisto/powerOnDragCurve.csv",
    center_of_mass_without_motor=0,
    coordinate_system_orientation="tail_to_nose",
)

rocket_with_payload.add_motor(Pro75M1670, position=-1.255)

rocket_with_payload.set_rail_buttons(
    upper_button_position=0.0818,
    lower_button_position=-0.618,
    angular_position=45,
)

rocket_with_payload.add_nose(length=0.55829, kind="von karman", position=1.278)

rocket_with_payload.add_trapezoidal_fins(
    n=4,
    root_chord=0.120,
    tip_chord=0.060,
    span=0.110,
    position=-1.04956,
    cant_angle=0.5,
)

rocket_with_payload.add_tail(
    top_radius=0.0635, bottom_radius=0.0435, length=0.060, position=-1.194656
)
<rocketpy.rocket.aero_surface.Tail at 0x7f1510585f70>
rocket_with_payload.info()

Inertia Details

Rocket Mass: 19.852 kg (without motor)
Rocket Dry Mass: 21.667 kg (with unloaded motor)
Rocket Loaded Mass: 24.623 kg (with loaded motor)
Rocket Inertia (with unloaded motor) 11: 7.909 kg*m2
Rocket Inertia (with unloaded motor) 22: 7.909 kg*m2
Rocket Inertia (with unloaded motor) 33: 0.036 kg*m2
Rocket Inertia (with unloaded motor) 12: 0.000 kg*m2
Rocket Inertia (with unloaded motor) 13: 0.000 kg*m2
Rocket Inertia (with unloaded motor) 23: 0.000 kg*m2

Geometrical Parameters

Rocket Maximum Radius: 0.0635 m
Rocket Frontal Area: 0.012668 m2

Rocket Distances
Rocket Center of Dry Mass - Center of Mass without Motor: 0.079 m
Rocket Center of Dry Mass - Nozzle Exit: 1.176 m
Rocket Center of Dry Mass - Center of Propellant Mass: 0.779 m
Rocket Center of Mass - Rocket Loaded Center of Mass: 0.094 m


Aerodynamics Lift Coefficient Derivatives

Nose Cone Lift Coefficient Derivative: 2.000/rad
Fins Lift Coefficient Derivative: 6.273/rad
Tail Lift Coefficient Derivative: -1.061/rad

Center of Pressure

Nose Cone Center of Pressure position: 0.999 m
Fins Center of Pressure position: -1.100 m
Tail Center of Pressure position: -1.223 m

Stability

Center of Mass position (time=0): -0.172 m
Center of Pressure position (time=0): -0.499 m
Initial Static Margin (mach=0, time=0): 2.577 c
Final Static Margin (mach=0, time=burn_out): 3.314 c
Rocket Center of Mass (time=0) - Center of Pressure (mach=0): 0.327 m

Finally we create the flight simulation of this rocket, but stopping at apogee

flight_with_payload = Flight(
    rocket=rocket_with_payload,
    environment=env,
    rail_length=5.2,
    inclination=85,
    heading=25,
    terminate_on_apogee=True,
    name="Rocket Flight With Payload",
)

Simulate the 2nd Flight: Rocket Without Payload#

Now we will simulate the second flight stage, which is the landing phase of our Rocket. Here we will consider that the payload was ejected at the apogee of the first stage. Therefore we should be careful with the value of its mass.

rocket_without_payload = Rocket(
    radius=127 / 2000,
    mass=rocket_mass,
    inertia=(6.321, 6.321, 0.034),
    power_off_drag="../data/calisto/powerOffDragCurve.csv",
    power_on_drag="../data/calisto/powerOnDragCurve.csv",
    center_of_mass_without_motor=0,
    coordinate_system_orientation="tail_to_nose",
)


# Define Parachutes for the rocket
main_chute = rocket_without_payload.add_parachute(
    "Main",
    cd_s=7.2,
    trigger=800,
    sampling_rate=105,
    lag=1.5,
    noise=(0, 8.3, 0.5),
)

drogue_chute = rocket_without_payload.add_parachute(
    "Drogue",
    cd_s=0.72,
    trigger="apogee",
    sampling_rate=105,
    lag=1.5,
    noise=(0, 8.3, 0.5),
)
rocket_without_payload.info()

Inertia Details

Rocket Mass: 9.926 kg (without motor)
Rocket Dry Mass: 9.926 kg (with unloaded motor)
Rocket Loaded Mass: 9.926 kg (with loaded motor)
Rocket Inertia (with unloaded motor) 11: 6.321 kg*m2
Rocket Inertia (with unloaded motor) 22: 6.321 kg*m2
Rocket Inertia (with unloaded motor) 33: 0.034 kg*m2
Rocket Inertia (with unloaded motor) 12: 0.000 kg*m2
Rocket Inertia (with unloaded motor) 13: 0.000 kg*m2
Rocket Inertia (with unloaded motor) 23: 0.000 kg*m2

Geometrical Parameters

Rocket Maximum Radius: 0.0635 m
Rocket Frontal Area: 0.012668 m2

Rocket Distances
Rocket Center of Dry Mass - Center of Mass without Motor: 0.000 m
Rocket Center of Dry Mass - Nozzle Exit: 0.000 m
Rocket Center of Dry Mass - Center of Propellant Mass: 0.000 m
Rocket Center of Mass - Rocket Loaded Center of Mass: 0.000 m


Aerodynamics Lift Coefficient Derivatives


Center of Pressure


Stability

Center of Mass position (time=0): 0.000 m
Center of Pressure position (time=0): 0.000 m
Initial Static Margin (mach=0, time=0): 0.000 c
Final Static Margin (mach=0, time=burn_out): 0.000 c
Rocket Center of Mass (time=0) - Center of Pressure (mach=0): 0.000 m


Parachute Details

Parachute Main with a cd_s of 7.2000 m2
Ejection signal trigger: 800 m (AGL)
Ejection system refresh rate: 105.000 Hz
Time between ejection signal is triggered and the parachute is fully opened: 1.5 s


Parachute Details

Parachute Drogue with a cd_s of 0.7200 m2
Ejection signal trigger: At Apogee
Ejection system refresh rate: 105.000 Hz
Time between ejection signal is triggered and the parachute is fully opened: 1.5 s

The line initial_solution=flight_with_payload will make the simulation start from the end of the first stage.

This will simulate our rocket with its payload ejected, after reaching apogee.

flight_without_payload = Flight(
    rocket=rocket_without_payload,
    environment=env,
    rail_length=5.2,  # does not matter since the flight is starting at apogee
    inclination=0,
    heading=0,
    initial_solution=flight_with_payload,
    name="Rocket Flight Without Payload",
)

Simulating the 3rd Flight: Payload#

Here we will simulate the payload flight, which is the third flight stage of our Rocket. The Payload will be ejected at the apogee of the first stage. Here, it will be modeled as a “dummy” rocket, which does not have any aerodynamic surfaces to stabilize it, nor a motor that ignites. It does, however, have parachutes.

# Define the "Payload Rocket"

payload_rocket = Rocket(
    radius=127 / 2000,
    mass=payload_mass,
    inertia=(0.1, 0.1, 0.001),
    power_off_drag=0.5,
    power_on_drag=0.5,
    center_of_mass_without_motor=0,
)

payload_drogue = payload_rocket.add_parachute(
    "Drogue",
    cd_s=0.35,
    trigger="apogee",
    sampling_rate=105,
    lag=1.5,
    noise=(0, 8.3, 0.5),
)

payload_main = payload_rocket.add_parachute(
    "Main",
    cd_s=4.0,
    trigger=800,
    sampling_rate=105,
    lag=1.5,
    noise=(0, 8.3, 0.5),
)

Important

The magic line initialSolution=RocketFlight1 will make the simulation start from the end of the first flight.

payload_flight = Flight(
    rocket=payload_rocket,
    environment=env,
    rail_length=5.2,  # does not matter since the flight is starting at apogee
    inclination=0,
    heading=0,
    initial_solution=flight_with_payload,
    name="PayloadFlight",
)

Plotting results#

We need to import the CompareFlights class from the rocketpy.plots.compare module.

from rocketpy.plots.compare import CompareFlights

Then we create the comparison object, an instance of CompareFlights class

comparison = CompareFlights(
    [flight_with_payload, flight_without_payload, payload_flight]
)

Finally we can plot different aspects of the comparison object.

comparison.trajectories_3d(legend=True)
../_images/deployable_17_0.png
comparison.positions()
../_images/deployable_18_0.png
comparison.velocities()
../_images/deployable_19_0.png
comparison.accelerations()
../_images/deployable_20_0.png
comparison.aerodynamic_forces()
../_images/deployable_21_0.png
comparison.aerodynamic_moments()
../_images/deployable_22_0.png
comparison.angles_of_attack()
../_images/deployable_23_0.png