MegaWrapper
Control DC motors and servos on an Arduino over Firmata — with optional VL53L0X time-of-flight distance sensors.
from megawrapper import Board
board = Board("/dev/ttyUSB0")
motor = board.attach_motor(2, 4, 11)
motor.forward(100)
board.close()
Installation
From PyPI (recommended):
pip install megawrapper # core (pyfirmata2)
pip install 'megawrapper[pyserial]' # + built-in Firmata backend
pip install 'megawrapper[sensor]' # + VL53L0X ToF sensor
pip install 'megawrapper[pyserial,sensor]' # all extras
From source (editable):
git clone https://github.com/vihaanvp/MegaWrapper.git
cd MegaWrapper/repo
pip install -e .
Requirements: Python 3.8+, Arduino running StandardFirmata.
Dependencies:
| Dep | Type | For |
|---|---|---|
pyfirmata2 |
hard | Default Firmata backend |
pyserial |
optional ([pyserial]) |
Alternative built-in Firmata client |
adafruit-circuitpython-vl53l0x |
optional ([sensor]) |
VL53L0X ToF sensor (Raspberry Pi / Blinka) |
Quick Start
1. Upload StandardFirmata to your Arduino
Arduino IDE → File → Examples → Firmata → StandardFirmata → Upload.
2. Find the serial port
| OS | Typical port |
|---|---|
| Linux | /dev/ttyUSB0, /dev/ttyACM0 |
| macOS | /dev/tty.usbserial-* |
| Windows | COM3, COM4 |
3. Run a motor
import time
from megawrapper import Board
board = Board("/dev/ttyUSB0")
motor = board.attach_motor(2, 4, 11) # d1, d2, pwm pins
motor.forward(75)
time.sleep(2)
motor.stop()
board.close()
API Reference
Board — Arduino connection
from megawrapper import Board
# Connect
board = Board(port="/dev/ttyUSB0", stby=None)
# Attach motors
motor = board.attach_motor(d1=2, d2=4, pwm=11, name=None) # → Motor
# Control
board.stop_all() # coast all motors
board.wake() # STBY → HIGH (requires stby pin)
board.sleep() # STBY → LOW (requires stby pin)
# Lifecycle
board.close() # clean teardown
with Board(...) as b: # context manager — auto-close
# Singleton access
Board.get_active_board() # → Board | raises RuntimeError
Board.has_active_board() # → bool
__repr__: Board(port='COM3', motors=2) (pyserial mode) or Board(motors=2) (pyfirmata2).
Backend mode (optional kwarg on Board):
board = Board("/dev/ttyUSB0", backend="pyserial") # built-in Firmata via pyserial
board = Board("/dev/ttyUSB0") # pyfirmata2 (default)
Motor — DC motor via H-bridge
Drives a motor through 2 direction pins + 1 PWM pin (L298N, TB6612FNG, L293D, MX1508).
motor.forward(speed=100) # 0–100, default full
motor.backward(speed=100) # 0–100, default full
motor.stop() # coast (both direction pins LOW)
motor.brake() # short terminals (both HIGH)
motor.set_speed(50) # change speed, keep direction
motor.speed # current speed (0–100), settable
motor.direction # "forward" | "backward" | "stopped" | "braked"
motor.name # optional label from attach_motor()
Raises InvalidSpeedError if speed is not a number or outside 0–100.
Servo — standard servo on PWM pin
from megawrapper import Servo
servo = Servo()
servo.attach(pin=9) # requires a Board to exist first
servo.write(90) # 0–180 (clamped)
servo.read() # last commanded angle
servo.move_smooth(180, 15) # step 1° at a time
servo.sweep(0, 180, 1, 15) # continuous sweep
servo.detach() # release pin
servo.pin # attached pin or None
servo.current_angle # last angle or None
Raises:
RuntimeErrorif no Board exists or servo not attachedValueErrorif angle is not a number orstep ≤ 0
VL53L0X — Time-of-Flight Distance Sensor
I²C-based, independent of Board/Firmata. Runs on the host (Raspberry Pi / Blinka).
from megawrapper.sensor import VL53L0X # or: from megawrapper import VL53L0X
# Single sensor
sensor = VL53L0X() # auto I²C, address 0x29
print(sensor.distance) # centimetres
# Multiple sensors on one bus
sensors = VL53L0X.auto_address([17, 27, 22]) # GPIO pins for XSHUT
for s in sensors:
print(s.distance)
| Method / Property | Description |
|---|---|
VL53L0X(i2c=None, address=0x29) |
Constructor. Auto-creates I²C bus if omitted. |
.distance |
Measured distance in cm (raw mm ÷ 10). |
VL53L0X.auto_address(xshut_pins, i2c=None) |
Wake up to 16 sensors, assign addresses 0x30–0x3F. |
Requires: pip install 'megawrapper[sensor]' and Blinka-compatible hardware.
Utilities
from megawrapper import delay, millis
delay(1000) # pause 1 second
now = millis() # epoch milliseconds
Exceptions
MegaWrapperError # base (catch-all)
├── InvalidSpeedError # speed not a number or outside 0–100
├── BoardConnectionError # cannot reach Arduino
└── StandbyNotConfiguredError # wake()/sleep() without STBY pin
Examples
8 ready-to-run scripts in examples/:
| File | Shows |
|---|---|
single_motor.py |
Basic forward / stop |
dual_motor.py |
Two motors with names |
keyboard_control.py |
Interactive CLI motor control |
endless_sweep.py |
Servo sweep loop |
move_smooth.py |
Smooth servo movement |
pyserial_control.py |
Built-in pyserial Firmata backend |
vl53l0x_sensor.py |
Single VL53L0X distance readout |
vl53l0x_multi_sensor.py |
Multi-sensor auto-addressing |
python examples/single_motor.py
Motor/servo examples need an Arduino; sensor examples need a Raspberry Pi (or Blinka board) with VL53L0X.
Testing
python -m pytest tests/ -v
91 tests (90 passing, 1 pre-existing env-related skip), all mock the Arduino — no hardware required.
Project Wiki
Full documentation lives on the GitHub Wiki:
License
MIT © Vihaan Parlikar
Metadata
Release files for megawrapper 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| megawrapper-0.2.2.tar.gz | 15.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| megawrapper-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.5 kB
Release files / megawrapper-0.2.2.tar.gz
| Download URL | megawrapper-0.2.2.tar.gz |
|---|---|
| Size | 15.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5b306f1df270fe80077929fcd80ddd8ca0c3bb6a2d2dd7902c6a74f66a0be1a3
|
|
BLAKE2b-256 checksum How to use checksums |
76fbb5fae257716ff09768f4de8323fe9f96ca4c24108de3b7db713ac4041d14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.
Transparency logRelease files / megawrapper-0.2.2-py3-none-any.whl
| Download URL | megawrapper-0.2.2-py3-none-any.whl |
|---|---|
| Size | 9.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c4919acdd0f969d8acb5b98520f1175a461edd7f5f91a1095c69c6461e891160
|
|
BLAKE2b-256 checksum How to use checksums |
952be1a68db512fca5d6daed901036c8b2b0076eaf51a72ad54cc44f83912e3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.
Transparency log