Tuning parameters: Difference between revisions

From 'Engineers of Innovation Wiki'
Jump to navigation Jump to search
No edit summary
No edit summary
 
Line 171: Line 171:
| 19 || <code>F</code> || <code>PTCH_RATE_FF</code> || 0 || 4 || 0.01 || 0.05 ||  || Common-mode angle in direct proportion to the pitch rate being asked for: moves both wings the instant a pitch change is demanded. Seeded from the model plant inverse
| 19 || <code>F</code> || <code>PTCH_RATE_FF</code> || 0 || 4 || 0.01 || 0.05 ||  || Common-mode angle in direct proportion to the pitch rate being asked for: moves both wings the instant a pitch change is demanded. Seeded from the model plant inverse
|-
|-
| 20 || <code>M</code> || <code>PTCH_RATE_IMAX</code> || 0 || 40 || 0.1 || 0.5 ||  || Cap on the standing common-mode angle the pitch integrator may hold. Radian units, as roll: full travel = IMAX 0.785, so the seeded 17.5 is no cap. '''The script overrides it in RAM:''' <code>hydrofoils.lua</code> sets it to 0 while the hull is down, then restores this value at unstick. That gate, with the 2° <code>HYD_CMDMAX</code> clamp, is why the fronts reached only about 4° hull-down on 2026-10-18: trim + P + FF, with no integrator
| 20 || <code>M</code> || <code>PTCH_RATE_IMAX</code> || 0 || 40 || 0.1 || 0.5 ||  || Cap on the standing common-mode angle the pitch integrator may hold. Radian units, as roll: full travel = IMAX 0.785, so the seeded 17.5 is no cap. '''The script overrides it in RAM:''' <code>hydrofoils.lua</code> sets it to 0 while the hull is down, then restores this value at unstick. That gate, with the 2° <code>HYD_CMDMAX</code> clamp, is why the fronts reached only about 4° hull-down on 2026-10-18: trim + P + FF, with no integrator. In wheelie mode (<code>SCR_USER1</code> = 1) the script holds it at 0.35 (44% of travel) instead, against the windup that lifted a front foil out of the water in run 14; leaving wheelie mode restores this value
|-
|-
| 21 || <code>C</code> || <code>PTCH2SRV_TCONST</code> || 0.1 || 2 || 0.05 || 0.1 ||  || Angle→rate time constant (s): the pitch-rate demand is the pitch error divided by this, so it sets how much the wings deflect per degree of pitch error. With the hull pinned in the run-up, a smaller value means more front angle for the same demand. Too small overshoots in flight
| 21 || <code>C</code> || <code>PTCH2SRV_TCONST</code> || 0.1 || 2 || 0.05 || 0.1 ||  || Angle→rate time constant (s): the pitch-rate demand is the pitch error divided by this, so it sets how much the wings deflect per degree of pitch error. With the hull pinned in the run-up, a smaller value means more front angle for the same demand. Too small overshoots in flight
Line 284: Line 284:
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description
|-
|-
| 48 || <code>y</code> || <code>SCR_USER1</code> || 0 || 1 || 1 || 1 || '''yes''' || Operating mode. 0 = height control (full cascade). 1 = roll test / wheelie: the height loop is off, FBWA holds a fixed nose-up pitch (<code>SCR_USER2</code>) so the front wings lift the bow while the stern stays in the water, and the rear foil is parked at its low-lift setpoint. Takes effect on the next 10 Hz iteration: a mode change, not a tweak, hence the lock
| 48 || <code>y</code> || <code>SCR_USER1</code> || 0 || 1 || 1 || 1 || '''yes''' || Operating mode. 0 = height control (full cascade). 1 = roll test / wheelie: the height loop is off, FBWA holds a fixed nose-up pitch (<code>SCR_USER2</code>) so the front wings lift the bow while the stern stays in the water, and the rear foil is parked at its low-lift setpoint. The pitch integrator is capped at <code>PTCH_RATE_IMAX</code> 0.35 while in it. Keep below about 22 km/h: there is no height loop, so a fixed pitch target at rising speed lifts the bow until the foils breach. Takes effect on the next 10 Hz iteration: a mode change, not a tweak, hence the lock
|-
|-
| 49 || <code>q</code> || <code>SCR_USER2</code> || −10 || 10 || 0.5 || 1 ||  || Wheelie-mode pitch target (°); 0 uses the built-in 3°. Higher = more front-foil angle and a higher bow
| 49 || <code>q</code> || <code>SCR_USER2</code> || −10 || 10 || 0.5 || 1 ||  || Wheelie-mode pitch target (°); 0 uses the built-in 3°. Higher = more front-foil angle and a higher bow

