Troubleshooting
Solutions for common issues when developing and running RapidKit applications.
Installation Issues#
ModuleNotFoundError: No module named 'RapidKit'#
Cause: Package not installed, or wrong Python environment.
Fix:
# Activate your virtual environment first, then:
pip install -e . # from the project rootVerify: python -c "import RapidKit; print('OK')
ModuleNotFoundError: No module named 'teslasuit_sdk'#
Cause: teslasuit_sdk/ directory is not on the Python path.
Fix: Either use pip install -e . (which adds the project root to the path),
or set PYTHONPATH manually:
# PowerShell
$env:PYTHONPATH = "C:\path\to\fes_framework"ModuleNotFoundError: No module named 'pylsl'#
Fix:
pip install pylslpip install PyQt5 fails#
Try pinning a stable version:
pip install PyQt5==5.15.10Hardware Connection Issues#
Application hangs on startup / hardware init timeout#
Cause: Teslasuit not detected.
Checklist:
- Is Teslasuit Control Center open and running?
- Is the suit powered on (LED indicators lit)?
- Are the suit and your computer on the same WiFi network?
- Does Control Center show the suit as connected (green indicator)?
Fix: Restart Control Center and re-power the suit. Try increasing the hardware init delay:
launch(MyStrategy, hardware_init_delay=10.0)TimeoutError: LSLInlet: Stream 'X' not found within 5.0s#
Cause: External LSL stream not discovered.
Fix:
- Verify the external device is actively publishing (check with LabRecorder).
- Ensure both devices are on the same network / localhost.
- Increase the timeout:
ext.add("StreamName", timeout=15.0)
Calibration Issues#
Calibration returns success=False#
Cause: Suit not fully streaming, or SDK timeout.
Fix:
- Ensure the suit is streaming (check Control Center).
- Wait a few seconds after connecting before triggering calibration.
- Retry calibration once.
Strategy / Runtime Issues#
AttributeError: 'NoneType' object has no attribute 'X' in process()#
Cause: Accessing self.params before it is set (first cycle).
Fix: Guard with if self.params is not None: or initialise in setup():
def setup(self, muscles=None, config=None) -> None:
super().setup(muscles, config)
# Do not access self.joints or self.contacts here — they are not set yetStimulation not activating#
Checklist:
- Is
IsMutedset toFalseon theEMSParamData? - Is
UtilityMessage.FesIsActiveset toTrue? - Are
Amplitude,PulseWidth, andPeriodall non-zero? - Is the strategy actually being called? Add a print in
process()to verify. - Is the condition in
process()evaluating toTrue? Print the input values.
process() not being called#
Cause: Engine not running, or strategy not passed correctly.
Fix: Ensure ControlStrategyBase is the last in the MRO for multiple-inheritance
strategies:
class MyStrategy(MyMixin, ControlStrategyBase): # ControlStrategyBase last
...Strategy runs but joint angles are all 0.0#
Joint-angle collection runs by default — self.joints.* should refresh
every cycle out of the box. If you see a flat-line plot, check these
in order:
-
Did something disable biomech collection? The most common cause.
DataStreamer.set_biomech_collection(False)(or the equivalentUtilityMessage.BiomechanicalDataCollectionIsActive = False) skips the SDK IK call entirely, leavingself.joints.*at its zero- initialised values. Search your app for those calls and re-enable them, or simply leave the default. If you intentionally disabled it for performance, re-enable it whenever you do need joint angles:self.data_streamer.set_biomech_collection(True) -
Mocap not streaming. Verify the suit is streaming in Teslasuit Control Center.
-
Calibration not performed. Call
engine.calibration.calibrate()beforeengine.run(). (Without calibration the IK solver runs but the angles can be inaccurate.) -
DataStreamer.run_cycle()raising silently. Check the log for exceptions.
GUI Issues#
GUI appears but shows no data / plots are flat#
Cause: SharedRingBuffer not created, or name mismatch between processes.
Fix:
- Backend creates the buffer in
on_start()— ensure this hook is called. - Buffer name must be identical in backend and GUI processes.
- The GUI attaches with
create=False— it must attach after the backend creates it. Increasehardware_init_delayif needed.
GUI controls don't affect strategy behaviour#
Cause: ControlMessage subclass not wired to the engine.
Fix: Override __init__ in your engine subclass to replace the default message:
class MyEngine(ClosedLoopEngine):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.control_message = MyControlMessage() # replace defaultAnd pass the same subclass to QueueHandler in the GUI:
handler = QueueHandler(..., control_message=MyControlMessage())RuntimeError: QApplication must be created before QPaintDevice#
Cause: GUI components instantiated outside of gui_runner.
Fix: Create QApplication inside gui_runner() (not at import time).
LSL Issues#
No LSL outlets appear in LabRecorder#
Cause: LSL not enabled, or LabRecorder and the application are on different network interfaces.
Fix:
- Confirm
lsl_enabled=Trueis passed tolaunch()orClosedLoopEngine. - Check LabRecorder's "Update" button — outlets are created at startup.
- Try running LabRecorder on the same machine as the application first.
LSL outlet data looks wrong / duplicated channels#
Cause: Multiple engine instances running simultaneously.
Fix: Use a unique source_id per instance:
engine = ClosedLoopEngine(..., source_id="my_app_session_1")Performance Issues#
Control loop running slower than 100 Hz#
Cause: Heavy computation in process(), or DataStreamer.process() override taking too long.
Fix:
- Profile your
process()— avoid loops over large arrays, file I/O, or blocking calls. - Move non-critical processing to
on_cycle_complete()(still in the loop, but post-stimulation). - Use
cycle_count % Nto run expensive logic less frequently:def on_cycle_complete(self) -> None: if self.cycle_count % 10 == 0: # every 10 cycles = 10 Hz self._update_statistics()
GUI freezing or lagging#
Cause: GUI doing too much work in the update timer callback.
Fix: Keep the 30 Hz timer callback lightweight — only read buffer and update plots. Move any heavy processing to a background QThread.
