MicroPython Basics

From Bespoke Robot Society
Revision as of 20:15, 11 October 2025 by John (talk | contribs) (Created page with "{{Tutorial |name=MicroPython Basics |competency=Software |difficulty=Beginner |time=3-5 hours (split across multiple sessions) |prerequisites=None - complete beginner friendly |materials=Raspberry Pi Pico ($4), USB cable, computer with Thonny IDE (free), LED, resistor (220Ω), breadboard |next_steps=SimpleBot assembly, MicroPython Programming, Electronics Fundamentals }} '''MicroPython Basics''' is your introduction to programming microcontrollers for ro...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
MicroPython Basics
Competency Software
Difficulty Beginner
Time Required 3-5 hours (split across multiple sessions)
Prerequisites None - complete beginner friendly
Materials Needed Raspberry Pi Pico ($4), USB cable, computer with Thonny IDE (free), LED, resistor (220Ω), breadboard
Next Steps SimpleBot assembly, MicroPython Programming, Electronics Fundamentals

MicroPython Basics is your introduction to programming microcontrollers for robotics. This tutorial covers everything you need to write your first robot program, from installing MicroPython to controlling GPIO pins.

By the end of this tutorial, you'll understand:

  • What MicroPython is and why it's great for robotics
  • How to install MicroPython on Raspberry Pi Pico
  • How to use Thonny IDE and the REPL
  • Python basics: variables, functions, loops, conditionals
  • How to control LEDs and read buttons
  • How to write simple robot programs

This tutorial is hands-on. You'll write and run code on real hardware.

Part 1: What is MicroPython?

MicroPython is a version of Python designed for microcontrollers - tiny computers that control robots.

Why MicroPython for Robotics?

  • Easy to learn - Python is one of the most beginner-friendly programming languages
  • Interactive - Test code immediately with the REPL (Read-Eval-Print Loop)
  • Fast development - Write code quickly without compiling
  • Rich libraries - GPIO, PWM, I2C, SPI built in
  • Low cost - Raspberry Pi Pico costs $4 and runs MicroPython perfectly

Comparison to other options:

  • Arduino (C/C++) - Faster execution, larger community, but harder to learn
  • Python on Raspberry Pi - Full Python ecosystem, but not real-time, more expensive
  • MicroPython - Best balance of simplicity and capability for beginners

What is a Microcontroller?

A microcontroller is a tiny computer designed to control hardware:

  • CPU - Processes instructions (runs your code)
  • RAM - Temporary storage for variables (264 KB on Pico)
  • Flash - Permanent storage for programs (2 MB on Pico)
  • GPIO - General-Purpose Input/Output pins to connect sensors and motors

Raspberry Pi Pico specifications:

  • Dual-core ARM Cortex-M0+ @ 133 MHz
  • 264 KB RAM, 2 MB flash
  • 26 GPIO pins (digital I/O, PWM, ADC, I2C, SPI, UART)
  • USB for programming and power
  • Costs $4

Part 2: Installing MicroPython

Step 1: Download MicroPython Firmware

  1. Go to MicroPython Downloads
  2. Download the latest .uf2 file (e.g., "rp2-pico-latest.uf2")
  3. Save it to your computer

Step 2: Flash MicroPython to Pico

  1. Hold the BOOTSEL button on Raspberry Pi Pico
  2. While holding BOOTSEL, plug USB cable into computer
  3. Release BOOTSEL button
  4. Pico appears as a USB drive named "RPI-RP2"
  5. Drag the .uf2 file to the RPI-RP2 drive
  6. Pico automatically reboots with MicroPython installed!

Troubleshooting:

  • RPI-RP2 drive doesn't appear? Make sure you're holding BOOTSEL before plugging in USB
  • File won't copy? Try a different USB cable (some are power-only)
  • Pico disconnects after copying? This is normal! It's rebooting with MicroPython

Step 3: Install Thonny IDE

Thonny is a beginner-friendly Python IDE with built-in MicroPython support.

  1. Download from thonny.org
  2. Install Thonny (Windows: run installer, macOS: drag to Applications, Linux: apt install thonny)
  3. Open Thonny
  4. Click bottom-right corner where it says "Python" and select MicroPython (Raspberry Pi Pico)
  5. Connect Pico via USB - Thonny should detect it

You should see:

  • A code editor (top half) - Write programs here
  • A Shell/REPL (bottom half) - Interactive Python console

Part 3: Your First MicroPython Program

The REPL (Interactive Shell)

The REPL (Read-Eval-Print Loop) lets you test Python code immediately:

  1. Type in the Shell (bottom half of Thonny)
  2. Press Enter
  3. See the result instantly

Try this:

>>> print("Hello, Robot!")
Hello, Robot!

>>> 2 + 2
4

>>> name = "SimpleBot"
>>> print(f"My robot is {name}")
My robot is SimpleBot

Why the REPL is amazing:

  • Test sensor readings instantly
  • Debug code by checking variable values
  • Learn Python by experimenting

Blink the Onboard LED

Raspberry Pi Pico has an LED on pin 25 (the "onboard LED"). Let's blink it!

Type this in the REPL:

>>> from machine import Pin
>>> import time
>>> led = Pin(25, Pin.OUT)
>>> led.on()

The LED should turn ON!

Now turn it OFF:

>>> led.off()

Make it blink:

>>> for i in range(10):
...     led.toggle()
...     time.sleep(0.5)

Note: After typing "for i in range(10):", press Enter, then type the indented lines, then press Enter twice to run.

Write Your First Program

Now let's write a complete program in the editor (top half):

from machine import Pin
import time

led = Pin(25, Pin.OUT)

while True:
    led.toggle()
    time.sleep(0.5)

Run the program:

  1. Click the green "Run" button (or press F5)
  2. Thonny will ask "Where to save?" - choose MicroPython device
  3. Save as blink.py
  4. The LED blinks forever!

Stop the program:

  • Click the red "Stop" button or press Ctrl+C

What this code does:

  • from machine import Pin - Import Pin class for GPIO control
  • import time - Import time module for delays
  • led = Pin(25, Pin.OUT) - Configure pin 25 as output
  • while True: - Loop forever
  • led.toggle() - Switch LED state (on→off or off→on)
  • time.sleep(0.5) - Wait 0.5 seconds

Part 4: Python Basics for Robotics

Variables

Variables store values (sensor readings, motor speeds, states):

# Numbers
speed = 100
distance = 15.5

# Strings (text)
robot_name = "SimpleBot"

# Booleans (True/False)
line_detected = True
obstacle_ahead = False

Comments

Comments explain code (Python ignores them):

# This is a comment
speed = 100  # Set motor speed to 100%

Math Operations

# Basic math
x = 10 + 5    # Addition: 15
y = 10 - 3    # Subtraction: 7
z = 10 * 2    # Multiplication: 20
w = 10 / 4    # Division: 2.5
q = 10 // 4   # Integer division: 2
r = 10 % 3    # Modulo (remainder): 1

# Comparisons (result is True or False)
10 > 5   # Greater than: True
10 < 5   # Less than: False
10 == 10 # Equal: True
10 != 5  # Not equal: True

Conditionals (If/Else)

Make decisions based on sensor readings:

from machine import Pin

sensor = Pin(14, Pin.IN, Pin.PULL_UP)

if sensor.value() == 0:
    print("Line detected!")
else:
    print("No line")

Multiple conditions:

sensor_left = Pin(14, Pin.IN, Pin.PULL_UP)
sensor_right = Pin(15, Pin.IN, Pin.PULL_UP)

if sensor_left.value() == 0 and sensor_right.value() == 0:
    print("Both sensors on line")
elif sensor_left.value() == 0:
    print("Left sensor on line")
elif sensor_right.value() == 0:
    print("Right sensor on line")
else:
    print("No line detected")

Loops (While and For)

While loop - Repeat until condition is false:

count = 0
while count < 10:
    print(count)
    count += 1  # Shorthand for count = count + 1

Infinite loop - Robot main loop:

while True:
    # Read sensors
    # Make decisions
    # Control motors
    time.sleep(0.01)  # Small delay

For loop - Repeat a specific number of times:

for i in range(5):
    print(i)  # Prints 0, 1, 2, 3, 4

# Blink LED 10 times
for i in range(10):
    led.toggle()
    time.sleep(0.2)

Functions

Functions organize code into reusable blocks:

def blink_led(times, delay):
    """Blink LED a specific number of times"""
    for i in range(times):
        led.toggle()
        time.sleep(delay)

# Call the function
blink_led(5, 0.3)  # Blink 5 times, 0.3 second delay
blink_led(10, 0.1) # Blink 10 times, 0.1 second delay

Functions with return values:

def read_sensor():
    """Read sensor and return True if line detected"""
    sensor = Pin(14, Pin.IN, Pin.PULL_UP)
    return sensor.value() == 0  # Returns True or False

# Use the function
if read_sensor():
    print("Line detected!")

Part 5: GPIO Control

GPIO (General-Purpose Input/Output) pins connect sensors and actuators to the microcontroller.

Digital Output (Control LED)

Wiring:

  • LED long leg → GPIO pin 15
  • LED short leg → 220Ω resistor → GND

Code:

from machine import Pin

led = Pin(15, Pin.OUT)

led.on()   # Turn LED on (pin = HIGH = 3.3V)
led.off()  # Turn LED off (pin = LOW = 0V)
led.value(1)  # Alternative: 1 = on, 0 = off
led.toggle()  # Switch state

Digital Input (Read Button)

Wiring:

  • Button one side → GPIO pin 14
  • Button other side → GND
  • Internal pull-up resistor (no external resistor needed)

Code:

from machine import Pin

button = Pin(14, Pin.IN, Pin.PULL_UP)

while True:
    if button.value() == 0:  # Button pressed (connects to GND = LOW)
        print("Button pressed!")
    else:
        print("Button not pressed")
    time.sleep(0.1)

Why Pin.PULL_UP?

  • Without pull-up, the input "floats" (undefined voltage) when button is not pressed
  • Pull-up resistor connects input to 3.3V by default (HIGH)
  • When button pressed, it connects to GND (LOW)
  • This is an active LOW button (pressed = LOW)

Example: Button-Controlled LED

from machine import Pin

button = Pin(14, Pin.IN, Pin.PULL_UP)
led = Pin(15, Pin.OUT)

while True:
    if button.value() == 0:  # Button pressed
        led.on()
    else:
        led.off()

Improvement: Toggle LED on button press

from machine import Pin
import time

button = Pin(14, Pin.IN, Pin.PULL_UP)
led = Pin(15, Pin.OUT)

last_button_state = 1  # Not pressed initially

while True:
    button_state = button.value()

    # Detect button press (transition from HIGH to LOW)
    if button_state == 0 and last_button_state == 1:
        led.toggle()
        time.sleep(0.2)  # Debounce delay

    last_button_state = button_state
    time.sleep(0.01)

Part 6: Analog Input (Read Variable Voltage)

Some sensors output variable voltage (temperature, light, distance). Use ADC (Analog-to-Digital Converter) to read them.

Reading a Potentiometer

Wiring:

  • Potentiometer middle pin → GPIO 26 (ADC0)
  • Potentiometer left pin → 3.3V
  • Potentiometer right pin → GND

Code:

from machine import ADC, Pin
import time

pot = ADC(Pin(26))  # GPIO 26 is ADC0

while True:
    value = pot.read_u16()  # Read 16-bit value (0-65535)
    voltage = value * 3.3 / 65535  # Convert to voltage
    percent = value / 65535 * 100  # Convert to percentage

    print(f"Value: {value}, Voltage: {voltage:.2f}V, Percent: {percent:.1f}%")
    time.sleep(0.5)

What this does:

  • pot.read_u16() - Returns 0 (0V) to 65535 (3.3V)
  • Turn potentiometer dial and watch the value change
  • This is how robots read analog sensors (photoresistors, battery voltage)

Example: ADC-Controlled LED Brightness

Note: This requires PWM, which we'll cover in MicroPython Programming. For now, we'll use a simple threshold:

from machine import ADC, Pin
import time

pot = ADC(Pin(26))
led = Pin(15, Pin.OUT)

while True:
    value = pot.read_u16()

    if value > 32768:  # If pot is more than 50%
        led.on()
    else:
        led.off()

    time.sleep(0.1)

Part 7: Your First Robot Program

Let's combine everything into a simple robot behavior:

Scenario: A robot with two line sensors that follows a line.

Simplified hardware (for testing without a robot):

  • 2 buttons represent line sensors (pressed = line detected)
  • 2 LEDs represent motors (on = motor running)

Wiring:

  • Button 1 (left sensor) → GPIO 14 → GND, with Pin.PULL_UP
  • Button 2 (right sensor) → GPIO 15 → GND, with Pin.PULL_UP
  • LED 1 (left motor) → GPIO 16 → 220Ω → GND
  • LED 2 (right motor) → GPIO 17 → 220Ω → GND

Code:

from machine import Pin
import time

# Sensors (buttons for testing)
sensor_left = Pin(14, Pin.IN, Pin.PULL_UP)
sensor_right = Pin(15, Pin.IN, Pin.PULL_UP)

# Motors (LEDs for testing)
motor_left = Pin(16, Pin.OUT)
motor_right = Pin(17, Pin.OUT)

def drive_forward():
    motor_left.on()
    motor_right.on()

def turn_left():
    motor_left.off()
    motor_right.on()

def turn_right():
    motor_left.on()
    motor_right.off()

def stop():
    motor_left.off()
    motor_right.off()

# Main loop
while True:
    left = sensor_left.value()
    right = sensor_right.value()

    # Both sensors on line (both buttons pressed)
    if left == 0 and right == 0:
        drive_forward()
    # Left sensor on line, right sensor off
    elif left == 0 and right == 1:
        turn_left()
    # Right sensor on line, left sensor off
    elif left == 1 and right == 0:
        turn_right()
    # Neither sensor on line
    else:
        stop()

    time.sleep(0.01)  # Small delay

Try this:

  • Press left button only → left LED off, right LED on (turning left)
  • Press right button only → left LED on, right LED off (turning right)
  • Press both buttons → both LEDs on (driving forward)
  • Release both buttons → both LEDs off (stopped)

This is the foundation of Activity:Line Following!

Part 8: Saving Programs to Pico

Where Code is Stored

  • main.py - Runs automatically when Pico powers on
  • Other .py files - Can be imported as modules

Create a Startup Program

  1. Write your code in Thonny
  2. Click "Save as..." and choose MicroPython device
  3. Name it main.py
  4. Disconnect Pico and reconnect it
  5. Your program runs automatically!

Tip: Add a delay at the start so you can interrupt it if needed:

import time
time.sleep(2)  # 2-second delay before starting
# Your code here

Organize Code into Modules

You can split code into multiple files:

robot.py (on Pico):

from machine import Pin

class Robot:
    def __init__(self):
        self.led = Pin(25, Pin.OUT)

    def blink(self, times):
        for i in range(times):
            self.led.toggle()
            time.sleep(0.2)

main.py (on Pico):

from robot import Robot

bot = Robot()
bot.blink(10)

Part 9: Debugging and Troubleshooting

Print Debugging

The most useful debugging technique is printing values:

while True:
    sensor_value = sensor.value()
    print(f"Sensor: {sensor_value}")  # See what the sensor reads

    if sensor_value == 0:
        motor.on()
        print("Motor ON")  # Confirm this branch executes
    else:
        motor.off()
        print("Motor OFF")

    time.sleep(0.1)

LED Indicator Debugging

When you can't connect to serial console (robot is moving), use LED patterns:

def indicate_error():
    for i in range(5):
        led.toggle()
        time.sleep(0.1)  # Fast blink = error

def indicate_success():
    led.on()
    time.sleep(1)  # Long on = success
    led.off()

Common Errors

IndentationError: Python uses indentation (spaces/tabs) to group code:

# Wrong - inconsistent indentation
if sensor.value() == 0:
  motor.on()
    led.on()  # Error: too many spaces

# Correct - consistent indentation
if sensor.value() == 0:
    motor.on()
    led.on()

NameError: Variable not defined:

# Wrong
print(speed)  # Error: speed not defined

# Correct
speed = 100
print(speed)

AttributeError: Calling wrong method:

# Wrong
led.turnon()  # Error: no such method

# Correct
led.on()

REPL Error Messages

Read error messages carefully - they tell you what's wrong:

Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
NameError: name 'speed' is not defined
  • Line 5 - Error is on line 5
  • NameError - Variable name doesn't exist
  • speed not defined - You forgot to create variable "speed"

Part 10: Skills Checklist

By now, you should be able to:

  • ☐ Install MicroPython on Raspberry Pi Pico
  • ☐ Use Thonny IDE to write and run code
  • ☐ Use the REPL to test code interactively
  • ☐ Write Python variables, conditionals, loops, functions
  • ☐ Control digital outputs (LEDs)
  • ☐ Read digital inputs (buttons)
  • ☐ Read analog inputs (potentiometer, sensors)
  • ☐ Write a simple robot behavior (line following simulation)
  • ☐ Save programs to Pico (main.py)
  • ☐ Debug with print statements and LED indicators

If you can check most of these boxes, you're ready to program SimpleBot!

Next Steps

Build SimpleBot

Apply your MicroPython knowledge to a real robot:

Learn More Programming

Practice Projects

  • Reaction timer - Press button, wait random time, LED lights, measure reaction
  • Light tracker - Use photoresistor to control LED brightness
  • Morse code - Blink LED in Morse code patterns
  • Night light - Turn LED on when photoresistor detects darkness

Common Beginner Mistakes

  • Forgetting to import modules - Always from machine import Pin at the start
  • Using time.sleep() in interrupts - Interrupts must be fast (no delays!)
  • Not configuring pin mode - Always specify Pin.IN or Pin.OUT
  • Forgetting pull-up/pull-down resistors - Digital inputs need them to avoid floating
  • Mixing up HIGH/LOW logic - Check if sensor is active HIGH or active LOW
  • Infinite loops without sleep - Always add small delay to avoid maxing out CPU

Tools and Resources

Essential Software

Hardware Needed

  • Raspberry Pi Pico - $4 from Raspberry Pi
  • USB cable (micro USB) - $2-5
  • Breadboard - $5-10
  • Jumper wires - $5-10
  • LEDs and resistors - $5-10 for assorted kit

External Resources

See Also