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
|
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
|
## 11. Verification checklist
|
||||||
|
|
||||||
| Check | How | Tower 121 |
|
| Check | How | Tower 121 |
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,8 @@ public:
|
||||||
deviation_ = true;
|
deviation_ = true;
|
||||||
} else if (verb == "RESET") {
|
} else if (verb == "RESET") {
|
||||||
deviation_ = false;
|
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") {
|
} else if (verb == "MOVE") {
|
||||||
std::string a;
|
std::string a;
|
||||||
in >> a;
|
in >> a;
|
||||||
|
|
|
||||||
|
|
@ -247,3 +247,19 @@ TEST_CASE("a partial answer leaves the axis in NEEDCFG") {
|
||||||
m.sendCommand("HOME");
|
m.sendCommand("HOME");
|
||||||
CHECK_FALSE(m.telemetry().yaw.ready());
|
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