Skip to content

Latest commit

 

History

History
317 lines (240 loc) · 16.3 KB

pc-cli.md

File metadata and controls

317 lines (240 loc) · 16.3 KB

OpenMuscle CLI

The openmuscle command-line tool provides a unified interface for all PC-side operations.

Installation

If you are setting up a kit, use the installer for your computer and follow getting-started.md. It puts the program in a private folder, ~/OpenMuscle/app, so the openmuscle command is not on your computer's search path. Use its full path, or python -m openmuscle:

Computer The openmuscle command
Windows "%USERPROFILE%\OpenMuscle\app\Scripts\openmuscle.exe" (PowerShell: & "$env:USERPROFILE\OpenMuscle\app\Scripts\openmuscle.exe")
Mac and Linux ~/OpenMuscle/app/bin/openmuscle

For development, install into your own virtual environment from a clone (Python 3.10 or newer):

cd pc/
pip install -e .          # Basic install
pip install -e ".[dev]"   # With test/lint tools
pip install -e ".[all]"   # Everything including VisPy 3D viz

Then openmuscle --help lists the commands and python -m openmuscle works too.

Commands

openmuscle receive

Listen for devices and display a live heatmap.

openmuscle receive                          # Default port 3141
openmuscle receive --port 3141 --save-dir data/raw/flexgrid

openmuscle web

Launch the browser-based Studio UI: a live FlexGrid heatmap, device/source discovery, recording + labeled sessions, training, and live prediction, with a WebXR companion at /vr for Quest hand-tracking capture.

openmuscle web                      # http://localhost:8000, this computer only;
                                    #   opens your browser and prints where data is saved
openmuscle web --port 8000 --udp-port 3141
openmuscle web --model-left L.pkl --model-right R.pkl   # per-hand live prediction

Defaults for a first run:

Flag Effect
(none) Plain HTTP on 127.0.0.1:8000 (reachable from this computer only). Opens the page in your default browser once the server is up and prints a short banner: the address, the data folder, "leave this window open", and the firewall sentence. If port 8000 is busy it uses the next free port and says so.
--no-browser Do not open the browser automatically.
--lan Listen on all interfaces (0.0.0.0) so a phone or headset on the same Wi-Fi can open the page. Anyone on that network can reach it.
--vr Headset workflow: implies --lan and serves https when a mkcert pair (vr-cert.pem + vr-key.pem) is found in ~/.openmuscle/, in OPENMUSCLE_SSL_CERTFILE / OPENMUSCLE_SSL_KEYFILE, or the current directory. See vr-setup.md.
--ssl-certfile / --ssl-keyfile Serve https from an explicit cert/key pair (also opens the LAN, as the headset needs).
--data-dir DIR Where captures, sessions and models are saved. Same as setting OPENMUSCLE_HOME.
--captures-dir DIR Save captures somewhere specific (sessions go in a sessions folder next to it).
--verbose Show server request logs and low-level startup lines.
--no-keep-awake Let the computer sleep as usual. By default the computer is kept awake while OpenMuscle runs, so a recording is not cut off (Windows and macOS; nothing is done on Linux). Closing a laptop lid still puts it to sleep: that is the operating system's lid setting and is not overridden.

TLS is opt-in: a plain openmuscle web stays on http even if you have certificates in ~/.openmuscle/, and prints nothing about TLS, WebXR or adb.

Where your files go. Everything is saved under one folder, ~/OpenMuscle (for example C:\Users\you\OpenMuscle on Windows), no matter which directory you start the program from:

~/OpenMuscle/captures   recorded CSVs and their .meta.json / .labels.schema.json sidecars
~/OpenMuscle/sessions   one JSON file per labeled session
~/OpenMuscle/models     trained models (one folder per model)
~/OpenMuscle/exports    prediction exports
~/OpenMuscle/logs       server logs

Set the environment variable OPENMUSCLE_HOME (or pass --data-dir) to use a different root; ~ is expanded on every OS. GET /api/storage returns the absolute paths the running server uses. If you launch from a folder that still holds an older data/raw/merged or data/models directory, the banner prints a one-line hint: copy those files into the matching ~/OpenMuscle subfolder to see them.

While the server runs, the console prints one line when a band is found (Found FlexGrid band at 192.168.1.23) and one if it goes quiet (Lost FlexGrid band at ...).

Debug mode (--debug): serves plain HTTP on all interfaces (no TLS) so the PC, phone, and Quest all connect with zero cert friction, and unlocks a verbose Debug panel (per-device stream health, per-channel matrix stats, IMU raw + orientation, forearm, a raw-frame inspector), both flexgrid heatmaps at once (side-by-side or stacked), and a live capture-quality verdict while recording. The server is LAN-open and unauthenticated in this mode: lab-bench / demo use only.

openmuscle web --debug              # http://<lan-ip>:8000, all devices, verbose UI