Latest revision as of 22:02, 20 October 2026

The tuning parameters are the live-adjustable knobs of the autopilot's foiling control system: the roll and pitch attitude loops, the ride-height loop, the rear-foil schedule, coordinated-turn banking, and the operating-mode switches. Every one of them can be read and written over the CAN bus while the boat is running, from the helm keyboard, the datalogger, or any other node — which is what makes on-water tuning possible without a laptop, a cable, or a MAVLink link.

The autopilot side of this is foil_tune.lua, a small dedicated script on the flight controller that bridges CAN to the parameter system. It is deliberately separate from the control script (hydrofoils.lua): a bug in the tuning bridge can never take down the control loop, and simply not uploading the file removes the tuning surface entirely. The two never talk to each other — parameters are the shared state. The keyboard tool (tools/foil_tune.py) and the display's foiling screen mirror the same map; the hotkeys and cursor grid are documented in FOILING_PARAMETERS.md of the eoi-can repository.

At a glance

Tuning bridge summary
Property Value
Protocol version 11 (both sides check it at connect; index 0xFE returns it)
CAN identifiers 0x260 set · 0x261 value/ack · 0x262 request — 11-bit standard IDs
Value encoding IEEE754 float32, little-endian
Parameters 49 tunable entries (indices 1–59 with gaps; 37/38/54/58 retired, 59 off the grid)
Persistence All writes volatile by default — a power-cycle reverts a bad tune; persisting to flash is an explicit flag
Safety FC-side whitelist with min/max clamps; envelope and mode entries locked while foiling
Boot behaviour One unsolicited full dump ~5 s after every FC boot, so passive listeners repopulate
Pacing Dumps and bulk restores stream at ≤ 8 frames per 50 ms; senders pace to ~40 frames/s
Bus priority The 0x2xx tuning IDs lose CAN arbitration to every safety frame (0x010–0x012) — tuning can only use idle bus time
Source of truth The PT table in foil_tune.lua; mirrored in tools/foil_tune.py, which generates this page (tools/export_wiki.py)

How a parameter is read and written

Three frame types carry everything. A set (0x260) names a parameter by its index, carries the new value as a float32, and one flag bit: persist-to-flash, which is normally left off so that everything written during a tuning session evaporates on the next power-cycle unless deliberately saved. A request (0x262) asks for one index, or for the whole table (0xFF), or for the protocol version (0xFE). Every set and every request is answered by a value frame (0x261) that carries a status byte and — crucially — the value read back from the flight controller after clamping, locking and type-casting. The reply never echoes what was merely requested: it reports what the boat is actually using. A display that simply listens to 0x261 therefore mirrors every tuning change made by anyone, in real time, without sending a single frame.

Status byte in the 0x261 reply
Code Name Meaning
0 ok Accepted (or read) as-is
1 unknown No such index (includes the retired indices 37 and 38)
2 clamped The value hit the whitelist's min/max; the reply carries the clamped value in force
3 failed The parameter system refused the write (should not happen in practice)
4 unavailable The parameter does not exist yet — HYD_* before hydrofoils.lua has booted, or TRN_* when foil_turn.lua is not uploaded at all. For the turn parameters this doubles as the "is the feature installed?" probe
5 LOCKED Refused: the entry is envelope/mode-class and the boat is under autopilot control (see below). The reply carries the unchanged value in force

