Skip to content

Your first MARLIN program

This page builds the smallest useful MARLIN program: one thruster controlled by the left stick.

The goal is not to build a good robot yet. The goal is to understand the shape of every MARLIN program.

Complete program

This is the whole file. Save it as src/main.py in a MARLIN project. The extension runs that file, so there is nothing else to create and nothing to select.

from marlin import Robot, Thruster

THRUSTER = "M1"          # change thruster to your thruster port number

robot = Robot()

robot.configure(
    sensors={},
    effectors={THRUSTER: Thruster},
)


def autonomous(robot):
    while robot.running:
        pass


def driver(robot):
    while robot.running:
        power = robot.controller.joystick("ONE").value
        robot.thruster(THRUSTER).set_duty(power)


robot.run(autonomous=autonomous, driver=driver)

1. Import MARLIN classes

from marlin import Robot, Thruster

Robot is the main object. Almost everything goes through it.

Thruster is a type token. You use it to tell MARLIN what kind of hardware is plugged into a port.

2. Create the robot object

robot = Robot()

This creates your program's handle to MARLIN. It does not open USB directly. The VS Code extension owns the Controller USB connection.

3. Declare hardware

THRUSTER = "M1"

robot.configure(
    sensors={},
    effectors={THRUSTER: Thruster},
)

configure() tells MARLIN what hardware your robot has.

This example has:

  • no sensors
  • one thruster on effector port M1.

THRUSTER is an ordinary variable holding the port name. Naming it once at the top means you change one line when your thruster moves to a different port, instead of hunting through the file for every "M1". Sensor ports are S1S6 and effector ports are M1M8.

Pass hardware classes such as Thruster, not constructed objects such as Thruster("M1").

4. Write match behaviour

def autonomous(robot):
    while robot.running:
        ...

The autonomous function runs during the Autonomous Period. This example does nothing there yet, but it still needs the while robot.running: loop around it. MARLIN calls the function once, when the phase starts, so a function that returns straight away hands control back immediately instead of staying in charge for the phase; MARLIN says so in the console when that happens. Leave the stub in place; you fill in the body when you write an auton routine.

def driver(robot):
    while robot.running:
        # write your driver code inside this loop

Your loop does not need a wait at the end. Reading robot.running paces it to fifty times a second on its own, matching the rate MARLIN sends commands to the robot. Do not add a time.sleep() of your own. See running.

The driver function runs during the Driver Controlled Period.

Inside it, while robot.running: keeps your code active until the phase ends. When the phase ends, robot.running becomes false and the loop exits.

robot.controller.joystick("ONE").value reads the latest cached stick position. MARLIN does not stop and wait for a new controller packet.

"ONE" names one axis of one stick: the left stick's up and down direction. The controller has four axes in total, named "ONE" to "FOUR"; see Controller input for the diagram.

.value is a number from -100 to 100. set_duty() takes a number from -100 to 100. The ranges match on purpose, so power can be passed straight through without conversion.

robot.thruster(THRUSTER).set_duty(power) updates the command for the thruster on port M1. set_duty() returns nothing; you call it for its effect on the robot.

5. Start the match

robot.run(autonomous=autonomous, driver=driver)

run() waits for the match, calls your callbacks for each phase, idles outputs when callbacks finish, and shuts the robot down safely when the match ends.

This ordering is a safety step, not a formality: run() only starts after configure() has already succeeded, so the robot never accepts commands against a hardware layout you did not declare.

What to remember

  • Create one Robot.
  • Call configure() once before run().
  • Put repeated behaviour inside while robot.running:.
  • Read controller and sensor state from the Robot.
  • Command hardware through accessors like robot.thruster("M1").
  • Do not open serial ports from your Python code.

Run it

This file does nothing until the extension runs it. Save it as src/main.py in a MARLIN project, then follow Run your program.

You should see: pushing the left stick forward spins the thruster, pulling it back reverses it, and centring the stick stops it.

Where to go next

Get this running before you go further. Everything after this assumes you can put code on the robot and watch it move.

Then build the Complete robot program. It starts from the file on this page and grows it one step at a time into two thrusters, a servo, an IMU, and both match phases.

For the concepts behind the shape you just wrote, read Program structure.