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 });