Development Examples
Complete, working examples
PoseLab ships with runnable example plugins and metric scripts. Copy any of them into the matching directory (Settings › Device Plugins or Settings › Metric Scripts), press Reload, and use Run Mock or Test Metrics to see them work — no hardware needed.
A complete device plugin
Cadence Sensor — crank RPM
from standard Cycling Speed & Cadence (CSC)
frames. Exercise it with the built-in CSC crank mock
(characteristic 2a5b). It shows
metadata, per-frame decoding of a rolling counter,
and returning several named values at once:
"""Pedal speed plugin: crank RPM from CSC-style BLE frames."""
import logging
log = logging.getLogger(__name__)
META = {
"display_name": "Cadence Sensor",
"version": "1.0.0",
"description": "Crank cadence (RPM) from a CSC speed/cadence sensor.",
"service_uuid": "00001816-0000-1000-8000-00805f9b34fb", # Cycling Speed and Cadence
"data_char": "00002a5b-0000-1000-8000-00805f9b34fb", # CSC Measurement (notify)
"stream_on_connect": True,
"is_pose_provider": False,
}
_last = None
def process(frame):
global _last
payload = frame.get("payload") or []
if len(payload) < 5 or not (payload[0] & 0x02):
return None
revs = payload[1] | (payload[2] << 8)
event_time = payload[3] | (payload[4] << 8)
if _last is None:
_last = (revs, event_time)
return None
d_revs = (revs - _last[0]) & 0xFFFF
d_time = (event_time - _last[1]) & 0xFFFF
_last = (revs, event_time)
if d_time == 0:
return None
rpm = d_revs / (d_time / 1024.0) * 60.0
return {
"cadence_rpm": rpm,
"total_revs": float(revs),
"last_rev_ms": event_time / 1.024,
}
Plugin catalogue
The example plugins that ship in
examples/plugins/:
| File | What it demonstrates |
|---|---|
pedal_speed.py |
Crank cadence (RPM) from CSC frames; returning multiple named values. |
race_posture_sensor.py |
Decodes the mock back-angle stream and explicitly exposes pitch/sway measurements for a paired metric. |
pose_mock.py |
A 3D pose provider that plays back a captured clip (or a synthetic walking loop). |
pressure_map.py +
pressure_map.frag
|
A viz provider: reassembles a fragmented 32×32 pressure stream and renders it with a user fragment shader. Note, this does not represent a pressure map but illustrates the graphical pipeline, how it's used, and how to work around BLE bandwidth limitations for a rich display. |
Metric-script examples
| File | What it demonstrates |
|---|---|
trunk_lean.py |
Trunk-lean angle from vertical, smoothed over the pose window, with an optional-numpy mean. |
posture_consistency.py |
Consumes a paired plugin's named values and turns five seconds of pitch/sway history into a 0–100 consistency score. |
Walkthrough: a plugin and a metric together
The race_posture_sensor.py plugin and
the posture_consistency.py metric are
designed to work as a pair — the plugin
exposes sensor values, the metric consumes them. To
try it:
-
Copy
race_posture_sensor.pyinto your plugin directory andposture_consistency.pyinto your metric-script directory. - Press Reload in both Settings sections.
- Start Run Mock for “Race Posture Sensor (Example)” in the Devices panel.
- Run pose capture so the custom metric is evaluated.
The metric discovers the compatible device from its exposed value names, so nothing needs to be wired by id — a good pattern for scripts meant to travel between machines.