Hardware configuration¶
Before MARLIN moves anything, you have to tell it where each piece of hardware is plugged in. This page is about getting that declaration right, and what MARLIN does when it disagrees with the robot in front of it.
Robot.configure() declares which sensors and effectors are connected to the
robot. Call it exactly once, before Robot.run().
Port declarations¶
A port is a labelled socket on the robot brain. The label printed next to the socket is the string you use as the key:
flowchart TB
brain["Robot brain"]
subgraph sen["Sensor ports S1 to S6, declared in sensors"]
senlist["IMU, at most 2<br/>RadioBeacon, at most 1"]
end
subgraph eff["Effector ports M1 to M8, declared in effectors"]
efflist["Thruster<br/>Servo"]
end
brain --> sen
brain --> eff
Both mappings are dictionaries. The keys are port names and the values are MARLIN classes:
| Mapping | Valid ports | Supported types |
|---|---|---|
sensors |
S1 through S6 |
IMU, RadioBeacon |
effectors |
M1 through M8 |
Thruster, Servo |
The Python library validates these port names before sending configuration to the robot. The robot still verifies the complete declaration and can reject unsupported physical ports or hardware.
Pass the classes themselves, not instances:
Sensor limits¶
Each robot may declare at most:
- 2
IMUsensors - 1
RadioBeaconsensor
The beacon limit exists because every radio beacon receiver on a robot listens
on the same LoRa channel: the one set by the Beacon channel dropdown in
the extension's Controller card. A second RadioBeacon would report the same
data as the first, so it would tell you nothing new.
The game manual describes the Robot Brain as having six Sensor Ports. That is
the connector count, not a licence to declare six of one sensor. The per-type
limits above are what configure() enforces, and the spare ports are there for
the additional sensor types coming in future MARLIN seasons.
Exceeding either limit raises ValueError and names the offending ports:
robot.configure(
sensors={"S2": IMU, "S3": IMU, "S4": IMU},
effectors={},
)
# ValueError: At most 2 IMU may be configured; got 3 (S2, S3, S4).
Configuration verification¶
During configuration, the library:
- validates the local declarations;
- opens its local connection to the MARLIN extension;
- sends the configuration to the robot through the extension;
- waits for the parsed configuration to be echoed back;
- raises an error if the echo does not match.
In other words, a mismatch raises an error immediately, during configure(),
instead of failing silently and showing up later as confusing behaviour on the
field. This prevents a program from running against a different hardware
layout than the one you declared.
Accessing configured hardware¶
configure() only declares the hardware. To command or read a piece of
hardware, ask the robot for it by port name:
front_sensor = robot.sensor("S6")
left_thruster = robot.thruster("M8")
gripper_servo = robot.servo("M2")
robot.effector(port) returns whatever effector is on that port. The specific
ones, robot.thruster() and robot.servo(), raise TypeError if the port
holds the other kind. That catches typos early.
Typed sensor accessors¶
robot.imu(port) and robot.radiobeacon(port) are methods, not properties.
Call them, and always name the port:
The port must be one you declared in configure(). If it holds a different
kind of sensor, the call raises TypeError, which is the point: the typo stops
your program now rather than during a match.
Naming the port is what lets a second sensor of the same type just work: