Generic GUI (reference template)
Reference PyQt5 GUI template wired to the framework's reusable
widget toolkit (fes_framework.gui.app.FesApp,
fes_framework.gui.data_adapter.DataAdapter, plus tab classes).
No application-specific control logic — copy this when starting a
new GUI from scratch.
Source: examples/generic_gui/
What it shows#
The framework ships a small PyQt5 widget toolkit under
fes_framework/gui/. It's not a fully-featured GUI — it's a
collection of reusable building blocks:
FesApp— main application class; manages the QApplication, the DataAdapter, the queue handler, and the tab layout.DataAdapter— attaches to aSharedRingBuffer, decodes the application-defined frame dtype, and exposes rolling buffers for selected fields at 30 Hz.OverviewTab— a generic per-muscle slider/toggle panel.SensorDataTab— bilateral side-by-side plots driven from theDataAdapter.FesWidget— base class for custom tabs. Overridebuild_ui()andrefresh().
This example wires them together with a no-op DummyStrategy so
you can see the GUI light up without delivering any stimulation.
Project layout#
examples/generic_gui/
├── __init__.py
└── main.py ── strategy + GUI wiring + launch()A single file. The toolkit it uses lives in
fes_framework/gui/.
Anatomy of main.py#
The file walks through every wiring decision you have to make for a GUI-based application:
# 1. Pick a frame dtype for the SharedRingBuffer.
FRAME_DTYPE = shared_memory_frame # framework default (biomech + steps)
# 2. Decide which fields the GUI should plot.
BUFFERED_FIELDS = [
"ShoulderFlexExtR", "ShoulderFlexExtL",
"ElbowFlexExtR", "ElbowFlexExtL",
"KneeFlexExtR", "KneeFlexExtL",
"HipFlexExtR", "HipFlexExtL",
"StepDetectorRight", "StepDetectorLeft",
]
# 3. Decide which muscles the OverviewTab exposes as sliders.
MUSCLES = [
"biceps_left", "biceps_right",
"triceps_left", "triceps_right",
# ...
]
# 4. Group sensor fields for the SensorDataTab.
SENSOR_SERIES = [
("Shoulder Flex/Ext", "ShoulderFlexExtL", "ShoulderFlexExtR", "deg"),
("Knee Flex/Ext", "KneeFlexExtL", "KneeFlexExtR", "deg"),
# ...
]
# 5. (Optional) define your own tabs.
class ConnectionTab(FesWidget):
def build_ui(self): ...
def refresh(self): ...
# 6. Wire the GUI process entry point.
def gui_main(control_queue, utility_queue):
adapter = DataAdapter(buffer_name="fes_shared_buffer", ...)
app = FesApp(
control_queue=control_queue,
utility_queue=utility_queue,
data_adapter=adapter,
title="fes_framework — Generic Example",
tabs=[
("Overview", partial(OverviewTab, muscles=MUSCLES)),
("Sensor Data", partial(SensorDataTab, series=SENSOR_SERIES)),
("Connection", ConnectionTab),
],
)
app.run()
# 7. Launch.
launch(DummyStrategy, gui_runner=gui_main, lsl_enabled=False)Each block above is the answer to one question:
- What dtype is in shared memory?
- Which fields do you plot?
- Which muscles get sliders?
- How are the sensor plots grouped?
- Do you need custom tabs? (Optional)
- How are widgets composed?
- Run it.
Running it#
python -m examples.generic_gui.mainA two-or-three-tab window appears. The Overview tab has muscle toggles and amplitude sliders; the Sensor Data tab plots joint angles in real time once data is flowing; the Connection tab shows a coloured indicator.
The strategy is a no-op (no stimulation), so flipping muscle
toggles in the Overview tab won't actually fire anything. To see
stimulation you'd swap DummyStrategy for one of your own.
What you'd change for your own application#
Three edits, no new files needed:
- Replace
DummyStrategywith your ownControlStrategyBasesubclass. - Change
FRAME_DTYPEif your strategy needs to expose custom fields to the GUI (the default is biomech + step detector; for an elbow-flexion app you'd add anElbowAnglefield). - Update
MUSCLESandSENSOR_SERIESto match what your application actually controls and reads.
If you want a richer GUI (custom auto-tune buttons, calibration panels, plot widgets that aren't bilateral), you'd:
- Subclass
FesWidgetfor one-off panels. - Or compose your own QWidget hierarchy and bypass the toolkit.
When to use this vs. building from scratch#
| Use this template | Build from scratch |
|---|---|
| Two-tab operator interface | Need three+ tabs with rich custom layout |
| Bilateral side-by-side plots | Need 3D viz, video, or unusual widgets |
| Standard amplitude/PW/period sliders per muscle | Need PID gain knobs, FFT plots, etc. |
| Want consistent look across applications | Need bespoke branding |
The toolkit is a starting point, not the final destination. Both
elbow_flexion/ and
walking_fes/ build their own GUIs (with similar
patterns to the toolkit but more specialised); they're worth
reading after this one.
See also#
fes_framework/gui/— the widget toolkit source- Concepts → IPC and processes — how the GUI talks to the backend
- Implementation Guide → Step 8 — adding a GUI walkthrough
- Examples → Walking FES — full GUI in production
