Skip to content

picobot API Reference (Robot Class)

The picobot library provides a high-level Robot class used throughout the labs. It is designed in layers so you can start with simple calls and later access lower-level components.


Quick Start

from picobot import Robot
import time

robot = Robot()

robot.demo_lightshow()
robot.beep(880, 150)
robot.forward(80, 1.0)
robot.stop()

Layers of Use

Layer 0 (Magic): - demo_lightshow(), demo_dance(), demo_dj(), demo_dj_live(), play_melody(), drive_square()

Layer 1 (Control): - forward(), backward(), turn_left(), turn_right() - turn_degrees(), line_follow(), line_follow_step() - set_motors(), stop(), read_distance() - get_heading(), reset_heading(), at_junction(), line_lost()

Layer 2 (Direct Access): - robot.motors — dual motor controller - robot.sensors.line — 4-channel line sensor array - robot.sensors.distance — HC-SR04 ultrasonic sensor - robot.imu — BMI160 IMU (gyroscope + accelerometer) - robot.leds — 8× WS2812B NeoPixel strip - robot.buzzer — piezo buzzer - robot.mic — electret microphone (ADC)


Common Methods

Layer 0 — Demos

Method Purpose Notes
demo_lightshow(duration=5) LED animation Rainbow cycling
demo_dance(duration=5) Movement sequence Forward, back, spin
demo_dj(duration=10, bpm=128) Techno beats, lights, dance Four-on-the-floor + build-ups + drops
demo_dj_live(duration=60, sensitivity=80) React to music via microphone Play music near robot
play_melody(name="twinkle") Buzzer melody Names: twinkle, scale, alert, success, error
drive_square(side_cm=30, speed=80) Drive in a square Time-based, approximate

Layer 1 — Control

Method Purpose Notes
forward(speed=80, duration=None) Drive forward Speed 0–255. If duration given, stops after.
backward(speed=80, duration=None) Drive backward Speed 0–255
turn_left(speed=80, duration=0.5) Turn left in place Adjust speed + duration to calibrate
turn_right(speed=80, duration=0.5) Turn right in place Same pattern as forward/backward
turn_degrees(degrees, speed=80) IMU-based turn Positive = left, negative = right
set_motors(left, right) Set motor speeds -255 to 255
stop() Stop all motors
line_follow(speed=80, kp=30, duration=None) Blocking line follow Ctrl+C to stop
line_follow_step(speed=80, kp=30) One control step Returns error or None
read_distance() Ultrasonic distance (cm) Slow (~25 ms)
get_heading() Current IMU heading (degrees) Calls imu.update() internally
reset_heading() Reset heading to zero
at_junction() All sensors see black? Returns True/False
line_lost() No sensors see black? Returns True/False
set_leds(colors) Set LED colors Single tuple (all same) or list of 8
set_led(index, color) Single LED Index 0–7, color = (R, G, B)
leds_off() LEDs off
beep(freq=440, duration=100) Simple tone Duration in ms

Peripherals (Direct Access)

Motors

robot.motors.set_speed(left, right)   # -255 to 255
robot.motors.stop()
robot.motors.left.set_speed(100)      # Individual motor
robot.motors.right.set_speed(100)
robot.motors.left.set_pwm(50)         # Raw duty cycle 0-100%

Line Sensors

robot.sensors.line.read_raw()      # [0,1,1,0] — 0=black, 1=white
robot.sensors.line.get_error()     # -1.5 to +1.5, None if lost
robot.sensors.line.at_junction()   # True if all see black
robot.sensors.line.line_lost()     # True if none see black
robot.sensors.line.get_pattern()   # "█░░█" visual representation

Ultrasonic Distance

robot.sensors.distance.read_cm()       # Distance in cm (slow ~25ms!)
robot.sensors.distance.last_reading    # Last value without blocking
robot.sensors.distance.read_raw_us()   # Raw pulse duration (µs)

IMU (BMI160 Gyroscope + Accelerometer)

robot.imu.calibrate(samples=100)  # Calibrate bias — keep robot still!
robot.imu.update()                # Update heading (call every loop)
robot.imu.heading                 # Current heading in degrees (property)
robot.imu.reset_heading()         # Reset to zero
robot.imu.gyro_z()                # Raw angular velocity (°/s)
robot.imu.accel()                 # (ax, ay, az) in g units
robot.imu.bias                    # Calibrated bias value (property)

LEDs

robot.leds.fill((0, 255, 0))          # All LEDs one color
robot.leds.set(index, (r, g, b))      # Single LED
robot.leds.set_all([(r,g,b), ...])    # List of 8 colors
robot.leds.off()                       # All off
robot.leds.show_state("FOLLOW")        # Color by state name
robot.leds.show_error(error)           # Visualize line error
robot.leds.show_distance(cm)           # Visualize distance
robot.leds.count                       # Number of LEDs (property)

Predefined colors: LEDStrip.RED, GREEN, BLUE, YELLOW, CYAN, MAGENTA, WHITE, ORANGE, OFF

Buzzer

robot.buzzer.tone(440)           # Start playing frequency
robot.buzzer.off()               # Stop
robot.buzzer.beep(440, 100)      # Play for duration (ms)
robot.buzzer.note('A4')          # Play by note name (C4-C6)
robot.buzzer.play_sequence([(440, 200), (0, 100), (880, 200)])  # Sequence

Microphone

robot.mic.calibrate()                        # Re-calibrate (keep quiet, motors off!)
robot.mic.read_raw()                         # Raw ADC value (0-65535, ~32768 = silence)
robot.mic.amplitude()                        # Distance from silence (0-32768)
robot.mic.level()                            # Smoothed sound level (0-100)
robot.mic.beat(threshold=40, cooldown_ms=200)  # True if beat detected

Helper Classes

DataLogger

from picobot import DataLogger

logger = DataLogger("experiment.csv")
logger.start("error", "speed", "heading")   # Column names

for i in range(100):
    logger.log(error, speed, heading)        # One row per call
    time.sleep(0.02)

logger.stop()
# Download: mpremote cp :experiment.csv .

Timer (Non-blocking)

from picobot import Timer

fast_timer = Timer(10)   # 10ms period
slow_timer = Timer(100)  # 100ms period

while True:
    if fast_timer.ready():     # True when period elapsed
        do_fast_thing()

    if slow_timer.ready():
        do_slow_thing()

StateMachine

from picobot import Robot, StateMachine

robot = Robot()
sm = StateMachine(robot)

sm.add_state("IDLE", action=robot.stop)
sm.add_state("FOLLOW", action=lambda: robot.line_follow_step())
sm.add_transition("IDLE", "FOLLOW", condition=lambda: True)

sm.run(loop_period_ms=20)   # Runs until Ctrl+C

# Properties and methods:
sm.state              # Current state name
sm.time_in_state()    # ms since entering current state
sm.set_state("IDLE")  # Force state change
sm.get_history()      # Recent transitions

Notes

  • read_distance() is slow by physics (~25ms). Do not call it every loop.
  • turn_left(speed, duration) / turn_right(speed, duration) are time-based. Calibrate by tweaking both parameters. Precision comes with turn_degrees() (IMU-based).
  • get_heading() calls imu.update() internally. If accessing robot.imu.heading directly, call robot.imu.update() first.
  • Motor speeds are -255 to 255. Values below the deadband (~20-30%) won't move the motors.

Reference Index