You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7e95c1e
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: README.md
+32-1Lines changed: 32 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,6 +32,7 @@ whole workflow: no code changes.
32
32
|`configs/controller.yaml`| the ArduPilot parameters (real names) and the assumed controller gains |
33
33
|`configs/scenarios.yaml`| the named scenarios and the ensemble ranges |
34
34
|`configs/study.yaml`| which analyses to run, effort, draft or release mode, parallelism |
35
+
|`configs/ardupilot_defaults.yaml`| optional: the values ArduPilot ships with, used only as a reference column and a simulated comparison case |
35
36
36
37
Every data entry has a value, a unit (any unit; converted once on load), a source and an evidence
37
38
status (`measured`, `datasheet`, `derived`, `documented`, `stated`, `assumed`, `TBD`). The report shows
@@ -52,6 +53,7 @@ how much of each result rests on assumptions. **`configs/README.md` documents ev
52
53
|**Q2**| can the pusher reach the transition speed at altitude, against mass? |
53
54
|**C**| what can the autopilot be *configured* to do? (ArduPilot-parameter optimisation) |
54
55
|**B1**| what is the best open-loop trajectory? (direct collocation, energy against altitude excursion) |
56
+
|**FT**| which `AIRSPEED_MIN`, `Q_TRANSITION_MS`, `TKOFF_THR_MAX` and `Q_TRAN_PIT_MAX` take it from hover to wing-borne flight without losing altitude or stalling? |
55
57
| sensitivity | which inputs drive each result, and how firmly do we know them? |
56
58
57
59
## Command line
@@ -62,13 +64,42 @@ python run.py run everything configured
62
64
python run.py --only A D E just these analyses
63
65
python run.py --mode release refuse unless nothing is TBD or missing
64
66
python run.py --force ignore cached results
67
+
python run.py --fresh-cache delete the task cache of this run, then compute everything
65
68
python run.py --serial one process (easier to debug)
66
69
python run.py --verify also run the test suite and feed the release gate
70
+
python run.py --view [FOLDER] open existing results as report.html (+ tables.xlsx); runs nothing
67
71
```
68
72
73
+
`--view` is a viewer: it reads a results folder that already exists (default: `output_dir/run_name` of
74
+
`study.yaml`), writes `report.html` and `tables.xlsx` next to the tables and opens the page
75
+
(`--no-open` to skip that). With no results in the folder it writes and opens nothing and exits 2.
76
+
69
77
Results are cached per task and keyed by a hash of every result-relevant input, so an unchanged re-run
70
78
only rebuilds the report and changing one value only re-runs what depends on it.
71
79
80
+
## Acceptance run
81
+
82
+
A full study from nothing, then the viewer. From a fresh clone (the commands are the same in the
Copy file name to clipboardExpand all lines: configs/README.md
+9-7Lines changed: 9 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,6 +21,7 @@ them with real data as you get it.
21
21
|`controller.yaml`| register | the ArduPilot parameters (by their real names) and the assumed controller gains |
22
22
|`scenarios.yaml`| plain | the named scenarios (S-01…S-06) and the ensemble ranges |
23
23
|`study.yaml`| plain | which analyses to run, how much effort, run name, draft/release mode, parallelism |
24
+
|`ardupilot_defaults.yaml`| register (optional) | the values ArduPilot ships with (Plane-4.7.2), same names and units as `controller.yaml`; a reference only, never an input (docs/DEFAULTS_spec.md) |
24
25
25
26
**Register files** are the *data*: every entry carries a value, a unit, a source and an evidence
26
27
status, and the toolkit tracks how much of every result rests on assumptions. **Plain files** are
@@ -188,19 +189,18 @@ a measured table is not supported yet (see "Not supported yet").
188
189
| `descent.kappa` | - | 0.25 | vortex-ring fraction of induced velocity. **Unsourced: must come from a sourced boundary (Johnson, NASA).** Analysis F refuses to run without it |
189
190
| `descent.v_fragility`, `v_sensor`, `h_slow`, `v_final` | m/s, m/s, m, m/s | 3, *omitted*, 5, 0.5 | payload-fragility and sensor limits; the final slow descent |
190
191
| `requirements.range_primary_km`, `range_p95_km` | km | 100, 113 | range requirements the budget is checked against |
191
-
| `speeds.entry_eas_ms` | m/s | 22 | equivalent airspeed at the start of the back-transition |
192
192
193
193
## `controller.yaml` reference
194
194
195
195
The `ardupilot` group uses the **real parameter names**.
196
196
197
197
| Entry | Unit | Placeholder | Meaning |
198
198
| --- | --- | --- | --- |
199
-
| `AIRSPEED_MIN` | m/s | 14 | transition speed. The simulated controller compares *true* airspeed; whether ArduPilot compares EAS or TAS is open (O-02) |
199
+
| `AIRSPEED_MIN` | m/s | 14 | transition speed, read as an **equivalent** airspeed by D, C, B1 and FT (`D.entry_convention: eas`; ArduPilot compares EAS, O-14 and O-23). E reads it the same way (`Q2.feed_convention: eas`) |
200
200
| `Q_TRANSITION_MS` | ms | 5000 | rotor fade time after `AIRSPEED_MIN` (documented default) |
| `PTCH_LIM_MAX_DEG` | deg | 35 | fixed-wing pitch limit (fixed in analysis C, not searched) |
203
+
| `PTCH_LIM_MAX_DEG` | deg | 20 | the ArduPilot default (`PITCH_MAX` 20, Plane-4.7.2); fixed in analysis C, not searched. The pitch cap is `min(Q_A_ANGLE_MAX, PTCH_LIM_MAX_DEG)`, so a `Q_A_ANGLE_MAX` above this does nothing |
| `TKOFF_THR_MAX` | - | 0.7 | pusher throttle in AUTO during the forward transition |
206
206
| `Q_TRANS_FAIL` | ms | 0 | stuck-transition timeout; 0 disables it |
@@ -232,11 +232,12 @@ recommendation. Add scenarios by adding lines; refer to them by name in `study.y
232
232
| `analyses` | which of `A D F E Q2 C B1 sensitivity` to run; `--only` overrides it |
233
233
| `switch_test` | `ground` or `air`: the speed used in the switch-point test (O-02) |
234
234
| `A`, `D`, `F`, `E`, `Q2` | grids and scenario lists for the quick analyses. `A` also takes `alpha_min_deg` and `cl_frac`: the wing angle-of-attack band the feasibility scan must stay inside (lower end of the lift fit; the angle where C_L = `cl_frac` x C_L,max, provisional because C_L,max is), and `vrs_enforce` (default `false`: the rotor V_c / v_h ratio is only reported; `true`: also infeasible when it is below `-descent.kappa`) |
235
-
| `D` (more) | Entry is the AIRBRAKE exit at `max(AIRSPEED_MIN - 2, q_assist_speed_ms)` (`entry_convention` `tas`/`eas`). `ff_mode` (`lift_aware` is an oracle at tau 0 and scale 1), `theta_fw0_deg` (placeholder), `pit_lim_mode`, `enforce_alpha` (report-only checks always run), `alpha_gate_ms`, `sink_tol_ms`, `rotor_lag_s`, `v0_eas_ms` (diagnostic grid), `sens` (sensitivity sweeps), `recommendation` (`ensemble_n` a power of two, `percentile`, `corners`, `n_boot`, `design_ground_speed_ms` inside the curve or null), `curve.ground_speeds_ms` (the `D_a_rec_curve` speeds, each above the 1 m/s end speed), `trade`. `E.a_plan_fallback_ms2` is used when D gives no recommendation |
236
-
| `Q2`, `E` (more) | `Q2` also takes `soc`, `conventions` (`tas`, `eas`: how `AIRSPEED_MIN` is read) and `feed_convention` (the one E reads), `isa_offset_k`, `n_speed`, `write_profile`. `E.a_fwd_mode` is `case` (Q2 at E's own site), `worst` (the Q2 grid) or `mission` (`a_fwd` in `mission.yaml`); `E.a_fwd_metric` is `min` or `equiv` |
235
+
| `D` (more) | Entry is the AIRBRAKE exit at `AIRSPEED_MIN - 2` (`entry_convention` `tas`/`eas`; `Q_ASSIST_SPEED` is not modelled, the study assumes it is 0, O-20). `ff_mode` (`lift_aware` is an oracle at tau 0 and scale 1), `theta_fw0_deg` (placeholder), `pit_lim_mode`, `enforce_alpha` (report-only checks always run), `alpha_gate_ms`, `sink_tol_ms`, `rotor_lag_s`, `v0_eas_ms` (diagnostic grid), `sens` (sensitivity sweeps), `recommendation` (`ensemble_n` a power of two, `percentile`, `corners`, `n_boot`, `design_ground_speed_ms` inside the curve or null), `curve.ground_speeds_ms` (the `D_a_rec_curve` speeds, each above the 1 m/s end speed), `trade`. `E.a_plan_fallback_ms2` is used when D gives no recommendation |
236
+
| `Q2`, `E` (more) | `Q2` also takes `soc`, `conventions` (`tas`, `eas`: how `AIRSPEED_MIN` is read) and `feed_convention` (the one E reads), `isa_offset_k`, `n_speed`, `write_profile`. `E.a_fwd_mode` is `case` (Q2 at E's own site), `worst` (the Q2 grid) or `mission` (`a_fwd` in `mission.yaml`); `E.a_fwd_metric` is `min` or `equiv` (with `min` the wait is a constant worst-case acceleration and overstates the wait at altitude); `E.fade_wing_share` (0.4, ASSUMED) is the wing's share of the weight at the hand-over, taken from FT's simulated hand-overs, so E's rotor fade is not an independent check of FT |
237
237
| `E` (sites) | `E.sites_amsl_m` (airfield elevations; the cruise altitude is the site plus `mission.profile.climb_height_m`) and `E.missions` (`round_trip`, `one_way`). The range is an output; `ranges_km` and the requirements are report points. `mission.yaml` no longer holds `cruise_amsl_m`, `ground_amsl_m`, `v_climb` or `v_glide` (omit the last two to use the cruise speed) and gains `climb_height_m`, `v_cruise_ref_amsl_m`, `payload_kg`, `t_drop_s` and `battery_window.soc_start` |
238
+
| `FT` | analysis FT, the forward transition from hover (docs/FT_spec.md). The start is `mission.profile.clearance_agl_m` above the site; the accepted altitude loss and gain are `mission.profile.fwd_alt_loss_max_m` and `fwd_alt_gain_max_m` (status `assumed`). Ensemble size, seed and `headwind_ms` range; search `popsize` (the seeds and iterations are under `scan` and `grid`); `rotor_lag_s`; `t_end_s` and `t_settle_s`; `tecs_start` (`warm` or `cold`: does TECS run in the VTOL hover? open); `stall_margin` (EAS over the stall speed from the hand-over on, 1.2); `rec_cl_frac`; `proj_is_failure`; `weights`; `bounds` for `AIRSPEED_MIN` (EAS), `Q_TRANSITION_MS`, `TKOFF_THR_MAX` and `Q_TRAN_PIT_MAX`; `scan`, `history_scenarios` and `sens`. The new `controller.yaml` entries (`Q_TRAN_PIT_MAX`, `TKOFF_THR_MIN`, `TRIM_THROTTLE`, `THR_MIN`, `THR_MAX`, `THR_SLEWRATE`, `PTCH_LIM_MIN_DEG` and the `tecs` group) are ArduPilot defaults with status `TBD` |
238
239
| `C` | analysis C from the AIRBRAKE exit (entry from the `D` block). Ensemble size and seed, search `seeds`, `popsize`, `maxiter`; `rotor_lag_s` (0.25, D's lumped lag); `rotor_start` (`idle` is O-13, unverified, or `carry`); `os_tol_m` and `sink_tol_ms` (the overshoot and end-sink tolerances that make a run fail; PROPOSED, and the overshoot tolerance decides the answer); `weights` (the normalisers `h_ref`, `E_ref`, `x_ref`); `bounds` for `T_bt`, `theta_A_deg`, `spin_min` and `q` (`Q_TRANS_DECEL`, a searched variable); `z` (ArduPilot's vertical-loop gains); `q_curve` and `sens` (the grids of `C_q_curve` and `C_sens`). `a_plan_source` was removed and is rejected |
239
-
| `B1` | B1 from the AIRBRAKE exit (entry rotor start and sink tolerance from `C`, entry speed rule from `D`). `scenarios`, the collocation mesh (`intervals`, `refine_from`, `max_iter`), `eps_h_m` (the headline altitude band, a list), `eps_x_m` (the distance caps swept: the front), `end_vh_band_ms` (null = `C.sink_tol_ms`), `variants` (the stated wing limits: each has `name`, exactly one of `alpha_margin` or `alpha_max_deg`, and `theta_cmd_max_deg`; there is no "no limit" variant), `band_sweep` and `sens` (sensitivities), and `gap_c` (the C parameters the same-problem gap uses; null = the register values at q = 2). A scalar `eps_x_m` (the old format) is rejected |
240
+
| `B1` | B1 from the AIRBRAKE exit (entry rotor start and sink tolerance from `C`, entry speed rule from `D`). `scenarios`, the collocation mesh (`intervals`, `refine_from`, `max_iter`), `eps_h_m` (the headline altitude band, a list), `eps_x_m` (the distance caps swept: the front), `end_vh_band_ms` (null = `C.sink_tol_ms`), `variants` (the stated wing limits: each has `name`, exactly one of `alpha_margin` or `alpha_max_deg`, and `theta_cmd_max_deg` (`null` = the register's `PTCH_LIM_MAX_DEG`, which is what `c_envelope` uses, so it follows the register); there is no "no limit" variant), `band_sweep` and `sens` (sensitivities), and `gap_c` (the C parameters the same-problem gap uses; null = the register values at q = 2). A scalar `eps_x_m` (the old format) is rejected |
240
241
| `sensitivity` | the scenario, the two Morris sizes, and whether to include the energy budget |
241
242
242
243
Effort knobs worth knowing: `C.maxiter`, `B1.intervals` and `sensitivity.r_large`
@@ -281,5 +282,6 @@ Exit codes: `0` ok, `1` a task failed, `2` the inputs are unusable (or release m
281
282
Table-driven maps (CSV over J and μ) and a measured open-circuit-voltage / equivalent-circuit table
282
283
need B-spline interpolants in the model and are the next step; the register already accepts `file:`
283
284
entries, but nothing reads them.
284
-
* **A forward-transition optimisation** and a simulated forward transition in the energy budget.
285
+
* **A simulated forward transition in the energy budget.** E uses a quasi-steady estimate; the forward
286
+
transition is simulated and optimised by analysis FT, which does not feed E (E's `a_fwd` is not wired to it).
285
287
* **Per-scenario vehicle changes** other than mass (a hot-day derating of the motors, say).
# ArduPilot factory defaults of the parameters this study decides or assumes. REFERENCE ONLY
2
+
# (docs/DEFAULTS_spec.md): never a recommendation, never used as an input. Same format and status
3
+
# words as controller.yaml. Every entry was read from the ArduPilot source at tag Plane-4.7.2 on
4
+
# 2026-10-27. Names that no analysis decides (THR_SLEWRATE, the TECS_* group, PTCH_LIM_MIN_DEG,
5
+
# PTCH_LIM_MAX_DEG) are not listed: their register values in controller.yaml already are the
6
+
# defaults.
7
+
#
8
+
# Two entries store a "use another parameter" value as ArduPilot does and are resolved by
9
+
# inputs.resolve_default: TKOFF_THR_MAX 0 means THR_MAX; Q_A_ANGLE_MAX is the attitude controller's
10
+
# ANGLE_MAX, whose default is 30 deg.
11
+
12
+
ardupilot:
13
+
AIRSPEED_MIN: {value: 9.0, unit: "m/s", source: "AIRSPEED_FBW_MIN 9 in ArduPlane/config.h (the default of AIRSPEED_MIN in Parameters.cpp), Plane-4.7.2; the same value as Plane-4.6.3", status: documented}
0 commit comments