WebXR hand-tracking needs a secure context: either openmuscle web --vr with the mkcert pair in place (https over the LAN), or tether the Quest over USB with adb reverse tcp:8000 tcp:8000 and open http://localhost:8000/vr.

Only one OpenMuscle at a time. If OpenMuscle is already running, a second openmuscle web stops within a second with one line (OpenMuscle is already running at http://localhost:8000 ...) and exits with a non-zero code instead of starting a second server that would fight over the bands. The UDP data port (3141) is opened exclusively for the same reason: if another program holds it, openmuscle web says so and stops before anything starts. If only the discovery port (3140) is taken it prints a note and keeps going (bands can still be found with the search buttons). GET /api/mode includes "app": "openmuscle" so launchers can tell an OpenMuscle server from any other program on the port.

openmuscle doctor

Checks this computer and network in a few seconds and says what to fix. One line per check, PASS, WARN or FAIL, with the fix under anything that is not a pass. The exit code is 0 when nothing failed and 1 otherwise, so it can sit in a launcher.

openmuscle doctor                       # the normal check
openmuscle doctor --report              # also write openmuscle-report.txt to send to support
openmuscle doctor --report my-pc.txt    # ... with a file name of your choice
openmuscle doctor --port 8010 --udp-port 3141 --announce-port 3140
openmuscle doctor --no-discover         # skip the quick search for bands

It checks: the Python version and installed packages, the browser page files, that the data folder can be written, the HTTP port (8000), the UDP data port (3141) and the UDP discovery port (3140), this computer's network address, the Wi-Fi network name, the Windows firewall rules and network type (Private or Public), internet access for the 3D hand viewer, a self-test sensor frame sent to this computer, and a quick "discover" broadcast to see which bands answer. It ends with the most likely reason a band is not showing up: firewall, different network, client isolation (a guest network or router setting that keeps devices apart), or the band being off.

The report is a plain text file with versions and these results. It never contains Wi-Fi names, passwords or recordings. While it runs, Windows may ask whether to allow Python through the firewall; choose Allow. The same checks run inside the app: GET /api/discovery/diagnose returns them as JSON and POST /api/support-report writes a zip (report, results, recent log lines with file names and secrets removed) into ~/OpenMuscle/exports and returns its path.

openmuscle firewall

On Windows the bands cannot reach OpenMuscle until a firewall rule allows incoming UDP on ports 3140 and 3141 for your network type. This command prints the exact rule and the command behind it, asks, and only then opens the normal Windows administrator prompt. It never runs by itself.

openmuscle firewall                # show the rule, ask, then add it (Private and Domain networks)
openmuscle firewall --print-only   # just print it
openmuscle firewall --public       # also allow on Public networks
openmuscle firewall --remove       # take the rule out again

The rule is netsh advfirewall firewall add rule name="OpenMuscle UDP 3140-3141" dir=in action=allow protocol=UDP localport=3140,3141 profile=private,domain. On macOS and Linux the command only explains what to allow.

openmuscle setup-usb

Gives a band its Wi-Fi name and password over its USB cable, with no setup network to join. Plug the band into this computer with a cable that carries data, then run it. The band saves the details, restarts, and joins your Wi-Fi within about 20 seconds; the Studio then shows it. The password is only sent down the cable to the band, and is never printed or logged. The Studio's Set up a device page does the same thing with buttons; see wifi-setup.md.

openmuscle setup-usb --ssid "My Wi-Fi"                 # asks for the password, shows nothing while you type
openmuscle setup-usb --port COM5 --ssid "My Wi-Fi"    # when more than one band is plugged in
openmuscle setup-usb --forget                          # make the band forget its Wi-Fi (it restarts into setup mode)

With no --port it uses the one band that answers on USB (a band is recognised by its USB ids, port names look like COM5, /dev/ttyACM0 or /dev/cu.usbmodem...). It stops with a plain sentence when no band is found, when more than one answers, or when the band does not answer (unplug the cable and plug it back in, or press the BOOT button). A --password on the command line stays in your shell history, so leave it out and type it when asked.

openmuscle record

Record paired band + labeler data to CSV with temporal matching, without the browser. Only labelers that send UDP (the LASK5) work here; the camera and headset need the browser, so use openmuscle web for those.

openmuscle record -o ~/OpenMuscle/captures/session_01.csv
openmuscle record -o capture.csv --port 3141 --duration 60

openmuscle train

Train an ML model from captured data.

openmuscle train ~/OpenMuscle/captures/session_01.csv
openmuscle train data.csv -o ~/OpenMuscle/models/my_model.pkl --trees 200 --test-split 0.3

openmuscle predict

Run real-time inference with live visualization.

openmuscle predict -m ~/OpenMuscle/models/random_forest_20250101_120000/model.pkl
openmuscle predict -m my_model.pkl --port 3141

openmuscle simulate

Send synthetic data for testing without hardware.

No hardware at all? One command runs a whole V4 kit next to openmuscle web:

openmuscle web                                  # terminal 1
openmuscle simulate --device-type rehearsal     # terminal 2

rehearsal is the practice run. It starts two 15x4 pressure bands (60 cells each, flexgrid-sim-left and flexgrid-sim-right) and a LASK5 (lask5-sim: four pistons 0..1 plus a joystick) at 25 Hz. The bands announce on the discovery beacon port and answer the command channel, so they show up in the Sources list like real hardware, with IMU and battery telemetry. Once discovered they are tagged left / right and the LASK5 as labeler for you (--no-tag-roles to do it by hand in Sources). The practice bands keep the role the Studio gives them, like real bands: it shows in their get_info reply and in their status frames. The bands and the LASK5 are driven by the same finger curls, with a rest then move schedule, so a capture you record from them is learnable: record, train and predict give a sensible model. Left and right have different per-cell gain and offset, so train one model per hand.

openmuscle simulate --device-type rehearsal --bands 1               # left band only
openmuscle simulate --device-type rehearsal --labeler webcam        # hand from a camera feed
openmuscle simulate --device-type rehearsal --labeler quest         # hand as a Quest would send it
openmuscle simulate --device-type rehearsal --noise high            # a weak dataset on purpose
openmuscle simulate --device-type rehearsal --noise 3 --seed 7      # numeric noise multiplier

--noise takes low, default, high or a number. default gives a held-out score well above 0.6 after about 40 s of recording; high buries the signal (held-out score near zero), which is handy for seeing how the app reports a weak dataset. The webcam and quest labelers stream to the web server, over wss:// automatically when the server is HTTPS (--web-scheme auto|http|https). Use --web-port and --announce-port if the server is not on 8000 / 3140.

The other device types below are plumbing tests only: flexgrid and lask5 send random noise, so a model trained on them learns nothing. combo is learnable too (a 16x4 flexgrid plus a Quest hand from the same curls).

openmuscle simulate --device-type flexgrid
openmuscle simulate --device-type lask5 --target-ip 192.168.1.100
openmuscle simulate --replay ~/OpenMuscle/captures/my_take.csv

# Synthetic WebXR hand: streams 25-joint frames to the running
# `openmuscle web` server's /ws/quest WebSocket (no headset needed).
openmuscle simulate --device-type quest_hand

# Combo: the same latent finger-curl signal drives BOTH a flexgrid UDP
# device and the quest hand, so the capture is learnable and the whole
# record -> train -> predict pipeline can be exercised end to end with
# zero hardware. Use --web-port if the web server is not on 8000.
openmuscle simulate --device-type combo

openmuscle bundle

Pack a session, or chosen takes, into one zip to send to someone. The Studio's Export session button does the same thing.

openmuscle bundle "morning baseline"                 # -> ~/OpenMuscle/exports/openmuscle-session-<id>.zip
openmuscle bundle "morning baseline" -o baseline.zip
openmuscle bundle --take a.csv --take b.csv          # loose takes, no session
openmuscle bundle <session> --raw --notes            # opt in to raw streams and notes

The zip holds README.txt (every file and column explained in plain words), session.json, summary.csv (one row per take with its quality verdict) and a takes/ folder with each take's CSV and helper files. Raw streams and typed notes are left out unless you ask, and trained models are never included. See your-data.md.

openmuscle export, convert, combine

Smaller helpers. export -m model.pkl -d capture.csv -o out.json writes a model's predictions next to the ground truth as JSON for a website. convert old.txt -o new.csv turns a legacy capture text file into a CSV. combine a.csv b.csv -o all.csv joins captures that share the same columns (it refuses to join different shapes).

openmuscle models

List all trained models in the registry.

openmuscle models

openmuscle assets

Offline copies of the browser files the webcam page and the 3D hand viewer use (MediaPipe hand tracker, its model, three.js). Without them those pages load the files from the internet.

openmuscle assets fetch              # download, verify checksums, install (about 17.6 MB + 1.3 MB)
openmuscle assets fetch --with-nosimd  # also the tracker files for processors without SIMD
openmuscle assets status             # which files are present and correct
openmuscle assets status --hashes    # also print each installed file's sha256

Files go to <data folder>/assets (default ~/OpenMuscle/assets) and are served under /static/vendor/. Every file is checked against a size and checksum pinned in the code; a mismatch is discarded and nothing is installed for that file. See webcam-labeling.md.

Typical Workflow

The normal way is the Studio (openmuscle web): record with the Record button, train with Train, and watch Ground truth vs Predicted. getting-started.md walks through it.

The same loop from the command line, for a FlexGrid and a LASK5 that send UDP:

# 1. Capture training data (FlexGrid + LASK5 paired)
openmuscle record -o ~/OpenMuscle/captures/training_session.csv

# 2. Train a model
openmuscle train ~/OpenMuscle/captures/training_session.csv

# 3. Run real-time predictions (a model folder name looks like random_forest_<date>_<time>)
openmuscle predict -m ~/OpenMuscle/models/<model folder>/model.pkl