Add the handshake bring-up runbook (plus the mock/test changes)
This commit is contained in:
parent
07de495840
commit
816242725a
|
|
@ -738,6 +738,128 @@ gimbal heading setup # ties yaw to true north by sighting landmarks; no IMU
|
|||
gimbal pitch setup # needs an IMU; skip on a rig without one
|
||||
```
|
||||
|
||||
## 10b. Bringing up the config handshake on an existing tower
|
||||
|
||||
This is the one upgrade that changes what an **unconfigured** tower does: the new
|
||||
firmware boots into `NEEDCFG` and refuses `HOME` / `MOVE` / `ENABLE` until the
|
||||
host has answered its `NEED` lines. Flashing it onto a tower whose `hardware.ini`
|
||||
predates the drivetrain keys leaves the gimbal inert — working, talking, and not
|
||||
turning.
|
||||
|
||||
So the order matters. **Host first, firmware second.** Each step below either
|
||||
changes nothing or is reversible, and the step that could strand the tower comes
|
||||
after the one that prevents it.
|
||||
|
||||
### 0. Record what you are rolling back to
|
||||
|
||||
```bash
|
||||
gimbal dump # the running firmware's build id and register state
|
||||
cat /etc/fire_gimbal_control/hardware.ini
|
||||
git -C ~/projects/fwt_2a/firmware rev-parse --short HEAD
|
||||
```
|
||||
|
||||
Keep the dump. It is the only record of what the old firmware was holding, and
|
||||
the comparison that tells you whether the new one adopted the same values.
|
||||
|
||||
### 1. Update `hardware.ini` — nothing else, and no restart yet
|
||||
|
||||
Add the `[Motor.<axis>]` block (section 5). The five keys the new firmware will
|
||||
not run without are `steps_per_rev`, `enc_deviation`, `sw_mode`, plus the two
|
||||
speeds; `install.sh --stdout` generates the block if you would rather not type it.
|
||||
|
||||
Doing this **before** flashing is what keeps the window at zero: the host is ready
|
||||
to answer the moment the firmware starts asking.
|
||||
|
||||
### 2. Deploy the new host against the OLD firmware
|
||||
|
||||
A real test, and it risks nothing. The old firmware never sends `NEED`, so the
|
||||
host must behave exactly as it did before — which is also the guarantee the whole
|
||||
Delta fleet depends on.
|
||||
|
||||
```bash
|
||||
scripts/fgc start --start
|
||||
scripts/fgc peek
|
||||
test hardware motor
|
||||
```
|
||||
|
||||
Expect: no handshake lines at all, and the motor leaf reporting a **version skew**
|
||||
rather than a mismatch —
|
||||
|
||||
```
|
||||
; yaw_current: yaw: firmware echoes only part of the current (2 of 3 fields
|
||||
absent), so it cannot be confirmed -- it predates the full CURRENT echo. Re-flash it
|
||||
```
|
||||
|
||||
If instead you see wrong *values*, stop: something in `hardware.ini` disagrees
|
||||
with what the tower is really running, and flashing will not fix it.
|
||||
|
||||
### 3. Flash
|
||||
|
||||
```bash
|
||||
cd firmware && ./deploy.sh # uploads; --compile-only if you want a dry run first
|
||||
```
|
||||
|
||||
Watch the banner. A `NEED` line per axis should follow it:
|
||||
|
||||
```
|
||||
BOOT build=<rev>
|
||||
NEED Y steps_per_rev global_scaler run_irun homing_irun center_count soft_margin ...
|
||||
```
|
||||
|
||||
**No `NEED` line means the axis is not in `NEEDCFG`** — either the flash did not
|
||||
take, or the image is older than you think. Check the build id before going on.
|
||||
|
||||
### 4. Confirm the handshake completed
|
||||
|
||||
The host answers within a control-loop tick. Expect:
|
||||
|
||||
```
|
||||
firmware config: answered 11 keys for axis Y
|
||||
```
|
||||
|
||||
Then prove it landed rather than trusting the log:
|
||||
|
||||
```
|
||||
gimbal dump # state should be 1 (RESET), NOT 5 (NEEDCFG)
|
||||
# cfg_rx should be the full required mask
|
||||
test hardware motor # both metrics PASS
|
||||
```
|
||||
|
||||
`test hardware motor` is the real gate: it compares every declared value against
|
||||
what the firmware echoes, so a `SET` that was lost on the wire shows up here and
|
||||
nowhere else.
|
||||
|
||||
### 5. Prove the refusal actually refuses
|
||||
|
||||
Worth doing once per firmware version, because a guard that silently stopped
|
||||
working looks exactly like a guard that is working.
|
||||
|
||||
On a **bench** board, not a mast: power-cycle it without the host running, then
|
||||
send `HOME` over a serial monitor. Expect `ERR need config`. Send `RESET` and try
|
||||
again — still `ERR need config`, because a RESET is deliberately not a way out.
|
||||
`USE DEFAULTS` is, and should then let `HOME` through.
|
||||
|
||||
### 6. Only then, move the axis
|
||||
|
||||
```
|
||||
gimbal home # at the reduced homing current
|
||||
```
|
||||
|
||||
Check against the recorded figures: travel ~1,210,778 counts, repeatable to
|
||||
~0.3 %, and the derived `counts_per_deg` near 3552.87. A travel that disagrees by
|
||||
more than a few percent means the axis homed against something that was not the
|
||||
endstop.
|
||||
|
||||
### If it goes wrong
|
||||
|
||||
The board is recoverable over the network as long as USB CDC comes up:
|
||||
`BOOTSEL` over the serial port, then `./deploy.sh` with the previous firmware
|
||||
checked out. Only an image that wedges *before* `Serial.begin()` needs a physical
|
||||
button press — which is why `Serial.begin()` is the first thing `setup()` does.
|
||||
|
||||
`USE DEFAULTS` is the in-place escape: it puts every axis on the compile-time
|
||||
table and lets the tower move while you work out what `hardware.ini` is missing.
|
||||
|
||||
## 11. Verification checklist
|
||||
|
||||
| Check | How | Tower 121 |
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ public:
|
|||
deviation_ = true;
|
||||
} else if (verb == "RESET") {
|
||||
deviation_ = false;
|
||||
// A RESET is not a way out of NEEDCFG (firmware motor.cpp says why).
|
||||
if (needcfg_ && !configured_) homed_ = false;
|
||||
} else if (verb == "MOVE") {
|
||||
std::string a;
|
||||
in >> a;
|
||||
|
|
|
|||
|
|
@ -247,3 +247,19 @@ TEST_CASE("a partial answer leaves the axis in NEEDCFG") {
|
|||
m.sendCommand("HOME");
|
||||
CHECK_FALSE(m.telemetry().yaw.ready());
|
||||
}
|
||||
|
||||
TEST_CASE("RESET is not a way out of NEEDCFG") {
|
||||
// Found by reading the firmware before flashing it: Motor::reset() set
|
||||
// ST_RESET unconditionally, so an axis that was never told its drivetrain
|
||||
// would come back accepting HOME and MOVE on the compile-time table -
|
||||
// reached by a command typed for unrelated reasons.
|
||||
MockMotorController m(/*needcfg=*/true);
|
||||
m.start();
|
||||
m.takeNeedLines();
|
||||
|
||||
m.sendCommand("RESET");
|
||||
CHECK_FALSE(m.configured());
|
||||
m.sendCommand("HOME");
|
||||
CHECK_FALSE(m.telemetry().yaw.ready());
|
||||
CHECK(m.telemetry().yaw.state == AxisState::NeedConfig);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue