<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.engineersofinnovation.nl/index.php?action=history&amp;feed=atom&amp;title=Tuning_parameters</id>
	<title>Tuning parameters - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.engineersofinnovation.nl/index.php?action=history&amp;feed=atom&amp;title=Tuning_parameters"/>
	<link rel="alternate" type="text/html" href="https://wiki.engineersofinnovation.nl/index.php?title=Tuning_parameters&amp;action=history"/>
	<updated>2026-09-20T10:12:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://wiki.engineersofinnovation.nl/index.php?title=Tuning_parameters&amp;diff=342&amp;oldid=prev</id>
		<title>Aran Dokoupil: Created page with &quot;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...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.engineersofinnovation.nl/index.php?title=Tuning_parameters&amp;diff=342&amp;oldid=prev"/>
		<updated>2026-08-18T17:49:30Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;The &amp;#039;&amp;#039;&amp;#039;tuning parameters&amp;#039;&amp;#039;&amp;#039; are the live-adjustable knobs of the &lt;a href=&quot;/wiki/Autopilot&quot; title=&quot;Autopilot&quot;&gt;autopilot&lt;/a&gt;&amp;#039;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 &lt;a href=&quot;/wiki/CAN-bus&quot; title=&quot;CAN-bus&quot;&gt;CAN bus&lt;/a&gt; while the boat is running, from the helm keyboard, the &lt;a href=&quot;/wiki/Datalogger&quot; title=&quot;Datalogger&quot;&gt;datalogger&lt;/a&gt;, or any other node — which is what makes on-water tuning possible...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;The '''tuning parameters''' are the live-adjustable knobs of the [[Autopilot|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|CAN bus]] while the boat is running, from the helm keyboard, the [[Datalogger|datalogger]], or any other node — which is what makes on-water tuning possible without a laptop, a cable, or a MAVLink link.&lt;br /&gt;
&lt;br /&gt;
The autopilot side of this is &amp;lt;code&amp;gt;foil_tune.lua&amp;lt;/code&amp;gt;, a small dedicated script on the flight controller that bridges CAN to the parameter system. It is deliberately separate from the control script (&amp;lt;code&amp;gt;hydrofoils.lua&amp;lt;/code&amp;gt;): 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 (&amp;lt;code&amp;gt;tools/foil_tune.py&amp;lt;/code&amp;gt;) and the [[Instrumentation Panel|display]]'s foiling screen mirror the same map; the hotkeys and cursor grid are documented in &amp;lt;code&amp;gt;FOILING_PARAMETERS.md&amp;lt;/code&amp;gt; of the eoi-can repository.&lt;br /&gt;
&lt;br /&gt;
== At a glance ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tuning bridge summary&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|-&lt;br /&gt;
| Protocol version || '''7''' (both sides check it at connect; index &amp;lt;code&amp;gt;0xFE&amp;lt;/code&amp;gt; returns it)&lt;br /&gt;
|-&lt;br /&gt;
| CAN identifiers || &amp;lt;code&amp;gt;0x260&amp;lt;/code&amp;gt; set · &amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt; value/ack · &amp;lt;code&amp;gt;0x262&amp;lt;/code&amp;gt; request — 11-bit standard IDs&lt;br /&gt;
|-&lt;br /&gt;
| Value encoding || IEEE754 float32, little-endian&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || 50 tunable entries (indices 1–57 with gaps; 37/38 retired)&lt;br /&gt;
|-&lt;br /&gt;
| Persistence || All writes '''volatile''' by default — a power-cycle reverts a bad tune; persisting to flash is an explicit flag&lt;br /&gt;
|-&lt;br /&gt;
| Safety || FC-side whitelist with min/max clamps; envelope and mode entries '''locked while foiling'''&lt;br /&gt;
|-&lt;br /&gt;
| Boot behaviour || One unsolicited full dump ~5 s after every FC boot, so passive listeners repopulate&lt;br /&gt;
|-&lt;br /&gt;
| Pacing || Dumps and bulk restores stream at ≤ 8 frames per 50 ms; senders pace to ~40 frames/s&lt;br /&gt;
|-&lt;br /&gt;
| Bus priority || The &amp;lt;code&amp;gt;0x2xx&amp;lt;/code&amp;gt; tuning IDs lose CAN arbitration to every safety frame (&amp;lt;code&amp;gt;0x010&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x012&amp;lt;/code&amp;gt;) — tuning can only use idle bus time&lt;br /&gt;
|-&lt;br /&gt;
| Source of truth || The &amp;lt;code&amp;gt;PT&amp;lt;/code&amp;gt; table in &amp;lt;code&amp;gt;foil_tune.lua&amp;lt;/code&amp;gt;; mirrored in &amp;lt;code&amp;gt;tools/foil_tune.py&amp;lt;/code&amp;gt; and this page&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== How a parameter is read and written ==&lt;br /&gt;
&lt;br /&gt;
Three frame types carry everything. A '''set''' (&amp;lt;code&amp;gt;0x260&amp;lt;/code&amp;gt;) 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''' (&amp;lt;code&amp;gt;0x262&amp;lt;/code&amp;gt;) asks for one index, or for the whole table (&amp;lt;code&amp;gt;0xFF&amp;lt;/code&amp;gt;), or for the protocol version (&amp;lt;code&amp;gt;0xFE&amp;lt;/code&amp;gt;). Every set and every request is answered by a '''value frame''' (&amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt;) 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 &amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt; therefore mirrors every tuning change made by anyone, in real time, without sending a single frame.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Status byte in the &amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt; reply&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || ok || Accepted (or read) as-is&lt;br /&gt;
|-&lt;br /&gt;
| 1 || unknown || No such index (includes the retired indices 37 and 38)&lt;br /&gt;
|-&lt;br /&gt;
| 2 || clamped || The value hit the whitelist's min/max; the reply carries the clamped value in force&lt;br /&gt;
|-&lt;br /&gt;
| 3 || failed || The parameter system refused the write (should not happen in practice)&lt;br /&gt;
|-&lt;br /&gt;
| 4 || unavailable || The parameter does not exist yet — &amp;lt;code&amp;gt;HYD_*&amp;lt;/code&amp;gt; before &amp;lt;code&amp;gt;hydrofoils.lua&amp;lt;/code&amp;gt; has booted, or &amp;lt;code&amp;gt;TRN_*&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;foil_turn.lua&amp;lt;/code&amp;gt; is not uploaded at all. For the turn parameters this doubles as the &amp;quot;is the feature installed?&amp;quot; probe&lt;br /&gt;
|-&lt;br /&gt;
| 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&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Three bus behaviours are worth knowing when building anything that listens:&lt;br /&gt;
&lt;br /&gt;
* '''Boot dump.''' About five seconds after every flight-controller boot, the bridge transmits one unsolicited full dump — one &amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt; per entry, then an end marker (index &amp;lt;code&amp;gt;0xFF&amp;lt;/code&amp;gt;, value = entry count). A passive listener is repopulated after every power-cycle without asking, and can always re-request with &amp;lt;code&amp;gt;0x262&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0xFF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Cursor convention.''' When the helm keyboard's cursor settles on a cell, the tool ''re-requests'' that cell's parameter(s). The resulting &amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt; is read-only — no value changes — but tells the display where the cursor is: the latest solo value frame is &amp;quot;cursor here&amp;quot;. During active tuning the acks serve the same purpose.&lt;br /&gt;
* '''Congestion is a non-issue by construction.''' CAN arbitration gives numerically ''lower'' IDs priority, so the tuning traffic (&amp;lt;code&amp;gt;0x260&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x262&amp;lt;/code&amp;gt;) and the [[Throttle|throttle]] beeper (&amp;lt;code&amp;gt;0x338&amp;lt;/code&amp;gt;) always yield to the safety frames — rear foil &amp;lt;code&amp;gt;0x010&amp;lt;/code&amp;gt;, height sensors &amp;lt;code&amp;gt;0x011&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0x012&amp;lt;/code&amp;gt; — bit-for-bit, without delaying them. A full 50-parameter restore plus its 50 acks costs about 13 ms of wire time at 1 Mbit/s, and is paced anyway to protect the FC's receive buffer.&lt;br /&gt;
&lt;br /&gt;
== Safety model ==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
* '''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 &amp;lt;code&amp;gt;P = 0&amp;lt;/code&amp;gt; means &amp;quot;inner loop off&amp;quot;, which is not a tune and must not be one key-repeat away on a manned foiler. Likewise &amp;lt;code&amp;gt;HYD_RKP&amp;lt;/code&amp;gt; cannot go below 0.15: it is the artificial tailplane that makes the boat statically stable at all (0.059 exactly neutralises the natural −59 mm stability margin), so &amp;quot;0&amp;quot; would hand back a divergent boat.&lt;br /&gt;
* '''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''' (&amp;lt;code&amp;gt;ROLL_LIMIT_DEG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PTCH_LIM_*&amp;lt;/code&amp;gt;) 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''' &amp;lt;code&amp;gt;SCR_USER1&amp;lt;/code&amp;gt; (flips to roll-test mode, dropping the height loop on the very next 10 Hz iteration) and &amp;lt;code&amp;gt;SCR_USER4&amp;lt;/code&amp;gt; (open-loop rear-foil jog, a bench calibration function) are flight-mode changes, not parameter tweaks. &amp;lt;code&amp;gt;TRN_REV&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;may I change this?&amp;quot; is the opposite of the safe default for &amp;quot;should I control the boat?&amp;quot;. Note that &amp;lt;code&amp;gt;TRN_ENABLE&amp;lt;/code&amp;gt; is deliberately ''not'' locked: it is the in-flight off-switch for the banking feature, and switching it off ramps the bank out at &amp;lt;code&amp;gt;TRN_RATE&amp;lt;/code&amp;gt; rather than snapping.&lt;br /&gt;
&lt;br /&gt;
Recovery from a bad (volatile) tune is always the same: enable off, power-cycle — everything not explicitly persisted reverts to the values in flash.&lt;br /&gt;
&lt;br /&gt;
== Parameter map ==&lt;br /&gt;
&lt;br /&gt;
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: &amp;lt;code&amp;gt;P&amp;lt;/code&amp;gt; is the rate loop's P, &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt; the height loop's). ''Fine'' and ''coarse'' are the increment sizes used by the keyboard's volume keys / &amp;lt;code&amp;gt;+−&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;&amp;amp;gt;&amp;lt;/code&amp;gt; respectively — conventions of the tools, not of the protocol, which always carries absolute values.&lt;br /&gt;
&lt;br /&gt;
=== Roll inner loop ===&lt;br /&gt;
&lt;br /&gt;
The ArduPlane FBWA rate-plus-angle controller, driving the two front foils differentially (elevon mixing). Roll is the high-authority axis — about 14.5 °/s of response per degree of foil — so its gains are numerically small.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;P&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_P&amp;lt;/code&amp;gt; || 0.02 || 2 || 0.005 || 0.02 || || Roll rate P gain. Floor is non-zero on purpose: 0 would switch the inner loop off&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;I&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_I&amp;lt;/code&amp;gt; || 0 || 2 || 0.005 || 0.02 || || Roll rate integrator gain — holds trim against steady asymmetry (e.g. crew weight)&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_D&amp;lt;/code&amp;gt; || 0 || 0.5 || 0.001 || 0.005 || || Roll rate damping gain&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_FF&amp;lt;/code&amp;gt; || 0 || 3 || 0.01 || 0.05 || || Roll rate feed-forward — the workhorse term in ArduPlane's rate loop&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;M&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_IMAX&amp;lt;/code&amp;gt; || 0 || 30 || 0.1 || 0.5 || || Integrator clamp, in the rate PID's ''output'' units where full surface = 45. A 75 kg driver leaning 100 mm needs ~20 units at the bottom of the speed envelope, hence the ceiling of 30&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL2SRV_TCONST&amp;lt;/code&amp;gt; || 0.1 || 2 || 0.05 || 0.1 || || Angle→rate time constant (s): how aggressively the angle loop chases a roll target&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL2SRV_RMAX&amp;lt;/code&amp;gt; || 0 || 180 || 5 || 15 || || Maximum commanded roll rate (°/s)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ROLL_LIMIT_DEG&amp;lt;/code&amp;gt; || 5 || 20 || 1 || 5 || '''yes''' || Bank-angle envelope (°). 45° of roll on a foiling boat is a capsize, not a limit — locked in flight because it is the airframe envelope, not a gain&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_FLTT&amp;lt;/code&amp;gt; || 0 || 100 || 1 || 5 || || Rate-target low-pass filter (Hz)&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_FLTE&amp;lt;/code&amp;gt; || 0 || 100 || 1 || 5 || || Rate-error low-pass filter (Hz)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_FLTD&amp;lt;/code&amp;gt; || 0 || 100 || 1 || 5 || || D-term low-pass filter (Hz) — the first knob against high-frequency oscillation&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RLL_RATE_SMAX&amp;lt;/code&amp;gt; || 0 || 200 || 5 || 20 || || Output slew-rate limit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pitch inner loop ===&lt;br /&gt;
&lt;br /&gt;
The same controller structure for pitch, driving the front foils in common mode plus the rear foil (elevator, forwarded over CAN as &amp;lt;code&amp;gt;0x010&amp;lt;/code&amp;gt;). Pitch is the ''low''-authority axis — about 2.42 °/s per degree of foil, six times weaker than roll — so its gains run roughly six times higher for the same loop bandwidth; the wider P/I ceilings exist because the model-derived pitch P (≈5.65) exceeded the old limit of 2.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 16 || &amp;lt;code&amp;gt;P&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_P&amp;lt;/code&amp;gt; || 0.02 || 8 || 0.02 || 0.1 || || Pitch rate P gain (non-zero floor, as roll)&lt;br /&gt;
|-&lt;br /&gt;
| 17 || &amp;lt;code&amp;gt;I&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_I&amp;lt;/code&amp;gt; || 0 || 8 || 0.02 || 0.1 || || Pitch rate integrator gain&lt;br /&gt;
|-&lt;br /&gt;
| 18 || &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_D&amp;lt;/code&amp;gt; || 0 || 0.5 || 0.001 || 0.005 || || Pitch rate damping gain&lt;br /&gt;
|-&lt;br /&gt;
| 19 || &amp;lt;code&amp;gt;F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_FF&amp;lt;/code&amp;gt; || 0 || 4 || 0.01 || 0.05 || || Pitch rate feed-forward&lt;br /&gt;
|-&lt;br /&gt;
| 20 || &amp;lt;code&amp;gt;M&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_IMAX&amp;lt;/code&amp;gt; || 0 || 40 || 0.1 || 0.5 || || Integrator clamp, output units (full surface = 45)&lt;br /&gt;
|-&lt;br /&gt;
| 21 || &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH2SRV_TCONST&amp;lt;/code&amp;gt; || 0.1 || 2 || 0.05 || 0.1 || || Angle→rate time constant (s)&lt;br /&gt;
|-&lt;br /&gt;
| 22 || &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH2SRV_RMAX_UP&amp;lt;/code&amp;gt; || 0 || 180 || 5 || 15 || || Maximum nose-up pitch rate (°/s). On the display this is one cell with &amp;lt;code&amp;gt;RMAX_DN&amp;lt;/code&amp;gt;: the two are edited together and kept equal&lt;br /&gt;
|-&lt;br /&gt;
| 23 || &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH2SRV_RMAX_DN&amp;lt;/code&amp;gt; || 0 || 180 || 5 || 15 || || Maximum nose-down pitch rate (°/s); paired with &amp;lt;code&amp;gt;RMAX_UP&amp;lt;/code&amp;gt; as above&lt;br /&gt;
|-&lt;br /&gt;
| 24 || &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH2SRV_RLL&amp;lt;/code&amp;gt; || 0 || 1.5 || 0.01 || 0.05 || || Roll→pitch cross-feed (coordinated-turn pitch compensation). The boat's seed sets 0 — a displacement hull does not pitch in a bank the way an aircraft does; the floor was lowered from ArduPlane's customary 0.7 for exactly that reason&lt;br /&gt;
|-&lt;br /&gt;
| 25 || &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_LIM_MAX_DEG&amp;lt;/code&amp;gt; || 1 || 10 || 1 || 5 || '''yes''' || Pitch envelope, nose-up (°). One display cell with &amp;lt;code&amp;gt;LIM_MIN&amp;lt;/code&amp;gt;, mirrored: + widens the envelope. Locked in flight; the old ceiling of 30° was, in the audit's words, a backflip demand&lt;br /&gt;
|-&lt;br /&gt;
| 26 || &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_LIM_MIN_DEG&amp;lt;/code&amp;gt; || −10 || −1 || 1 || 5 || '''yes''' || Pitch envelope, nose-down (°); mirrored pair of &amp;lt;code&amp;gt;LIM_MAX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 27 || &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_FLTT&amp;lt;/code&amp;gt; || 0 || 100 || 1 || 5 || || Rate-target filter (Hz)&lt;br /&gt;
|-&lt;br /&gt;
| 28 || &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_FLTE&amp;lt;/code&amp;gt; || 0 || 100 || 1 || 5 || || Rate-error filter (Hz)&lt;br /&gt;
|-&lt;br /&gt;
| 29 || &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_FLTD&amp;lt;/code&amp;gt; || 0 || 100 || 1 || 5 || || D-term filter (Hz)&lt;br /&gt;
|-&lt;br /&gt;
| 30 || &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PTCH_RATE_SMAX&amp;lt;/code&amp;gt; || 0 || 200 || 5 || 20 || || Output slew-rate limit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Speed scaling ===&lt;br /&gt;
&lt;br /&gt;
One parameter stands apart because it silently retunes ''everything above'': ArduPlane multiplies every surface gain on both axes by &amp;lt;code&amp;gt;SCALING_SPEED / airspeed&amp;lt;/code&amp;gt; (clamped to roughly [0.5, 2]). 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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 31 || &amp;lt;code&amp;gt;Q&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SCALING_SPEED&amp;lt;/code&amp;gt; || 4 || 15 || 0.5 || 1 || || Gain-scaling reference speed (m/s). Rescales every roll and pitch surface gain at once&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Height outer loop ===&lt;br /&gt;
&lt;br /&gt;
The ride-height controller in &amp;lt;code&amp;gt;hydrofoils.lua&amp;lt;/code&amp;gt;: it turns the EKF's height-above-water estimate into a pitch-target bias for the inner loop. These parameters are created when that script boots, so they answer ''unavailable'' (status 4) for the first seconds after power-on.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 32 || &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_KP&amp;lt;/code&amp;gt; || 0 || 2000 || 10 || 50 || || Height-error → pitch-demand proportional gain&lt;br /&gt;
|-&lt;br /&gt;
| 33 || &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_KI&amp;lt;/code&amp;gt; || 0 || 500 || 5 || 20 || || Height integrator gain — trims out steady offsets (loading, speed)&lt;br /&gt;
|-&lt;br /&gt;
| 34 || &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_KD&amp;lt;/code&amp;gt; || 0 || 2000 || 10 || 50 || || Vertical-velocity damping gain, acting on the EKF's fused climb rate (phase-consistent with the P term, and blind to wave-surface motion by design)&lt;br /&gt;
|-&lt;br /&gt;
| 35 || &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_IMAX&amp;lt;/code&amp;gt; || 0 || 500 || 10 || 50 || || Height integrator clamp&lt;br /&gt;
|-&lt;br /&gt;
| 36 || &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_TARGET&amp;lt;/code&amp;gt; || 0 || 1 || 0.01 || 0.05 || || Ride-height setpoint (m) — the most-used control on the water&lt;br /&gt;
|-&lt;br /&gt;
| 37 || — || ''retired'' || || || || || || Was &amp;lt;code&amp;gt;HYD_HSRC&amp;lt;/code&amp;gt; (height-source select, removed when control went EKF-exclusive). Answers ''unknown''; the index is reserved forever&lt;br /&gt;
|-&lt;br /&gt;
| 38 || — || ''retired'' || || || || || || Was &amp;lt;code&amp;gt;HYD_HDIV&amp;lt;/code&amp;gt; (EKF-vs-geometric divergence gate, removed — EKF3's own innovation gating covers it). Reserved forever&lt;br /&gt;
|-&lt;br /&gt;
| 39 || &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_ARM&amp;lt;/code&amp;gt; || 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&lt;br /&gt;
|-&lt;br /&gt;
| 52 || &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_CMDMAX&amp;lt;/code&amp;gt; || 0.5 || 5 || 0.1 || 0.5 || || The height loop's ''own'' nose-up demand clamp (°) — its authority, distinct from the airframe envelope &amp;lt;code&amp;gt;PTCH_LIM_*&amp;lt;/code&amp;gt; which stays locked. One display cell with &amp;lt;code&amp;gt;CMDMIN&amp;lt;/code&amp;gt;, mirrored&lt;br /&gt;
|-&lt;br /&gt;
| 53 || &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_CMDMIN&amp;lt;/code&amp;gt; || −8 || −0.5 || 0.1 || 0.5 || || Nose-down authority (°): sets how hard the loop can push the bow down, i.e. the fly-up overshoot — the first knob to reach for after watching a fly-up&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Rear-foil schedule ===&lt;br /&gt;
&lt;br /&gt;
The rear foil's static trim and speed schedule, also in &amp;lt;code&amp;gt;hydrofoils.lua&amp;lt;/code&amp;gt;. This group is what makes the boat statically stable in pitch, so it has the map's most protective floor.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 54 || &amp;lt;code&amp;gt;K&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_RKP&amp;lt;/code&amp;gt; || 0.15 || 1.2 || 0.02 || 0.1 || || The '''artificial tailplane''' gain. K = 0.059 exactly neutralises the natural −59 mm static margin, so the floor is 0.15, not 0: the tuner must never be able to hand back a divergent boat&lt;br /&gt;
|-&lt;br /&gt;
| 55 || &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_RSCALE&amp;lt;/code&amp;gt; || 0.5 || 1.2 || 0.02 || 0.1 || || Rear decalage scale — the rear foil runs shallower than the fronts; the floor keeps it from being scheduled to nothing&lt;br /&gt;
|-&lt;br /&gt;
| 56 || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_RSCHED&amp;lt;/code&amp;gt; || 0 || 1200 || 5 || 25 || || Speed-schedule strength (deg·m²/s²)&lt;br /&gt;
|-&lt;br /&gt;
| 57 || &amp;lt;code&amp;gt;V&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HYD_FRNTFF&amp;lt;/code&amp;gt; || 0 || 0.5 || 0.01 || 0.05 || || Fraction of the rear schedule fed forward to the front-foil trims&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Coordinated-turn banking ===&lt;br /&gt;
&lt;br /&gt;
Served by a third script, &amp;lt;code&amp;gt;foil_turn.lua&amp;lt;/code&amp;gt;, which banks the boat into turns from the steering input. If that script is not uploaded, all six answer ''unavailable'' — which is itself the &amp;quot;is the feature installed?&amp;quot; check.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 40 || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TRN_ENABLE&amp;lt;/code&amp;gt; || 0 || 1 || 1 || 1 || || Feature on/off. Deliberately ''not'' locked: this is the in-flight kill switch, and disabling ramps the bank out at &amp;lt;code&amp;gt;TRN_RATE&amp;lt;/code&amp;gt; instead of snapping&lt;br /&gt;
|-&lt;br /&gt;
| 41 || &amp;lt;code&amp;gt;U&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TRN_ON&amp;lt;/code&amp;gt; || 5 || 60 || 1 || 5 || || Steering input (%) at which banking starts&lt;br /&gt;
|-&lt;br /&gt;
| 42 || &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TRN_FULL&amp;lt;/code&amp;gt; || 10 || 100 || 1 || 5 || || Steering input (%) giving full bank&lt;br /&gt;
|-&lt;br /&gt;
| 43 || &amp;lt;code&amp;gt;Z&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TRN_MAX&amp;lt;/code&amp;gt; || 0 || 20 || 0.5 || 2 || || Maximum bank angle (°); 0 = never bank&lt;br /&gt;
|-&lt;br /&gt;
| 44 || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TRN_RATE&amp;lt;/code&amp;gt; || 1 || 20 || 0.5 || 2 || || Bank slew rate (°/s)&lt;br /&gt;
|-&lt;br /&gt;
| 45 || &amp;lt;code&amp;gt;J&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TRN_REV&amp;lt;/code&amp;gt; || 0 || 1 || 1 || 1 || '''yes''' || Steering-sense reverse. Locked in flight: flipping it mid-turn would drive the bank to the opposite stop&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Mode and test knobs ===&lt;br /&gt;
&lt;br /&gt;
The scripting user parameters that &amp;lt;code&amp;gt;hydrofoils.lua&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Idx !! Hotkey !! Parameter !! Min !! Max !! Fine !! Coarse !! Locked !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 48 || &amp;lt;code&amp;gt;y&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SCR_USER1&amp;lt;/code&amp;gt; || 0 || 1 || 1 || 1 || '''yes''' || Operating mode: 0 = height control (full cascade), 1 = roll-test/wheelie (height loop bypassed, fixed nose-up pitch). Takes effect on the next 10 Hz iteration — a mode change, not a tweak, hence the lock&lt;br /&gt;
|-&lt;br /&gt;
| 49 || &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SCR_USER2&amp;lt;/code&amp;gt; || −10 || 10 || 0.5 || 1 || || Roll-test pitch target (°); 0 uses the built-in 3° default&lt;br /&gt;
|-&lt;br /&gt;
| 50 || &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SCR_USER3&amp;lt;/code&amp;gt; || −20 || 20 || 1 || 5 || || Roll-step demand (°) for step-response tuning; 0 = level. Watch the achieved attitude come back on telemetry &amp;lt;code&amp;gt;0x250&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 51 || &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SCR_USER4&amp;lt;/code&amp;gt; || 0 || 2100 || 10 || 50 || '''yes''' || Rear-foil jog (PWM µs, 0 = off): drives the rear actuator open-loop for bench calibration. Only honoured while the boat is disabled — and locked while foiling for the same reason&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Special indices ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0xFE&amp;lt;/code&amp;gt; || Protocol-version query: the reply's value is the version (currently '''7'''). Any tool should check this before trusting its own copy of this map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0xFF&amp;lt;/code&amp;gt; || As a request: dump the whole table (one &amp;lt;code&amp;gt;0x261&amp;lt;/code&amp;gt; per entry, paced). As a reply: the end-of-dump marker, value = number of entries sent&lt;br /&gt;
|-&lt;br /&gt;
| 13–15, 46–47 || Unused, free for future entries in their groups&lt;br /&gt;
|-&lt;br /&gt;
| 37, 38 || Retired (&amp;lt;code&amp;gt;HYD_HSRC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HYD_HDIV&amp;lt;/code&amp;gt;) — reserved forever, never reuse&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Config slots, undo and factory reset ==&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;9&amp;lt;/code&amp;gt; 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. &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt; undoes the last change (one step back per press — a slot restore or factory reset counts as a single step), and &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
== Keeping this page true ==&lt;br /&gt;
&lt;br /&gt;
The authoritative copy of this map is the &amp;lt;code&amp;gt;PT&amp;lt;/code&amp;gt; whitelist in &amp;lt;code&amp;gt;foil_tune.lua&amp;lt;/code&amp;gt; on the flight controller, mirrored by &amp;lt;code&amp;gt;PARAMS&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;tools/foil_tune.py&amp;lt;/code&amp;gt; and by the display's &amp;lt;code&amp;gt;FOILING_PARAMETERS.md&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;.csv&amp;lt;/code&amp;gt;. Any change to indices, ranges or locks bumps &amp;lt;code&amp;gt;PROTO_VERSION&amp;lt;/code&amp;gt; on both sides of the wire — if the version on this page and the one the boat reports at index &amp;lt;code&amp;gt;0xFE&amp;lt;/code&amp;gt; disagree, trust the boat and update this page.&lt;/div&gt;</summary>
		<author><name>Aran Dokoupil</name></author>
	</entry>
</feed>