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)