Participant API and local kit — 0.3.0

New to the league? Start with the one-page quickstart, then use the student handbook when you need a detail. This page is the compact sensor/API reference. Values below are the kit defaults; the organizer can configure a class differently.

First match in five minutes

Install Python 3.11+ and use these commands from this checkout:

sh
python -m pip install -e .
robosoccer new my_bot.py
robosoccer check my_bot.py
robosoccer run my_bot.py --vs chaser --seed 3 --watch

The package is installable from a local wheel too; it has not been published to PyPI. No third-party runtime dependencies are required. NumPy is not required by the engine or references. Each team executes in a separate subprocess with hard wall-clock deadlines, no-ops on errors and forfeits after repeated violations. check uses the same smoke validator as uploads. benchmark measures local timing margin. This classroom edition uses normal Python imports and trusted code.

Two functions, one file

python
def setup(info: dict) -> dict | None:
    return {"speed": info["robot"]["cruise_speed"]}

def act(robot_id: int, sensors: dict, memory: dict) -> dict:
    for obj in sensors["camera"]:
        if obj["kind"] == "ball":
            return {"move": (memory["speed"], 4 * obj["bearing"]),
                    "kick": 1.0 if sensors["ball_in_kicker"] else 0.0,
                    "broadcast": [obj["distance"], obj["bearing"]]}
    return {"move": (0.0, 1.5), "kick": 0.0}

setup is called once per team. It may be omitted or return None. info contains engine version, team ID and initial side, robot count, field dimensions, public landmark coordinates, robot/kick limits, sensor/communication settings, rules and timestep. It contains no hidden seed, realized randomization values or true starting poses. The fixed landmark map is available for localization; landmark observations provide only bearing and distance.

The engine owns a per-team memory dictionary partitioned by robot ID. Each robot sees only its own dictionary, initialized from a deep copy of the setup result. This resolves the shared-memory/communication ambiguity: robots cannot use memory as an instantaneous team-wide channel. Mutate the supplied dictionary to persist JSON state. Limits are 16 KiB per robot and 64 KiB source per file. Globals are reinitialized before each call. Imports of random use independent engine-seeded per-robot streams. Timings include that initialization and serialization.

Ordinary globals are reset for cooperative bots; this is not a security mechanism. Normal imports are available. Use math, seeded standard-library random, collections, itertools, heapq, functools, dataclasses and typing for portable deterministic bots. Optional NumPy must be installed separately and its RNG is not seeded automatically. Use the engine-seeded random stream instead. The classroom scope deliberately excludes import restrictions and security hardening.

Returning an invalid action or raising an exception produces a no-op for that robot. Memory commits only when the action and updated memory are JSON-compatible and finite. Errors keep a traceback in a separate .errors.json file and in the selected debug log. Host timings remain in .summary.json, outside the replay.

Sensor dictionary

FieldMeaning
tick, dt, half, phasePublic clock; phase is kickoff/playing/finished
scorePublic [team_0, team_1] score
attack_direction+1 toward right goal, -1 toward left; swaps at half time
cameraList of {kind, distance, bearing, id?} detections
ball_in_kickerNoisy range threshold and forward-arc test
imu{heading, angular_velocity} in radians / radians per second
odometry{forward, lateral} measured body-frame velocity in m/s
proximityNearby wall/robot {kind, distance, bearing, bump, id?} entries
stamina, kick_cooldownOwn energy in [0,1], remaining cooldown in seconds
messagesReceived teammate packets {sender, sent_tick, received_tick, data}

Positive bearing is counterclockwise/left relative to the robot's forward axis. camera.kind is ball, teammate, opponent, goal, landmark or line. Robot IDs are team-relative visual identifiers. Goal IDs are left/right. Landmark IDs are corner_sw, corner_nw, corner_se, corner_ne, center. Line IDs are left/right, bottom/top and halfway; each reading is the closest point on that painted segment. Camera distance is center-to-center. Proximity distance is surface-to-surface. The camera uses point visibility and circular-robot occlusion; a robot can hide another object. There is no image pixel processing. Ghosts have no debug flag.

There is no true global robot position, ball position or velocity in sensor data. IMU heading is a noisy absolute direction with accumulated drift. Robots can infer position from landmarks, odometry and nearby known walls. Replay ground truth is for spectators/debugging and is never passed to act.

Noise defaults (single source: robosoccer/config.toml)

ParameterDefault
Camera FOV / range110° / 2.5 m
Distance σ0.015 + 0.020 × distance m
Bearing σ0.010 + 0.004 × distance rad
Miss probability6% per visible object per tick
False-positive probability0.5% per robot/tick, at most one ball/opponent ghost
Per-match sensor noise scaleUniform [0.85, 1.15]
Kicker threshold σ0.025 m
IMU heading σ / angular velocity σ0.004 rad / 0.020 rad/s
IMU drift incrementsGaussian σ = 0.002 × sqrt(elapsed seconds) rad
Wheel odometry σ0.030 m/s per body-frame axis
Proximity range / distance σ0.35 m / 0.005 m
Bump threshold0.015 m surface gap

The match noise scale multiplies Gaussian standard deviations. Miss/ghost probabilities remain as configured. Range/FOV/occlusion tests use true geometry, then noise is applied, so measurements can extend slightly beyond range/FOV. Noise uses independent per-robot streams and is cached per tick. Re-reading a tick or changing robot read order cannot improve or perturb measurements. Proximity bearing and bump flags are exact geometric readings; proximity distance is noisy. Kicker noise perturbs range, not the facing arc or true engine kick eligibility.

--perfect-sensors disables Gaussian error, drift, missed detections and ghosts. It preserves FOV, range and occlusion, and does not change radio loss/delay or physics randomization. This flag is local only. Turning it on is recorded in replay metadata. To change radio conditions locally, copy the full default config and modify its communication section with --config.

Coordination

Return "broadcast": [up to 16 finite numbers]. There is at most one packet per robot per tick, sent independently to every other teammate. Self-delivery and opponent delivery do not occur. Each recipient independently loses 10% of packets and receives the others after an inclusive uniform delay of 2–5 ticks. Delivery is measured from the observation tick that produced the action. Radios operate during kickoff too; all in-flight messages are cleared on a new kickoff to discard stale pre-reset positions. Future packets are not visible, even to robots called later on the same tick. Repeat reads of an inbox return the same detached packets.

Reference bots and local commands

collision avoidance, goalward approach, and striker bids over delayed radio.

sh
robosoccer run my_bot.py --vs other_bot.py --matches 20 --seeds random --fast
robosoccer run decent-team --vs chaser --matches 4 --seeds 3,4 --replay series.json
robosoccer run my_bot.py --vs goalkeeper --debug-robot 2 --debug-log robot-2.jsonl
robosoccer league my_bots_folder/ --fast --output league-replays/

The first bot starts left, then right with the same seed; each next pair uses the next seed. Match summaries report outcomes relative to the first bot. Random seeds are printed and saved. League runs every local pair twice with side swaps, awarding 3/1/0 points and using goal difference then name to break ties. The server uses the same scoring with configurable even matches per pair (default 4), including all four references. No Elo is used. --fast disables stored sensor overlays, not sensor calls or replay physics. Every match still records its engine version and config.

Debug logs contain one JSON line per tick: sensors, memory before/after, action, error and traceback. --debug-robot N selects the first bot's robot even on a side swap. Source hashes identify bot versions. Absolute host paths and elapsed host time are excluded from replay hashing. Use the same engine, config, seed, source and perfect-mode setting for an identical replay. Cross-runtime math caveats from the engine contract still apply.