Three bus behaviours are worth knowing when building anything that listens:

  • Boot dump. About five seconds after every flight-controller boot, the bridge transmits one unsolicited full dump — one 0x261 per entry, then an end marker (index 0xFF, value = entry count). A passive listener is repopulated after every power-cycle without asking, and can always re-request with 0x262/0xFF.
  • Cursor convention. When the helm keyboard's cursor settles on a cell, the tool re-requests that cell's parameter(s). The resulting 0x261 is read-only — no value changes — but tells the display where the cursor is: the latest solo value frame is "cursor here". During active tuning the acks serve the same purpose.
  • Congestion is a non-issue by construction. CAN arbitration gives numerically lower IDs priority, so the tuning traffic (0x260–0x262) and the throttle beeper (0x338) always yield to the safety frames — rear foil 0x010, height sensors 0x011/0x012 — bit-for-bit, without delaying them. A full 49-parameter restore plus its acks costs about 13 ms of wire time at 1 Mbit/s, and is paced anyway to protect the FC's receive buffer.

Safety model

Two independent mechanisms protect the boat from the tuning surface itself, because the bridge is reachable from any node on a shared bus and — since the helm keyboard exists — from a single keystroke:

  • Whitelist and clamps (wrong values). Only the entries in the table below exist; everything else is refused. Every accepted value is clamped FC-side to the listed min/max, so no UI bug can write an out-of-range gain. A few floors are deliberately non-zero: the rate-loop P gains cannot go below 0.02, because P = 0 means "inner loop off", which is not a tune and must not be one key-repeat away on a manned foiler. (HYD_RKP, the rear pitch term, was floored at 0.15 on the same reasoning until 2026-08-24, then 0, and was retired with the term in 2026-09.)
  • In-flight locks (wrong moments). Some entries are refused outright (status 5) whenever the enable pin says the autopilot is controlling the boat. These are the entries that are not tuning at all: they change what the system is doing rather than how well it does it. A wrong gain degrades gradually; these act instantly. The attitude envelope (ROLL_LIMIT_DEG, PTCH_LIM_*) defines what the boat is ever allowed to do — its whole legal range contains capsize territory, so changing it is an ashore decision. The mode knobs SCR_USER1 (flips to roll-test mode, dropping the height loop on the very next 10 Hz iteration) and SCR_USER4 (open-loop rear-foil jog, a bench calibration function) are flight-mode changes, not parameter tweaks. TRN_REV flips the steering sense — mid-turn that would drive the bank to the opposite stop. To change any of them: enable off, write, re-enable — a deliberate two-hand action.

The lock's arbiter is the enable pin, and its ambiguity fails safe: if the button configuration is not verifiably in place, the bridge assumes the boat is under control and locks — the safe default for "may I change this?" is the opposite of the safe default for "should I control the boat?". Note that TRN_ENABLE is deliberately not locked: it is the in-flight off-switch for the banking feature, and switching it off ramps the bank out at TRN_RATE rather than snapping.

Recovery from a bad (volatile) tune is always the same: enable off, power-cycle — everything not explicitly persisted reverts to the values in flash.

How the parameters reach the foils

The boat has three foils, and they are driven in two quite different ways. Knowing which parameter reaches which foil, and in which direction, is most of what is needed on the water.

Front foils (the two elevons)

Each front wing's angle is the sum of three parts, recomputed ten times a second. Angles are the foil's angle to the hull; in the water add the hull's pitch.

What makes up a front wing's angle
Part Set by Typical size
Trim SERVO_LIMITS in hydrofoils.lua: the 8 m/s cruise angle, the same on both wings +2.8°
Feed-forward HYD_FRNTFF × (rear schedule angle − its 9 m/s angle), so HYD_RSCHED and HYD_RSCALE reach the fronts through it. The same on both wings; it moves with speed only, by shifting the trim +3.8° in the run-up, +2.0° at 28 km/h, 0 at 9 m/s (at the seeded 0.944)
FBWA output Pitch (common mode, both wings the same way) ± roll (differential, opposite ways) from the rate loops, × SCALING_SPEED / speed From the trim up to the +9.5° stop, or down to the −7.5° stop

Both wings stop at −7.5° and +9.5°, matched in degrees since 2026-10-18, so at the +2.8° trim FBWA has 6.7° of up travel and 10.3° of down. The feed-forward moves the trim itself, and ArduPlane scales the FBWA output between that moved trim and the stops: a larger feed-forward leaves less up travel for FBWA, and the sum can never pass a stop.

