Guidance, Navigation and Control · Theory · M11
M11-T4 — Attitude Control with Wheels and Thrusters
Reaction wheels give clean, fuel-free attitude control, but they store the momentum of every disturbance. The control law is the easy part. The limits and the unloading are the design.
A spacecraft attitude controller turns an error between the current and the target attitude into a torque. Reaction wheels deliver it with no propellant, but each wheel has a torque limit and a momentum limit, and everything the environment adds to the vehicle accumulates in them. This lesson designs the quaternion feedback law that works for any rotation, shows what the limits do to a 90° slew of a small satellite (23 s ideal, 28 s limited), computes how long a wheel takes to fill and how it is unloaded by magnetorquers or thrusters, and sets against it the thruster phase-plane controller, whose fuel use is set by the disturbance and not by the deadband.
Learning objectives
After this lesson, you should be able to:
- Write the quaternion-feedback law that produces a critically or lightly damped slew about the eigen-axis.
- Show the effect of wheel torque and momentum limits on the slew and the settling time.
- Estimate the time to fill a wheel and the time and cost of unloading by magnetorquers and thrusters.
- Explain a minimum-impulse deadband controller and why its fuel use depends on the disturbance.
The intuition
UAV M5-T5: Attitude control gives the attitude loop of a multirotor, with the motors as the actuators, and UAV M5-T4: Quaternion-based orientation the quaternion error. A spacecraft has the same kinematics and a different set of actuators and constraints, which is what this lesson adds: wheels with limited torque and momentum, magnetic torquers that work only perpendicular to the Earth's field, and thrusters that deliver impulses. Hopper's own gimbal is the equivalent of a wheel in that it has a position and a rate limit that the loop must respect.
The quaternion law
Let be the error quaternion between the target and the current attitude. Its vector part points along the axis of the shortest rotation that removes the error and has the magnitude for a rotation angle . A PD law on it, , rotates the body about the eigen-axis with the response of a second-order system of frequency and damping for small errors, and it works for any error angle up to 180°. The sign of the scalar part decides which way to go round: the short way. For the example satellite (moments 0.30, 0.22, 0.10 kg m²) with rad/s and , the ideal slew of 90° settles to 0.5° in 22.9 s and demands a peak wheel torque of 8.8 mN m and a momentum of 14.6 mN m s.
What the limits do
A small wheel can deliver 2 mN m and store 10 mN m s. The law asks for 8.8 mN m: it saturates for much of the slew, and the wheel reaches its momentum limit (10.1 mN m s peak), after which it cannot deliver torque in that direction. The slew takes 28.0 s instead of 22.9, still stable because the saturation is mild and the dynamics about a principal axis have no unstable coupling; a bang-bang slew at the torque limit alone would take 17.7 s, the lower bound. A 60° slew about (1, 1, 1) with the same limits takes 28.2 s, also with the momentum at the limit.
Momentum accumulates
A wheel is a momentum store: with a constant environmental torque of 2 µN m (gravity gradient and drag) the wheel fills in 1.39 h, 0.9 orbits. The wheels must be unloaded by a torque from outside. A magnetorquer produces : for a dipole of 0.2 A m² in a 30 µT field the largest torque is 6.0 µN m, and since only the part perpendicular to the field is available (about half on average) unloading 10 mN m s takes 56 min. A thruster pair with a 0.15 m arm and 50 mN of thrust does it in 1.3 s with 0.1 g of cold-gas propellant at an Isp of 60 s.
Thruster control
A satellite without wheels holds attitude with pulses. The phase-plane controller fires a minimum-impulse pulse when the attitude leaves a deadband. With a minimum pulse of 20 ms from a 5 mN m thruster on a 0.1 kg m² axis, each pulse changes the rate by 1 mrad/s. Against a constant disturbance of 10 µN m, which alone changes the rate by 1 mrad/s every 10 s, the controller fires 360 times an hour and uses 0.41 g of propellant, whatever the deadband (1° or 0.1°): the fuel is set by the disturbance impulse, 0.036 N m s per hour, and the deadband only changes how far the attitude wanders.
A quaternion PD law gives an eigen-axis slew; the real design is the limits (torque, momentum) and the unloading of the momentum that the environment pushes into the wheels. For thrusters, fuel follows the disturbance, not the deadband.
Definitions
- Error quaternion
- : the rotation from the target to the current attitude.
- Reaction wheel
- A spinning rotor whose speed change gives a reaction torque on the body; it has a torque limit and a momentum (speed) limit.
- Momentum unloading
- The use of an external torque (magnetic, thruster, gravity gradient) to reduce the wheels' stored momentum.
- Magnetorquer
- A coil that makes a magnetic dipole and a torque in the Earth's field .
- Phase-plane controller
- A controller on the angle-rate plane that fires thrusters when the state reaches the edge of a deadband.
Derivation: why the quaternion law gives a second-order response, and the limit on the slew
The linearization about a small error, and the effect of the torque limit.
For a small rotation of angle φ about the axis the vector part is half the rotation vector.
Substitute the law into the rotational dynamics, neglecting the gyroscopic term (small at small rates): a second-order system in each axis with the chosen frequency and damping, whatever the inertia.
The standard second-order equation: for rad/s and the time constant is 4.4 s.
The torque limit
At the start of a 90° slew the law asks for the largest torque: 8.8 mN m for the yaw axis, 4.4 times the 2 mN m limit.
With the torque saturated for half the slew in each direction, the double-integrator time of M9-T1: The Optimal Control Problem and the Minimum Principle sets the lower bound; the limited law takes 28.0 s because it does not use the full torque for the whole manoeuvre.
A slew of 90° at the torque limit reaches a rate of 0.177 rad/s, which needs 17.7 mN m s of momentum: more than the 10 mN m s wheel. The wheel momentum limit, not the torque, caps the slew rate in the example (the controller never exceeds 14.6 mN m s even when ideal).
Fuel and the deadband
Each minimum pulse changes the rate by this amount.
A steady disturbance builds the same rate in 10 s, so one pulse every 10 s is needed to hold the state against it: 360 an hour.
The torque impulse equals the disturbance impulse (10 µN m × 3600 s = 0.036 N m s), independent of the deadband.
A quaternion PD law gives a second-order response about the eigen-axis for any inertia. The torque and momentum limits of the wheels set how fast a large slew can be, and the momentum the environment adds sets the unloading. Thruster fuel follows the disturbance impulse.
A worked example
The small satellite of the last lesson (0.30, 0.22, 0.10 kg m²) with wheels limited to 2 mN m and 10 mN m s per axis, rad/s and .
- Slew, ideal wheels. A 90° slew about the yaw axis settles to 0.5° and 0.005 rad/s at 22.9 s, with a peak wheel torque of 8.84 mN m and a peak momentum of 14.62 mN m s.
- Slew, limited wheels. At 28.0 s, with the torque at its 2.00 mN m limit and the momentum reaching 10.10 mN m s. The lower bound at the torque limit is 17.7 s. A 60° slew about (1, 1, 1) settles at 28.2 s with the same limits.
- Filling. A constant disturbance of 2 µN m fills a 10 mN m s wheel in 1.39 h (0.9 orbits).
- Unloading. A magnetorquer with a dipole of 0.2 A m² in a 30 µT field: at most 6.0 µN m; about 56 min for 10 mN m s. A thruster with a 0.15 m arm and 50 mN of thrust: 1.3 s and 0.1 g of cold gas at Isp 60 s.
- Phase-plane control. With a 5 mN m thruster, a minimum pulse of 20 ms (1 mrad/s per pulse) and a disturbance of 10 µN m, one hour takes 360 pulses and a torque impulse of 0.0360 N m s: 0.408 g of propellant for both a 1° and a 0.1° deadband.
import math
import gnckit as g
J = (0.30, 0.22, 0.10) # kg m^2
TW, HW = 0.002, 0.010 # reaction wheel limits per axis: torque 2 mN m, momentum 10 mN m s
WN, ZETA = 0.25, 0.9
def cross(a, b): return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]
def clamp(x, lo, hi): return max(lo, min(hi, x))
def slew(qt, wheel_limits, T=120.0, dt=0.05):
"""Quaternion feedback with reaction wheels. State: q (body from reference), body rate w, wheel momentum h (3).
J w' = -w x (J w + h) - h' ; the controller asks for a body torque tau_c, the wheels absorb h' = -tau_c within their limits."""
q = [1.0, 0.0, 0.0, 0.0]; w = [0.0, 0.0, 0.0]; h = [0.0, 0.0, 0.0]
peak_tau = 0.0; peak_h = 0.0; t_settle = None
hist = []
for k in range(int(T / dt)):
qe = g.quat_mul(g.quat_conj(qt), q) # error quaternion: attitude relative to the target
s = 1.0 if qe[0] >= 0 else -1.0 # take the short way round
tau_c = [-2 * J[i] * WN ** 2 * s * qe[1 + i] - 2 * ZETA * WN * J[i] * w[i] for i in range(3)]
hdot = [-tc for tc in tau_c]
if wheel_limits:
for i in range(3):
hdot[i] = clamp(hdot[i], -TW, TW)
if (h[i] >= HW and hdot[i] > 0) or (h[i] <= -HW and hdot[i] < 0): hdot[i] = 0.0
Jw_h = [J[i] * w[i] + h[i] for i in range(3)]
gyro = cross(w, Jw_h)
wd = [(-gyro[i] - hdot[i]) / J[i] for i in range(3)]
w = [w[i] + wd[i] * dt for i in range(3)]
h = [h[i] + hdot[i] * dt for i in range(3)]
q = g.quat_normalize(g.quat_integrate(q, w, dt))
ang = 2 * math.acos(min(1.0, abs(g.quat_mul(g.quat_conj(qt), q)[0])))
peak_tau = max(peak_tau, max(abs(x) for x in hdot)); peak_h = max(peak_h, max(abs(x) for x in h))
if t_settle is None and ang < math.radians(0.5) and math.sqrt(sum(x * x for x in w)) < 0.005:
t_settle = (k + 1) * dt
hist.append((k * dt, math.degrees(ang)))
return t_settle, peak_tau, peak_h, hist
qt = g.quat_from_axis_angle([0.0, 0.0, 1.0], math.radians(90.0))
print(f'90 degree slew about the yaw axis, quaternion feedback with wn = {WN} rad/s and zeta = {ZETA}:')
for label, lim in (('ideal wheels (no limits)', False), (f'wheels limited to {TW * 1e3:.0f} mN m and {HW * 1e3:.0f} mN m s', True)):
ts, pt, ph, hist = slew(qt, lim)
print(f' {label:42s}: settled (0.5 deg) at {ts if ts is None else round(ts, 1)} s, peak wheel torque {pt * 1e3:.2f} mN m, peak wheel momentum {ph * 1e3:.2f} mN m s')
print(' a bang-bang slew at the torque limit would take 2 sqrt(theta J / T) = %.1f s (the lower bound for this wheel)' % (2 * math.sqrt(math.radians(90.0) * J[2] / TW)))
qt3 = g.quat_from_axis_angle([1.0, 1.0, 1.0], math.radians(60.0))
ts, pt, ph, hist = slew(qt3, True)
print(f' 60 degrees about (1, 1, 1) with the limits: settled at {ts if ts is None else round(ts, 1)} s, peak wheel torque {pt * 1e3:.2f} mN m, peak momentum {ph * 1e3:.2f} mN m s')
print('Momentum accumulation and unloading:')
d_tau = 2e-6 # a constant disturbance torque (N m), an aerodynamic plus gravity-gradient estimate
n = 1.131e-3
print(f' a constant disturbance of {d_tau * 1e6:.0f} micro-N m fills a {HW * 1e3:.0f} mN m s wheel in {HW / d_tau / 3600:.2f} h = {HW / d_tau / (2 * math.pi / n):.1f} orbits')
Bfield, mdip = 3e-5, 0.2
tau_mag = Bfield * mdip
print(f' a magnetorquer with a dipole of {mdip} A m^2 in a field of {Bfield * 1e6:.0f} micro-T gives at most {tau_mag * 1e6:.1f} micro-N m; only the component perpendicular to B is available, about half on average, so unloading {HW * 1e3:.0f} mN m s takes {HW / (0.5 * tau_mag) / 60:.0f} min')
print(f' a thruster with a 0.15 m arm and 50 mN of thrust unloads the same momentum in {HW / (0.15 * 0.05):.1f} s and uses {HW / (0.15 * 60 * 9.80665) * 1e3:.1f} g of propellant at an Isp of 60 s')
print('Thruster phase-plane control of one axis (torque 5 mN m, minimum pulse 20 ms, disturbance 10 micro-N m, J = 0.1):')
Jz, Tq, dist = 0.1, 0.005, 1e-5
db = math.radians(1.0)
TMIN = 0.02 # minimum pulse length of the thruster valve, s
def phase_plane(db, dist, w0=0.0, hours=1.0, dt=0.01):
"""Deadband control with minimum-impulse pulses: when the angle reaches an edge of the deadband, fire one minimum pulse back toward the centre."""
th, w = 0.0, w0
a = Tq / Jz
n_fire = 0; impulse = 0.0; pulse_left = 0.0; sign = 0.0
edges = []
for k in range(int(hours * 3600 / dt)):
if pulse_left <= 0.0:
if th > db and w > -0.0:
sign = -1.0; pulse_left = TMIN; n_fire += 1
elif th < -db and w < 0.0:
sign = 1.0; pulse_left = TMIN; n_fire += 1
else:
sign = 0.0
u = sign * Tq if pulse_left > 0.0 else 0.0
if pulse_left > 0.0:
pulse_left -= dt; impulse += abs(u) * dt
w += (u + dist) / Jz * dt
th += w * dt
if n_fire and (not edges or edges[-1][0] != n_fire): edges.append((n_fire, k * dt))
return n_fire, impulse, edges
for label, d_, w0_ in (('constant disturbance of 10 micro-N m', 1e-5, 0.0),):
for dbd in (1.0, 0.1):
nf, imp, edges = phase_plane(math.radians(dbd), d_, w0_)
print(f' {label:40s}, deadband {dbd:3.1f} degrees: {nf:4d} pulses in an hour, torque impulse {imp:.4f} N m s, about {imp / (0.15 * 60 * 9.80665) * 1e3:.3f} g of propellant (0.15 m arm, Isp 60 s)')
print(f' one minimum pulse changes the rate by {Tq / Jz * TMIN * 1e3:.2f} mrad/s; the disturbance alone is a rate change of {1e-5 / Jz * 1e3 * 10:.2f} mrad/s every 10 s, which is why the pulse rate against a constant disturbance does not depend on the deadband')90 degree slew about the yaw axis, quaternion feedback with wn = 0.25 rad/s and zeta = 0.9: ideal wheels (no limits) : settled (0.5 deg) at 22.9 s, peak wheel torque 8.84 mN m, peak wheel momentum 14.62 mN m s wheels limited to 2 mN m and 10 mN m s : settled (0.5 deg) at 28.0 s, peak wheel torque 2.00 mN m, peak wheel momentum 10.10 mN m s a bang-bang slew at the torque limit would take 2 sqrt(theta J / T) = 17.7 s (the lower bound for this wheel) 60 degrees about (1, 1, 1) with the limits: settled at 28.2 s, peak wheel torque 2.00 mN m, peak momentum 10.10 mN m s Momentum accumulation and unloading: a constant disturbance of 2 micro-N m fills a 10 mN m s wheel in 1.39 h = 0.9 orbits a magnetorquer with a dipole of 0.2 A m^2 in a field of 30 micro-T gives at most 6.0 micro-N m; only the component perpendicular to B is available, about half on average, so unloading 10 mN m s takes 56 min a thruster with a 0.15 m arm and 50 mN of thrust unloads the same momentum in 1.3 s and uses 0.1 g of propellant at an Isp of 60 s Thruster phase-plane control of one axis (torque 5 mN m, minimum pulse 20 ms, disturbance 10 micro-N m, J = 0.1): constant disturbance of 10 micro-N m , deadband 1.0 degrees: 360 pulses in an hour, torque impulse 0.0360 N m s, about 0.408 g of propellant (0.15 m arm, Isp 60 s) constant disturbance of 10 micro-N m , deadband 0.1 degrees: 360 pulses in an hour, torque impulse 0.0360 N m s, about 0.408 g of propellant (0.15 m arm, Isp 60 s) one minimum pulse changes the rate by 1.00 mrad/s; the disturbance alone is a rate change of 1.00 mrad/s every 10 s, which is why the pulse rate against a constant disturbance does not depend on the deadband
In robotics
Almost every small satellite uses wheels plus magnetorquers, and the numbers above are typical of them.
- Sizing wheels. The torque limit sets the slew time of the fastest manoeuvre the mission needs; the momentum capacity sets the interval between unloadings, and the disturbance torque budget (gravity gradient, drag, residual dipole) sets how fast it fills. A wheel that fills in 0.9 orbits needs unloading every orbit.
- Magnetic unloading. The magnetorquer provides the unloading torque for free in low orbit: it is slow (an hour) but uses only electrical power, and it works only perpendicular to the field, so the three-axis unloading law is a cross-product law with the field measured by a magnetometer.
- Detumbling. A satellite released tumbling is first brought to rest with the B-dot law (a dipole proportional to minus the rate of change of the measured field), which uses only a magnetometer and magnetorquers, then pointed by the wheels, as in the lab M11-L1: Detumble and Point.
- Thrusters. A satellite with thrusters only (or during propulsion modes) uses the phase-plane law; the minimum impulse bit, the thruster torque and the deadband are the design parameters. Against a constant disturbance the fuel is fixed, so a smaller deadband costs no extra propellant but a more frequent firing, with wear.
- Singularities and redundancy. Four wheels in a pyramid give redundancy and a null space of momentum; the allocation of module 5 distributes the torque and handles a failed wheel.
The dynamics that this law controls are M11-T3: Attitude Dynamics Without Air. The loop margins of the attitude controller with wheel lag are those of M3-T4: The Nyquist Criterion and Stability Margins; the allocation among wheels is M5-T6: Control Allocation.
Common misconceptions
“A reaction wheel adds angular momentum to the satellite.”
It exchanges it: the total (body plus wheel) is unchanged by the wheel torque. Only an external torque changes it, and the wheels store the momentum the environment adds.
“Wheel torque is the limit on slew speed.”
The momentum limit may bind first: at the torque limit a 90° slew would need 17.7 mN m s against a wheel capacity of 10, so the slew is momentum-limited, not torque-limited.
“Saturation of the wheels just slows the slew.”
For a stable principal-axis slew it only slows (22.9 to 28.0 s). With coupling between axes and a stored momentum the gyroscopic term can matter, and an integrator would wind up; the limits must be in the controller design.
“A smaller thruster deadband costs more propellant.”
Against a steady disturbance the propellant is set by the disturbance impulse: 0.41 g per hour for both a 1° and a 0.1° deadband. The deadband changes the number of cycles and the pointing error.
“Magnetorquers can unload momentum in any direction.”
A magnetic torque is perpendicular to the field. About half the dipole is useful on average, and the torque along the field direction is not available, so unloading takes an hour and needs the orbit to rotate the field.
Key takeaways
- The quaternion law gives a second-order eigen-axis slew; the sign of the scalar part picks the short way.
- A 90° slew settles in 22.9 s with ideal wheels (peak 8.84 mN m, 14.6 mN m s) and 28.0 s with 2 mN m and 10 mN m s limits.
- A constant 2 µN m disturbance fills a 10 mN m s wheel in 1.39 h (0.9 orbits).
- Magnetic unloading of 10 mN m s takes 56 min with a 0.2 A m² dipole; a thruster takes 1.3 s and 0.1 g.
- A minimum-pulse phase-plane controller against a 10 µN m disturbance fires 360 times an hour and uses 0.41 g, independent of the deadband.
- The design questions are the limits, the momentum budget and the unloading, not the control law.
References and further reading
Each source is marked free or paid. Free to read does not mean free to reuse: the course resources page lists every source with its licence.
- B. Wie, Space Vehicle Dynamics and Control, 2nd edition, AIAA, 2008, the chapters on quaternion feedback, momentum management and thruster control. Paid.
- M. J. Sidi, Spacecraft Dynamics and Control: A Practical Engineering Approach, Cambridge University Press, 1997. Paid.
- F. L. Markley and J. L. Crassidis, Fundamentals of Spacecraft Attitude Determination and Control, Springer, 2014. Paid.
- MIT 16.851 Satellite Engineering (OpenCourseWare) , the lectures on attitude control and momentum management. Free; licence CC BY-NC-SA 4.0.
Knowledge check
Three questions. Write an answer, then reveal the explanation. Your answers stay in your browser.
Question 1
A wheel stores at most 10 mN m s and a constant disturbance of 5 µN m acts on the satellite. After how long must the momentum be unloaded, and how many orbits is that at 92.6 min per orbit?
Explanation
The wheel fills when 5×10⁻⁶ N m × t = 0.010 N m s, so t = 2000 s = 33 min, 0.36 of an orbit. Unloading must therefore happen several times per orbit, so the disturbance (or the wheel size) is too large for a magnetorquer that takes about an hour to unload; the design needs bigger wheels, smaller disturbances, or thrusters.
Question 2
Why does a saturated wheel slow a slew without making it unstable in the example?
Explanation
Rotation about a principal axis has no coupling between axes, and the law only asks for less torque than it wants, so the closed loop is a saturated but still decelerating second-order system: the error reaches zero a little later. The risk of instability arises when the gyroscopic coupling is large (a fast spin or large stored momentum) or when an integrator winds up against the limit, neither of which is present here.
Question 3
A thruster controller against a constant disturbance uses 0.41 g of propellant per hour with a 1° deadband. Predict the use with a 0.5° deadband and explain.
Explanation
It is the same, 0.41 g per hour. The torque impulse needed per hour equals the disturbance impulse (disturbance torque × time), and the thrusters deliver it in minimum pulses, so the propellant is fixed by the disturbance and the thruster arm and specific impulse. A narrower deadband makes the limit cycle smaller and the pulses more frequent but does not change the total, until the pulse size forces more than one pulse per crossing.
What’s next
Related content
Nothing below is required to finish this lesson.
- BeforeM11-T3: Attitude Dynamics Without Air
Write Euler's equations, predict torque-free motion about each principal axis, and compute the gravity-gradient torque.
- LabM11-L1: Detumble and Point
A small satellite is released tumbling. Stop the rotation, slew to a target attitude with reaction wheels that saturate, and unload the stored momentum.
Other courses on this site treat neighbouring topics from their own angle:
- UAV M5-T4: Quaternion-based orientation
- UAV M5-T5: Attitude control
- Linear Algebra M7-T4: SO(3)
- Linear Algebra M10-T4: The Exponential Map
- SLAM M2-T3: Rotation Matrices, Quaternions, and Pose Representation
This course leaves the following to the pages that already teach them:
- Quaternion algebra and the rotation group
- Mission design, launch windows and interplanetary transfers (outside the scope of this site)
- Structural, thermal and propulsion design (outside the scope of this site)
Get notified when the next lesson and new labs are released.
One email per new lesson or lab.