Pybricks vs LEGO Firmware: Code, Features and FLL Rules
Pybricks or the official LEGO firmware for SPIKE Prime and Robot Inventor? Side-by-side Python code, the features only each one has, how to install Pybricks and what FLL and WRO rules allow.
Pybricks is open source firmware, free for Python programming, that replaces the official software on LEGO robotics hubs so you can program them in Python, with motor and driving tools built for precise robots. It matters more than ever now that official support is winding down: LEGO Education ended sales of SPIKE Prime and SPIKE Essential on June 30, 2026, and the MINDSTORMS Robot Inventor app was discontinued on October 1, 2026. This comparison sets out what actually differs between the official LEGO firmware and Pybricks, with side-by-side code, installation steps, competition rules and a migration guide.
Table of Contents
- Quick Comparison Table
- Performance: What Really Differs
- API Code Comparisons
- Feature Differences
- Installation & Setup
- Migration Guide
- Which Should You Choose?
Quick Comparison Table
| Feature | Official LEGO | Pybricks | Winner |
|---|---|---|---|
| Programming Options | Word blocks (Scratch-based) and Python | Python; block coding for paying supporters | ✅ LEGO |
| Motor Control | Speed, acceleration and stop mode per command | Adds adjustable PID gains, torque limits and gear ratios | ✅ Pybricks |
| Driving a Two-Wheeled Robot | Motor pairs, measured in wheel degrees | DriveBase in millimeters and degrees, with optional gyro assist | ✅ Pybricks |
| Multitasking | Yes (async and await with runloop) | Yes (async and await with multitask) | Tie |
| Supported Hubs | Separate LEGO apps for different hubs | One tool for SPIKE Prime, SPIKE Essential, Robot Inventor, Technic, City and BOOST hubs | ✅ Pybricks |
| Beginner Friendly | Yes (free blocks and lessons) | Best for Python learners | ✅ LEGO |
| Official Support | SPIKE App: bug fixes until June 30, 2031. MINDSTORMS app: ended October 1, 2026 | Community forums and an open source team | Depends on your hub |
| Documentation | In-app help and LEGO Education lessons | Detailed online docs with units for inputs and outputs | ✅ Pybricks |
| Competition Legal (FLL) | Yes | Yes, current rules allow any software | Tie |
Performance: What Really Differs
We could not find an official head-to-head benchmark from LEGO or the Pybricks team, so this guide does not quote a speed multiplier. Loop timings change with the hub, the firmware version and whatever else your program is doing, and on a competition mat they matter far less than how accurately the robot drives and turns. Below is a short test you can run on your own hub, followed by the places where the two firmwares are genuinely built differently.
Loop Speed: Test It on Your Own Hub
If you want a number, count how many times an empty loop runs in one second on each firmware. Keep the hub connected while it runs so you can see the printed result.
Official LEGO (SPIKE App 3)
import runloop
import time
async def main():
count = 0
start = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start) < 1000:
count += 1
print(count, "loops in one second")
runloop.run(main()) Pybricks
from pybricks.tools import StopWatch
watch = StopWatch()
count = 0
while watch.time() < 1000:
count += 1
print(count, "loops in one second") Treat the result as a rough comparison of the two Python interpreters and nothing more. Most competition programs spend much of their time waiting for moves to finish, and a faster empty loop does not make a robot drive any straighter.
Motor Control and Accuracy
On both firmwares the motor control loop runs on the hub itself, using the rotation sensor built into every SPIKE and Robot Inventor motor. The differences are in how much of it you can see and adjust:
- Units and stopping. Both use degrees per second for motor speed and let a motor brake, coast or hold its position at the end of a move. Pybricks holds by default, which keeps an arm from drooping after it lifts.
- Tuning. Pybricks lets you read and change the controller itself: PID gains, speed, acceleration and torque limits, and the tolerances that decide when a move counts as finished. The official Python API sets speed, acceleration, deceleration and stop mode for each command, but it does not expose the controller gains.
-
Gearing. Tell Pybricks the gear train on a motor (for example
gears=[12, 36]) and every command and reading is in degrees at the output, not at the motor. -
Homing. Pybricks has
run_until_stalled(), which is handy for pushing an attachment gently against a stop so it starts every run from the same place.
Driving, Sensors and Multitasking Together
Competition robots often need to drive, watch a sensor and move an attachment at the same time. Both firmwares handle this with Python's async and await: the SPIKE App uses the runloop module, and Pybricks uses multitask() and run_task(). The practical difference is how much is left for you to write. In Pybricks, a DriveBase can drive a set distance in millimeters and turn a set number of degrees, with the hub's gyro correcting the heading, while a second task moves an arm:
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase
from pybricks.tools import multitask, run_task
hub = PrimeHub()
left = Motor(Port.A, Direction.COUNTERCLOCKWISE)
right = Motor(Port.B)
arm = Motor(Port.C)
# Measure your own robot: wheel diameter and axle track in mm
drive_base = DriveBase(left, right, wheel_diameter=56, axle_track=112)
drive_base.use_gyro(True)
async def drive():
await drive_base.straight(500)
await drive_base.turn(90)
async def lift_arm():
await arm.run_angle(300, 180)
async def main():
await multitask(drive(), lift_arm())
run_task(main())
print("Heading:", hub.imu.heading()) With the official firmware you can build the same behavior, but the gyro correction and the conversion from wheel degrees to distance are code you write and tune yourself. Example 2 below shows what that looks like.
API Code Comparisons
Example 1: Motor Control
Official LEGO (SPIKE App 3)
from hub import port
import motor
import runloop
async def main():
# 360 degrees at 500 degrees per second
await motor.run_for_degrees(port.A, 360, 500)
runloop.run(main()) Pybricks
from pybricks.pupdevices import Motor
from pybricks.parameters import Port
motor = Motor(Port.A)
# 360 degrees at 500 degrees per second, then hold
motor.run_angle(500, 360) Both programs turn the motor one full rotation. In the SPIKE App, commands that wait for a move to finish are awaited inside an async function started by runloop.run(). Pybricks runs from top to bottom, and you only add async code when you want several things to happen at once.
Example 2: PID Motor Control
Both firmwares already run closed-loop control inside every motor command, so you never need to write a PID loop just to turn a motor accurately. The difference shows up in two places: how much of that controller you can adjust, and whether higher-level jobs such as driving straight on the gyro come built in.
In Pybricks, the controller settings belong to each motor. You can read them, change them, and declare a gear train so commands work in output degrees:
from pybricks.pupdevices import Motor
from pybricks.parameters import Port, Direction
# A 12-tooth gear on the motor drives a 36-tooth gear on the arm
arm = Motor(Port.C, Direction.CLOCKWISE, gears=[12, 36])
print(arm.control.pid()) # kp, ki, kd, integral_deadzone, integral_rate
print(arm.control.limits()) # speed, acceleration, torque
arm.run_target(200, 90) # 90 degrees at the arm, not at the motor To change the gains, pass new values to arm.control.pid(kp, ki, kd, integral_deadzone, integral_rate). The defaults work well for most builds, so try adjusting speed and acceleration limits before you touch the gains.
The official SPIKE App 3 Python API does not expose the controller gains. When you need correction on top of the built-in motor control, such as holding a robot on its heading, you write that loop yourself. Here is a simple proportional correction using the hub's yaw angle:
from hub import port, motion_sensor
import motor_pair
import runloop
async def main():
motor_pair.pair(motor_pair.PAIR_1, port.A, port.B)
motion_sensor.reset_yaw(0)
for _ in range(200):
yaw = motion_sensor.tilt_angles()[0] / 10 # decidegrees to degrees
steering = int(max(-100, min(100, -2 * yaw)))
motor_pair.move(motor_pair.PAIR_1, steering, velocity=400)
await runloop.sleep_ms(10)
motor_pair.stop(motor_pair.PAIR_1)
runloop.run(main()) This drives for roughly two seconds. If the robot swings away from its heading instead of back toward it, change -2 to 2. From there you would tune the gain, add a distance check and write a matching turn function. In Pybricks, drive_base.use_gyro(True) and drive_base.straight() cover the same ground.
Example 3: Sensor Reading
Both APIs return real units rather than raw sensor counts, but they use different scales, and that trips people up when they switch. The official SPIKE App 3 reports force in decinewtons and the hub's angles in decidegrees, so you divide by 10 to get newtons and degrees. Pybricks uses newtons, millimeters and degrees throughout.
Official LEGO (SPIKE App 3)
from hub import port, motion_sensor
import color_sensor
import distance_sensor
import force_sensor
import runloop
async def main():
print(color_sensor.reflection(port.C)) # percent, 0 to 100
print(distance_sensor.distance(port.D)) # mm, or -1 if nothing detected
print(force_sensor.force(port.E)) # decinewtons, 0 to 100
print(motion_sensor.tilt_angles()[0]) # yaw in decidegrees
runloop.run(main()) Pybricks
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import ColorSensor, UltrasonicSensor, ForceSensor
from pybricks.parameters import Port
hub = PrimeHub()
color = ColorSensor(Port.C)
eyes = UltrasonicSensor(Port.D)
button = ForceSensor(Port.E)
print(color.reflection()) # percent, 0 to 100
print(eyes.distance()) # mm, or 2000 if nothing detected
print(button.force()) # newtons
print(hub.imu.heading()) # degrees Watch the "nothing detected" value in particular. The official distance sensor function returns -1 when it cannot measure a distance, while Pybricks returns 2000 mm. A check such as if distance < 100 treats an empty view as "very close" on the official firmware and as "far away" on Pybricks.
Feature Differences
Features Only in Pybricks
- Motor controller settings you can read and change (PID gains, speed, acceleration and torque limits)
- DriveBase class for two-wheeled robots, with distances in millimeters, turns in degrees and optional gyro assist
- Gear ratios built into motor setup
-
run_until_stalled()for homing attachments - One programming tool for SPIKE Prime, SPIKE Essential, Robot Inventor, Technic, City and BOOST hubs
- Open source under the MIT license, independent of LEGO's app support schedule
Features Only in Official LEGO
- Free, Scratch-based word blocks (Pybricks offers block coding only to paying supporters)
- LEGO Education lessons and units built around the kits
- Official app integration
- Support from LEGO Education (for the SPIKE App, bug fixes and operating system updates until June 30, 2031)
- Nothing to install: it is the firmware the hub ships with
Installation & Setup
Installing Pybricks replaces the firmware on the hub. It does not change the hardware, and you can switch back later. Before you start, check that you have:
- A Windows 10 or 11, macOS, Linux, Android or ChromeOS computer or tablet with Bluetooth. iPads and iPhones are not supported.
- Google Chrome or Microsoft Edge. Firefox and Safari do not support Web Bluetooth, so they will not work.
- For SPIKE Prime, SPIKE Essential and MINDSTORMS Robot Inventor hubs, a micro USB cable for the install. Technic, City and BOOST hubs have no USB port and install over Bluetooth.
- A charged hub battery, so the hub does not switch off partway through.
Installation Steps
- Visit pybricks.com/install for the current instructions, then open the Pybricks Code editor at code.pybricks.com.
- Start the firmware installer, choose your hub type and accept the software licenses.
- Give the hub a name. This helps when several hubs share one room.
- Put the hub into update mode by following the video in the installer. On SPIKE and Robot Inventor hubs, this is where the USB cable comes in.
- Connect when prompted. The installation starts on its own; leave the hub alone until the installer says it has finished.
- Connect to the hub over Bluetooth and run a short test program, such as the loop test above.
Troubleshooting
- The hub never shows up in update mode. Try a different USB cable (some cables only carry power) and follow the button sequence in the installer video exactly.
- A SPIKE Prime hub made in 2026 is not recognized. LEGO changed the hub's internal electronics in 2026, and those hubs need new Pybricks firmware. The Pybricks team released support for them at beta.pybricks.com in July 2026, and its installer there does not need any hub buttons pressed. As of early October 2026 that support was still in beta only, so check the Pybricks site for the current status before assuming the hub is faulty.
- Chrome cannot find the hub over Bluetooth. Check that Bluetooth is switched on, the hub is powered, and no LEGO app is still connected to it.
Migration Guide: LEGO → Pybricks
Most of the move from the SPIKE App to Pybricks is mechanical. Motors and sensors become objects you create once, port.A becomes Port.A, and wheel-degree driving becomes millimeters and degrees with DriveBase. Use this table as a starting point:
| Task | SPIKE App 3 Python | Pybricks |
|---|---|---|
| Set up a motor |
import motor, then pass port.A to each call |
m = Motor(Port.A) |
| Run until told to stop | motor.run(port.A, 500) |
m.run(500) |
| Turn a set number of degrees | await motor.run_for_degrees(port.A, 360, 500) |
m.run_angle(500, 360) |
| Stop a motor | motor.stop(port.A) |
m.stop(), m.brake() or m.hold()
|
| Read speed (deg/s) | motor.velocity(port.A) |
m.speed() |
| Read position (degrees) | motor.relative_position(port.A) |
m.angle() |
| Drive straight |
motor_pair.move_for_degrees(), in wheel degrees |
drive_base.straight(200), in mm |
| Turn the robot | Steering or tank commands, in wheel degrees |
drive_base.turn(90), in degrees of robot rotation |
| Read heading |
motion_sensor.tilt_angles()[0], in decidegrees |
hub.imu.heading(), in degrees |
| Pause | await runloop.sleep_ms(500) |
wait(500) |
| Run tasks together | runloop.run(task_a(), task_b()) |
await multitask(task_a(), task_b()) inside a function started with run_task()
|
Motor Control Migration
# MINDSTORMS Robot Inventor app Python
from mindstorms import Motor
motor = Motor('A')
motor.start(50) # speed as a percentage
# Pybricks equivalent
from pybricks.pupdevices import Motor
from pybricks.parameters import Port
motor = Motor(Port.A)
motor.run(500) # speed in degrees per secondCommon Gotchas
- Port naming: 'A' or port.A → Port.A
- Speed units: the MINDSTORMS app used percentages; Pybricks uses deg/s for motors and mm/s for DriveBase (SPIKE App 3 already uses deg/s)
- Waiting: run_angle() and run_target() wait for the move to finish unless you pass wait=False
- Sensor values: no more dividing decinewtons and decidegrees by 10, and an empty distance reading is 2000 mm, not -1
Which Should You Choose?
Is Pybricks Allowed in Competitions?
For FIRST LEGO League Challenge, yes. The BIOGLOW (2026-27) Robot Game Rulebook says teams "can use any software or programming language," as long as the robot is autonomous during the match and no remote controllers are used. The 2025-26 rulebook used the same wording. Challenge Updates released during the season override the rulebook, so check the latest ones. WRO's 2026 RoboMission General Rules also allow any software to code the robot, but Bluetooth and other wireless connections must be switched off during check time and robot runs, or left unused if they cannot be turned off, so ask your WRO organizer how they want Pybricks hubs handled.
Choose Official LEGO Firmware If:
- ✅ You're teaching beginners (Scratch is valuable)
- ✅ Your class follows LEGO Education lessons
- ✅ You want official support and app integration
- ✅ Your school or event requires the official LEGO software
Choose Pybricks If:
- ✅ You want precise, repeatable driving (DriveBase with gyro assist)
- ✅ You're comfortable with Python-only workflow
- ✅ You need motor settings the official app does not expose (PID gains, torque limits, gear ratios)
- ✅ You're building complex autonomous robots
- ✅ You own a Robot Inventor hub and want it programmable now that the MINDSTORMS app ended on October 1, 2026
- ✅ Competition rules allow alternative firmware
Hybrid Approach (Recommended)
You don't have to choose forever, because switching back is a firmware restore. A sensible plan:
- Learn with official LEGO firmware
- Switch to Pybricks for competition season
- Keep backup hub with LEGO firmware for Scratch demos
A Note on Buying Hardware in 2026
Neither kit is a current LEGO product. MINDSTORMS Robot Inventor was discontinued in 2022, and LEGO Education ended sales of SPIKE Prime and SPIKE Essential on June 30, 2026, so you will be looking at remaining retailer stock or secondhand kits. LEGO Education says it will keep fixing bugs in the SPIKE App and supporting new operating system versions until June 30, 2031, without adding new features. The MINDSTORMS Robot Inventor app was discontinued on October 1, 2026, with no further updates or support. Pybricks does not depend on either app, which is a big part of why it keeps these hubs useful.
Ready to write Pybricks code? 10 Beginner Python Projects for LEGO MINDSTORMS and SPIKE starts from the light matrix, the line-following robot tutorial covers proportional and PID steering, and Programming LEGO MINDSTORMS Robot Inventor covers life after the MINDSTORMS app.
Learning Resources
Use Our Tools to Go Further
Get more insights about the sets mentioned in this article with our free LEGO tools