What the FBWA output is asked for comes down a chain: ride-height error → HYD_KP / HYD_KI / HYD_KD, clamped to HYD_CMDMIN … HYD_CMDMAX → pitch target (within PTCH_LIM_*) → ÷ PTCH2SRV_TCONST → pitch-rate target → PTCH_RATE_FF / P / I / D → both wings. Roll runs the same chain from the roll target: level, a bank from foil_turn.lua, or a roll step.

While the hull is in the water it holds the pitch, so the chain never closes. The wings sit at a steady deflection set by the pitch demand (HYD_KP × the height error, clamped at HYD_CMDMAX), PTCH2SRV_TCONST, the pitch P and FF gains and SCALING_SPEED. Meanwhile the script holds both integrators off, the height loop's and FBWA's pitch-rate integrator, so nothing winds up against the hull. On 2026-10-18 that left the fronts at about 4° at 27 km/h: the 2.8° trim plus about 1.3° of elevon from a ~2° demand, with HYD_FRNTFF at 0. The live knobs that add front angle in the run-up are HYD_FRNTFF (by far the largest), PTCH2SRV_TCONST and SCALING_SPEED.

Rear foil (the stepper)

The rear angle comes from the speed schedule alone: −4.5° + HYD_RSCHED / speed², held between −2° and the +5.6° run-up cap, × HYD_RSCALE and capped again. A slow follow-up (HYD_RTKI, off the grid) adds whatever standing demand the height integrator is carrying. No FBWA gain and no height-loop gain moves the rear directly.

Which parameters move which foil
Parameters Front foils Rear foil
RLL_*, RLL2SRV_*, ROLL_LIMIT_DEG, TRN_*, SCR_USER3 Differential (roll) —
PTCH_*, PTCH2SRV_*, HYD_KP … HYD_CMDMIN, HYD_TARGET, SCR_USER2 Common mode (pitch) —
SCALING_SPEED Scales both, roll and pitch —
HYD_RSCHED, HYD_RSCALE Common mode, through HYD_FRNTFF Yes: the schedule
HYD_FRNTFF Common mode (the feed-forward) No
SCR_USER4 — Bench jog, only while disabled

Parameter map

Indices are the wire contract: they are only ever appended, never renumbered, and a change bumps the protocol version. Hotkey is the helm-display key that jumps to the cell (case matters: P is the rate loop's P, p the height loop's). Fine and coarse are the increment sizes used by the keyboard's volume keys / +− and <> respectively — conventions of the tools, not of the protocol, which always carries absolute values.

Roll inner loop

The ArduPlane FBWA rate-plus-angle controller, driving the two front foils differentially: one wing's angle goes up while the other's goes down (elevon mixing), which rolls the boat. A right-roll demand raises the left foil and lowers the right. Roll is the high-authority axis, about 16 °/s of roll rate per degree of differential foil at 8 m/s, so its gains are numerically small.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
1 P RLL_RATE_P 0.02 2 0.005 0.02 Differential front-foil angle per °/s of roll-rate error: how hard the two wings work against each other to stop an unwanted roll. Higher = a firmer, quicker correction; too high and the wings flap against each other in a fast roll wobble. The floor is non-zero on purpose: 0 would switch the roll loop off
2 I RLL_RATE_I 0 2 0.005 0.02 Builds up a standing differential angle that holds the boat level against a steady roll moment: a leaning driver, uneven load, a side current. Too low and the boat flies with a standing heel; too high and it wallows slowly from side to side. ArduPlane freezes this integrator whenever the speed estimate is at or below AIRSPEED_MIN (5 m/s), so below that a lean is held by P and FF alone
3 D RLL_RATE_D 0 0.5 0.001 0.005 Differential angle against roll acceleration: damps fast roll motion, but feeds sensor noise straight into wing chatter. Seeded 0
4 F RLL_RATE_FF 0 3 0.01 0.05 Differential angle in direct proportion to the roll rate being asked for. It moves the wings the moment a bank or roll step is demanded, before any error builds up: ArduPlane's workhorse term. The seed is the model plant inverse (0.33), not a fitted value
5 M RLL_RATE_IMAX 0 30 0.1 0.5 Cap on how much standing differential the roll integrator may hold. The units are the PID's internal radians: full differential travel is IMAX 0.785, so the seeded 10 is no cap at all (only the anti-windup at full surface applies). A 0.1 m driver lean at unstick speed needs about 0.37
6 C RLL2SRV_TCONST 0.1 2 0.05 0.1 Angle→rate time constant (s): the roll-rate demand is the roll error divided by this. Smaller = the wings are driven harder per degree of heel and the boat levels faster; too small overshoots
7 R RLL2SRV_RMAX 0 180 5 15 Cap on the roll rate the angle loop may ask for (°/s), and so on how fast the wings swing apart after a big disturbance. 0 = no cap
8 L ROLL_LIMIT_DEG 5 20 1 5 yes Largest roll target the controller will ever ask for (°). It bounds turn banking and roll steps, and so the differential foil angle used to reach them. 45° of roll on a foiling boat is a capsize, not a limit. Locked in flight: it is the airframe envelope, not a gain
9 T RLL_RATE_FLTT 0 100 1 5 Low-pass filter on the roll-rate target (Hz). Lower = smoother wing motion but more lag, which costs stability margin
10 E RLL_RATE_FLTE 0 100 1 5 Low-pass filter on the roll-rate error (Hz); same trade as FLTT
11 G RLL_RATE_FLTD 0 100 1 5 Low-pass filter on the D term (Hz), the first knob against high-frequency wing chatter
12 S RLL_RATE_SMAX 0 200 5 20 Slew guard: when the roll output moves faster than this, ArduPlane automatically lowers P and D until it calms down. An anti-oscillation safety net, not a tuning gain. 0 = off

