The sandbox
The sandbox is a simulated building at https://sandbox.plynth.build. Your robots' software rides it through the same API a real building uses: an elevator bank, doors, a gas-protected server room, and scenario doors and elevators that always answer one way. Nothing in it is a real device, and nothing in it moves.
What's in it
| ID | What it is | Floor |
|---|---|---|
lift | An elevator bank, cars A and B. Its car comes about 1.5 seconds after a call, and reaches the destination about 1.5 seconds after boarded. Robots may ride alone here | 1 to 3 |
door | A door | 1 |
secure-door | A badge door into server-room, a gas-protected server room. Every robot here has an active badge | 2 |
The doors have a 0.86 m clear opening. The cars are 1.6 m wide and 1.4 m deep inside, with a 1.07 m door and a 1,150 kg rated load, so you can try a profile against them.
The floor plate is 40 m from west to east and 30 m from north to south, the same on floors 1, 2 and 3; floor 1 is the lobby. A corridor runs across the middle of each floor, at z 0.5, with a spur to the elevators. On the plate, door is at x 0.2, z 0.6; secure-door at x 0.8, z 0.6; and the elevators' landing at x 0.5, z 0.33. The guide explains x and z.
Each floor has a holding zone, Robot Holding, at x 0.05 to 0.2 and z 0.1 to 0.25, with room for four robots; an emergency drill sends a robot there when it has shared its position. On floor 2, server-room has its safe spot outside, Server Room Exit, and its door's swing, Server Room Door Swing, is a no-stop area with a 5-second dwell limit. Data centers covers its drills.
One rule lets every robot here use every place, all day. Every robot company shares the one building, as in a real one: your robots see only their own trips, and your drills reach only your robots.
Scenario doors and elevators
Each of these always answers one way, so you can write a handler for every refusal and failure before any site visit. They're in GET /v1/places like the rest, and every robot here may use them. The doors are on floor 1, and the elevators serve floors 1 to 3.
| Place | What it does | What your robot gets |
|---|---|---|
door-closed | Closed for a while, with a set end that moves on before it comes | DENIED, closed, retry_after until the end; asking again then is refused again, with a new end |
door-hours | Open 03:30 to 03:45 UTC only | DENIED, outside_hours, retry_after until it opens |
door-approval | A person answers each robot, yes after 5 s | AWAITING_APPROVAL with approval_code, then OPEN_COMMANDED; with "ref": "decline", DENIED approval_declined |
door-jam | The controller refuses to open it | FAILED, device_refused |
lift-slow | The car takes 20 s to come, and 20 s to ride | The usual states, slowly: check your timeouts |
lift-recall | Fire service recall 3 s after boarding; back in 30 s | The ride ends: FAILED, fire_recall |
lift-dropout | Once aboard, no answer for 20 s, as a car out of Wi-Fi | The stream ends and calls hang until your timeout; reconnect with Last-Event-ID (it answers once the 20 s are over), then report exited |
door-busy | The first request of each trip is told to slow down | HTTP 429 with Retry-After: 5; wait, send the same request with the same passage ID, and go through |
door-approval's front desk is simulated: it answers each robot about 5 seconds after it asks, and says yes unless the request's ref is decline. lift-dropout stops answering your robot for 20 seconds once it's aboard, as a car out of Wi-Fi does: its calls get no answer, and its stream drops. Treat a call with no answer as no answer, and keep your robot in the car. Once the sandbox answers again, reconnect with Last-Event-ID, then report exited.
Keys
Design partners
Plynth sends you a sign-in link to your company's page. It works once, for 7 days. Choose a password; after that, sign in at https://sandbox.plynth.build/ui/ with your email and password.
Under Credentials, Get Secret gives each robot's secret, once, with a file to download, plynth-sandbox.env. It holds the address, the robot ID and the secret, as GATEWAY_URL, GATEWAY_ROBOT_ID and GATEWAY_ROBOT_SECRET. Keep it like a password. Plynth never emails a secret.
Your robot IDs are your company's ID and a number, such as acme-1, and sandbox secrets start plynth_sbx_. Later, Rotate issues a new secret and keeps the old one working for 24 hours, Revoke Old stops the old one at once, and Read-Only Key gives a key for a dashboard (GET calls only). Each is shown once. The page also shows your robots' trips and refusals as they happen, with the reason for each and the code your software gets.
Add a Robot, beside Your Robots, adds one more robot and gives its secret the same way, up to 10 robots in all; for more, ask Plynth. Under How Your Robots Look, set how the building's screen draws them: each of your models (one of the screen's forms, such as a tall cart, a sidewalk rover or a humanoid, with its length, width and height), which model each robot is, your brand color and your logo. The screen keeps your color's hue, muted to sit with its drawing and clear of the colors it uses for alarms, waiting and moving. Your logo shows on each robot's pin, and on its lid in one color.
Under Spec Sheets, file each model's spec sheet, a PDF of up to 4 MB. Its values (size, weight, payload, speed, the slope and thresholds it manages, its radios and certifications) are read for you, each beside the line it came from: check them, fill in what wasn't read, and confirm. The sandbox then goes by them for that model's robots unless a robot sends its own (POST /v1/profile), so its doors and elevators answer too_big or over_rated_load as a building would. A sheet scanned as a picture reads nothing: fill it in from the sheet.
Visitor keys
Anyone may take a key of their own, with Get a Test Key in the quickstart, or from a terminal:
curl -X POST https://sandbox.plynth.build/docs/keys -H "Accept: application/json"
{"robot_id": "visitor-cb0a6c67", "secret": "plynth_sbx_...", "until": 1792648994.0,
"url": "https://sandbox.plynth.build", "docs": "https://sandbox.plynth.build/docs", "kit": "https://sandbox.plynth.build/docs/robot-kit.zip"}
- It's your own robot,
visitor-and eight hex digits, in a company of its own, for 24 hours. The key is shown once, and nothing about you is kept. - It rides the elevators and uses the doors. Its POST calls are trips (
POST /v1/passages, and each passage'sreport,cancelandheartbeat) andPOST /v1/heartbeatwithbatteryandstateonly. Every other POST answers 403,not_for_this_key: drills, positions, help, the profile and the rest come with a company's own keys. Every GET is open to it. - Each request is at most 2 KB (413,
too_large), and it has limits of its own. - Plynth switches visitor keys on at launch. Until then,
/docsshows no button, and/docs/keysanswers 404 (unavailable). When a great many keys are out at once, it answers 503: try again in a few minutes.
A visitor key's robot isn't a visitor robot in the building's sense: it needs no pass.
The test kit
The kit is plynth, version 0.2.2, under the Apache License 2.0: the reference client (plynth.client), the conformance check (plynth.conformance), a key check (plynth.hello) and the sandbox's grade of your own software (plynth.grade, Getting certified), in standard-library Python 3.9 or later. Copy it into your own code as you need.
| Download | What it is |
|---|---|
| robot-kit.zip | The kit. Unzip it and run it from inside robot-kit; nothing to install |
| plynth_robot_kit-0.2.2-py3-none-any.whl | The same, to pip install |
| plynth-ros2.zip | Two ROS 2 Jazzy packages on the kit's client: plynth_ros_example, a node that goes through a door and rides an elevator, and plynth_rmf_adapter, an Open-RMF lift and door adapter. Its README says how to build and run them |
| SHA256SUMS | SHA-256 sums of each, and of plynth-robot-kit-0.2.2.zip: the same kit, unzipping to plynth-robot-kit-0.2.2/ rather than robot-kit/ |
| CHANGELOG.md | What changed in each version |
Download it, check your key, then run the conformance check:
curl -sO https://sandbox.plynth.build/docs/robot-kit.zip && unzip -q robot-kit.zip && cd robot-kit
python3 -m plynth.hello --env ../plynth-sandbox.env
python3 -m plynth.conformance --env ../plynth-sandbox.env --report conformance.json
plynth.hello says whether the gateway accepts the key, whose robot it is, whether your clock is right, and which doors and elevators the robot may use. It exits 0 when the key works, 1 when the gateway refuses it or can't be reached, and 2 when a setting is missing.
The address, robot ID and secret come from GATEWAY_URL, GATEWAY_ROBOT_ID and GATEWAY_ROBOT_SECRET, or from --env with the file from your company's page. To set them by hand, keeping the secret out of your shell history:
export GATEWAY_URL=https://sandbox.plynth.build GATEWAY_ROBOT_ID=<your robot ID>
read -rs GATEWAY_ROBOT_SECRET; export GATEWAY_ROBOT_SECRET
Against the sandbox, the conformance check uses the door door and the elevator lift, riding from 1 to 2, unless you name others with --door, --elevator, --from and --to. Going live says what it checks, and how its report fits a building's go-live.
To install it with pip instead:
python3 -m pip install https://sandbox.plynth.build/docs/kit/plynth_robot_kit-0.2.2-py3-none-any.whl
plynth-hello --env plynth-sandbox.env
plynth-conformance --env plynth-sandbox.env --report conformance.json
To check a download, compare the output of shasum -a 256 robot-kit.zip (or sha256sum robot-kit.zip) with its line in SHA256SUMS. The kit's old module names, gateway.client and gateway.conformance, still work in the unzipped kit; the wheel has plynth only.
Limits
| What | Limit | Past it |
|---|---|---|
| Each robot | 20 requests a second, in bursts of up to 40 | 429, rate_limited, with Retry-After |
| Each caller address | 80 requests a second, in bursts of up to 160, so a fleet behind one address isn't held to one robot's share | The same |
| Visitor keys, from each address | 5 requests a second, after a first burst of 40: one run of the test kit | The same |
| Visitor keys, all together | 6 requests a second, and a new trip a second, so a busy day slows visitors first | The same |
| New visitor keys | 3 from each address, then one every 20 minutes; 30 for everyone, then one every 20 seconds | The same |
| Streams | Two open per robot | A third closes the oldest |
| Visitors' streams | 10 open for all visitor keys together, so design partners always get in | 429, with Retry-After: 30 |
| Request size | 64 KiB; a passage request, 4,096 bytes of JSON; a visitor key's request, 2 KB | 413, or 400 for a passage request |
| Bookings | 20 open per robot | 409 |
Retry-After is in whole seconds: wait that long before you send again. The kit's client does it for you, up to wait_429 seconds a call (10 by default; the conformance check waits up to 60). A full conformance run stays well inside these limits. Errors has more on 429.
Resets
Every night at 03:00 UTC, the sandbox starts afresh, in about two seconds. Its whole database is cleared: trips and their record, profiles, bookings, closures, drills and help requests. Positions are forgotten. Keys, sign-ins, how your robots look and your spec sheets stay. Streams drop, so reconnect, and send your robots' profiles again. Event IDs start again after a reset, so don't drop an event because its ID is lower than one you saw before.
Between test runs, POST /v1/sandbox/clear starts your company afresh without waiting. Your company's drills end, and its robots hear all clear; your robots' trips not yet aboard a car are cancelled; and their shared positions are forgotten. A robot already in a car rides on: it gets out and reports exited. Nothing of any other company's changes. The answer lists what ended and what was cancelled:
{"ended": [3], "cancelled": ["3f2b9c1e-6a4d-4e8b-9f1a-2c7d5e0b8a14"]}
In a building, POST /v1/sandbox/clear answers 404.
Drills
On the sandbox, your software may start an emergency drill to test its answers against. In a building, POST /v1/drills answers 404: the building runs its own drills, with your robot there.
POST /v1/drills
{"kind": "fire alarm"}
kindisfire alarm(the default, as from the building's panel),evacuation(addfloorfor one floor),lockdown,power lossorearthquake.make wayandmedicalneed afloorand anarea: one to eight boxes,[x, z, w, d]on the plate, the route to keep clear.- A data center's
smoke alert,pre-discharge,dischargeandemergency power offneed a room:"room": "server-room". A pre-discharge takesseconds, its countdown, 5 to 120 (the room's is 30).power transferneeds no room.
The answer is {"emergency": <its ID>, "message": <the notice your robot gets, or null>}.
A drill reaches only your company's robots: those online (heard from in the last minute), or placed by a position shared in the last 15 seconds, exactly as a building's emergency would (who is told). Share a position first (POST /v1/position) so your robot is sent to a zone rather than told to clear and hold.
A fire alarm drill holds your robots at every door and elevator (fire_alarm) and gives them a fire alarm notice, while every other company's robots carry on. Other drills refuse your robots' passages in their scope, with emergency. A drill ends after 2 minutes, or with POST /v1/drills/end, which ends your company's drills and no one else's; your robots then hear all clear. Visitor keys can't start drills.
What the simulation doesn't do
The sandbox is kinder than any building. Here is where it differs, so you know what's left to test on site.
| The sandbox | A real building | |
|---|---|---|
| Car arrival | lift's car comes about 1.5 seconds after the call, every time (lift-slow: 20 seconds) | Often 10 to 25 seconds, and longer when the bank is busy |
| Travel | About 1.5 seconds after boarded, whatever the floors (lift-slow: 20 seconds) | Depends on the floors, and on stops for other riders |
| Doors | A door counts as open as soon as it's commanded, and never closes. Car doors aren't modeled, so a door hold does nothing | Doors take seconds to open, close on their own timers, and reopen for obstacles. Your robot's sensors decide when the way is clear |
| Other riders | None: no people in the car, no full car, no stops on the way | People ride too, cars fill up, and other calls add stops |
| Destination dispatch | Cars are given in turn, A then B. No hall kiosks and no grouping of riders | A dispatcher picks the car, sometimes only when it arrives; car says which |
| Connection in the car | Never lost, except on lift-dropout (once aboard, the stream ends and calls hang unanswered for 20 seconds) | Wi-Fi often drops in a car or a shaft |
| Device faults | lift, door and secure-door never fail, go out of service or go into recall; door-jam and lift-recall do, one way each | Maintenance, out of service, fire recall, staff taking a car, a controller offline |
| Badges | Every robot's badge is active at secure-door | The site's own badge system can refuse a robot (badge_inactive) |
| The owner's rules | One rule lets every robot use every place, all day; the scenario places give the other refusals | Rules, hours, closures, no-robot windows, limits, approvals and passes vary by building |
| Places | No chargers, handoff spots, cages, mantrap, keep-out zones or named areas | Wherever the building has them |
| People | No one answers a help request or watches the owner's screen | The building's people answer help requests and see your robots |
| One shared building | Every company's robots share it; you see only your own trips, and your drills reach only your robots | The same, with the owner's own robots too |
| Time | Rules run on UTC | Rules run on the building's local time |
| Network | One small machine in New Jersey, over the internet | The gateway is on the building's own network |
| Certificate | A public certificate: nothing to pin | Pin the building's fingerprint, or trust its CA |
| Nightly reset | At 03:00 UTC the whole database is cleared (trips, profiles, bookings); keys, sign-ins, how your robots look and your spec sheets stay | Nothing resets; the record is kept for the building's retention period |
| Devices | None is real, and nothing moves | Real doors open and real cars move: run tests with someone from the site watching |
On your own computer
The sandbox runs here, hosted, for now. A local copy to run on your own computer isn't distributed yet. Until it is, you can't practice certificate pinning against a sandbox, since this one has a public certificate; the guide shows how to pin a building's gateway.