Plan with multiple groupsΒΆ

This example runs with the Franka Duo. On multi-arm robots the kinematics handle has no unambiguous default planning group, so call kinematics.group(name) to bind each arm. Bound handles share the same lazily cached robot model; end-effector access, pose(), and move_* then target that group.

Hand groups (for named open / close states) remain accessible through kinematics.model.group(...) (Python) or (await kinematics.getModel()).group(...) (TypeScript).

from olo import Client
from olo.spatial import Point, Pose

# This example runs with the Franka Duo.
LEFT_ARM = "left_fr3_arm"
RIGHT_ARM = "right_fr3_arm"
LEFT_HAND = "left_fr3_hand"
RIGHT_HAND = "right_fr3_hand"
POSE_OFFSET = 0.1

with Client() as client:
    robot = client.robot()
    kin = robot.kinematics

    # Multi-arm robots have no unambiguous default group, so bind each arm.
    left = kin.group(LEFT_ARM)
    right = kin.group(RIGHT_ARM)
    left_gripper = left.ee
    right_gripper = right.ee
    if left_gripper is None or right_gripper is None:
        raise RuntimeError("This example requires grippers on both arms")

    # Read each arm's starting pose to define 'up' poses.
    left_start = left.pose()
    right_start = right.pose()

    left_up = Pose(
        position=Point(
            x=left_start.position.x,
            y=left_start.position.y,
            z=left_start.position.z + POSE_OFFSET,
        ),
        orientation=left_start.orientation,
    )
    right_up = Pose(
        position=Point(
            x=right_start.position.x,
            y=right_start.position.y,
            z=right_start.position.z + POSE_OFFSET,
        ),
        orientation=right_start.orientation,
    )

    # Move each arm up and close its gripper.
    left.move_pose(left_up)
    left_gripper.close()
    right.move_pose(right_up)
    right_gripper.close()

    # Return home and open each gripper, this time with a combined motion/gripper
    left_open = kin.model.group(LEFT_HAND).group_state("open").joints.positions[0]
    right_open = kin.model.group(RIGHT_HAND).group_state("open").joints.positions[0]
    left.move_pose(left_start, gripper_position=left_open)
    right.move_pose(right_start, gripper_position=right_open)
import { groupState } from "olo/kinematics";
import { Point, Pose } from "olo/spatial";
import { connect } from "olo/web";

// This example runs with the Franka Duo.
const LEFT_ARM = "left_fr3_arm";
const RIGHT_ARM = "right_fr3_arm";
const LEFT_HAND = "left_fr3_hand";
const RIGHT_HAND = "right_fr3_hand";
const POSE_OFFSET = 0.1;

const client = connect();
const robot = await client.robot();
const kin = robot.kinematics;

// Multi-arm robots have no unambiguous default group, so bind each arm.
const left = kin.group(LEFT_ARM);
const right = kin.group(RIGHT_ARM);
const leftGripper = await left.getEndEffector();
const rightGripper = await right.getEndEffector();
if (leftGripper === undefined || rightGripper === undefined) {
  throw new Error("This example requires grippers on both arms");
}

// Resolve all required model data before commanding either arm.
const model = await kin.getModel();
const leftOpen = groupState(model.group(LEFT_HAND), "open").joints
  .positions[0]!;
const rightOpen = groupState(model.group(RIGHT_HAND), "open").joints
  .positions[0]!;

// Read each arm's starting pose to define 'up' poses.
const leftStart = await left.pose();
const rightStart = await right.pose();

const leftUp = new Pose(
  new Point(
    leftStart.position.x,
    leftStart.position.y,
    leftStart.position.z + POSE_OFFSET,
  ),
  leftStart.orientation,
);
const rightUp = new Pose(
  new Point(
    rightStart.position.x,
    rightStart.position.y,
    rightStart.position.z + POSE_OFFSET,
  ),
  rightStart.orientation,
);

// Move each arm up and close its gripper.
await left.movePose(leftUp);
await leftGripper.close();
await right.movePose(rightUp);
await rightGripper.close();

// Return home and open each gripper, this time with a combined motion/gripper
await left.movePose(leftStart, { gripperPosition: leftOpen });
await right.movePose(rightStart, { gripperPosition: rightOpen });