Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c919c2c
Add actuator dynamics in TVC and ThrottleControl
chichunwang May 5, 2026
1cf76b8
Refactor actuator_tau parameters to use None as default in TVC and Th…
chichunwang May 5, 2026
cb78b68
Add actuator dynamics to RollControl
chichunwang May 30, 2026
bbc5cd3
Move actuators to a new actuator folder and rename actuator classes
zuorenchen Jun 6, 2026
3656f7e
Refactor roll, throttle, and thrust vector acutator with a new actuat…
zuorenchen Jun 6, 2026
233666b
Add pytest for all actuators
zuorenchen Jun 6, 2026
9892e50
Update rocket.py and flight.py for actuator class update
zuorenchen Jun 6, 2026
f13f92a
Fix actuator class calls
zuorenchen Jun 6, 2026
32bf679
Update active control example with new actuator class
zuorenchen Jun 6, 2026
53e588d
Update time_overshoot in flight.py to align rocketpy commit #45a89
zuorenchen Jun 7, 2026
879a921
Fix actuator unit tests
zuorenchen Jun 14, 2026
a26cd8c
Enhance ThrustVectorActuator2D with serialization methods and improve…
zuorenchen Jun 14, 2026
b3187ed
Fix comment msg
zuorenchen Jun 14, 2026
ee0dcf0
Fix pylint unused parameters
zuorenchen Jun 14, 2026
9f0a956
Remove unused import
zuorenchen Jun 14, 2026
29841c2
Fix pylint warnings
zuorenchen Jun 14, 2026
837e0f4
Refactor __run_in_serial() to fix pylint too much statement warning
zuorenchen Jun 14, 2026
02ba66e
Fix: use warning instead of printf
zuorenchen Jun 14, 2026
8281a6a
Fix comment
zuorenchen Jun 14, 2026
0ec4556
Fix: use warning instead of printf
zuorenchen Jun 14, 2026
4398e40
Run ruff format
zuorenchen Jun 14, 2026
13f53f0
Fix thrust3 and effective_thrust name
zuorenchen Jun 14, 2026
9fa47f5
Fix pytests
zuorenchen Jun 14, 2026
647ed91
Fix pytest utilities
zuorenchen Jun 14, 2026
e914ec0
Fix integration/gnss pytest
zuorenchen Jun 14, 2026
1d48998
Update readme
zuorenchen Jun 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@
ActiveRocketPy is the enhanced version of [RocketPy](https://github.com/RocketPy-Team/RocketPy), a powerful Python package for simulating the trajectories of high-power rockets. This fork introduces a range of active control and guidance, navigation, and control (GNC) features.

## Main features (ActiveRocketPy)
1. **Thrust Vector Control (TVC)**
- Implementation of TVC control class
- Feed X & Y gimbal angles through a control function
- Actuator dynamics and limits for realistic TVC simulations (WIP)

2. **Roll Control**
- Implementation of roll control class
- Feed ideal roll torque through a control function
- Actuator dynamics and limits for realistic roll control simulations (WIP)

3. **Throttle Control**
- Implementation of throttle control class
- Feed throttle percentage through a control function
- Actuator dynamics and limits for realistic throttle control simulations (WIP)

4. **Step simulation**

1. **Actuator Classes for active control**
- Actuator dynamics and limits for realistic active flight simulations
- **Thrust Vector Control (TVC)**
- Feed X & Y gimbal angles through a control function
- **Roll Control**
- Feed ideal roll torque through a control function
- **Throttle Control**
- Feed throttle percentage through a control function
- Known limitation: The mass properties are pre-calculated before flight according to max flow rate and burn time. Throttle commands does not affect the change of the mass properties in-flight. It is equivalent to throttling the Isp of rocket engine while the flow rate remains constant. The engine is cut off when burn time is reached

2. **Step simulation**
- Step through the simulation one time step at a time
- Update control inputs and step simulations in loop

Expand Down Expand Up @@ -76,7 +72,6 @@ Check out documentation details using the links below:
- [RocketPy Technical Documentation](https://docs.rocketpy.org/en/latest/technical/index.html)
- [RocketPy Flight Examples](https://docs.rocketpy.org/en/latest/examples/index.html)


<br>

# Getting Started
Expand All @@ -100,7 +95,6 @@ pip install -r requirements-tests.txt # install test/dev requirements

ActiveRocketPy is forked and maintained by [ZuoRen Chen](https://github.com/zuorenchen), along with the team from [Advanced Rocket Research Center (ARRC)](https://github.com/ARRC-Rocket).


## Citation

If you run ActiveRocketPy in your research, please consider citing:
Expand All @@ -114,4 +108,5 @@ If you run ActiveRocketPy in your research, please consider citing:
url = {https://github.com/ARRC-Rocket/ActiveRocketPy}
}
```
To cite RocketPy, please check its repository for the latest citation information: [RocketPy](https://github.com/RocketPy-Team/RocketPy)

To cite RocketPy, please check its repository for the latest citation information: [RocketPy](https://github.com/RocketPy-Team/RocketPy)
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,11 @@
" Accelerometer,\n",
" Environment,\n",
" Flight,\n",
" Function,\n",
" GnssReceiver,\n",
" Gyroscope,\n",
" Rocket,\n",
")\n",
"from rocketpy.motors import CylindricalTank, Fluid, HybridMotor\n",
"from rocketpy.motors.tank import MassFlowRateBasedTank\n",
"from rocketpy.tools import quaternions_to_spin\n",
"\n",
"plt.style.use(\"seaborn-v0_8-colorblind\")"
]
Expand Down Expand Up @@ -284,30 +281,36 @@
"outputs": [],
"source": [
"def tvc_controller_function(\n",
" time, sampling_rate, state, state_history, observed_variables, tvc, sensors\n",
" time,\n",
" sampling_rate,\n",
" state,\n",
" state_history,\n",
" observed_variables,\n",
" thrust_vector_control,\n",
" sensors,\n",
"):\n",
" # state = [x, y, z, vx, vy, vz, e0, e1, e2, e3, wx, wy, wz]\n",
"\n",
" # print(time)\n",
"\n",
" tvc.gimbal_angle_x = 0\n",
" tvc.gimbal_angle_y = 0\n",
" thrust_vector_control.gimbal_angle_x = 0\n",
" thrust_vector_control.gimbal_angle_y = 0\n",
" # Return variables of interest to be saved in the observed_variables list\n",
" return (\n",
" time,\n",
" tvc.gimbal_angle_x,\n",
" tvc.gimbal_angle_y,\n",
" thrust_vector_control.gimbal_angle_x,\n",
" thrust_vector_control.gimbal_angle_y,\n",
" )\n",
"\n",
"\n",
"tvc, tvc_controller = HALCYON.add_tvc(\n",
" gimbal_range=10,\n",
"thrust_vector_control, tvc_controller = HALCYON.add_thrust_vector_control(\n",
" controller_function=tvc_controller_function,\n",
" sampling_rate=100,\n",
" max_gimbal_angle=10,\n",
" gimbal_rate_limit=100,\n",
" controller_function=tvc_controller_function,\n",
" return_controller=True,\n",
")\n",
"tvc.info()\n",
"thrust_vector_control.x.info()\n",
"tvc_controller.info()"
]
},
Expand Down Expand Up @@ -373,17 +376,14 @@
" )\n",
"\n",
" # Return variables of interest to be saved in the observed_variables list\n",
" return (\n",
" time,\n",
" roll_control.roll_torque,\n",
" )\n",
" return (time, roll_control.roll_torque, gyro_data, accel_data)\n",
"\n",
"\n",
"roll_control, roll_controller = HALCYON.add_roll_control(\n",
" max_roll_torque=10,\n",
" sampling_rate=100,\n",
" torque_rate_limit=100,\n",
" controller_function=roll_controller_function,\n",
" sampling_rate=100,\n",
" max_roll_torque=10,\n",
" torque_rate_limit=1000,\n",
" return_controller=True,\n",
")\n",
"roll_control.info()\n",
Expand All @@ -408,33 +408,26 @@
" # state = [x, y, z, vx, vy, vz, e0, e1, e2, e3, wx, wy, wz]\n",
"\n",
" # Throttle command: 0.5 Hz sinusoid, centered at 0.8, amplitude 0.2\n",
" throttle_control.throttle = 0.8 + 0.2 * np.sin(2 * np.pi * 0.5 * time)\n",
" throttle_command = 0.8 + 0.2 * np.sin(2 * np.pi * 0.5 * time)\n",
" throttle_control.throttle = throttle_command\n",
" throttle_actual = throttle_control.throttle\n",
"\n",
" # Return variables of interest to be saved in the observed_variables list\n",
" return (\n",
" time,\n",
" throttle_control.throttle,\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
" throttle_command,\n",
" throttle_actual,\n",
" )\n",
"\n",
"\n",
"throttle_obj, throttle_controller = HALCYON.add_throttle_control(\n",
" controller_function=throttle_controller_function,\n",
" sampling_rate=100,\n",
" throttle_range=(0.0, 1.0),\n",
" throttle_rate_limit=100,\n",
" initial_throttle=1.0,\n",
" throttle_time_constant=0.5,\n",
" return_controller=True,\n",
" clamp=True,\n",
")\n",
"print(\"has add_throttle_control:\", hasattr(HALCYON, \"add_throttle_control\"))\n",
"print(\"has throttle_control:\", hasattr(HALCYON, \"throttle_control\"))\n",
"print(\"throttle_control:\", getattr(HALCYON, \"throttle_control\", None))"
")"
]
},
{
Expand All @@ -461,22 +454,24 @@
" verbose=False,\n",
")\n",
"# test_flight.plots.attitude_data()\n",
"# ===== 先看 throttle 有沒有真的變 =====\n",
"# ===== Plot commanded throttle vs filtered actuator output =====\n",
"obs = np.array(throttle_controller.observed_variables)\n",
"\n",
"t_cmd = obs[:, 0]\n",
"th_cmd = obs[:, 1]\n",
"th_act = obs[:, 2]\n",
"\n",
"plt.figure()\n",
"plt.plot(t_cmd, th_cmd, label=\"Throttle\")\n",
"plt.plot(t_cmd, th_cmd, label=\"Throttle command\")\n",
"plt.plot(t_cmd, th_act, label=\"Filtered throttle\")\n",
"plt.xlabel(\"Time (s)\")\n",
"plt.ylabel(\"Throttle\")\n",
"plt.title(\"Throttle Command\")\n",
"plt.title(\"Throttle Command vs Actuator Output\")\n",
"plt.legend()\n",
"plt.grid()\n",
"plt.show()\n",
"\n",
"# ===== 再看推力有沒有跟著變 =====\n",
"# ===== Then check thrust response =====\n",
"plt.figure()\n",
"plt.plot(\n",
" test_flight.net_thrust[:, 0], test_flight.net_thrust[:, 1], label=\"Effective Thrust\"\n",
Expand All @@ -491,15 +486,6 @@
"time1, ax, ay, az = zip(*accelerometer_clean.measured_data)\n",
"time2, gx, gy, gz = zip(*gyro_clean.measured_data)\n",
"\n",
"# plt.plot(time1, ax, label=\"Accelerometer X\")\n",
"# plt.plot(time1, ay, label=\"Accelerometer Y\")\n",
"# plt.plot(time1, az, label=\"Accelerometer Z\")\n",
"# plt.xlabel(\"Time (s)\")\n",
"# plt.ylabel(\"Acceleration (m/s^2)\")\n",
"# plt.legend()\n",
"# plt.grid()\n",
"# plt.show()\n",
"\n",
"plt.plot(time2, gx, label=\"Gyroscope X\")\n",
"plt.plot(time2, gy, label=\"Gyroscope Y\")\n",
"plt.plot(time2, gz, label=\"Gyroscope Z\")\n",
Expand Down Expand Up @@ -532,7 +518,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": ".venv (3.14.3.final.0)",
"language": "python",
"name": "python3"
},
Expand All @@ -546,7 +532,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.10"
"version": "3.14.3"
}
},
"nbformat": 4,
Expand Down
35 changes: 35 additions & 0 deletions rocketpy/prints/roll_actuator_prints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class _RollActuatorPrints:
"""Class that contains all roll actuator prints."""

def __init__(self, roll_actuator):
"""Initializes _RollActuatorPrints class

Parameters
----------
roll_actuator: rocketpy.RollActuator
Instance of the RollActuator class.

Returns
-------
None
"""
self.roll_actuator = roll_actuator

def basics(self):
"""Prints information of the roll actuator."""
print(f"Information of {self.roll_actuator.name}:")
print("----------------------------------")
print(f"Torque demand rate: {self.roll_actuator.demand_rate} Hz")
print(
f"Torque range: {self.roll_actuator.actuator_range[0]:.2f} to {self.roll_actuator.actuator_range[1]:.2f} N·m"
)
print(f"Torque rate limit: {self.roll_actuator.actuator_rate_limit} N·m/s")
print(
f"Torque clamping: {'Enabled' if self.roll_actuator.clamp else 'Disabled'}"
)
print(f"Torque time constant: {self.roll_actuator.actuator_time_constant} sec")
print(f"Current roll torque: {self.roll_actuator.roll_torque:.2f} N·m")

def all(self):
"""Prints all information of the roll actuator."""
self.basics()
30 changes: 0 additions & 30 deletions rocketpy/prints/roll_control_prints.py

This file was deleted.

35 changes: 35 additions & 0 deletions rocketpy/prints/throttle_actuator_prints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class _ThrottleActuatorPrints:
def __init__(self, throttle_actuator):
"""Initializes _ThrottleActuatorPrints class

Parameters
----------
throttle_actuator: rocketpy.ThrottleActuator
Instance of the ThrottleActuator class.

Returns
-------
None
"""
self.throttle_actuator = throttle_actuator

def basics(self):
"""Prints information of the throttle actuator."""
print(f"Information of {self.throttle_actuator.name}:")
print("----------------------------------")
print(f"Throttle demand rate: {self.throttle_actuator.demand_rate} Hz")
print(
f"Throttle range: {self.throttle_actuator.actuator_range[0]:.2f} to {self.throttle_actuator.actuator_range[1]:.2f}"
)
print(f"Throttle rate limit: {self.throttle_actuator.actuator_rate_limit}")
print(
f"Throttle Clamping: {'Enabled' if self.throttle_actuator.clamp else 'Disabled'}"
)
print(
f"Throttle time constant: {self.throttle_actuator.actuator_time_constant} sec"
)
print(f"Current throttle: {self.throttle_actuator.throttle:.2f}")

def all(self):
"""Prints all information of the throttle actuator."""
self.basics()
15 changes: 0 additions & 15 deletions rocketpy/prints/throttle_control_prints.py

This file was deleted.

Loading
Loading