Skip to content

fix(bioreactor-v1): default impeller_pwm to 100, not full speed - #61

Merged
CameronBrooks11 merged 2 commits into
mainfrom
fix/60-impeller-pwm-default
Aug 9, 2026
Merged

CameronBrooks11 merged 2 commits into
mainfrom
fix/60-impeller-pwm-default

Conversation

@CameronBrooks11

Copy link
Copy Markdown
Member

Closes #60.

Problem

impeller_pwm defaulted to 255 — the top of its own range. Every other actuation default in the file is inert or gentle:

parameter default
impeller_enable false
dose1_enable / dose2_enable false
dose1_max_pulses_per_hour / dose2_max_pulses_per_hour 0
dose1_startup_delay_s / dose2_startup_delay_s 60
impeller_pwm 255

which makes 255 read as deliberate when it is more likely just the maximum.

impeller_enable correctly defaults to false, so nothing moves on entering AUTO. But enabling the impeller is the single obvious next action after activating automation, and the runbook says to enable conservatively without mentioning a PWM — so a first-user following it literally gets a full-speed start on their first autonomous run. On this machine that is the largest current transient it produces, on a shared and undersized 12 V rail.

We set 100 by hand on the bench specifically to avoid this. That step existed nowhere in the procedure.

Change

  • impeller_pwm default 255 → 100, in the automation and full profiles, in both config/ and config-release/. 100 visibly stirred the vessel on the bench; raising it should be a deliberate act.
  • The parameter table in docs/runbook.md updated to match.
  • A note added to that table recording that parameters are not persisted.

On the persistence half

A better default reduces the blast radius but does not fix the other half of this hazard, which the issue picked up in a comment: automation parameters revert to config defaults on every runtime restart, including across an upgrade, silently and with no log line. So an operator who tunes the impeller down mid-run gets the default back after any restart — and the direction of that silent change is toward more actuation.

Filed against the runtime as anolishq/anolis#273, including the detail that parameter_manager.hpp documents "optional persistence back to YAML (disabled by default)" while no implementation exists — which is how a reader concludes it is switched off rather than absent.

This matters immediately: the next planned action on the rig is an upgrade to 0.1.41, which is a restart.

Verification

Config-only change; this repo has no build. All ten bioreactor-v1 YAML files parse, machine-profile.yaml is untouched and still parses, and no impeller_pwm default of 255 remains anywhere in the project.

The behaviour tree reads the parameter through GetParameter and passes it as motor2_pwm to dcmt0 (behaviors/bioreactor_stir_dual_dosing.xml:16,43), so the value flows unchanged — only its starting point moves.

impeller_pwm defaulted to 255 — the top of its own range. Every other
actuation default in the file is inert or gentle (both enables false, both
dose rate caps 0, both startup delays 60 s), which makes 255 read as
deliberate when it is more likely just the maximum.

impeller_enable correctly defaults to false, so nothing moves on entering
AUTO. But enabling the impeller is the single obvious next action, and the
runbook says to enable conservatively without mentioning a PWM — so a
first-user following it literally gets a full-speed start on their first
autonomous run. On this machine that is the largest current transient it
produces, on a shared and undersized 12 V rail.

100 was run on the bench and visibly stirred the vessel. Raising it should
be a deliberate act.

Also documents that parameters are not persisted. They revert to these
defaults on every runtime restart, including across an upgrade, silently
and with no log line — so the defaults are not merely a starting point,
they are what the machine does every time it comes back. That is the half
of this hazard a better default does not fix: an operator who tunes the
impeller down mid-run gets full speed again after any restart. Tracked
separately against the runtime.

Applied to the automation and full profiles in both config/ and
config-release/, and to the parameter table in docs/runbook.md.

Closes #60
…ange

From review. Both are claims I asserted without checking, in text whose
whole job is to be trusted.

The runbook note said the revert happens "silently and with no log line".
That is false and it points operators away from the evidence: the behaviour
tree logs every parameter it reads on every tick
(core/automation/bt_nodes.cpp:402), so at tick_rate_hz: 2 the live value is
in the journal twice a second. An operator who believed the note would skip
the one command that shows them, in a second, that they are back at the
default after an upgrade. Now says what is true — nothing announces the
revert — and gives the grep.

The YAML comment asserted that a full-speed start is the largest current
transient this machine makes. There is no measurement of that anywhere: no
brownout, no throttled event, no inrush record. Worse, the impeller failure
it leans on happened while commanded at PWM 100 — the value this change
makes the default — so the comment implied a reduction in exposure that
this change does not deliver. Replaced with what is actually established:
impeller_pwm is a continuous-duty setpoint gated only by impeller_enable,
unlike the dose pumps which also carry a rate cap of 0, and 100 ran
continuously through a full culture.

The default change itself is unaffected and still right.
@CameronBrooks11

Copy link
Copy Markdown
Member Author

Review gate: returned DO NOT MERGE, both findings valid

The config change itself came back clean and well-evidenced. What did not was the text I wrote around it — twice, asserting things I had not checked. Fixed in 2f04118.

1. The safety note was factually wrong, in the direction that hurts

I wrote that a parameter revert happens "silently and with no log line". The behaviour tree logs every parameter it reads on every tick:

core/automation/bt_nodes.cpp:402
LOG_INFO("[GetParameterNode] Read parameter '" << param_name.value() << "' = " << output_value);

At tick_rate_hz: 2 that is the live value in the journal twice a second. So an operator who believed my note would skip journalctl -u anolis-runtime | grep GetParameterNode — the one command that shows them in a second that they are back at the default after an upgrade.

A safety note that trains people away from the available evidence is worse than no note. It now says what is true (nothing announces the revert) and gives the command.

2. I asserted an electrical cause I never measured — and it points the wrong way

The YAML comment claimed "a full-speed start is the largest current transient this machine makes, on a shared 12 V rail." There is no measurement of that anywhere: no brownout, no throttled event, no inrush record.

Worse: the impeller failure I was leaning on happened while commanded at PWM 100 — the value this PR makes the default. So the comment implied a reduction in exposure that this change does not deliver, and four config files would have carried that as settled fact.

Replaced with what is actually established: impeller_pwm is a continuous-duty setpoint gated only by impeller_enable — unlike the dose pumps, which also carry max_pulses_per_hour: 0 — and 100 ran continuously through a full culture.

What the review confirmed

  • 100 is safe, no stall risk. No minimum PWM, deadband or locked-rotor guard exists in Slice_DCMT firmware, the bread provider, or the protocol. A supervised spin at PWM 60 turned the shaft under vessel load, and the full ~8.7-day culture held exactly 100. So 100 is ~1.7x the lowest duty proven to move it.
  • dose*_pwm: 240 is correctly untouched — different in kind, and double-gated.
  • No default: 255 remains in this repo; config/ and config-release/ differ only in the intended binary/BT paths; all YAML parses; nothing consumes the old default programmatically.

Filed separately

anolishq/anolis-workbench#305 — tests/fixtures/imported-profile/ is a stale snapshot of bioreactor-v1 still carrying impeller_pwm: 255. Nothing asserts on it so nothing breaks, but it is a fixture people copy from.

@CameronBrooks11
CameronBrooks11 merged commit 26b311e into main Aug 9, 2026
2 checks passed
@CameronBrooks11
CameronBrooks11 deleted the fix/60-impeller-pwm-default branch August 9, 2026 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bioreactor-v1: impeller_pwm defaults to 255 (full speed) — first AUTO enable jumps to maximum

1 participant