Demo: Interactive Exchange
The robot accepts an item from a user and gives another item back. The reference implementation uses a dollar-bill-to-snack example: the user places a bill near the robot, the robot sets it aside, then presents a small snack item.
This demo assumes any received bill is a $1 bill and is only for supervised classroom interaction. It is not real payment processing or currency validation.
Example setup
Place a light snack item, such as a small chip packet, on the table near the robot. The user places a bill in front of the robot. The robot moves the bill to one side, reaches toward the snack item, and presents or pushes it toward the user. The same state machine works for any give-one-item, get-one-item exchange — a token, a card, or a classroom object — the bill and snack are simply the reference example.
What students learn
Students learn how a larger robot behavior can be broken into states. The robot is not doing one magic action; it is moving through a controlled sequence.
Hardware used
- RealSense camera
- Arm servos
- Hand servos
- Small tabletop object
- Optional speaker
Concepts covered
- Human-robot interaction
- Sequenced manipulation
- Simple object handoff
- Vision or manual trigger
- Safe arm movement
- State machine thinking
Run command
State machine
- IDLE
- WAIT_FOR_ITEM
- ACCEPT_ITEM
- PLACE_ITEM_ASIDE
- PICK_GIVE_ITEM
- HAND_ITEM_TO_USER
- RETURN_HOME
Starter code
This version uses an enum.Enum state machine so every stage of the interaction is named. Students can add print statements to each state transition to see the sequence in the terminal.
"""
Demo: Interactive Exchange
Purpose:
A classroom interaction demo where the user gives the robot an item,
the robot accepts it, sets it aside, then presents a different item
in return. The reference example uses a $1 bill exchanged for a snack.
Important:
This is not real payment processing or currency validation.
The robot assumes every received bill is a $1 bill.
This demo is for supervised classroom interaction only.
"""
import enum
from time import sleep, time
from swayform.motion import MotionClient
from swayform.vision import RealSenseInput
from swayform.audio import AudioPrompt
ITEM_WAIT_TIMEOUT = 15.0
ITEM_HOLD_SECONDS = 0.6
HANDOFF_HOLD_SECONDS = 1.5
class ExchangeState(enum.Enum):
WAIT_FOR_ITEM = "wait_for_item"
ACCEPT_ITEM = "accept_item"
PLACE_ITEM_ASIDE = "place_item_aside"
PICK_GIVE_ITEM = "pick_give_item"
HAND_ITEM_TO_USER = "hand_item_to_user"
RETURN_HOME = "return_home"
def wait_for_item(camera: RealSenseInput, timeout: float) -> bool:
"""Poll until an item is detected in the exchange area, or timeout."""
start = time()
while time() - start < timeout:
if camera.object_in_zone("exchange_area"):
return True
sleep(0.1)
return False
def run_exchange(motion: MotionClient, audio: AudioPrompt) -> None:
state = ExchangeState.ACCEPT_ITEM
while state != ExchangeState.RETURN_HOME:
print(f"State: {state.value}")
if state == ExchangeState.ACCEPT_ITEM:
motion.safe_pose("item_pickup")
motion.set_hand_pose("right_hand", "gentle_close")
sleep(ITEM_HOLD_SECONDS)
state = ExchangeState.PLACE_ITEM_ASIDE
elif state == ExchangeState.PLACE_ITEM_ASIDE:
motion.safe_pose("item_side_drop")
motion.set_hand_pose("right_hand", "open")
sleep(0.3)
state = ExchangeState.PICK_GIVE_ITEM
elif state == ExchangeState.PICK_GIVE_ITEM:
motion.safe_pose("give_item_pickup")
sleep(0.4)
state = ExchangeState.HAND_ITEM_TO_USER
elif state == ExchangeState.HAND_ITEM_TO_USER:
motion.safe_pose("give_item_handoff")
audio.say("Here you go.")
sleep(HANDOFF_HOLD_SECONDS)
state = ExchangeState.RETURN_HOME
motion.safe_pose("idle")
def main() -> None:
motion = MotionClient()
camera = RealSenseInput()
audio = AudioPrompt()
motion.safe_pose("idle")
audio.say("Ready. Place your item on the table.")
item_detected = wait_for_item(camera, ITEM_WAIT_TIMEOUT)
if not item_detected:
audio.say("No item detected. Returning to idle.")
motion.safe_pose("idle")
return
try:
motion.lock_behavior("interactive_exchange")
run_exchange(motion, audio)
finally:
motion.unlock_behavior("interactive_exchange")
motion.safe_pose("idle")
if __name__ == "__main__":
main()
Code walkthrough
print(f"State: {state.value}") line shows students the state machine running live.Try changing this
- Change the given-back item.
- Add a thank-you sound.
- Change the timeout if no item is detected.
- Make the robot wave after completing the exchange.
Use only light tabletop objects. This demo is for supervised classroom interaction, not real vending, payment, or unattended operation.
After Interactive Exchange, try Lab 09: Behavior Priority and Motion Locking.