SwayForm/Learning Hub
Learning Hub/Demo Code/Pick and Place

Demo: Pick and Place

Status Available
Level Beginner+
Time 15–20 minutes

The robot reaches to a fixed pickup zone, closes its hand around a light object, lifts it, moves to a separate place zone, and releases it. This is the same category of task — sense, reach, grasp, transport, release — behind pick-and-place work in real manufacturing and warehouse robotics.

Honest note

The pickup and place positions in this version are fixed, tested poses rather than fully general object localization. This teaches the manipulation sequence — approach, grasp, lift, transport, release — without pretending the robot can pick up arbitrary objects anywhere on the table.

What students learn

Students learn how a manipulation task breaks into stages, why lift height matters before a horizontal move, and how grasp and release are just hand-pose commands like any other.

Hardware used

  • Shoulder, elbow, and wrist servos
  • Hand and finger servos
  • Optional RealSense camera for zone detection
  • Motion node

Concepts covered

  • Approach and grasp poses
  • Lift-before-move sequencing
  • Hand open/close as a pose command
  • Transport between two fixed poses
  • Behavior sequencing

Run command

Terminal
ros2 run swayform_demos pick_and_place

Starter code

Each stage of the pick-and-place sequence is its own function, so students can test approach, grasp, or place independently before running the whole thing.

Note: These examples are written as classroom starter code. Final hardware APIs can be adjusted to match the installed SwayForm software image.
python — pick_and_place.py
"""
Demo: Pick and Place

Purpose:
Pick up a light object from a fixed pickup zone and place it in a
fixed place zone.

Important:
Pickup and place positions are tested, fixed poses in this version,
not general-purpose object localization.
"""

from time import sleep
from swayform.motion import MotionClient


LIFT_HOLD_SECONDS = 0.6
TRANSPORT_HOLD_SECONDS = 0.8

PICKUP_APPROACH = {"shoulder_pitch": 30, "shoulder_roll": 5, "elbow_pitch": 55, "wrist_yaw": 0}
PICKUP_GRASP    = {"shoulder_pitch": 34, "shoulder_roll": 5, "elbow_pitch": 62, "wrist_yaw": 0}
LIFT_POSE       = {"shoulder_pitch": 10, "shoulder_roll": 5, "elbow_pitch": 40, "wrist_yaw": 0}
PLACE_APPROACH  = {"shoulder_pitch": 20, "shoulder_roll": -25, "elbow_pitch": 55, "wrist_yaw": 0}


def approach_object(motion: MotionClient) -> None:
    """Move over the pickup zone before descending to grasp."""
    motion.move_joint_group("right_arm", PICKUP_APPROACH)
    sleep(0.5)


def grasp_object(motion: MotionClient) -> None:
    """Descend to the object and close the hand."""
    motion.move_joint_group("right_arm", PICKUP_GRASP)
    sleep(0.4)
    motion.set_hand_pose("right_hand", "gentle_close")
    sleep(LIFT_HOLD_SECONDS)


def lift_and_transport(motion: MotionClient) -> None:
    """Lift clear of the table before moving sideways to the place zone."""
    motion.move_joint_group("right_arm", LIFT_POSE)
    sleep(LIFT_HOLD_SECONDS)

    motion.move_joint_group("right_arm", PLACE_APPROACH)
    sleep(TRANSPORT_HOLD_SECONDS)


def release_object(motion: MotionClient) -> None:
    """Open the hand to release the object in the place zone."""
    motion.set_hand_pose("right_hand", "open")
    sleep(0.4)


def main() -> None:
    motion = MotionClient()
    motion.safe_pose("idle")

    try:
        motion.lock_behavior("pick_and_place")
        approach_object(motion)
        grasp_object(motion)
        lift_and_transport(motion)
        release_object(motion)
    finally:
        motion.safe_pose("idle")
        motion.unlock_behavior("pick_and_place")


if __name__ == "__main__":
    main()

Code walkthrough

Four named poses
Approach, grasp, lift, and place are each a named dictionary. Students can tune one pose without breaking the rest of the sequence.
Approach before grasp
The arm moves over the object first, then descends. Going straight to the grasp pose risks knocking the object away.
Lift before transport
The arm rises to a clear height before moving sideways, so the object does not drag across the table.
Hand pose as grasp/release
set_hand_pose is the same call used in other demos. Grasping is just a hand pose, not a special mechanism.
finally block
Returns the robot to idle and releases the motion lock even if a step fails mid-sequence.

Try changing this

  • Change the place zone to the other side of the robot.
  • Add a second object and a second place zone.
  • Slow down the lift for a heavier object.
  • Add a RealSense check that the pickup zone is occupied before starting.
Safety

Use only light, easy-to-grip objects. Do not test grasp poses on fingers or hands — the hand should only ever close around a tested tabletop object.

Next step

After Pick and Place, try Lab 04: Head Tracking Basics.