Pitch inner loop

The same controller structure for pitch, driving both front foils together (common mode): nose-up raises both wings' angle, adding lift at the bow. The rear foil is not on this loop: it follows its speed schedule only (below). Pitch is the low-authority axis, about 1.8 °/s of pitch rate per degree of common-mode foil at 8 m/s, nine times weaker than roll, so its gains run several times higher. While the hull is in the water the pitch is pinned, so these gains set a steady wing deflection there rather than a pitch response.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
16 P PTCH_RATE_P 0.02 8 0.02 0.1 Common-mode front-foil angle (both wings together) per °/s of pitch-rate error. Higher = the bow is held more firmly; too high oscillates in pitch. In the run-up the hull pins the pitch, so the error never closes and P and FF hold a steady deflection: they are what deflects the wings there. Non-zero floor, as roll
17 I PTCH_RATE_I 0 8 0.02 0.1 Builds up the standing common-mode front angle that trims the boat at its current speed and load: the cruise trim. Too low and the boat rides off its pitch target; too high and it porpoises slowly. While the hull is in the water and the boat has not foiled since it was last slow, hydrofoils.lua holds this integrator at 0 (see PTCH_RATE_IMAX) so it cannot wind up against the hull
18 D PTCH_RATE_D 0 0.5 0.001 0.005 Common-mode angle against pitch acceleration: damps fast bow motion but feeds noise to the wings. Seeded 0
19 F PTCH_RATE_FF 0 4 0.01 0.05 Common-mode angle in direct proportion to the pitch rate being asked for: moves both wings the instant a pitch change is demanded. Seeded from the model plant inverse
20 M PTCH_RATE_IMAX 0 40 0.1 0.5 Cap on the standing common-mode angle the pitch integrator may hold. Radian units, as roll: full travel = IMAX 0.785, so the seeded 17.5 is no cap. The script overrides it in RAM: hydrofoils.lua sets it to 0 while the hull is down, then restores this value at unstick. That gate, with the 2° HYD_CMDMAX clamp, is why the fronts reached only about 4° hull-down on 2026-10-18: trim + P + FF, with no integrator. In wheelie mode (SCR_USER1 = 1) the script holds it at 0.35 (44% of travel) instead, against the windup that lifted a front foil out of the water in run 14; leaving wheelie mode restores this value
21 C PTCH2SRV_TCONST 0.1 2 0.05 0.1 Angle→rate time constant (s): the pitch-rate demand is the pitch error divided by this, so it sets how much the wings deflect per degree of pitch error. With the hull pinned in the run-up, a smaller value means more front angle for the same demand. Too small overshoots in flight
22 R PTCH2SRV_RMAX_UP 0 180 5 15 Cap on the nose-up pitch rate (°/s) the angle loop may ask for. On the display this is one cell with RMAX_DN: the two are edited together and kept equal
23 R PTCH2SRV_RMAX_DN 0 180 5 15 Cap on the nose-down pitch rate (°/s); paired with RMAX_UP as above
24 X PTCH2SRV_RLL 0 1.5 0.01 0.05 Extra nose-up asked for in a bank (aircraft turn compensation), which would move both front wings up in every turn. Seeded 0: a boat does not pitch in a bank the way an aircraft does, which is why the floor is 0 instead of ArduPlane's customary 0.7
25 L PTCH_LIM_MAX_DEG 1 10 1 5 yes Largest nose-up pitch the boat may ever be asked for (°). The boat lifts off by pitching up, so this sets the lowest foiling speed: the model unsticks at about 6.2 m/s with 5° and 5.75 m/s with 7°, but each degree costs about 1° of front-foil stall margin at that moment. One display cell with LIM_MIN, mirrored: + widens the envelope. Locked in flight
26 L PTCH_LIM_MIN_DEG −10 −1 1 5 yes Largest nose-down pitch (°). This bounds the top foiling speed: past the speed where the trim attitude reaches it (about 10.3 m/s at −3°), the boat cannot shed lift by pitching and climbs until the foils ventilate. Mirrored pair of LIM_MAX
27 T PTCH_RATE_FLTT 0 100 1 5 Low-pass filter on the pitch-rate target (Hz): smoother wing motion for more lag
28 E PTCH_RATE_FLTE 0 100 1 5 Low-pass filter on the pitch-rate error (Hz)
29 G PTCH_RATE_FLTD 0 100 1 5 Low-pass filter on the pitch D term (Hz)
30 S PTCH_RATE_SMAX 0 200 5 20 Slew guard for pitch, as roll: lowers P and D automatically when the wings start moving faster than this. 0 = off

