Expose joint-coupled iSWAP rotation: STARBackend.iswap_rotate_to_angles() - #1049
Conversation
_iswap_rotation_drive_resolve_to_increments and _iswap_wrist_drive_resolve_to_increments collapse the enum-or-float dispatch with snap-to-stop into two static helpers next to their _*_angle_to_increments siblings. iswap_rotate_to_angles and both single-axis rotators route their angle resolution through them, so the snap guarantee now also applies to the singles. As a side effect this restores the missing leading subject of the rotation_angle out-of-range error message in iswap_rotate_to_angles. No public-API changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rename iswap_rotation_drive_rotate_to_angle and iswap_wrist_drive_rotate_to_angle to underscored versions. The public entry point is iswap_rotate_to_angles, which covers the single-axis case via rotation_angle=None / wrist_angle=None and additionally drives both joints together. Keeping the renamed methods leaves a direct one-joint path available for troubleshooting without two parallel public APIs. No callers in the repo; symbols are <3 weeks old in upstream (introduced in PyLabRobot#1022 and PyLabRobot#1037). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Tested on real hardware (STAR, this branch checked out). Setup:
Totals: A = 6.55s, B = 3.62s → 1.81× overall. Also confirmed:
Conclusion: End-state parity is exact across all 9 angle pairs (0.0000° joint, 0.0000 mm FK pose, 0.0000° yaw) — the unified call lands in the same place as the sequential pair. The ~1.81× speedup is per-command overhead (single |
|
@rickwierenga, thank you very much for the thorough review and testing! |
Adds
iswap_rotate_to_angles(rotation_angle=, wrist_angle=, ...), a publicdeg-based wrapper over the private
_iswap_rotate_incrementsprimitive.The wrapped primitive issues a single
R0 PAcommand coupling the iSWAProtation drive (Joint 1) and wrist drive (Joint 2).
Both args are optional; at least one must be supplied.
gripper sweeps a straight joint-space path. Sequential single-axis calls
would instead produce a two-segment path through the intermediate
(W_target, T_now) pose.
and pinned. Same behaviour as the existing single-axis rotators.
ValueErrornaming both args.Position conversions go through the calibrated path: rotation floats use
piecewise-linear interpolation between the LEFT / FRONT / RIGHT EEPROM
stops (via the existing
_iswap_rotation_drive_angle_to_increments); wristfloats use the linear
iswap_wrist_drive_deg_per_incrementfactor anchoredon motor zero; enum inputs use the EEPROM increment directly. Float inputs
additionally snap to a stop's exact stored increment when within one
increment of precision, so values read via
iswap_rotation_drive_request_angleoriswap_wrist_drive_request_angleround-trip bit-exact (including PARKED_RIGHT where the extrapolated formula
is FP-vulnerable).
Speed and acceleration are in deg/sec and deg/sec²; defaults (77.4048 /
526.3524 / 101.5938 / 736.5548) round-trip bit-exact to the previous
firmware integer defaults (25_000 / 170 / 20_000 / 145), so motion
characteristics are unchanged.
Two refactor follow-ups in this PR:
The enum-or-float-with-snap logic is extracted into pure static helpers
(
_iswap_rotation_drive_resolve_to_increments,_iswap_wrist_drive_resolve_to_increments) next to the existing_*_angle_to_incrementssiblings. I/O-free, easy to test.The two single-axis rotators
iswap_rotation_drive_rotate_to_angle(Expose iSWAP rotation drive request/set angle #1022) and
iswap_wrist_drive_rotate_to_angle(ExposeSTARBackend.iswap_wrist_drive_{request,rotate_to}_angle()#1037) are renamed tounderscored private versions. The new method covers their case via
iswap_rotate_to_angles(rotation_angle=X)/(wrist_angle=X); therenamed methods remain available for direct one-joint troubleshooting.
No callers in the repo; symbols are <3 weeks old in upstream.
Part 16 of the "Tame the iSWAP" epic:
https://discuss.pylabrobot.org/t/intro-to-epic-tame-the-iswap/517
🤖 Generated with Claude Code