Problems while the program runs¶
Your program started and your callbacks are being called. These are the failures you hit from there on: the robot stopping, an error raised from an API call, or data you cannot trust.
The robot does not respond and robot.overtemp is True¶
The robot brain's board reached 50 °C and stopped itself. It will not accept commands again until the board cools to 45 °C.
Read robot.overtemp to detect this state. Let the board cool. The
extension brings the robot back once the temperature drops below 45 °C; your
program does not need to do anything else.
robot.estopped is True and nothing moves¶
The robot is e-stopped. E-Stop authority lives in the MARLIN extension and the pool dashboard. Your Python code cannot set or clear E-Stop.
Read robot.estopped to detect this state. Clear the E-Stop from the
extension or the pool dashboard, not from your program.
A callback stops running¶
What you see: the robot does the first thing you asked, then sits still for the rest of the period even though the phase clock is still counting down.
MARLIN calls autonomous(robot) and driver(robot) once each, at the start
of their phase. When that function returns, whether from an explicit return
or by simply reaching its last line, MARLIN treats the phase's work as
finished: it does not call the function again, and it idles every effector
until the next phase begins.
So this drives for a few milliseconds, not for the whole period:
Anything that should keep happening belongs inside the phase loop, which runs until the pool server ends the phase:
robot.running becomes false when the phase ends, so the loop exits on its own.
See Lifecycle for the full phase sequence.
A motor or servo set in initialize() never moves¶
What you see: the program runs and the match starts normally, but the one thing
you did in initialize(), such as stowing an arm or centring a servo, never
happened. There is no error.
initialize() runs before the match starts, so MARLIN is not sending effector
commands to the robot yet, and it idles every effector the moment
initialize() returns. The command is discarded either way:
Move anything that positions the robot to the top of the phase that needs it. It still runs once, before the loop:
def autonomous(robot):
robot.servo("M2").angle(0) # runs once, before the loop
while robot.running:
...
initialize() is still the place for setup that is not movement: reading
sensors, printing, and working out values your callbacks need. See
Lifecycle.
An accessor raises KeyError¶
The requested port was not declared in configure():
Use the same port spelling as the configuration mapping.
A typed accessor raises TypeError¶
robot.thruster(port) and robot.servo(port) verify the configured type. Use
the accessor matching the declaration, or use robot.effector(port) when code
intentionally accepts either type.
AttributeError on robot.imu.read or robot.radiobeacon.read¶
robot.imu and robot.radiobeacon are methods, not properties. Missing
the call parentheses:
reads the bound method object itself and then looks for .read on that,
which does not exist, producing a confusing AttributeError. Call the method
first, then read from what it returns:
robot.imu() or robot.radiobeacon() raises LookupError¶
You called the accessor without naming a port:
Name the port you wired the sensor to:
Leaving the port out asks MARLIN to guess, and it only can when exactly one
sensor of that type is configured. With none configured, or with two, there is
no single right answer and you get LookupError. Naming the port removes the
guess, so write it every time.
If the port is named and MARLIN still cannot find the sensor, it was never
declared. Add it to robot.configure(), on whichever port it is actually wired
to, and you will get KeyError until you do:
Naming the port also gives you working editor completion.
A thruster or servo will not go past a certain point¶
set_duty(), angle(), and micros() each clamp to their range: set_duty
takes -100 to 100, angle takes 0 to 180, and micros takes 500 to 2500. A
value past either end is pinned to that end and sent, so asking for 150 duty
runs the thruster at 100 and nothing reports a problem.
If a thruster seems stuck at full power, or a mix turns less sharply than the sticks suggest, print the value you are passing before you send it. A mix that clamps on one side only will skew the difference between two thrusters. See Range clamping.
A command prints is not a usable number¶
Typical message:
[API] M1: set_duty(nan) is not a usable number, so the setpoint is left as it was. Check the maths feeding it.
nan ("not a number") is the one value MARLIN cannot clamp, so the effector
holds whatever setpoint it already had. It usually comes from arithmetic on a
missing reading, such as dividing by zero or using a sensor value without
checking reading.ok first. The message prints once per setter, not once per loop.
joystick() raises ValueError¶
Typical message:
There are exactly four joystick axes, so MARLIN rejects any other name instead
of returning an axis that always reads zero. Use "ONE", "TWO", "THREE", or
"FOUR". See Controller input for which
physical axis each one is.
The robot creeps with the sticks released, or never reaches full speed¶
joystick() reads a raw ADC value, and no gimbal is perfect: released, it sits
a little off the middle of its range, and pushed hard over it stops short of the
electrical end. So an untouched stick can read a few counts instead of 0, and a
stick at the stop can read 90 instead of 100.
Click Calibrate Sticks in the Control Station. It measures the resting
position and the real travel of each stick and saves both into project.marlin.
See Calibrate Sticks. Calibration
is per project, so a fresh project starts uncalibrated.
If one axis still tops out short after calibrating, its sweep did not reach the edge all the way round; the status bar names the joystick to run again.
A sensor reading has ok == False¶
The sample is missing, marked invalid, or more than 250 ms old. Inspect
reading.age, check robot.link_ok, and use a safe fallback. Do not command
motion based on stale sensor values.
Controller input works but link_ok is false¶
Controller input and robot telemetry travel through different parts of the
system. The Controller can continue reporting sticks and buttons while the
Controller-to-robot link is down. Treat link_ok == False as a robot-link
failure even if controller values still change.