Skip to content

feat(embodiments): quadcopter preset + optional gripper + payload_release#132

Merged
rylinjames merged 1 commit into
mainfrom
feat/embodiments-quadcopter-foundation
May 15, 2026
Merged

feat(embodiments): quadcopter preset + optional gripper + payload_release#132
rylinjames merged 1 commit into
mainfrom
feat/embodiments-quadcopter-foundation

Conversation

@rylinjames
Copy link
Copy Markdown
Collaborator

Summary

Adds first-class quadcopter as a fourth shipped embodiment plus the structural schema changes that gripper-less robots need without special-casing every call site.

Surface Change
Schema gripper + constraints.max_gripper_velocity move from required to optional. New optional payload_release block. quadcopter added to embodiment enum. No reformatting noise.
Runtime EmbodimentConfig.has_gripper property. to_dict() omits empty optional fields. SafetyLimits.from_embodiment_config handles gripper-less embodiments by broadcasting max_ee_velocity.
Preset Quadcopter ships with 5-DOF action (3 body rates + thrust + payload), 10-DOF state (pos + quat + linear vel — matches PX4/MAVROS Odometry), 50 Hz control. Single canonical location.
Tests New TestGripperOptional class with 8 cases. Split max_ee_velocity_capped into arm (≤ 2 m/s) and drone (≤ 6 m/s) variants. 200 passing across embodiments + safety + guard.

Adapted from #125 and #126

@DsThakurRawat opened both PRs aiming at the same goal (quadcopter support). Credit for the conceptual direction goes to them (preserved via Co-Authored-By on the commit).

This PR differs by:

  1. Doesn't mark serve-drone-support: done in GOALS.yaml. That's a roadmap decision for the maintainer to flip, not something a contributor PR should self-assert.
  2. No schema.json reformatting noise. feat(embodiments): add payload_release schema and make gripper optional for drones #125 had ~500 LOC of whitespace churn (em-dash → , one-property-per-line, lost trailing newline). This PR only edits the lines that actually change semantics.
  3. Single canonical preset location. feat(embodiments): add payload_release schema and make gripper optional for drones #125 + feat(serve): first-class quadcopter drone embodiment support #126 both put quadcopter.json in BOTH configs/embodiments/ AND src/reflex/embodiments/presets/. The package reads from presets/; the other was a dev fallback. Drift risk eliminated.
  4. Real 10-DOF drone state. Both feat(embodiments): add payload_release schema and make gripper optional for drones #125 and feat(serve): first-class quadcopter drone embodiment support #126 had 4-DOF state (orientation + altitude). That's unusable for actual drone control — no velocity means no damping, no drift correction. This preset uses pos (3) + orient quat xyzw (4) + linear vel (3), which matches the PX4/MAVROS Odometry message.
  5. Doesn't bump the schema velocity cap (also separately submitted as feat(schema): raise velocity cap to 50 m/s and generalize description for drones #119). 5 m/s flight speed fits within the existing 10 m/s cap. Raising the cap zone-wide would loosen the safety boundary for arm presets too.
  6. payload_release as a clean new concept, not overloaded onto the gripper field (which feat(serve): first-class quadcopter drone embodiment support #126 did). They're semantically distinct end-effectors.
  7. Cross-field validation guards — gripper-presence implies max_gripper_velocity must also be present; payload_release component_idx must be in range; etc.
  8. Downstream caller (SafetyLimits.from_embodiment_config) updated so it doesn't crash on a gripper-less embodiment — with regression tests for both the new drone path and the unchanged arm path.

Closes / supersedes

Test plan

  • pytest tests/test_embodiments.py — 59/59 pass
  • pytest -k "embodiment or safety or guard or preset" — 200 pass, 3 unrelated skips
  • Live smoke once merged (no live drone available — placeholder preset is structurally valid; policy parity will need real drone-VLA training data)

…ease

Adds first-class quadcopter as a fourth shipped embodiment, and the
structural schema changes that drones (and future gripper-less robots)
need without special-casing every call site.

### Schema changes

- `gripper` moved from `required` to optional. Embodiments without a
  gripper (drones, future fixed-wing, AGVs) simply omit the block.
- `constraints.max_gripper_velocity` moved from required to optional —
  only meaningful when a gripper is present. Cross-field validation now
  enforces "gripper present implies max_gripper_velocity present" so
  arm presets can't accidentally drop it.
- New optional `payload_release` block with `component_idx` +
  `trigger_threshold`. Mutually exclusive with `gripper` in practice
  (an embodiment has one end-effector type).
- `quadcopter` added to the embodiment enum.

No reformatting of schema.json — only the lines that actually change.

### Runtime

- `EmbodimentConfig.gripper` and `EmbodimentConfig.payload_release` are
  now `default_factory=dict` so loading is order-insensitive.
- New `has_gripper` property — callers should use this instead of
  unconditionally accessing `gripper_idx`.
- `gripper_idx` still raises KeyError when no gripper is present (loud
  failure, not a silent -1 sentinel).
- `to_dict()` omits empty optional fields so round-trip output validates
  against the schema's `additionalProperties: false` constraint.
- `SafetyLimits.from_embodiment_config` handles gripper-less embodiments
  by broadcasting `max_ee_velocity` across all action dims. The
  existing arm path is unchanged — regression test added.

### Quadcopter preset

- 5-DOF action: body rates (roll/pitch/yaw, rad/s) + thrust [0,1] +
  payload release [0,1]. Action index 4 is the payload trigger.
- 10-DOF state: position (3) + orientation quat xyzw (4) + linear
  velocity (3). Matches PX4/MAVROS Odometry message shape, the
  canonical drone state. A 4-DOF "orientation only" state is unusable
  for real drone control (no damping, no drift correction).
- 50 Hz control loop (matches PX4 outer-loop rate), 20-action chunks.
- `max_ee_velocity: 5.0` (flight speed, ~11 mph) — fits within the
  existing schema cap of 10 m/s. The schema cap is intentionally NOT
  raised; if you need faster, override at the runtime layer or split
  per-embodiment in a future schema version.
- Single canonical location at `src/reflex/embodiments/presets/`
  (not duplicated in `configs/embodiments/`).

### Tests

- 200 passing across embodiments + safety + guard tests.
- New `TestGripperOptional` class with 8 cases: quadcopter omits gripper,
  validates clean, gripper_idx raises, arm presets unchanged, payload
  release idx bounds check, gripper-implies-velocity cross-check,
  SafetyLimits builds for both drone and arm.
- Split parameterised `test_max_ee_velocity_capped` into arm (≤ 2 m/s)
  and drone (≤ 6 m/s) variants.

Supersedes #125 and #126.

Co-Authored-By: Divyansh Rawat <186957976+DsThakurRawat@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rylinjames rylinjames merged commit c19b524 into main May 15, 2026
6 checks passed
@rylinjames rylinjames deleted the feat/embodiments-quadcopter-foundation branch May 15, 2026 20:03
rylinjames added a commit that referenced this pull request May 15, 2026
Adds docs/adding_a_robot.md walking new contributors through adding
a fifth embodiment to Reflex. Two worked examples — MyArm-6 (6-DOF
arm + gripper) and SkyScout (quadcopter delivery drone) — both
validated against the live src/reflex/embodiments/schema.json before
commit. The example JSONs use only real schema fields (mean_action /
std_action / mean_state / std_state, resolution + color_space, etc.)
so anyone copy-pasting can run validate_embodiment_config on them
and get a clean pass after Step 3.

Drops fabrications from the original attempt (#128):
- Field names like 'labels', 'mean'/'std' (instead of mean_action),
  camera 'width'/'height'/'encoding' (instead of resolution +
  color_space), 'workspace_bbox' — none of which are in schema.json
- The 'configs/embodiments/' duplicate-file step (that location was
  a dev fallback; #132 made src/reflex/embodiments/presets/ canonical)

Reflects what's actually shipped after recent foundation merges:
- Optional gripper + payload_release (from #132)
- New quadcopter preset with 10-DOF state matching MAVROS Odometry
- ROS2 bridge --state-msg-type flag (from #133) for drone deployments
- 'Common patterns by vertical' section reflects the FastCrest
  customer research vault's P0 verticals (warehouse AMR, farm, drone,
  smart-camera)

Supersedes #128.

Co-authored-by: Divyansh Rawat <186957976+DsThakurRawat@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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