Development¶
git clone https://github.com/rob089/servolab
cd servolab
uv sync --all-extras # installs Python, servolab (editable) and all extras
uv run pytest # all tests run without hardware
uv run servoscope --sim # try ServoScope with simulated motors
The library code (everything outside scope/) is meant to be read by students
with little Python experience: plain loops, explicit properties, units in the
docstrings, the Feetech SDK used in exactly one file. Please keep it that way.
How the code is organised¶
src/servolab/
__init__.py connect(), list_ports() <- start reading here
bus.py Bus: all motors on one cable
motor.py Motor: one motor, values in SI units
imu.py Imu: an IMU on the bus (gyro + accelerometer), values in SI units
feedback.py Feedback (snapshot of all motors), Rate (fixed loop rate)
plotting.py Recorder (record, plot afterwards), LivePlot (live window)
registers.py the memory table inside the motor
units.py raw numbers <-> SI units
errors.py what can go wrong
server.py servolab-server: share the motors over the network
ports/
feetech_port.py real motors (the only file using the Feetech SDK)
sim_port.py simulated motors
network_port.py motors on another computer (servolab-server)
mujoco_port.py a simulated robot (MuJoCo physics + servo firmware model)
robots/so102/ MuJoCo model of the SO102 arm (MJCF + meshes)
docs/ the guides (shown in ServoScope and on this website)
scope/ ServoScope, the web app (NiceGUI)
_sdk/ bundled Feetech SDK (internal, don't import)
firmware/xiao_imu/ firmware of the bus IMU (PlatformIO)
examples/ the example scripts
docs/ this website (MkDocs)
This website¶
The guides live in src/servolab/docs/, so ServoScope can show them without
internet. The Python API, the register tables and the examples are generated
from the code by docs/gen_pages.py, using the same list of API entries as
ServoScope (servolab/scope/reference.py). To work on the website:
uv run --group docs mkdocs serve # http://127.0.0.1:8000, reloads on every change
GitHub Actions builds the site on every push to main and publishes it on
GitHub Pages.
Releasing a new version¶
- Set the new version in
src/servolab/__init__.py(__version__; the package version is read from there). - Move the entries under "Unreleased" in
CHANGELOG.mdto a new section with the version and the date. - Commit, then tag and push:
git tag v1.1.0
git push origin v1.1.0
The tag starts the publish workflow: it checks that the tag matches
__version__, builds the package and uploads it to PyPI.