ADCS.controller.mtq_w_rw_LP module¶
- class ADCS.controller.mtq_w_rw_LP.MTQ_w_RW_LP(est_sat, p_gain, d_gain, c_gain, h_target=array([0., 0., 0.]))[source]¶
Bases:
ControllerLinear–Programming–Based Torque Allocation for Mixed RW–MTQ ADCS.
This controller allocates attitude control effort between reaction wheels (RWs) and magnetorquers (MTQs) using a geometry-aware linear program (LP). The LP computes the maximum physically achievable torque colinear with a requested torque direction while enforcing hard actuator saturation limits and the MTQ torque-plane constraint.
The implementation is intended for use with an estimated satellite model
EstimatedSatelliteand goal objects derived fromGoal.Actuator Models¶
Desired body-frame control torque:
\[\boldsymbol{\tau}_{\mathrm{des}} \in \mathbb{R}^3, \qquad T_{\mathrm{des}} = \|\boldsymbol{\tau}_{\mathrm{des}}\|, \qquad \hat{\boldsymbol{\tau}} = \frac{\boldsymbol{\tau}_{\mathrm{des}}}{T_{\mathrm{des}}}.\]Reaction wheels (for \(N_{\mathrm{rw}}\) wheels):
\[\boldsymbol{\tau}_{\mathrm{rw}} = \sum_{i=1}^{N_{\mathrm{rw}}} \boldsymbol{a}_i u_i = A_{\mathrm{rw}} \boldsymbol{u}_{\mathrm{rw}}, \qquad |u_i| \le u_{i,\max},\]where \(\boldsymbol{a}_i\) are unit wheel axes.
Magnetorquers (for \(N_{\mathrm{mtq}}\) rods) produce a dipole moment \(\boldsymbol{m} = A_{\mathrm{mtq}} \boldsymbol{u}_{\mathrm{mtq}}\) and torque:
\[\boldsymbol{\tau}_{\mathrm{mtq}} = \boldsymbol{m} \times \boldsymbol{B} = -[\boldsymbol{B}]_\times A_{\mathrm{mtq}} \boldsymbol{u}_{\mathrm{mtq}}, \qquad \boldsymbol{\tau}_{\mathrm{mtq}} \perp \boldsymbol{B},\]with the skew-symmetric matrix \([\boldsymbol{B}]_\times\) satisfying \([\boldsymbol{B}]_\times \boldsymbol{x} = \boldsymbol{B} \times \boldsymbol{x}\). The cross-product matrix is consistent with
skewsym().Combined actuator mapping:
\[\begin{split}\boldsymbol{\tau} = \begin{bmatrix} A_{\mathrm{rw}} & -[\boldsymbol{B}]_\times A_{\mathrm{mtq}} \end{bmatrix} \begin{bmatrix} \boldsymbol{u}_{\mathrm{rw}} \\ \boldsymbol{u}_{\mathrm{mtq}} \end{bmatrix} = A_{\mathrm{tot}} \boldsymbol{u}.\end{split}\]LP Formulation¶
Directly enforcing \(A_{\mathrm{tot}} \boldsymbol{u} = \boldsymbol{\tau}_{\mathrm{des}}\) may be infeasible due to underactuation (MTQ plane) and saturation. Instead, introduce a scalar availability variable \(T_{\mathrm{avail}} \ge 0\) and solve:
\[\max_{\boldsymbol{u},\,T_{\mathrm{avail}}}\; T_{\mathrm{avail}} \quad \text{s.t.}\quad A_{\mathrm{tot}} \boldsymbol{u} - T_{\mathrm{avail}}\hat{\boldsymbol{\tau}} = \boldsymbol{0}, \quad -u_{k,\max} \le u_k \le u_{k,\max}, \quad T_{\mathrm{avail}} \ge 0.\]Let \(T_{\max}\) be the optimizer value of \(T_{\mathrm{avail}}\).
If \(T_{\max} \ge T_{\mathrm{des}}\), the commanded effort is scaled to reproduce \(\boldsymbol{\tau}_{\mathrm{des}}\) exactly.
If \(T_{\max} < T_{\mathrm{des}}\), the controller applies the maximum feasible torque in the requested direction.
Define the scalar effectiveness metric:
\[\alpha = \frac{T_{\max}}{T_{\mathrm{des}}} \in [0,1].\]Pointing and Torque-Free Momentum Management¶
In pointing mode (non-
No_Goal), the controller:Computes a PD+gyro torque request using goal attitude error and angular-rate error. The goal error is obtained from
error()and the reference rate fromto_ref().Uses the LP allocator to achieve the largest feasible torque colinear with the request.
If both RWs and MTQs are present and authority remains, attempts a torque-free secondary desaturation by selecting MTQ torque (projected into the MTQ plane) to reduce stored wheel momentum and commanding an equal-and-opposite RW torque so the net additional body torque is approximately zero.
In desaturation mode (
No_Goal), the controller uses MTQ-only logic (B-dot style) with optional RW coordination to reduce rates and dump wheel momentum while respecting actuator limits.- allocate_max_torque_in_direction(tau_des, b_body, est_sat)[source]¶
Solve the LP to maximize feasible torque colinear with a desired torque direction.
This method implements the normalized LP:
\[\max_{\boldsymbol{u},\,T_{\mathrm{avail}}}\; T_{\mathrm{avail}} \quad \text{s.t.}\quad A_{\mathrm{tot}}\boldsymbol{u} = T_{\mathrm{avail}}\hat{\boldsymbol{\tau}}, \quad -u_{k,\max} \le u_k \le u_{k,\max}, \quad T_{\mathrm{avail}} \ge 0,\]where \(\hat{\boldsymbol{\tau}} = \boldsymbol{\tau}_{\mathrm{des}}/\|\boldsymbol{\tau}_{\mathrm{des}}\|\). The combined map is:
\[A_{\mathrm{tot}} = \begin{bmatrix} A_{\mathrm{rw}} & -[\boldsymbol{B}]_\times A_{\mathrm{mtq,axes}} \end{bmatrix}.\]The MTQ block uses the body magnetic field \(\boldsymbol{B}\) and enforces the plane constraint \(\boldsymbol{\tau}_{\mathrm{mtq}} \perp \boldsymbol{B}\) by construction.
Output scaling¶
Let \(T_{\max}\) be the optimizer value of \(T_{\mathrm{avail}}\) and \(T_{\mathrm{des}} = \|\boldsymbol{\tau}_{\mathrm{des}}\|\).
If \(T_{\max} \le T_{\mathrm{des}}\), the system is saturated and the method returns the maximizing command and \(\alpha = T_{\max}/T_{\mathrm{des}}\).
If \(T_{\max} > T_{\mathrm{des}}\), the method scales the maximizing command by \(T_{\mathrm{des}}/T_{\max}\) to match \(\boldsymbol{\tau}_{\mathrm{des}}\) exactly and returns \(\alpha = 1\).
Degenerate cases¶
If \(\|\boldsymbol{\tau}_{\mathrm{des}}\|\) is near zero, the method returns zeros and \(\alpha = 1\). If the LP solver fails (e.g., no torque achievable in the requested direction), the method returns zeros and \(\alpha = 0\).
- param tau_des:
Desired body-frame torque vector \(\boldsymbol{\tau}_{\mathrm{des}}\).
- type tau_des:
numpy.ndarray
- param b_body:
Body-frame magnetic field vector \(\boldsymbol{B}\).
- type b_body:
numpy.ndarray
- param est_sat:
Estimated satellite providing the RW and MTQ actuator sets and limits.
- type est_sat:
- return:
Tuple
(u_rw_cmd, u_mtq_cmd, alpha)whereu_rw_cmdhas shape(N_rw,),u_mtq_cmdhas shape(N_mtq,), andalphais the achievable torque fraction.- rtype:
tuple[numpy.ndarray, numpy.ndarray, float]
- Parameters:
tau_des (ndarray)
b_body (ndarray)
est_sat (EstimatedSatellite)
- Return type:
tuple[ndarray, ndarray, float]
- find_u(x_hat, sens, est_sat, os_hat, goal=None)[source]¶
Compute actuator commands for either pointing or desaturation mode.
If
goalisNo_Goal(orNone), this method routes tofind_u_desaturate(). Otherwise it routes tofind_u_pointing().The returned vector is ordered in the same actuator ordering as
est_sat.actuatorsand contains MTQ and RW command signals consistent with each actuator’su_maxbounds.- Parameters:
x_hat (numpy.ndarray) – Estimated state vector. The first 3 elements are body rates \(\boldsymbol{\omega}\) and elements 3:7 are the attitude quaternion. If present, elements 7:7+N_rw store RW scalar momentum states.
sens (numpy.ndarray) – Raw sensor vector used to estimate the body magnetic field via the MTM model.
est_sat (
EstimatedSatellite) – Estimated satellite object providing hardware configuration and inertia.os_hat (
Orbital_State) – Estimated orbital state used by the goal to compute reference vectors and rates.goal (
Goal| None) – Pointing goal. IfNone, the controller usesNo_Goal.
- Returns:
Actuator command vector in
est_sat.actuatorsordering.- Return type:
numpy.ndarray
- find_u_desaturate(x_hat, sens, est_sat, os_hat, goal=None)[source]¶
Compute actuator commands for desaturation mode (No_Goal).
This mode prioritizes: - Rate damping in the MTQ-achievable plane (perpendicular to \(\boldsymbol{B}\)). - Momentum dumping toward \(\boldsymbol{h}_{\mathrm{target}}\) when RWs exist.
Magnetic field estimation¶
The body magnetic field \(\boldsymbol{B}\) is reconstructed from MTM readings. If \(\|\boldsymbol{B}\|\) is near zero, no MTQ torque is possible and this method returns zeros.
Rate damping (B-dot style plane damping)¶
MTQs can only generate torque perpendicular to \(\boldsymbol{B}\). The method dampens body rates only in that plane. Let:
\[\hat{\boldsymbol{B}} = \frac{\boldsymbol{B}}{\|\boldsymbol{B}\|}, \qquad \boldsymbol{\omega}_{\perp} = \boldsymbol{\omega} - (\boldsymbol{\omega}\cdot\hat{\boldsymbol{B}})\hat{\boldsymbol{B}}.\]The plane-damping torque is:
\[\boldsymbol{\tau}_{\mathrm{bdot}} = -k_{\omega}\boldsymbol{\omega}_{\perp}.\]Momentum dumping¶
For RWs, the stored body-frame wheel momentum is:
\[\boldsymbol{h}_{\mathrm{rw}} = A_{\mathrm{rw}}\boldsymbol{h}_{\mathrm{rw,scalars}}.\]The error relative to the target is:
\[\boldsymbol{h}_{\mathrm{err}} = \boldsymbol{h}_{\mathrm{rw}} - \boldsymbol{h}_{\mathrm{target}}.\]A nominal dumping torque is computed (gain and sign follow the implementation):
\[\boldsymbol{\tau}_{\mathrm{dump}}^{\ast} = k_h \boldsymbol{h}_{\mathrm{err}}.\]The commanded dump torque is then projected into the MTQ-achievable plane:
\[\boldsymbol{\tau}_{\mathrm{dump},\perp} = \boldsymbol{\tau}_{\mathrm{dump}}^{\ast} - (\boldsymbol{\tau}_{\mathrm{dump}}^{\ast}\cdot\hat{\boldsymbol{B}})\hat{\boldsymbol{B}}.\]MTQ allocation and saturation scaling¶
The MTQ command is computed by a pseudoinverse of the effective MTQ torque map:
\[A_{\mathrm{mtq,eff}} = -[\boldsymbol{B}]_\times A_{\mathrm{mtq}}, \qquad \boldsymbol{u}_{\mathrm{mtq}} = A_{\mathrm{mtq,eff}}^{+}\boldsymbol{\tau}_{\mathrm{mtq,des}}.\]If any MTQ channel exceeds its limit, a scalar scale factor \(\alpha_{\mathrm{mtq}} \in [0,1]\) is applied to keep commands feasible.
RW coordination¶
When MTQ authority is limited (small \(\alpha_{\mathrm{mtq}}\)), the RW torque request is scaled accordingly to avoid injecting uncompensated body torque. The RW command is produced using the RW torque-to-command mapping built in the constructor and then saturated to bounds.
- param x_hat:
Estimated state vector containing body rates, quaternion, and optionally RW momentum states.
- type x_hat:
numpy.ndarray
- param sens:
Sensor vector used to estimate the body magnetic field from MTM measurements.
- type sens:
numpy.ndarray
- param est_sat:
Estimated satellite object providing actuators and inertia.
- type est_sat:
- param os_hat:
Estimated orbital state (not required by the current desaturation logic but included for interface compatibility).
- type os_hat:
- param goal:
Optional goal (unused in this mode). Included for signature compatibility.
- type goal:
Goal| None- return:
Actuator command vector in
est_sat.actuatorsordering for desaturation mode.- rtype:
numpy.ndarray
- Parameters:
x_hat (ndarray)
sens (ndarray)
est_sat (EstimatedSatellite)
os_hat (Orbital_State)
goal (Goal | None)
- find_u_pointing(x_hat, sens, est_sat, os_hat, goal)[source]¶
Compute actuator commands for pointing with LP allocation and torque-free desaturation.
This method performs two stages:
Stage 1: LP torque allocation in the requested direction¶
A desired control torque is computed as PD feedback plus a gyroscopic compensation term:
\[\boldsymbol{\tau}_{\mathrm{pd}} = -k_p \boldsymbol{q}_{\mathrm{err}} - k_d(\boldsymbol{\omega} - \boldsymbol{\omega}_{\mathrm{ref}}),\]where \(\boldsymbol{q}_{\mathrm{err}}\) is obtained from
error(), and \(\boldsymbol{\omega}_{\mathrm{ref}}\) is the body-frame reference rate fromto_ref()androt_mat().The gyroscopic term uses satellite inertia \(J\) and wheel momentum:
\[\boldsymbol{h}_{\mathrm{rw}} = A_{\mathrm{rw}}\boldsymbol{h}_{\mathrm{rw,scalars}}, \qquad \boldsymbol{\tau}_{\mathrm{gyro}} = \boldsymbol{\omega} \times (J\boldsymbol{\omega} + \boldsymbol{h}_{\mathrm{rw}}),\]giving:
\[\boldsymbol{\tau}_{\mathrm{des}} = \boldsymbol{\tau}_{\mathrm{pd}} + \boldsymbol{\tau}_{\mathrm{gyro}}.\]The body magnetic field \(\boldsymbol{B}\) is reconstructed from MTM readings using the sensor mapping built in the constructor. The LP allocator
allocate_max_torque_in_direction()then returns a feasible command achieving \(\alpha \boldsymbol{\tau}_{\mathrm{des}}\) with \(\alpha \in [0,1]\).- Parameters:
x_hat (ndarray)
sens (ndarray)
est_sat (EstimatedSatellite)
os_hat (Orbital_State)
goal (Goal)
- Return type:
ndarray
- plot_capacity(ax, points, face_color, edge_color, alpha=0.25)[source]¶
Plot a convex capacity set (line, polygon, or 3D hull) from a point cloud.
The method determines the intrinsic rank (dimension) of the point set by SVD and renders: - Rank 1: a line segment between extreme projections. - Rank 2: a filled convex polygon in 3D via a 2D convex hull in the best-fit plane. - Rank 3: a 3D convex hull surface, plus silhouette edges.
Rank detection¶
Let \(P \in \mathbb{R}^{N \times 3}\) be the unique points and \(\bar{\boldsymbol{p}}\) be their centroid. Compute the SVD of centered points:
\[P_c = P - \mathbf{1}\bar{\boldsymbol{p}}^{\mathsf{T}} = U \Sigma V^{\mathsf{T}}.\]The number of singular values above a tolerance defines the effective rank, which selects the plotting primitive.
- param ax:
A Matplotlib 3D axis object used for plotting.
- type ax:
matplotlib.axes.Axes
- param points:
Point cloud in torque space with shape
(N, 3).- type points:
numpy.ndarray
- param face_color:
Face color for polygon or hull rendering.
- type face_color:
str
- param edge_color:
Edge color for line/polygon edges and hull silhouettes.
- type edge_color:
str
- param alpha:
Transparency value used for filled primitives.
- type alpha:
float
- return:
None
- rtype:
None
- Parameters:
points (ndarray)
face_color (str)
edge_color (str)
alpha (float)
- plot_torques(tau_des, b_body, est_sat)[source]¶
Plot achievable torque envelopes and the allocated torque vectors in 3D.
This method: - Calls
allocate_max_torque_in_direction()to obtain RW and MTQ commands and the effectiveness metric \(\alpha\). - Constructs representative point clouds of extreme actuator combinations (hypercube corners) for RWs and MTQs and draws their convex hulls. - Plots vectors for RW torque, MTQ torque, total achieved torque, and desired torque.Torque reconstruction¶
RW torque is reconstructed as:
\[\boldsymbol{\tau}_{\mathrm{rw}} = A_{\mathrm{rw}}\boldsymbol{u}_{\mathrm{rw}}.\]MTQ torque is reconstructed from dipole moment and magnetic field:
\[\boldsymbol{\tau}_{\mathrm{mtq}} = \boldsymbol{m} \times \boldsymbol{B}, \qquad \boldsymbol{m} = A_{\mathrm{mtq,axes}}\boldsymbol{u}_{\mathrm{mtq}}.\]The achieved torque is:
\[\boldsymbol{\tau}_{\mathrm{ach}} = \boldsymbol{\tau}_{\mathrm{rw}} + \boldsymbol{\tau}_{\mathrm{mtq}}.\]Hull plotting uses
plot_capacity().- param tau_des:
Desired body-frame torque vector to visualize.
- type tau_des:
numpy.ndarray
- param b_body:
Body-frame magnetic field vector used for MTQ torque mapping.
- type b_body:
numpy.ndarray
- param est_sat:
Estimated satellite providing actuator configuration and limits.
- type est_sat:
- return:
None
- rtype:
None
- Parameters:
tau_des (ndarray)
b_body (ndarray)
est_sat (EstimatedSatellite)
- Return type:
None
- Parameters:
est_sat (EstimatedSatellite)
p_gain (float)
d_gain (float)
c_gain (float)
h_target (ndarray | list)