Skip to content

feat(controller): bump feetech-servo to v0.7.1; servo condition flags are data, not failed reads - #47

Merged
Nick Hehr (HipsterBrown) merged 15 commits into
mainfrom
feetech-0.7-condition-reads
Sep 8, 2026
Merged

Nick Hehr (HipsterBrown) merged 15 commits into
mainfrom
feetech-0.7-condition-reads

Conversation

@HipsterBrown

@HipsterBrown Nick Hehr (HipsterBrown) commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Why

internal/controller discarded a valid servo reading whenever the servo set any status flag. An overloaded servo (a gripper clamped on a part, a hot joint) was therefore unreadable, and the arm's dwell, IsMoving, JointPositions, motor-setup verification and arm bring-up all inherited that blindness.

feetech-servo v0.7.0/v0.7.1 fixed the library half: reads return the payload alongside a condition error, and feetech.ConditionStatus(err) says whether the payload is usable. This PR is the module half, extracted from #42 so the gripper grasp latch there can rebase onto it. It is wider than #42's two sites.

What changed

  • feetech-servo v0.6.1 → v0.7.1. No signature changes. v0.7.1 also makes writes return nil on condition-only flags; nothing on main inferred "overloaded" from a write error (checked every SyncWrite/WriteRegister/RegWrite/SetGoals/gain/torque write), so this is strictly fewer spurious failures. One visible effect: applyServoGains now completes D→I→P on a flagged servo instead of aborting mid-sequence.
  • One helper, tolerateCondition(err) (feetech.StatusError, error), is the single place the policy lives. Nine read paths in manager.go route through it right after their bus read: ServoPositionPercent, AnyServoMoving, SyncReadPositions, GetJointPositionsAndMovingForServos (the dwell's read), GetJointPositions, GetJointPositionsForServos, LoadForServos, Ping, PingServo. Only the first two expose the flags, because only they have a consumer; Ping logs them. ReadServoRegister and config.go's calibration reads are deliberately left intolerant.
  • servo_position / servo_moving carry condition as text (servo status error: [overload]), absent when clear. Text because a protobuf Struct turns every number into a float64 on a remote arm; a field because a typed error does not survive the DoCommand boundary at all. No consumer on main until Latch the grasp instead of inferring it, and add servo_load #42 lands — it is the wire contract Latch the grasp instead of inferring it, and add servo_load #42 rebases onto.
  • testfake.FakeTransport.SetStatus injects a status byte through the real protocol, so every path above is unit-tested without hardware via a clean-vs-flagged handle pair.
  • Docs: docs/arm.md response samples; one CLAUDE.md gotcha.

Hardware behaviour changes to know about

  • A clamped or hot gripper no longer fails arm bring-up (doServoInitialization → Ping) or reads as not_responding in motor_setup_verify.
  • feetech.Discover now includes condition-flagged servos (new FoundServo.Status), so discoverOneMotor sees a hot motor it previously dropped. Direction is right; untested here.
  • services/discovery's port probe still treats any ping error as "no servo" — it holds no handle. Follow-up.
  • WaitForServosToStop on an overloaded-but-stopped servo now returns when Moving = 0 instead of erroring (tested against the real fake-bus path).

Testing

go test ./..., -race on internal/... and components/..., go vet, gofmt -s clean. Mutation checks executed: stubbing the helper fails all seven position/moving/load subtests plus three helper cases; un-wiring one site fails exactly that site's subtest.

Hardware test: clamp the gripper by hand, then (1) servo_position on the arm returns a reading with condition set, (2) restart the arm component with the gripper still clamped and confirm it comes up.

🤖 Generated with Claude Code

Reads now return the payload alongside a condition-flag error; writes return
nil on condition-only flags. No signature changes; all tests green unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
…tion flag

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
…ondition flag

Both return the flags alongside the reading; WaitForServosToStop, the arm's
IsMoving/dwell callers, servocmd.ServoOps and FakeServoOps adapt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
FakeServoOps.AnyServoMoving returns no condition alongside an error, like the
real handle; comment the named-return assignment; pin the rejection error text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
SyncReadPositions, GetJointPositionsAndMovingForServos, GetJointPositions,
GetJointPositionsForServos and LoadForServos keep the reading and drop the
flags; nothing reads them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
Text, not a bitfield, because structpb renders numbers as float64 on a remote
arm and a typed error does not survive the DoCommand boundary at all.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
v0.7.1's Bus.Ping returns the model number alongside a condition error, so a
clamped gripper no longer fails arm bring-up or reads as not_responding in
motor setup. The discovery service's port probe is left alone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1ZbWg7v4RH7HcR6xUgAi
@HipsterBrown
Nick Hehr (HipsterBrown) merged commit 6ca09d0 into main Sep 8, 2026
2 checks passed
@HipsterBrown
Nick Hehr (HipsterBrown) deleted the feetech-0.7-condition-reads branch September 8, 2026 17:39
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.

1 participant