This project now has a clear online control pipeline:
- Read EEG from LSL
- Build sliding/overlapping windows
- Run model prediction
- Send UDP commands to the game
The main script for this is online_windowing.py.
online_windowing.py: online LSL windowing + model inference + optional UDP sendlsl_connect.py: full-featured EEG bridge with recording, diagnostics, and game controlmodel_Data28_BIS.pkl: CSP+LDA model used for predictiontest_lda.py: smoke test for model loading/predictionfake_lsl_eeg.py: fake EEG LSL stream generator for testingHacktion_game-main/: game with BCI integration (UDP receiver on127.0.0.1:5005)RECORDING_FIX.md: troubleshooting guide for EDF recording issues
pip install -r requirements.txtTerminal 1 (start game):
python Hacktion_game-main/Main.pyOptional model selection:
python Hacktion_game-main/Main.py --select-modelOr force one model:
python Hacktion_game-main/Main.py --model-path Hacktion_game-main/Model_simple/model_0010.pklTerminal 2 (start online BCI bridge):
python online_windowing.py \
--stream-type EEG \
--window-seconds 1.0 \
--overlap-seconds 0.8 \
--fixed-fs-hz 256 \
--model-path model_Data28_BIS.pkl \
--udp-host 127.0.0.1 \
--udp-port 5005Terminal A:
python fake_lsl_eeg.py --stream-name FakeEEG --stream-type EEG --sample-rate 250 --channels 8Terminal B:
python online_windowing.py \
--stream-name FakeEEG \
--window-seconds 1.0 \
--overlap-seconds 0.8 \
--fixed-fs-hz 256 \
--car \
--bandpass-low-hz 1 \
--bandpass-high-hz 40 \
--model-path model_Data28_BIS.pkl \
--udp-host 127.0.0.1 \
--udp-port 5005Default label-to-UDP payload map is:
left_hand -> "-1"right_hand -> "1"idle -> "0"
You can override with:
--udp-label-map '{"left_hand":"-1","right_hand":"1","idle":"0"}'or pass a JSON file path.
--window-seconds: window duration--overlap-secondsor--stride-seconds: sliding control--fixed-fs-hz: force model input sample rate (useful if model expects fixed rate)--car: apply common average reference--bandpass-low-hz,--bandpass-high-hz: optional FFT bandpass--min-confidence: minimum confidence required before UDP send--health-interval-seconds: periodic LSL health logs (samples/sec,windows/sec, stale/live)--no-samples-warn-seconds: warning threshold if stream goes silent
When you run python Hacktion_game-main/Main.py, the game now displays:
BCI UDP: WAITING/LIVE/STALE- total UDP packets and valid commands received
- last decoded BCI command with age
- keyboard fallback state
Press K in game to toggle keyboard fallback ON/OFF.
Set it to OFF to verify headset-only control.
From the game menu, run calibration. The calibration flow now:
- Records EEG from LSL and saves
calibrage_recording_YYYYMMDD_HHMMSS.edfat project root. - Tries to train a new CSP+LDA model from this EDF.
- Saves model weights under
Hacktion_game-main/Model_simple/model_<edf_name>.pkl. - Automatically sets this new model as active for the next game run in the same session.
Useful env options:
BCI_CALIBRATION_TRAIN=0to skip auto-training after calibrationBCI_STREAM_NAME=.../BCI_SOURCE_ID=...to target a specific EEG stream during calibration and game
Model smoke test:
python test_lda.py --model-path model_Data28_BIS.pkl --channels 8 --samples 256 --batch 3List available LSL streams:
python online_windowing.py --list-streams