Low‑latency joystick → channel mapper with a KivyMD UI for selecting "models" (channel layouts) and visualizing live channel values.
- Model selection from JSON files in
models/ - Live channel bars (bipolar, unipolar, button) with color coding
- Queue‑based input pipeline (reduced UI thread overhead)
- Automatic persistence of last selected model (
.last_model) - Pluggable stick/control mapping file (
pi_tx/input/mappings/stick_mapping.json)
python -m pip install -r requirements.txt
python -m pi_tx # launches the UIIf you run python pi_tx/main.py directly you may hit relative‑import issues; prefer -m which loads the package properly.
pi_tx/
config/ # central paths & constants
domain/ # model + channel domain abstractions
infrastructure/ # persistence helpers (e.g. last model)
input/ # InputController + mappings/
mappings/
stick_mapping.json # per‑device control definitions
ui/ # KivyMD GUI (create_gui)
app.py # run() helper
main.py / __main__.py # entry points
models/ # user model JSON files (channel layouts)
A model file (e.g. models/cat_d6t.json) looks like:
{
"name": "cat_d6t",
"channels": {
"1": {"device_path": "/dev/input/event14", "control_code": 1, "control_type": "bipolar"}
}
}Fields:
device_path: Linux evdev device pathcontrol_code: numeric event code within that devicecontrol_type:bipolar|unipolar|button
Add more numbered entries as needed. Omitted channels simply don't render.
pi_tx/input/mappings/stick_mapping.json describes raw device capabilities (axis ranges, fuzz/flat) used for normalization.
If you currently have a mapping at repository root (stick_mapping.json), move/copy it to the path above so the default InputController finds it. Or pass an explicit path:
from pi_tx.input.controls import InputController
ic = InputController(mapping_file="./stick_mapping.json")from pi_tx.app import run
from pi_tx.input.controls import InputController
ic = InputController(debug=True)
# then pass into GUI factory if embedding- Duplicate an existing JSON file in
models/ - Adjust channel mappings (ensure the
device_pathandcontrol_codeexist in your stick mapping file) - Start the app and choose the model from the toolbar menu (refresh icon rescans)
- The last chosen model is stored in
.last_model
Layered (lightweight):
- input: hardware event capture & normalization (evdev → queue)
- domain: ModelRepository (loads channel layout), ChannelStore (state + listeners)
- ui: visual layer drains queue each frame, updates bars
- infrastructure: persistence utilities
- config: path constants, separation from logic
- Console entry point (
pi-tx) viasetup.cfg/pyproject.toml - Hot‑plug device detection
- Model edit UI
- Network transmission of channel values
| Issue | Fix |
|---|---|
| No devices detected | Confirm permissions: run with access to /dev/input/event* (udev rule or sudo) |
| Values stuck at 0 | Ensure device_path & control_code match those in stick mapping |
| ImportError on run | Use python -m pi_tx instead of file path |
MIT (add explicit LICENSE file if distributing)