TeslasuitDocumentation
Frameworks

LSL Data Streams

This document describes all Lab Streaming Layer (LSL) data streams provided by RapidKit.

Overview#

RapidKit provides 7 LSL outlets from LSLStreamer (teslasuit_rapidkit/io/lsl_streamer.py):

  • TS_Biomechanics — Biomechanical joint angles
  • TS_API_StepDetector — Teslasuit SDK step detector
  • TS_EMSParameters — EMS stimulation parameters
  • AppData_ControlMessage — Application runtime parameters
  • AppData_UtilityMessage — System state flags
  • TS_BonePosition — Skeleton bone positions and rotations
  • TS_RawData — Raw IMU sensor data

All streams are disabled by default and must be enabled via lsl_enabled=True in ClosedLoopEngine. All streams run at 100 Hz nominal sample rate.


Framework Streams (LSLStreamer)#

1. Biomechanical Data Stream#

Stream Info:

  • Name: TS_Biomechanics
  • Type: Biomechanical
  • Source ID: {source_id}_biomech
  • Sample Rate: 100 Hz
  • Format: cf_double64 (64-bit float)
  • Channel Count: 29 channels

Description: Streams processed joint angles in degrees from the OpenSim biomechanical analysis. Contains all major body joint angles including pelvis, hips, knees, ankles, shoulders, elbows, and wrists. More about biomechnical data in Teslasuit you find here

Channel Structure: All fields from BiomechanicalData dataclass (excluding timestamp):

  • PelvisTilt, PelvisList, PelvisRotation
  • HipFlexExtL/R, HipAddAbdL/R, HipRotL/R
  • KneeFlexExtL/R
  • AnkleFlexExtL/R, FootProSupL/R
  • ShoulderFlexExtL/R, ShoulderAddAbdL/R, ShoulderRotL/R
  • ElbowFlexExtL/R
  • ForearmProSupL/R
  • WristFlexExtL/R, WristUlnRadDevL/R

Metadata per Channel:

  • label: Field name (e.g., "HipFlexExtL")
  • unit: "degrees"
  • type: "angle"
  • id: Channel index

2. Tesla Suit API Step Detector Stream#

Stream Info:

  • Name: TS_API_StepDetector
  • Type: StepDetection
  • Source ID: {source_id}_steps
  • Sample Rate: 100 Hz
  • Format: cf_float32 (32-bit float)
  • Channel Count: 2

Description: Streams foot contact detection from the Tesla Suit SDK's built-in step detector algorithm.

Channels:

  1. left_foot_contact - Boolean flag (0.0/1.0) for left foot ground contact
  2. right_foot_contact - Boolean flag (0.0/1.0) for right foot ground contact

Metadata per Channel:

  • label: "left_foot_contact" or "right_foot_contact"
  • unit: "boolean"
  • type: "contact"
  • id: Channel index

3. EMS Parameters Stream#

Stream Info:

  • Name: TS_EMSParameters
  • Type: EMSParameters
  • Source ID: {source_id}_ems
  • Sample Rate: 100 Hz
  • Format: cf_float32 (32-bit float)
  • Channel Count: 80 channels (20 muscles × 4 parameters)

Description: Streams electrical muscle stimulation parameters for all 20 muscle groups in EmsData. More about EMS parameters in Teslasuit you find here

Channel Structure: All 20 muscles from EmsData (10 lower body + 10 upper body), each with 4 parameters:

  • {Muscle}IsMuted - Boolean (0.0/1.0)
  • {Muscle}Amplitude - Percentage (0–100)
  • {Muscle}Period - Milliseconds (period between pulses)
  • {Muscle}PulseWidth - Microseconds (μs)

Metadata per Channel:

  • label: Field name (e.g., "LeftQuadAmplitude")
  • unit: "boolean", "percent", "Hz", or "us" (depending on parameter type)
  • type: "flag", "amplitude", "frequency", or "pulse_width"
  • id: Channel index

4. Control Message Stream#

Stream Info:

  • Name: AppData_ControlMessage
  • Type: ControlMessage
  • Source ID: {source_id}_control
  • Sample Rate: 100 Hz
  • Format: cf_float32 (32-bit float)
  • Channel Count: Application-dependent (determined by your ControlMessage subclass fields)

Description: Streams the runtime control parameters defined by your application's ControlMessage subclass. The base ControlMessage class is empty; fields are added by subclassing it in your application. Channel count and structure therefore depend entirely on what fields your subclass defines.

Metadata per Channel:

  • label: Field name from your ControlMessage subclass
  • unit: Depends on field type (e.g., "boolean", "Hz", "percent", "us")
  • id: Channel index

5. Utility Message Stream#

Stream Info:

  • Name: AppData_UtilityMessage
  • Type: UtilityMessage
  • Source ID: {source_id}_utility
  • Sample Rate: 100 Hz
  • Format: cf_float32 (32-bit float)
  • Channel Count: 5 channels

Description: Streams system utility flags including the global FES enable state, recording/calibration status, the step detection mode and the biomechanical data collection gate.

Channels: From UtilityMessage dataclass (excluding _on_change and FolderPath):

  • FesIsActive - Boolean flag (0.0/1.0)
  • RecordingIsActive - Boolean flag (0.0/1.0)
  • CalibrationLoopIsActive - Boolean flag (0.0/1.0)
  • TSAPIStepDetectionIsActive - Boolean flag (0.0/1.0)
  • BiomechanicalDataCollectionIsActive - Boolean flag (0.0/1.0)

Metadata per Channel:

  • label: Field name
  • unit: "boolean"
  • type: "recording_flag", "calibration_flag", or "status_flag"
  • id: Channel index

6. Bone Position Stream#

