Cookwala / SDK and scenarios / 011

The same recipe with and without a person in the kitchen

Cutting may not run unattended, whatever the device. With a person present the arm cuts under its camera and the person does the cooking the arm cannot; a full kitchen robot still needs the person for the knife work.

Audience: home cook · Goal: Robots for people · Level: beginner

Read first: /docs/CORE/ /docs/QUICKSTART/

Steps

  1. Shakshuka on the example arm, nobody home: refused at the first step. dryRun

  2. With a person: accepted. The arm cuts (verified by its camera) and later cracks the eggs; heating, sauteing, simmering and serving are assigned to the person. dryRun

  3. The kitchen robot with hob and thermometers can do every operation, and is still refused alone: the envelope for cutting says unattended is false. dryRun

  4. With a person nearby the robot does all thirteen steps itself; heating is verified by the pan thermometer. dryRun

Outcome

You know that presence is a safety input, not a convenience: a step the envelope marks unattended=false is refused when nobody is there. Next: scenario 028 collects the refusals an agent sees when nobody is home.

Command line

cookwala dryrun examples/shakshuka.cookwala.json --device examples/capabilities/robot-arm.json
cookwala dryrun examples/shakshuka.cookwala.json --device examples/capabilities/robot-arm.json --human-present
cookwala dryrun examples/shakshuka.cookwala.json --device examples/capabilities/demo-hob-robot.json
cookwala dryrun examples/shakshuka.cookwala.json --device examples/capabilities/demo-hob-robot.json --human-present

Recorded output

Status: ok

[1] dryRun: {"state": "refused", "refusal": {"reason": "needs_human_present", "node": "n1", "detail": "cw.op.cut may not run unattended"}, "plan": []}
[2] dryRun: {"state": "accepted", "plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": "human", "verifiedBy": "human"}, {"node": "n6", "op": "cw.op.saute", "by": "human", "verifiedBy": "human"}, {"node": "n7", "op": "cw.op.simmer", "b…
[3] dryRun: {"state": "refused", "refusal": {"reason": "needs_human_present", "node": "n1", "detail": "cw.op.cut may not run unattended"}, "plan": []}
[4] dryRun: {"state": "accepted", "plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.pan_surface_temp"}, {"node": "n5", "op": "cw.op.saute", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.pan_surface_temp"}, {"node": "n6", "op": "cw.op.saute", …

Code

Run: python scenarios/out/011-person-present-or-absent/python.py

# Scenario 011: The same recipe with and without a person in the kitchen
# Cutting may not run unattended, whatever the device. With a person present the arm cuts under its camera and the person does the cooking the arm cannot; a full kitchen robot still needs the person for the knife work.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: Shakshuka on the example arm, nobody home: refused at the first step.
armAlone = c.dry_run(recipe_id="shakshuka", device_id="robot-arm", human_present=False)
assert pick(armAlone, "state") == "refused", pick(armAlone, "state")
print("ok", "state", "=", "refused")
assert pick(armAlone, "refusal.reason") == "needs_human_present", pick(armAlone, "refusal.reason")
print("ok", "refusal.reason", "=", "needs_human_present")
assert pick(armAlone, "refusal.node") == "n1", pick(armAlone, "refusal.node")
print("ok", "refusal.node", "=", "n1")
assert pick(armAlone, "plan.length") == 0, pick(armAlone, "plan.length")
print("ok", "plan.length", "=", 0)

# Step 2: With a person: accepted. The arm cuts (verified by its camera) and later cracks the eggs; heating, sauteing, simmering and serving are assigned to the person.
armWithPerson = c.dry_run(recipe_id="shakshuka", device_id="robot-arm", human_present=True)
assert pick(armWithPerson, "state") == "accepted", pick(armWithPerson, "state")
print("ok", "state", "=", "accepted")
assert pick(armWithPerson, "plan.length") == 13, pick(armWithPerson, "plan.length")
print("ok", "plan.length", "=", 13)
assert pick(armWithPerson, "plan[0].by") == "device", pick(armWithPerson, "plan[0].by")
print("ok", "plan[0].by", "=", "device")
assert pick(armWithPerson, "plan[0].verifiedBy") == "sensor", pick(armWithPerson, "plan[0].verifiedBy")
print("ok", "plan[0].verifiedBy", "=", "sensor")
assert pick(armWithPerson, "plan[3].op") == "cw.op.heat", pick(armWithPerson, "plan[3].op")
print("ok", "plan[3].op", "=", "cw.op.heat")
assert pick(armWithPerson, "plan[3].by") == "human", pick(armWithPerson, "plan[3].by")
print("ok", "plan[3].by", "=", "human")

# Step 3: The kitchen robot with hob and thermometers can do every operation, and is still refused alone: the envelope for cutting says unattended is false.
robotAlone = c.dry_run(recipe_id="shakshuka", device_id="demo-hob-robot", human_present=False)
assert pick(robotAlone, "state") == "refused", pick(robotAlone, "state")
print("ok", "state", "=", "refused")
assert pick(robotAlone, "refusal.reason") == "needs_human_present", pick(robotAlone, "refusal.reason")
print("ok", "refusal.reason", "=", "needs_human_present")
assert pick(robotAlone, "refusal.node") == "n1", pick(robotAlone, "refusal.node")
print("ok", "refusal.node", "=", "n1")

# Step 4: With a person nearby the robot does all thirteen steps itself; heating is verified by the pan thermometer.
robotWithPerson = c.dry_run(recipe_id="shakshuka", device_id="demo-hob-robot", human_present=True)
assert pick(robotWithPerson, "state") == "accepted", pick(robotWithPerson, "state")
print("ok", "state", "=", "accepted")
assert pick(robotWithPerson, "plan[3].by") == "device", pick(robotWithPerson, "plan[3].by")
print("ok", "plan[3].by", "=", "device")
assert pick(robotWithPerson, "plan[3].rung") == "cw.sense.pan_surface_temp", pick(robotWithPerson, "plan[3].rung")
print("ok", "plan[3].rung", "=", "cw.sense.pan_surface_temp")

print("scenario complete")

scenarios/011-person-present-or-absent.json

Previous: 010 Next: 012