Add actuator dynamics support#9
Open
chichunwang wants to merge 10 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR migrates rocket control components (roll, throttle, TVC) from bespoke classes to a shared Actuator abstraction, updates simulation hooks to use the new actuators, and adds unit tests + updated example notebook.
Changes:
- Introduces a new
Actuatorbase class plusRollActuator,ThrottleActuator, andThrustVectorActuator(2D) implementations. - Updates
RocketandFlightto usethrust_vector_control/ new actuator APIs, removing legacy control classes and prints. - Adds a comprehensive unit test suite for the new actuators and updates the Halcyon example notebook accordingly.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/rocket/test_actuators.py | Adds unit tests for new actuator classes (init, clamp, serialization, dynamics, validation). |
| rocketpy/simulation/flight.py | Switches TVC usage to thrust_vector_control and changes reset behavior for controllables. |
| rocketpy/rocket/rocket.py | Replaces legacy control components with new actuators; renames TVC API to add_thrust_vector_control. |
| rocketpy/rocket/actuator/actuator.py | Adds common actuator dynamics (IIR + rate limiting + clamping). |
| rocketpy/rocket/actuator/roll.py | Implements roll actuator on top of Actuator. |
| rocketpy/rocket/actuator/throttle.py | Implements throttle actuator on top of Actuator. |
| rocketpy/rocket/actuator/thrust_vector.py | Implements 1D and 2D thrust vector actuators. |
| rocketpy/rocket/actuator/init.py | Exposes new actuator types at package level. |
| rocketpy/rocket/tvc.py | Removes legacy TVC implementation. |
| rocketpy/rocket/throttle_control.py | Removes legacy throttle control implementation. |
| rocketpy/rocket/roll_control.py | Removes legacy roll control implementation. |
| rocketpy/prints/thrust_vector_actuator_prints.py | Adds print helpers for thrust vector actuator. |
| rocketpy/prints/throttle_actuator_prints.py | Adds print helpers for throttle actuator. |
| rocketpy/prints/roll_actuator_prints.py | Adds print helpers for roll actuator. |
| rocketpy/prints/tvc_prints.py | Removes legacy TVC prints. |
| rocketpy/prints/throttle_control_prints.py | Removes legacy throttle control prints. |
| rocketpy/prints/roll_control_prints.py | Removes legacy roll control prints. |
| docs/examples/halcyon_flight_sim_roll_throttle.ipynb | Updates example to new actuator APIs and plots commanded vs filtered throttle. |
Comment on lines
2098
to
+2104
| controller_function, | ||
| sampling_rate, | ||
| throttle_range=(0, 1), | ||
| throttle=1.0, | ||
| clamp=True, | ||
| throttle_rate_limit=0, | ||
| clamp=True, | ||
| initial_throttle=1.0, | ||
| throttle_time_constant=None, |
Comment on lines
+82
to
+92
| if self.actuator_time_constant is not None and self.actuator_time_constant > 0: | ||
| if self.demand_rate is not None: | ||
| demand_period = 1.0 / self.demand_rate | ||
| self._alpha = demand_period / ( | ||
| self.actuator_time_constant + demand_period | ||
| ) | ||
| else: | ||
| print( | ||
| f"Warning: Actuator time constant currently only implemented on discrete controllers. '{self.name}' dynamics not applied." | ||
| ) | ||
| self._alpha = 1.0 # No filtering, direct pass-through |
Comment on lines
+123
to
+129
| print( | ||
| f"Warning: Actuator '{self.name}' output change {change:.3f} exceeds rate limit of {max_change:.3f} per time step." | ||
| ) | ||
| else: | ||
| print( | ||
| f"Warning: Actuator rate limit currently only implemented for discrete controllers. '{self.name}' rate limit not applied." | ||
| ) |
Comment on lines
+136
to
+138
| print( | ||
| f"Warning: Actuator '{self.name}' output {value:.3f} exceeds range limits {self.actuator_range}." | ||
| ) |
Comment on lines
+1750
to
+1759
| # reset controllable objects to initial state (air brakes, thrust vector control, throttle control, and roll control) | ||
| for air_brakes in self.rocket.air_brakes: | ||
| air_brakes._reset() | ||
| if hasattr(self.rocket, "thrust_vector_control"): | ||
| self.rocket.thrust_vector_control.x._reset() | ||
| self.rocket.thrust_vector_control.y._reset() | ||
| if hasattr(self.rocket, "roll_control"): | ||
| self.rocket.roll_control._reset() | ||
| if hasattr(self.rocket, "throttle_control"): | ||
| self.rocket.throttle_control._reset() |
Comment on lines
+66
to
+71
| initial_gimbal_angle : float, optional | ||
| Initial gimbal angle in deg. Default is 0.0 (no gimbal). | ||
| roll_torque_time_constant : float, optional | ||
| Time constant for the roll torque actuator dynamics (first-order IIR | ||
| filter) in seconds. If None, no actuator dynamics are applied. | ||
| Must be non-negative. Default is None. demand_rate must be specified if roll_torque_time_constant is not None. |
Comment on lines
+234
to
+237
| @property | ||
| def gimbal_angle_x(self): | ||
| """Returns the current gimbal angle around the y-axis (yaw).""" | ||
| return self.x.gimbal_angle |
Comment on lines
+2033
to
+2034
| Initial_roll_torque : int, float | ||
| Initial roll torque in N·m. Default is 0.0. |
Comment on lines
+131
to
+138
| def from_dict(cls, data): | ||
| return cls( | ||
| name=data.get("name"), | ||
| demand_rate=data.get("demand_rate"), | ||
| throttle_range=( | ||
| data.get("throttle_range")[0], | ||
| data.get("throttle_range")[1], | ||
| ), |
Comment on lines
+1830
to
+1834
| def add_thrust_vector_control( | ||
| self, | ||
| gimbal_range, | ||
| gimbal_rate_limit, | ||
| controller_function, | ||
| sampling_rate, | ||
| max_gimbal_angle, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test