Stream Info:

  • Name: TS_BonePosition
  • Type: BonePosition
  • Source ID: {source_id}_boneposition
  • Sample Rate: 100 Hz
  • Format: cf_double64 (64-bit float)
  • Channel Count: 140 channels (20 bones × 7 channels/bone)

Description: Streams processed skeleton data including 3D position and quaternion rotation for each bone in the Tesla Suit's skeletal model. More about processed skeleton data in Teslasuit you find here

Channel Structure: For each bone in ProcessedData dataclass (excluding timestamp), 7 channels:

  1. {bone}_pos_x - X position (meters or suit units)
  2. {bone}_pos_y - Y position
  3. {bone}_pos_z - Z position
  4. {bone}_rot_w - Quaternion W component
  5. {bone}_rot_x - Quaternion X component
  6. {bone}_rot_y - Quaternion Y component
  7. {bone}_rot_z - Quaternion Z component

Example bones:

  • Pelvis, Spine, Chest, Neck, Head
  • Shoulders, Upper Arms, Forearms, Hands (L/R)
  • Upper Legs, Lower Legs, Feet (L/R)

Metadata per Channel:

  • label: Flattened bone and component (e.g., "Pelvis_pos_x")
  • unit: "meters" for position, "quaternion" for rotation
  • type: "position" or "rotation"
  • id: Channel index

7. Raw Data Stream#

Stream Info:

  • Name: TS_RawData
  • Type: RawData
  • Source ID: {source_id}_raw
  • Sample Rate: 100 Hz
  • Format: cf_double64 (64-bit float)
  • Channel Count: 280 channels (20 sensors × 14 channels/sensor)

Description: Streams raw IMU (Inertial Measurement Unit) sensor data from Teslasuit sensors, including accelerometer, gyroscope, and orientation data. More about biomechnical data in Teslasuit you find here

Channel Structure: For each sensor in RawData dataclass (excluding timestamp), 14 channels:

  1. {sensor}_boneId - Integer bone identifier
  2. {sensor}_q6_w - Quaternion W component
  3. {sensor}_q6_x - Quaternion X component
  4. {sensor}_q6_y - Quaternion Y component
  5. {sensor}_q6_z - Quaternion Z component
  6. {sensor}_accel_x - Acceleration X (raw units)
  7. {sensor}_accel_y - Acceleration Y
  8. {sensor}_accel_z - Acceleration Z
  9. {sensor}_gyro_x - Gyroscope X (degrees/s or raw units)
  10. {sensor}_gyro_y - Gyroscope Y
  11. {sensor}_gyro_z - Gyroscope Z
  12. {sensor}_linear_accel_x - Linear acceleration X (gravity removed)
  13. {sensor}_linear_accel_y - Linear acceleration Y
  14. {sensor}_linear_accel_z - Linear acceleration Z

Metadata per Channel:

  • label: Flattened sensor and component (e.g., "LeftThigh_accel_x")
  • unit: "id", "quaternion", "raw", "deg/s", or "m/s^2" (depending on data type)
  • type: "boneId", "quaternion", "accel", "gyro", or "linear_accel"
  • id: Channel index

Data Flow Summary#

Teslasuit Hardware
        ↓  (WiFi via Teslasuit Control Center)
SuitHandler  (teslasuit_rapidkit/io/suit_handler.py)
        ↓  (raw ctypes frames)
DataStreamer  (teslasuit_rapidkit/io/data_streamer.py)
        ↓  (populated dataclasses)
    ┌───────────────────────────────────────────────────────┐
    │ BiomechanicalData  ProcessedData  StepDetectorData    │
    │ RawData  EmsData  ControlMessage  UtilityMessage      │
    └──────────────────────┬────────────────────────────────┘
                           ↓
               LSLStreamer (7 framework streams)
                           ↓
               Lab Streaming Layer Network
                           ↓
         External Applications (LabRecorder, MATLAB, Python, etc.)

LabRecorder#

All 7 framework streams are automatically discoverable in LabRecorder. Simply:

  1. Open LabRecorder
  2. Click "Update" to scan for streams
  3. Select desired streams
  4. Click "Record" to save to XDF format

Technical Notes#

Timestamp Handling#

  • Streams use pylsl.local_clock() for timestamping
  • Some dataclasses provide their own timestamps (biomechanical, skeleton, raw)
  • All timestamps are in LSL's global time domain for synchronization

Performance Considerations#

  • Total bandwidth: ~398 KB/s (569 channels, mixed float32/double64 formats)
  • Stream sizes:
    • Raw Data: 280 channels, 219 KB/s (largest)
    • Bone Position: 140 channels, 109 KB/s
    • Control Message: application-dependent (one channel per field of your ControlMessage subclass)
    • EMS Parameters: 32 channels, 13 KB/s
    • Biomechanical: 29 channels, 23 KB/s
    • Utility Message: 5 channels, 2 KB/s (smallest)
    • Step Detectors: 2 channels, 1 KB/s total

Data Types#

  • cf_float32: 32-bit float (4 bytes per sample) - Most streams
  • cf_double64: 64-bit float (8 bytes per sample) - Biomechanical, Skeleton, Raw
  • cf_int32: 32-bit integer (not currently used)

Troubleshooting#

Stream Not Appearing#

  • Ensure lsl_enabled=True was passed to ClosedLoopEngine or orchestrator.launch()
  • Ensure the backend engine is running
  • Check firewall settings (LSL uses UDP multicast)
  • Verify network connectivity if using remote streams

High Latency#

  • Check system CPU usage
  • Reduce number of active streams
  • Increase LSL buffer sizes

Data Discontinuities#

  • Check for Teslasuit connection issues
  • Verify model buffer warmup completed (30 samples)
  • Monitor for dropped samples in LSL inlet

See also#

External references#