Speed scaling

One parameter stands apart because it silently retunes everything above: ArduPlane multiplies every surface output on both axes by SCALING_SPEED / airspeed (clamped to roughly [0.5, 2]). So it changes how far both front wings move for a given error, at every speed. It must be set to the boat's real foiling cruise speed, or none of the seeded gains mean what they say: a boat doing 8 m/s with the firmware default of 15 would run nearly double gains.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
31 Q SCALING_SPEED 4 15 0.5 1 Multiplies every FBWA output, roll and pitch, on both front wings by SCALING_SPEED / speed. Lower it and the wings move less for the same error at every speed; raise it and they move more. Seeded 8. On 2026-10-18 it was lowered to 7, about 12% less elevon at 27 km/h. Listed in the Pitch group, but it is not a pitch gain, and it never touches the rear foil

Height outer loop

The ride-height controller in hydrofoils.lua: it turns the EKF's height-above-water estimate into a pitch demand for the inner loop, so it acts on the foils only through the front wings' common mode. Too low = nose-up = more front-foil angle. These parameters are created when that script boots, so they answer unavailable (status 4) for the first seconds after power-on.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
32 p HYD_KP 0 2000 10 50 Turns a height error into a nose-up pitch demand, and through FBWA into common-mode front-foil angle. At 960, 0.1 m below target asks for about 1° of nose-up. Higher = the boat chases its target harder; too high porpoises
33 k HYD_KI 0 500 5 20 Integrates the remaining height error into a standing pitch demand, which trims out steady offsets such as load or a wrong schedule. It only integrates while foiling (front-foil height above 0.18 m) and after the takeoff hold, and decays while the hull is down, so it cannot wind up in the run-up
34 d HYD_KD 0 2000 10 50 Damps on the climb rate: nose-down while climbing, nose-up while sinking. At 1800, climbing at 0.1 m/s asks for about 1.8° of nose-down. This is what stops the fly-up. It uses the EKF's fused climb rate, so it is phase-consistent with the P term and blind to wave-surface motion by design
35 h HYD_IMAX 0 500 10 50 Cap on the height integrator, in hundredths of a degree of pitch demand: 150 = 1.5°
36 t HYD_TARGET 0 1 0.01 0.05 Ride-height setpoint (m) at the front foils. Higher = the foils run shallower, closer to ventilating; the strut breaches at about 0.56 m. Lower = the hull starts touching in waves. The most-used control on the water
37 — retired Was HYD_HSRC (height-source select, removed when control went EKF-exclusive). Answers unknown; the index is reserved forever
38 — retired Was HYD_HDIV (EKF-vs-geometric divergence gate, removed — EKF3's own innovation gating covers it). Reserved forever
39 b HYD_ARM 0 3.8 0.05 0.2 Ride-height reference point: metres from the sensors back to the point whose height is controlled (2.4 = the front foils, 1.4 m forward of the FC). Vehicle geometry, not a gain: only change it if the foil station is re-measured. The ceiling is the true 3.8 m sensor arm
52 g HYD_CMDMAX 0.5 5 0.1 0.5 Most nose-up pitch the height loop may ask for (°): its own authority, separate from the airframe envelope PTCH_LIM_*, which stays locked. It only bites when HYD_KP × height error (+ D) asks for more. Hull down on 2026-10-18 the loop asked for about 2.1° against the 2.0 clamp, so raising it alone adds little front angle there: the demand, not the clamp, is what is small. Higher = more nose-up authority in flight, so a bigger possible fly-up. One display cell with CMDMIN, mirrored
53 g HYD_CMDMIN −8 −0.5 0.1 0.5 Most nose-down pitch the height loop may ask for (°): how hard it can push the bow down, and so the fly-up overshoot. The first knob to reach for after watching a fly-up

Rear-foil schedule

The rear foil's speed schedule, also in hydrofoils.lua. The rear is trim only: a stepper commanded over CAN to the angle that carries its share of the boat at the current speed, with no part in attitude or height control. Two of the three knobs here also move the front foils, through the front feed-forward, and HYD_FRNTFF moves only the fronts. See How the parameters reach the foils.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
54 — retired Was HYD_RKP (the rear foil's pitch-error term: 0 from tune rev 22, removed with the term at rev 23 / protocol v10 — the rear is trim only). Reserved forever
55 W HYD_RSCALE 0.5 1.2 0.02 0.1 Multiplies the rear foil's scheduled angle at every speed. The result is capped at the 5.6° run-up angle again, so above 1 it cannot raise the run-up angle, only keep the rear at the cap to a higher speed. It also moves the front trims, through HYD_FRNTFF. In steady foiling a change does not alter any foil's flying angle: it tilts the boat's trim attitude instead. In the run-up, with the hull holding the attitude, it changes the rear lift directly. 1.0 since rev 27
56 Y HYD_RSCHED 0 1200 5 25 Strength of the rear foil's speed schedule (deg·m²/s²): rear angle = −4.5° + RSCHED / speed², held between −2° and the 5.6° run-up cap. Higher = more rear angle at every speed, and the rear stays at the cap to a higher speed: at 493 it leaves the cap at 25 km/h and sits at 3.6° at 28 km/h. It moves the front trims too, through HYD_FRNTFF. Lowering it takes lift away in the run-up
57 V HYD_FRNTFF 0 1.2 0.01 0.05 Moves the front foils only, despite sitting in the Rear group. Both front trims move by this fraction of the rear schedule's change from its 9 m/s (cruise) angle: front trim += FRNTFF × (rear angle now − rear angle at 9 m/s). At 0.944 (moment balance, rev 27) that is +3.8° on both fronts in the run-up, +2.0° at 28 km/h, 0 at 9 m/s and negative above it. At 0 the fronts sit at their +2.8° trim at every speed (2026-10-18 run 21). It never changes the rear
58 — retired Was HYD_IGATE (integrator-gating bitmask, added to measure what the two integrator gates were worth and removed once measured). Reserved forever
59 — off the grid Is HYD_RTKI, since tune rev 22 the rate at which the height integrator's standing pitch demand is moved onto the rear foil (1/s; seeded 0.05 = a 20 s hand-over, 0 = off). It keeps the height loop centred when the speed schedule is wrong — a heavier driver, a current, a wrong RSCHED. On no cell of the grid on purpose: a rate to leave alone, not a knob for the water. Before rev 22 the same index was the abandoned front-deflection follow-up gain. The index is spoken for and must never be reused

Coordinated-turn banking

Served by a third script, foil_turn.lua, which banks the boat into turns from the steering input. If that script is not uploaded, all six answer unavailable — which is itself the "is the feature installed?" check.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
40 N TRN_ENABLE 0 1 1 1 Feature on/off. Deliberately not locked: this is the in-flight kill switch, and disabling ramps the bank out at TRN_RATE instead of snapping
41 U TRN_ON 5 60 1 5 Steering input (%) at which banking starts. Below it the roll target stays level and the wings get no turn differential
42 A TRN_FULL 10 100 1 5 Steering input (%) giving full bank (TRN_MAX)
43 Z TRN_MAX 0 20 0.5 2 Largest bank angle (°) the steering may ask for; 0 = never bank. The bank is a roll target, so it reaches the foils as front-wing differential. The height target drops with the bank so the outside foil keeps its depth, and the bank is limited to what the current ride height can pay for
44 H TRN_RATE 1 20 0.5 2 How fast the bank may change (°/s): into a turn, out of it, and on signal loss
45 J TRN_REV 0 1 1 1 yes Steering-sense reverse. Locked in flight: flipping it mid-turn would drive the bank to the opposite stop

Mode and test knobs

The scripting user parameters that hydrofoils.lua reads live. Two of them are flight-mode changes and therefore locked while foiling; the two roll-test demands stay live because sweeping them is the test.

Idx Hotkey Parameter Min Max Fine Coarse Locked Description
48 y SCR_USER1 0 1 1 1 yes Operating mode. 0 = height control (full cascade). 1 = roll test / wheelie: the height loop is off, FBWA holds a fixed nose-up pitch (SCR_USER2) so the front wings lift the bow while the stern stays in the water, and the rear foil is parked at its low-lift setpoint. The pitch integrator is capped at PTCH_RATE_IMAX 0.35 while in it. Keep below about 22 km/h: there is no height loop, so a fixed pitch target at rising speed lifts the bow until the foils breach. Takes effect on the next 10 Hz iteration: a mode change, not a tweak, hence the lock
49 q SCR_USER2 −10 10 0.5 1 Wheelie-mode pitch target (°); 0 uses the built-in 3°. Higher = more front-foil angle and a higher bow
50 f SCR_USER3 −20 20 1 5 Roll-step demand (°) for step-response tuning; 0 = level. Reaches the foils as front-wing differential. Watch the achieved attitude come back on telemetry 0x250
51 B SCR_USER4 0 2100 10 50 yes Rear-foil jog: a raw stepper setpoint, clamped to 1000–2000 (0.012° of mount per unit; 0 = off), driven open-loop for bench calibration. Only honoured while the boat is disabled, and locked while foiling for the same reason

Special indices

Index Meaning
0xFE Protocol-version query: the reply's value is the version (currently 11). Any tool should check this before trusting its own copy of this map
0xFF As a request: dump the whole table (one 0x261 per entry, paced). As a reply: the end-of-dump marker, value = number of entries sent
13–15, 46–47 Unused, free for future entries in their groups
37, 38 Retired (HYD_HSRC, HYD_HDIV) — reserved forever, never reuse

Config slots, undo and factory reset

The helm keyboard adds a layer on top of the protocol; none of this exists on the wire beyond the ordinary set/ack frames it generates. Digit keys 1–9 are configuration slots: tap to restore a slot (every stored parameter is re-sent over CAN, volatile, so the acks repopulate every listener), hold ≈1.2 s to store the current acked values into it. Slots are deliberately volatile — held in the tool's memory, wiped on restart, never written to flash — so a slot is a scratchpad for A/B comparisons on the water, not a configuration store; the flash write remains its own explicit action. ~ undoes the last change (one step back per press — a slot restore or factory reset counts as a single step), and 0 held down performs a factory reset to the values read at connect. Restoring while foiling is safe by construction: the locked entries simply refuse (status 5) and everything else lands.

Keeping this page true

This page is GENERATED by tools/export_wiki.py in the autopilot repository, from the same tables the keyboard tuner runs on; regenerate and re-paste it after any parameter change. The authoritative copy of the map is the PT whitelist in foil_tune.lua on the flight controller. Any change to indices, ranges or locks bumps PROTO_VERSION on both sides of the wire — if the version on this page and the one the boat reports at index 0xFE disagree, trust the boat and update this page.