1 · What you've built (5-min recap)
Across Labs 1–6 you assembled a complete cascade autopilot: the X-frame mixer (Wk 3), the inner attitude loop (Wk 5), the outer position/altitude loop (Wk 6), optionally LQR (Wk 7), state estimation (Wk 8), and trajectory tracking (Wk 9). Today they fly together, on the estimated state, under a disturbance — the realistic test.
2 · Setup (1 min)
# from the simulator/ directory, venv active export PYTHONPATH=. # Windows: set PYTHONPATH=.
Use your own StudentController if it passed Labs 2–3; otherwise the reference
CascadePID is the baseline. Either way you wrap it in EstimatedStateController.
3 · Fly the capstone mission
1 Assemble the full stack on the estimate
One controller object closes guidance → control → estimation:
import numpy as np from quadsim import Simulator, QuadParams from quadsim.controllers import CascadePID # or: from quadsim.controllers import StudentController from quadsim.estimators import EstimatedStateController from quadsim.dynamics import hover_state from quadsim import trajectories as traj p = QuadParams(); sim = Simulator(p) ctrl = EstimatedStateController(CascadePID(p), p) # fly on x̂, not x
2 Define a mission + wind, then run the test
Take off, fly a square of waypoints, land — under a steady cross-wind that a fixed-gain controller cannot fully reject:
mission = traj.waypoints([(0,0,1), (2,0,1.5), (2,2,1.5), (0,2,1), (0,0,1)])
log = sim.run(hover_state(position=(0,0,1.0)), ctrl, reference=mission,
t_final=30.0, wind=lambda t: np.array([2.5, 0.0, 0.0])) # strong gust in +x3 Collect the four baseline metrics measure
Numbers, not impressions — these define what your project must beat:
rmse = log.position_rmse() tilt = np.rad2deg(np.sqrt(log.euler[:,0]**2 + log.euler[:,1]**2)) sat = np.mean(np.any(np.abs(log.f - p.f_max) < 1e-6, axis=1)) # fraction of steps saturated drift = np.linalg.norm(log.position[-1] - [0,0,1.0]) # end-of-mission error print(f"RMSE {rmse:.3f} m | max tilt {tilt.max():.1f} deg | saturated {sat*100:.0f}% | drift {drift:.3f} m")
4 Render the figures for the report plots
from quadsim import plotting as viz viz.plot_pose_strobe(log, save="capstone_strobe.png", show=False) viz.plot_tracking_error(log, save="capstone_error.png", show=False)
4 · Find your limitation & propose the project
Look at your baseline and name one concrete weakness, then pick the method that addresses it:
| If your baseline shows… | …the gap is | Project method |
|---|---|---|
| Drift / large RMSE under wind | No disturbance rejection | RL with domain randomization, or MPC |
| Motors saturating, tilt clamped | No constraint planning | MPC (input/tilt limits) |
| Lag on fast trajectories | No preview / look-ahead | MPC with reference preview |
Self-check
5 · Deliverable & submission
| Criterion | What we look for | Weight |
|---|---|---|
| Capstone run | Full mission on the estimate under wind; four baseline metrics reported | 40% |
| Figures & analysis | Strobe + tracking-error plots, read correctly (where/why it struggles) | 30% |
| Project proposal | One-page: mission + named limitation + candidate method, with a target metric | 30% |
📤 Submit via the MUST LMS — Team case study (Week 10)
capstone_strobe.png & capstone_error.png + a 1-page project proposalMLTE03_LabReport7_<studentID>.pdf + MLTE03_Proposal_<studentID>.pdfThe six lab reports are 30% and this team case study 20% of the course grade; the final project is 40%.
Next → Week 11: Model Predictive Control. The tools to close your chosen gap start here; the final project is presented and demoed in Week 15.