Examples

The repo ships runnable example programs in examples/. Push any of them to a hub with openbricks run -n <name> <script> or try them in the simulator with openbricks sim run <script>.

Two representative ones are reproduced below.

Drive a square (ST-3032 drivebase)

# SPDX-License-Identifier: MIT
"""
Drive a square with the ST-3032 drivebase.

Four sides of ``SIDE_MM`` straight + ``+90°`` turn each. Demonstrates
``DriveBase.straight`` / ``turn`` composing into a closed loop — if
the chassis geometry (``WHEEL_DIAMETER_MM`` / ``AXLE_TRACK_MM``) is
calibrated correctly, the robot returns to within a few cm of its
starting pose after one lap.

Uses the new ``then="coast"`` default end-state (1.6.7), so the
wheels free-wheel briefly between segments. If your bench has
significant momentum carryover and you'd rather pin the wheels
between sides, pass ``then="brake"`` to the ``straight`` / ``turn``
calls (or ``then="hold"`` for active position lock — ST-3032
supports it).

Hardware: identical to ``examples/st3032_drivebase_test.py``.

Run with:
    openbricks run -n ls examples/st3032_drivebase_square.py
"""

from openbricks.drivers.st3032 import ST3032Motor
from openbricks.robotics import DriveBase


LEFT_ID, RIGHT_ID = 1, 2
UART_ID, TX, RX   = 1, 14, 6

WHEEL_DIAMETER_MM = 65    # EDIT to your wheels
AXLE_TRACK_MM     = 120   # EDIT to your chassis

# Geometry of the square. SIDE_MM 200 traces a 20 cm × 20 cm square —
# fits comfortably on a small mat. Bump for a larger arena.
SIDE_MM   = 200
NUM_LAPS  = 1

# Conservative chassis speeds for a small bench robot — well below
# the ST-3032 mechanical limit (datasheet no-load 888 dps at 12 V,
# loaded working point ~600 dps; see ``docs/datasheets/feetech_sts3032.pdf``).
# Dial down further if the chassis slips or the bus drops packets.
STRAIGHT_SPEED_MM = 150
TURN_RATE_DPS     = 200


def main():
    print("--- ST-3032 drivebase square (%d mm sides × %d laps) ---" %
          (SIDE_MM, NUM_LAPS))

    left  = ST3032Motor(servo_id=LEFT_ID,  uart_id=UART_ID, tx=TX, rx=RX)
    right = ST3032Motor(servo_id=RIGHT_ID, uart_id=UART_ID, tx=TX, rx=RX,
                        invert=True)

    db = DriveBase(left, right,
                   wheel_diameter_mm=WHEEL_DIAMETER_MM,
                   axle_track_mm=AXLE_TRACK_MM)
    db.settings(straight_speed=STRAIGHT_SPEED_MM, turn_rate=TURN_RATE_DPS)

    for lap in range(NUM_LAPS):
        for side in range(4):
            print("  lap %d side %d: straight(%d) → turn(+90)" %
                  (lap + 1, side + 1, SIDE_MM))
            db.straight(SIDE_MM)
            db.turn(90)

    print("--- done ---")


main()

Full robot (drivebase + IMU + color sensor array)

# SPDX-License-Identifier: MIT
"""
Example: a small robot that rolls forward until its colour sensor sees red,
then demos a servo wave.

Hardware:
    * ESP32-S3 DevKitC-1 (or classic ESP32 DevKitC-V4)
    * 2× JGB37-520 DC gear motors (with Hall-effect quadrature encoders)
        driven by a shared L298N (or TB6612FNG) H-bridge
    * 1× BNO055 9-DOF IMU on I2C
    * 1× TCS34725 RGB colour sensor on the same I2C bus
    * 1× ST-3215 serial bus servo on UART (optional — the servo demo
        at the bottom just prints a message if it isn't attached)

Edit the GPIOs at the top to match your wiring.
"""

import time

from machine import I2C, Pin, UART

from openbricks.drivers.bno055 import BNO055
from openbricks.drivers.jgb37_520 import JGB37Motor
from openbricks.drivers.st3215 import ST3215
from openbricks.drivers.tcs34725 import TCS34725
from openbricks.robotics import DriveBase

# ----- wiring -----

# Pins below are for the ESP32-S3 DevKitC-1 (avoid GPIO 19/20 = USB,
# 26-37 = flash/PSRAM, 0/3/45/46 = strapping). On a classic ESP32
# DevKitC-V4 use I2C 21/22 and remap the rest to that board's pins.
I2C_SDA  = 15
I2C_SCL  = 16

LEFT_IN1,  LEFT_IN2,  LEFT_PWM  = 4, 5, 6
LEFT_EA,   LEFT_EB               = 7, 8

RIGHT_IN1, RIGHT_IN2, RIGHT_PWM = 9, 10, 11
RIGHT_EA,  RIGHT_EB              = 12, 13

SERVO_TX, SERVO_RX = 17, 18
SERVO_ID = 1

WHEEL_DIAMETER_MM = 56
AXLE_TRACK_MM     = 114

# ----- init -----

i2c   = I2C(0, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL), freq=400_000)
imu   = BNO055(i2c)
color = TCS34725(i2c)

left  = JGB37Motor(in1=LEFT_IN1,  in2=LEFT_IN2,  pwm=LEFT_PWM,
                   encoder_a=LEFT_EA,  encoder_b=LEFT_EB)
right = JGB37Motor(in1=RIGHT_IN1, in2=RIGHT_IN2, pwm=RIGHT_PWM,
                   encoder_a=RIGHT_EA, encoder_b=RIGHT_EB)

drivebase = DriveBase(left, right,
                      wheel_diameter_mm=WHEEL_DIAMETER_MM,
                      axle_track_mm=AXLE_TRACK_MM)

# Optional: a serial bus servo on a second UART.
try:
    uart = UART(1, baudrate=1_000_000, tx=SERVO_TX, rx=SERVO_RX)
    arm  = ST3215(uart, servo_id=SERVO_ID)
except Exception as e:
    print("no servo attached:", e)
    arm = None

# ----- main loop: drive until red -----

while True:
    r, g, b = color.rgb()
    heading = imu.heading()

    print("rgb=({:3d},{:3d},{:3d})  heading={:6.1f}".format(r, g, b, heading))

    if r > g and r > b and r > 120:
        print("Red detected — stopping.")
        drivebase.stop()
        break

    drivebase.drive(speed_mm_s=150, turn_rate_dps=0)
    time.sleep_ms(50)

# Wave the arm once if present.
if arm is not None:
    arm.move_to(180, speed=500)
    time.sleep_ms(500)
    arm.move_to(0, speed=500)