Skip to content

Add Reach Alpha 5 device id and manipulator arm messages - #315

Merged
follesoe merged 7 commits into
masterfrom
follesoe/reach-alpha-5-device-id
Oct 1, 2026
Merged

follesoe merged 7 commits into
masterfrom
follesoe/reach-alpha-5-device-id

Conversation

@follesoe

@follesoe follesoe commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Adds what the drone needs for the Reach Robotics Reach Alpha 5, a five-function manipulator.

Device id

GUEST_PORT_DEVICE_ID_REACH_ROBOTICS_REACH_ALPHA_5 = 52, next to the Outland MP-200 (#310).

Manipulator arm

  • GripperCtrl keeps gripper_velocities at field 1 and gains:
    • oneof arm_input:
      • CartesianManipulatorInput: x forward, y right, z down, in the drone body frame.
      • CylindricalManipulatorInput: radial out from the base axis, vertical down along it, azimuth clockwise seen from above.
      • KnownPoseManipulatorInput: a ManipulatorPose (stowed or deployed) and a velocity (0..1) along the drone's path to it. Hold-to-run: the arm moves only while the velocity is above zero, and resumes from wherever it stopped.
      • Cartesian and cylindrical values are normalized to -1..1 and scaled by the drone to its configured maximum speeds. The chosen input says how the command is read, so there is no separate mode to disagree with it.
    • speed_modifier (-1..1): negative is slower, positive faster, 0 the drone's default speed. Scales arm_input only, not gripper_velocities.
    • Each command stands until the next one, as clients send on change: the arm stops on a command without arm input, or when the client watchdog lapses. Existing clients keep working unchanged.
  • GripperTel { Gripper }: how the last arm input was read (ManipulatorControlMode), joint positions, end position in the drone body frame (m), flags for a joint at its limit, a collision, jaws holding something and a joint fault, and the pose being moved towards.

Joint control stays a desk and service tool and is not in the protocol. Maximum speeds, grip current, where the arm sits on the hull and its obstacles stay in the drone's configuration.

The driver side (libblunux) follows in its own PR; nothing uses the new messages yet.

🤖 Generated with Claude Code

follesoe and others added 3 commits September 30, 2026 15:11
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ManipulatorCtrl moves a manipulator arm by velocity, read in a control
mode: cylindrical (the drone default) or cartesian in the drone frame. The
arm velocities use the names and signs of MotionInput, so the same stick
can drive the drone or the arm, and a speed modifier scales the drone's
default speed down or up. The jaw and wrist velocities are the existing
GripperVelocities; ManipulatorCtrl supersedes GripperCtrl while it keeps
arriving, so clients that only send GripperCtrl keep working.

ManipulatorPoseCtrl sends the arm to a named pose, stowed or deployed.
ManipulatorTel reports the joint positions, the end position in the drone
frame, and whether a joint limit, a collision or a fault stops the arm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@follesoe follesoe self-assigned this Sep 30, 2026
@follesoe
follesoe requested review from johannesschrimpf and a balanced review from Copilot September 30, 2026 13:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The protocol additions are consistent, documented, and compatible with existing generation workflows.

Review effort: Balanced
Findings: None

What changed in this PR

Adds protocol support for the Reach Robotics Reach Alpha 5 manipulator.

Changes:

  • Adds device ID 52.
  • Defines velocity, pose, and telemetry schemas.
  • Adds manipulator control and telemetry messages.
File Description
protobuf_definitions/​message_formats.proto Defines manipulator data types and device ID.
protobuf_definitions/​control.proto Adds velocity and named-pose commands.
protobuf_definitions/​telemetry.proto Adds manipulator state telemetry.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@johannesschrimpf johannesschrimpf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d prefer extending GripperCtrl with arm input instead of introducing a separate ManipulatorCtrl. This keeps one command path and avoids arbitration between legacy gripper commands and manipulator commands.

Preserve gripper_velocities at field 1 and use a oneof for the arm input:

message GripperCtrl {
  GripperVelocities gripper_velocities = 1;

  oneof arm_input {
    CartesianManipulatorInput cartesian = 2;
    CylindricalManipulatorInput cylindrical = 3;
  }

  float speed_modifier = 4;
}

The Cartesian input would contain x, y, z; the cylindrical input would contain radial, vertical, azimuth. Document the reference frames, positive directions, and normalized ranges for each.

This also removes the need for a separate control-mode field: the selected input determines how to interpret the command, and the two cannot disagree. Telemetry could still report the active mode if useful.

These names avoid overloading surge to mean radial extension, which is no longer forward relative to the drone once the arm swings sideways. Existing clients can continue sending their current commands; absent arm input should mean no arm movement, with consistent stop/watchdog behavior.

follesoe and others added 2 commits September 30, 2026 15:27
Following review: one command path instead of a separate ManipulatorCtrl,
so there is no arbitration between gripper and manipulator commands.
GripperCtrl keeps gripper_velocities at field 1 and gains an arm_input
oneof, CartesianManipulatorInput (x, y, z in the drone body frame) or
CylindricalManipulatorInput (radial, vertical, azimuth about the arm's
base axis), and speed_modifier. The chosen input says how the command is
read, so the separate control mode field goes; ManipulatorControlMode
stays for telemetry only. Without arm input the arm does not move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pose move runs to the end by itself; a nonzero arm_input or a lapse of
the client watchdog cancels it, gripper and rotation velocities do not.
speed_modifier scales arm_input only. The telemetry end position is in
the drone body frame, as the cartesian input is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@follesoe

Copy link
Copy Markdown
Member Author

Thanks, agreed. This is now one command path (20de6fb, 96d7b41):

  • GripperCtrl keeps gripper_velocities at 1, adds the arm_input oneof (CartesianManipulatorInput x/y/z in the drone body frame; CylindricalManipulatorInput radial/vertical/azimuth about the arm's base axis) and speed_modifier at 4. Frames, positive directions and ranges are documented; speed_modifier scales arm_input only, not gripper_velocities.
  • ManipulatorCtrl and the mode field are gone; ManipulatorControlMode remains only in telemetry, to report how the last arm input was read.
  • Without arm input the arm doesn't move, and it stops when the commands stop.
  • ManipulatorPoseCtrl: a pose move runs to the end by itself; a GripperCtrl with a nonzero arm_input or a lapse of the client watchdog cancels it, gripper and rotation velocities do not.
  • The telemetry end_position is in the drone body frame, the same axes as the cartesian input.

@johannesschrimpf

Copy link
Copy Markdown
Contributor

Thanks, this addresses my review: extending GripperCtrl gives us one command path, and the oneof makes the coordinate mode explicit without a separate mode field. The field names and documented frames are clearer.

Could we clarify the stop behavior during a named-pose move? GripperCtrl says that without arm input the arm does not move, but ManipulatorPoseCtrl says the pose continues unless interrupted by nonzero arm input or watchdog expiry.

I’d document that absent/zero arm input means no manual movement and does not cancel a pose. We should also define how a client explicitly cancels a pose without requesting movement or letting its watchdog expire—for example, whether ManipulatorPoseCtrl with MANIPULATOR_POSE_UNSPECIFIED cancels the current move.

Moving the arm to a named pose becomes an explicit, continuous action:
KnownPoseManipulatorInput is a third arm_input of GripperCtrl, holding
the pose and a velocity along the drone's path to it (0..1). The arm
moves only while the velocity is above zero and resumes from wherever it
stopped, so releasing the control stops it, as for the other inputs.
ManipulatorPoseCtrl and its separate cancellation rules go away, and the
telemetry mode gains KNOWN_POSE.

The GripperCtrl comment now matches how clients send it, on change: each
command stands until the next one, and the arm stops on a command without
arm input or when the client watchdog lapses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@follesoe

Copy link
Copy Markdown
Member Author

Good catch. We resolved it by removing the one-shot pose move altogether (08b3f6d), so there's no conflict left to document.

Moving to a known pose is now an explicit, hold-to-run action, and a third case of arm_input:

message KnownPoseManipulatorInput {
  ManipulatorPose pose = 1;
  float velocity = 2; // Speed along the path (0.0..1.0): 0 holds the arm where it is.
}

oneof arm_input {
  CartesianManipulatorInput cartesian = 2;
  CylindricalManipulatorInput cylindrical = 3;
  KnownPoseManipulatorInput known_pose = 5;
}
  • The arm moves towards the pose only while the latest GripperCtrl carries known_pose with a velocity above zero. The drone chooses the path; for the Reach Alpha 5 it lifts to upright, swings the base, then lowers, with the joints arriving together.
  • It stops where it is when the velocity goes to 0, when a command carries another arm input or none, or when the client watchdog lapses. There's no separate cancel: releasing the control is the cancel, and resuming continues from wherever the arm stopped.
  • So "without arm input the arm does not move" holds for poses too, and ManipulatorPoseCtrl is gone.
  • The GripperCtrl comment now matches how the app sends it, on change: each command stands until the next one, and the arm stops on a command without arm input or when the client watchdog lapses.
  • ManipulatorControlMode gains KNOWN_POSE, and ManipulatorTel.moving_to reports the pose being approached.

The idea is that moving the arm into a pose is never something that happens on its own: in the app it maps to holding a control (on a pad, the right stick pushed forward in a pose mode), and letting go stops the arm.

@follesoe follesoe added this to the Blunux v5.2 milestone Sep 30, 2026
@follesoe
follesoe requested a balanced review from Copilot October 1, 2026 06:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The additive protobuf changes are coherent, documented, and preserve existing wire compatibility.

Review effort: Balanced
Findings: None

@follesoe
follesoe requested a review from jp-pino October 1, 2026 08:17
@follesoe follesoe added the enhancement New feature or request label Oct 1, 2026
To match GripperCtrl: GripperTel carries a Gripper, the state of the
gripper and, on a manipulator arm, of the arm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@follesoe
follesoe merged commit 2d5d395 into master Oct 1, 2026
4 checks passed
@follesoe
follesoe deleted the follesoe/reach-alpha-5-device-id branch October 1, 2026 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants