stub — This page will be curated before publishing. Content reflects the current Python SDK (
cyberwave.driver).Overview
Edge drivers are built by composing mixins onBaseDriver or BaseROS2Driver. Each mixin registers part of the MQTT catalog and supplies seams (methods you implement) for hardware-specific behavior.
Import the public surface from cyberwave.driver:
Composition order (MRO)
Method resolution order matters. PutJointControllerMixin before ArmCapabilityMixin so joint targets from teleop and arm commands (ee_move, grip, …) both flow through JointControllerMixin._apply_joint_targets.
The Piper driver uses this exact stack:
__init__, define_interface, and tick() tie the mixins together at runtime.
Mixin reference
Control types (no mixin — used by mixins)
See Joint motion shaping for shaped vs passthrough motion.
Bidirectional joint/update
The cyberwave/joint/{uuid}/update topic carries both teleop commands and edge feedback. Split responsibility:
Teleop listeners reject
edge* messages so the driver never re-ingests its own feedback.
Reference pattern: ROS manipulator arm (Agilex Piper)
The Agilex Piper driver (PiperDriver) is the canonical integration: five base classes, a handful of seams, and one define_interface publisher — no hand-written MQTT joint bridge.
How the pieces connect
Mixins do not run in isolation. They wire together through shared state (_joint_states, _tele_inbox), super() calls, and the ROS tick() timer:
Class declaration and flags
JointControllerMixin must precede ArmCapabilityMixin so IK-produced joint targets and MQTT teleop both enter JointControllerMixin._apply_joint_targets.
__init__ — wire mixin state
_joint_states cache are never allocated.
define_interface — feedback publisher only
super().define_interface(iface) lets mixins register joint/update listener and twin/command listeners. Piper adds the outbound path:
wire_ros_publishers() subscribes on ROS, calls convert_joints_to_payload (uses joint_name_map()), throttles to rate_hz, and publishes with source_type=edge. Do not add a second joint/update listener — JointControllerMixin already owns teleop.
Seam map — what Piper implements per mixin
Command path end-to-end:
Passthrough motion vs shaped
Piper returnsNone from joint_controller_motion() so targets pass straight through; velocity and effort limits come from ROS parameters (joint_velocities, joint_efforts, gripper_effort) inside _build_joint_command_msg(). Arms that need SDK-side smoothing return trapezoidal_motion instead — see Joint motion shaping.
Operation modes and edge health
NO_OP: Piper resets the teleop inbox but keeps ROS lifecycle Active sofrom_rosfeedback continues (on_enter_no_op).- Teleop:
on_enter_teleop_local/remotecall vendor enable + CAN prime; commands flow only when hardware accepts them. - Liveness:
_touch_edge_health()on joint and arm-status callbacks;edge_healthpublishes at 1 Hz — no extra payload inedge_health_extras.
What stays driver-specific (not mixin)
Piper still owns vendor glue that mixins do not cover:managed_launch (piper_ros), CAN setup, /enable_srv, arm_status subscription, and homing repeats on teardown (HOME_ON_TEARDOWN). Mixins handle the Cyberwave contract; the driver handles hardware bring-up.
Client APIs vs driver plumbing
End users call
twin.joints.set() / twin.joints.get(); they do not implement from_ros.
Related
BaseROS2Driver
Dual lifecycle,
from_ros, wire_ros_publishers, manifest export.Joint motion shaping
Trapezoidal vs passthrough
joint_controller_motion().Writing compatible drivers
Platform contract, MQTT catalog, env vars.
Agilex Piper driver
Production reference — mixin integration, passthrough motion, managed launch.