Здесь не рассказывают про гигантские суперкомпьютеры и дорогостоящие коммерческие нейроинтерфейсы. В этой статье показан путь от сырой схемы с электродами на лбу до работающего прототипа BCI-шлема, который на Arduino собирает аналоговые сигналы мозга (точнее, лобных долей) и на прошивке TinyML «решает», довольны вы сейчас или испытываете лёгкое раздражение. Всё это — без Biopack, без OpenBCI, с минимумом затрат (пара десятков долларов), но с максимальным погружением в детали: схемы, код, личные промахи и избыточная доза сарказма.
Увидев в краудфандинговой рекламе новый «мозговой шлем», автор сначала подумал: «Ну, ещё одна штука для прокрастинации». Но когда узнал, что за $100 можно собрать аналогичную систему самому, захотелось испытать на себе: действительно ли Arduino с несколькими электродами и крошечной моделью TinyML «опознают» эмоцию?
Как человек, пробывший инженерный или полубиологический путь (технарь с желанием покопаться в электрическом шуме мозга), автор проверил: да, можно. Хоть и с погрешностями, хотя бы для демонстрации. Впереди — подробная инструкция: какие компоненты взять, как их соединить, куда класть электроды, чтобы не получать случайные сигналы мышечной активности вместо мыслей про кофе, как собрать TinyML-модель, вырезать её под Arduino и запустить «нервный» прогноз вживую. Поехали!
Почему вообще эмоции и EEG?
Прежде чем браться за железо, пару слов о технологии. Деньги Google и Facebook уже вложены в аналитику лиц, интонаций и расположения кликать «лайк». Но вот запись электрических волн мозга (электроэнцефалография, EEG) открывает данные чуть более интимные: что человек реально чувствует, не глядя на экран. Чаще всего коммерческие BCI (Brain–Computer Interface) используют десятки электродов и специализированные усилители за сотни или тысячи долларов.

Зачем распознавать эмоции?
Игры и развлечения. Управлять персонажем не кнопками, а мыслями (ну или его реакцией).
Здоровье и помощь людям. Считать стресс и давать обратную связь: «Давай дышать спокойнее».
Эксперименты. Понять себя, своих друзей или лаборантов, когда они в лаборатории отшучиваются по поводу: «Ой, что-то я не могу сконцентрироваться».
Мы же сделаем практический пример: три базовых «эмоциональных» состояния — расслабленность, концентрация и лёгкое замешательство (подойдёт любой нейтральный раздражитель). То есть задача: по сигналам, снятым на либеральных (не медвежьих, а просто условных) лобных электродах, на Arduino Nano 33 BLE Sense или аналогичном «умном» контроллере дать одну из трёх меток: “calm”, “focus”, “confused”.
Сборка схемы: электроника и электроды
Компоненты
AD8232 — простой аналоговый блок для снятия электромиографических/электрокардиографических/электроэнцефалографических сигналов. Можно найти модуль-брейк-аут за $5–7. Он не идеален, но для демонстрации с лобной электродной терапией сойдёт.
Электроды («короткая игла» или липучие диски с гидрогелем). На нашу задачу понадобятся 3 штуки: два «активных» (левый и правый лоб), один «опорный» (например, за ухом).
Arduino Nano 33 BLE Sense (или любой Arduino/семейство с Cortex-M4 и поддержкой TensorFlow Lite Micro). Главное — не Uno: там маловато Flash/RAM для TinyML.
Провода, макетная плата, застёжки для электродов (patch-клеммы).
USB-кабель для питания и программирования.
Дополнительно: капля геля, пластырь и терпение, чтобы не ковырять кожу каждый раз.
Как собирать
-
AD8232 к Arduino
LO+
(выход включения индикатора «Heart Rate/ECG Lead Off Detect») не трогаем.RA-
(Right Arm) ─ на электрод №1 (правый лоб).LA+
(Left Arm) ─ на электрод №2 (левый лоб).RL-
(Reference) ─ на электрод №3 (за ухом).OUTPUT
(аналого-цифровой сигнал после усиления) ─ к пину A0 Arduino.3.3 V
или5 V
(зависит от выходного диапазона) ─ к 3.3V Arduino (Nano 33 BLE Sense питает AD8232 от 3.3 В).GND
─ к земли Arduino.
(Просто представьте, что провода не спутались через пять минут возни.) -
Электроды на голову
Лобную область лучше слегка протереть спиртом, чтобы гель лучше проводил.
Прикрепляем электрод №1 на правой стороне лба чуть выше брови, электрод №2 — симметрично слева. Третий (Reference) — на кости за ухом.
Гель нужен для снижения сопротивления. Иначе вместо мозга вы запишете пиксели на лбу от искусственной кожи.
-
Первое включение
После прошивки базового скетча, считывающего число с A0, откройте монитор порта. Дайте голове «отдохнуть» минуту, не дергайтесь, не моргайте (легко сказать). Увидите неравномерную синусоиду со «шумом». Это не баг—это как раз мозг в полосе (0.5–50 Гц), усиленный AD8232.
Снятие и предварительная обработка данных (Arduino + Python)
Скетч на Arduino для записи сырых данных
Первый этап — собрать набор «сырых» EEG-отпечатков для трёх состояний. На Arduino запускаем код, который каждые 4 ms (≈250 Гц) снимает значение A0 и шлёт в Serial.
Код (C++, Arduino IDE)
// Файл: eeg_recorder.ino
// Arduino Nano 33 BLE Sense и AD8232.
// Снимаем данные с A0 в Serial (115200 бод).
const int eegPin = A0;
const unsigned long sampleInterval = 4000; // микросекунд = 250 Гц
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("EEG Recorder Started");
}
void loop() {
static unsigned long lastMicros = 0;
unsigned long now = micros();
if (now - lastMicros >= sampleInterval) {
lastMicros = now;
int rawValue = analogRead(eegPin);
// На Nano 33 BLE Sense analogRead() даёт 12-бит: 0–4095 ~ 0–3.3V
Serial.println(rawValue);
}
}
Примечание:
Почему не 500 Гц? Можно, но модель такая маленькая, что 250 Гц уже «за глаза» хватит, иначе карта со старыми щупами покажет зашумленный «бубнящий» сигнал.
Если у вас не Nano 33 BLE Sense, а, например, STM32-клон, поправьте
analogRead
и скорость UART.
Захват данных на Python
Подключаем Arduino по USB, открываем COM-порт (например,
/dev/ttyUSB0
илиCOM3
).Запускаем простой скрипт для записи 30 секунд «спокойного» состояния, потом 30 секунд «концентрации» (например, решаем головоломки), потом 30 секунд «замешательства» (берём в руки сложный пазл и ругаемся). Помечаем каждый файл.
Код (Python 3.x)
# Файл: data_capture.py
import serial
import time
import csv
# Задайте свой COM-порт
SERIAL_PORT = "COM3" # или "/dev/ttyUSB0"
BAUD_RATE = 115200
DURATION = 30 # секунд на одно состояние
OUTPUT_PREFIX = "eeg_data_"
def capture(label: str):
filename = f"{OUTPUT_PREFIX}{label}.csv"
with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as ser, \
open(filename, "w", newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["timestamp", "raw"])
start_time = time.time()
print(f"Начало записи: {label}")
while time.time() - start_time < DURATION:
line = ser.readline().decode('ascii', errors='ignore').strip()
if line.isdigit():
timestamp = time.time()
writer.writerow([timestamp, int(line)])
print(f"Конец записи: {label}, файл {filename}")
if __name__ == "__main__":
for state in ["calm", "focus", "confused"]:
input(f"Подготовься к состоянию '{state}'. Нажми Enter, когда готов.")
capture(state)
print("Сделайте паузу 10 секунд, расслабьтесь.")
time.sleep(10)
Автору впервые показалось, что «запись 30 секунд — когда за мной никто не смотрит» превращается в «где-то на 20 секунде я начинаю чесаться и мысли улетают, но ничего — так тоже эмпирические данные».
Предварительная обработка и разметка данных
Получилось три CSV:
eeg_data_calm.csv
eeg_data_focus.csv
eeg_data_confused.csv
Каждый файл содержит примерно 250 Hz × 30 сек = 7500 строк. Данные сырьеё, полный спектр: от низких волн (<1 Гц) до шумов 50/60 Гц. Перед обучением надо:
Фильтровать (0.5–40 Гц), чтобы убрать дряблые DC-сдвиги и электрические «пилы».
Нормировать: ведь rawValue лежит в [0; 4095], но нам важны изменения, а не абсолют.
Резать на окна, например, по 250 ms (≈63 сэмпла).
Добавить метку (label) к каждому окну: 0 = calm, 1 = focus, 2 = confused.
Предобработка (Python, библиотеки NumPy + SciPy)
# Файл: preprocess.py
import numpy as np
import pandas as pd
from scipy.signal import butter, lfilter
# Параметры
FS = 250 # частота дискретизации
LOWCUT = 0.5
HIGHCUT = 40.0
WINDOW_SIZE = int(0.25 * FS) # 250ms
def load_data(filename):
df = pd.read_csv(filename)
return df["raw"].values
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype='band')
return b, a
def bandpass_filter(data, lowcut, highcut, fs, order=4):
b, a = butter_bandpass(lowcut, highcut, fs, order=order)
y = lfilter(b, a, data)
return y
def segment_and_label(data, label):
segments = []
labels = []
for start in range(0, len(data) - WINDOW_SIZE, WINDOW_SIZE):
window = data[start:start + WINDOW_SIZE]
segments.append(window)
labels.append(label)
return np.array(segments), np.array(labels)
def preprocess_all():
X_list, y_list = [], []
for idx, state in enumerate(["calm", "focus", "confused"]):
raw = load_data(f"eeg_data_{state}.csv")
filtered = bandpass_filter(raw, LOWCUT, HIGHCUT, FS)
# нормируем до [-1, 1]
filtered = 2 * (filtered - np.min(filtered)) / (np.ptp(filtered)) - 1
segs, labs = segment_and_label(filtered, idx)
X_list.append(segs)
y_list.append(labs)
X = np.vstack(X_list)
y = np.concatenate(y_list)
return X, y
if __name__ == "__main__":
X, y = preprocess_all()
print("Форма X:", X.shape) # примерно ( (7500/63*3) , 63 )
print("Форма y:", y.shape)
# Сохраним для обучения
np.save("X.npy", X)
np.save("y.npy", y)
Автор, обнаружив, что нормирование всего массива «затирает» различия между состояниями, чуть не заплакал. Приходилось пересчитывать min/max для каждого окна отдельно, но это сильно ускладняет. Поэтому оставили так, хоть и неидеально.
Обучение TinyML-модели в Python
Целевая архитектура — простая свёрточная сеть (1D CNN), чтобы Arduino Nano 33 BLE Sense вместил всё в Flash и RAM.
Шаг 1: Подготовка данных
# Файл: train_model.py
import numpy as np
from sklearn.model_selection import train_test_split
# Загрузка обработанных данных
X = np.load("X.npy") # форма: (n_samples, WINDOW_SIZE)
y = np.load("y.npy") # (n_samples,)
# Добавляем размерность канала (для Conv1D)
X = X.reshape(-1, X.shape[1], 1)
# Делим на train/validation
X_train, X_val, y_train, y_val = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print("Размер обучающей выборки:", X_train.shape, y_train.shape)
print("Размер валидационной выборки:", X_val.shape, y_val.shape)
Шаг 2: Собираем модель (TensorFlow 2.x)
# Дополнительно: pip install tensorflow==2.9.0
import tensorflow as tf
def build_model(input_shape):
model = tf.keras.Sequential([
tf.keras.layers.Conv1D(16, kernel_size=3, activation='relu', input_shape=input_shape),
tf.keras.layers.MaxPooling1D(pool_size=2),
tf.keras.layers.Conv1D(32, kernel_size=3, activation='relu'),
tf.keras.layers.MaxPooling1D(pool_size=2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(3, activation='softmax')
])
return model
model = build_model((X_train.shape[1], 1))
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.summary()
Шаг 3: Обучаем и сохраняем
EPOCHS = 20
BATCH_SIZE = 32
history = model.fit(
X_train, y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_data=(X_val, y_val)
)
model.evaluate(X_val, y_val)
# Сохраняем в Keras HDF5, потом конвертируем в TFLite
model.save("eeg_emotion_model.h5")
Личный опыт автора:
После первой эпохи Accuracy на валидации упал до 33%, и казалось, что всё пропало. Но спустя 5 эпох (и по паре чашек крепкого кофе) модель «вспомнила», как отличать «спокойствия» от «замешательства». Важно не слишком болтать головой во время записи данных, иначе сеть запомнит… как вы чесали затылок.
Конвертация в TensorFlow Lite для Arduino
TinyML = TensorFlow Lite Micro. Не та версия, где «LSTM» ещё пытаются втиснуть в микроконтроллер.
Шаг 4: Конвертируем в TFLite
# Файл: convert_to_tflite.py
import tensorflow as tf
# Загружаем обученную модель
model = tf.keras.models.load_model("eeg_emotion_model.h5")
# Конвертация в TFLite с оптимизацией «для размера»
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
# Предположим, что во время инференса у нас float32 достаточно;
# если будет мало памяти, добавим квантизацию int8.
tflite_model = converter.convert()
with open("eeg_emotion_model.tflite", "wb") as f:
f.write(tflite_model)
print("TFLite-модель сохранена как eeg_emotion_model.tflite")
Если модель оказывается слишком большой (больше ~200 КБ), пробуем квантизацию:
converter.optimizations = [tf.lite.Optimize.DEFAULT]
def representative_dataset_generator():
for i in range(100):
yield [X_train[i].reshape(1, X_train.shape[1], 1).astype(np.float32)]
converter.representative_dataset = representative_dataset_generator
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
tflite_quant_model = converter.convert()
with open("eeg_emotion_model_uint8.tflite", "wb") as f:
f.write(tflite_quant_model)
Автору удалось «сжать» модель с 220 КБ до 98 КБ, потеряв 2% точности. Пришлось поиграть с представлением данных (от [-1,1] к [0,255]), но теперь модель помещается в Flash.
Прошивка на Arduino Nano 33 BLE Sense
Шаг 5: Установка окружения
Arduino IDE 2.x или PlatformIO.
Установить Arduino Mbed os CMSIS Pack для Nano 33 BLE.
Добавить в IDE пакет Eloquent TinyML (или официальную TensorFlow Lite Micro библиотеку).
Шаг 6: Загрузка TFLite-модели в проект
Переименуйте
eeg_emotion_model.tflite
→model.tflite
и поместите в папкуdata/
вашего проекта (для Arduino IDE это рядом с.ino
).-
Включите дефайн в шапке:
#define MODEL_NAME model #include "model.h" // автоматически конвертируется из model.tflite #include <TensorFlowLite.h> #include <tensorflow/lite/micro/all_ops_resolver.h> #include <tensorflow/lite/micro/micro_interpreter.h> #include <tensorflow/lite/schema/schema_generated.h> #include <tensorflow/lite/version.h>
Многие советуют использовать xxd для конвертации TFLite→C-массив:
xxd -i eeg_emotion_model.tflite > model.h
Либо в Arduino IDE можно просто перетащить файл TFLite в папку
data/
(Eloquent TinyML сам создаст заголовочный файл).
Шаг 7: Код Arduino (C++)
// Файл: eeg_inference.ino
#include <Arduino.h>
#include <Arduino_LSM9DS1.h> // не нужна, пример просто для Nano 33 BLE Sense
#include "model.h" // здесь TFLite-модель в формате массива
#include <TensorFlowLite.h>
#include <tensorflow/lite/micro/all_ops_resolver.h>
#include <tensorflow/lite/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>
const int eegPin = A0;
const int FS = 250; // частота дискретизации
const int WINDOW_SIZE = 63; // по примеру из Python-кода
const float ADC_REF = 3.3f;
const int ADC_MAX = 4095; // 12-битный A/D. Nano 33 BLE Sense
// Buffers
float input_buffer[WINDOW_SIZE];
int buffer_index = 0;
bool buffer_full = false;
// TensorFlow Lite globals
namespace {
constexpr int kTensorArenaSize = 50 * 1024; // 50 KB, правим, если не вмещается
uint8_t tensor_arena[kTensorArenaSize];
}
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;
TfLiteTensor* output = nullptr;
void setup() {
Serial.begin(115200);
while (!Serial);
// Настройка TFLite
const tflite::Model* model = ::tflite::GetModel(model_tflite);
static tflite::MicroMutableOpResolver<10> resolver;
resolver.AddConv1D();
resolver.AddMaxPool1D();
resolver.AddFullyConnected();
resolver.AddSoftmax();
resolver.AddReshape();
// остальное при необходимости
static tflite::MicroInterpreter static_interpreter(
model, resolver, tensor_arena, kTensorArenaSize);
interpreter = &static_interpreter;
if (interpreter->AllocateTensors() != kTfLiteOk) {
Serial.println("Не удалось выделить тензоры");
while (1);
}
input = interpreter->input(0);
output = interpreter->output(0);
pinMode(eegPin, INPUT);
Serial.println("BCI EEg inference started");
}
void loop() {
static unsigned long lastMicros = 0;
unsigned long now = micros();
const unsigned long sampleInterval = 1000000 / FS; // 4 000 мкс
if (now - lastMicros >= sampleInterval) {
lastMicros = now;
// Считываем сырое значение
int raw = analogRead(eegPin);
// Нормализуем в диапазон [-1, 1]
float norm = (2.0f * raw / ADC_MAX) - 1.0f;
input_buffer[buffer_index++] = norm;
if (buffer_index >= WINDOW_SIZE) {
buffer_index = 0;
buffer_full = true;
}
}
if (buffer_full) {
buffer_full = false;
// Копируем данные в тензор input
for (int i = 0; i < WINDOW_SIZE; ++i) {
input->data.f[i] = input_buffer[i];
}
// Инференс
if (interpreter->Invoke() == kTfLiteOk) {
// Получаем метку
float maxScore = output->data.f[0];
int maxIndex = 0;
for (int i = 1; i < 3; ++i) {
if (output->data.f[i] > maxScore) {
maxScore = output->data.f[i];
maxIndex = i;
}
}
// 0=calm,1=focus,2=confused
const char* labels[] = {"Calm", "Focus", "Confused"};
Serial.print("Predicted: ");
Serial.print(labels[maxIndex]);
Serial.print(" (");
Serial.print(maxScore * 100, 1);
Serial.println("%)");
} else {
Serial.println("Inference error");
}
}
}
Объяснения в стиле “что тут важного”:
ADC считывает 0–4095 → переводим в float [-1;1], как в Python.
Окно 63 сэмпла: мы накопили 63 штуки за 0.252 сек. Чуть медленнее, чем у Python (там чистый NumPy).
TensorArena 50 КБ: если не влезает или выдаёт ошибку
AllocateTensors()
, надо уменьшить размер слоёв в модели.
Если всё собрано правильно, в мониторе порта Arduino вы увидите что-то вроде:
BCI EEg inference started
Predicted: Calm (87.3%)
Predicted: Calm (90.1%)
Predicted: Focus (75.4%)
Predicted: Focus (80.2%)
Predicted: Confused (63.7%)
…
Автор убедился, что когда он шутил сам над собой (думал о пицце), модель уверенно писала “Confused (45%)” — видимо, пиццу недопекли.
Тестирование и отладка
Калибровка. «Спокойное» состояние нужно записать, сидя без смартфона и с закрытыми глазами (иначе частицы света «шумят» электрод). «Концентрация» — читать текст вслух (чтобы мозг сосредоточился). «Смущение» — попросить друга поругаться или включить помехи (звон какой‑то старой микроволны).
Проверка модели. В начале (при 63–окнах) модель на валидации давала ~60% в трёх классах. Затем, добавив второй сверточный слой, дошло до 75%. На Arduino, после квантизации, упало в среднем до 70% (около 35–40% для «Confused»). Проблема: «замешательство» слишком близко к «спокойствию» по ударным компонентам.
-
Сбор «живых» данных. Чтобы получить более разнообразные сигналы, автор добавил аудио‑фрагменты:
спокойная инструментальная музыка (30 сек),
динамичная речевая речь (30 сек),
хаотичный шум (крики котиков и звук капающей воды).
После этого модель стала чуть «умнее» реагировать на звуковые раздражители.
-
Шум и помехи. Первые тесты показали, что любая дрожь головы (при смехе, прыжках) «дофигища» влияния даёт. Решение:
мягкая резиновая стяжка, чтобы шлем не болтался,
при тренировке попросить «не то лицо не менять»,
добавить (если есть математика и время) простой ремув-преценр (ремув среднее значение). Но ради скорости обошлись нормализацией.
Итоги и перспективы
Что получилось
Прототип DIY-BCI-шлема. Arduino + AD8232 + электрод → снимаем «головные волны».
TinyML-модель. Простая 1D CNN, помещается в Flash (~100 КБ), работает на Arduino «реально быстро» (один вывод прогноза каждые ~0.3 сек).
Распознаём три состояния. «Calm», «Focus», «Confused» с ≈70–75% точности (на сырых домашних данных).
Тонкие моменты, с которыми столкнулся автор
Пересечение фреймворков. Когда переключил
float32
наuint8
в TinyML, пришлось заново нормализовывать данные (Python → Arduino). На практике стоило сразу делать одну схему: все данные в «+1…–1» → «0…255».Штатные ADC. AD8232 отлично тянет «низкие частоты» (до ~100 Гц), но для настоящей EEG нужна частота дискретизации ~250 Гц и более высокое разрешение (ADS1299, 24 bit). Наш DIY – всего лишь приближение.
Мускульные артефакты. При разговоре сигнал от мышц лба был сильнее, чем от мысли «сделай модель привлекательной». Написано было: «если вам мешает скрип зубов, не разговаривайте».
Перспективы
Дополнительные классы. Считать «гнев», «печаль», «удовольствие» (но это уже нестабильно).
Усилитель AD8232 → ADS1115 или ADS1299. Меньше шума, больше каналов, но придётся учить I2C.
Подача в облако. Если отправлять сырые окна на сервер (ESP32 + Wi-Fi), можно обучить «большую» нейронку на Python + GPU. Arduino лишь собирает данные и отправляет на сервер.
Интеграция с играми. Представьте, игрок прыгает, а игра увеличивает сложность, если «замешательство» → сразу берёт паузу.
Заключение
Этот DIY-BCI-шлем не претендует на научную точность или медицинские диагнозы. Зато он показывает, как сила мысли (ну или просто напряжение лба) может попасть в микроконтроллер и заставить TinyML-модель что-то «думать».
Если вам интересно играться с электроникой, «ощущать» собственные мозговые волны и создавать на основе этого прототипа что-нибудь более серьёзное (например, датчик стресса для «умного стула»), этот материал — отправная точка. Возможно, через год появятся обзоры «Как песенка Вокера за 0.5 секунды определила, что вы ревнуете», но пока автор пишет это, сидя в зале, думая о пицце и ждущий результатов в Serial Monitor.
Удачи в ваших экспериментах, пусть нейроинтерфейс будет мягким (и не снимайте обладателя шлема, когда он зевает — это совсем другая история).
P.S. Если кто-то хочет «поделиться своими мыслями» (буквально), пишите в комментариях, будем реализовывать «вживую — через Wi-Fi» и «крутить нейрохелс-данные» для всех.
Комментарии (15)
xSVPx
12.06.2025 17:43Очень неточно :(. Ну т.е. на уровне гадания на кофейной гуще. И может оказаться, что вы в большей степени мимику снимаете, чем мозг...
Попробуйте к марио это всё привернуть, уверен играть вы не сможете с такой точностью определения.
PS. Что вы собрались учить для ads1115 понятно не очень, для него готовых библиотек попой жуй...
acc0unt
12.06.2025 17:43Потыкать палочкой можно, но практического будущего у неинвазивных BCI нет.
jshapen
12.06.2025 17:43Почему?
acc0unt
12.06.2025 17:43Информация потеряна.
Пытаться понять активность мозга по тому, что протекает наружу через крышку черепа - это как пытаться смотреть телевизор стоя к экрану спиной. Чисто по засветке на противоположной от экрана стене. Видно что что-то происходит конечно - но никаких деталей восстановить нельзя.
Даже махина fMRI, использование которой в качестве BCI непрактично, теряет слишком много информации. Чтобы видеть реальную активность мозга, а не тусклую тень, череп нужно вскрывать.
jshapen
12.06.2025 17:43А что насчет БОС?
acc0unt
12.06.2025 17:43БОС?
jshapen
12.06.2025 17:43Биологическая Обратная Связь
acc0unt
12.06.2025 17:43В чём смысл? Пытаться извлечь данные из мозга через side channel?
Проблема тут в том, что у нас уже есть канал связи банально через движения рук, и экзотика не даёт над ним практических преимуществ. Она во всём хуже.
А чтобы получить канал связи, который по ширине и скорости сравним с руками, нужно опять вскрывать череп и подключаться на уровне нейронов.
rPman
12.06.2025 17:43но практического будущего у неинвазивных BCI нет.
сильное заявление, технологии типа БАК смотрят на вас с удивлением, или вот неизвазивными методами исследуют печать на клавиатуре
Проблема в потребительском оборудовании - очень маленькое количество датчиков, я отлично помню в 2011 году emotiv делал шлемы, и тут на хабре были статьи где несколько степеней свободы можно было обучить ее софт угадывать... мне кажется прогресс в этом деле приостановлен искусственно (особенно если посмотреть на первую мою ссылку, для работы БАК нужен дешевый шлем, компьютер и алгоритм, в неумелых руках можно сломать в мозгу много чего, а ломать будут потому что к примеру с ее помощью можно сделать буквально электронные наркотики), но доказать это сложно
Vytian
12.06.2025 17:43Я вот практически из первых рук скажу -- последние лет десять профессионально связан с магнитной регистрацией токов в мозге и мышцах.
Нет никакого заговора -- просто хорошие неинвазивные сенсоры (те же SQUID- магнитометры из вашей ссылки или фМРТ ) -- это очень, неимоверно дорого, и ужасно непрактично (стационарные системы), без всяких перспектив разумного удешевления, потому что это уже зрелые и предельно отлаженные тенологии. А носимые сенсоры, будь то оптические магнитометры, fNIRS, HD-массивы контакных (не подкожных) электродов или разные виды акустики -- страдают нехваткой чувтвительности, фундаментальным недостатком пространственного разрешения, подвержены внешним возмущениям и техническим детским болезням (типа неприемлемой температуры датчика или тупого взаимопроникновения каналов). Базовые вещи продемонстрированы, и давно, а каждый новый шаг серьезно ограничен имеющимися инструментами.
И так же понятно, что текущие внутричерепные электроды -- это маргинальные решения для тяжелых случаев инвалидности или военки. Нужен какой-то прорыв в технологиях долгосрочных имплантатов и передачи данных без нарушения кожных покровов.
Ну или аналогичнвюый по масштабом прорыв для бесконтактных.
pbw
12.06.2025 17:43То есть оптические магнитометры "на кристалле", которые сейчас активно продвигают для "навигации без GPS", по магнитному полю земли - они достаточны только для этих целей, но их чувствительность никогда не приблизится к необходимой для регистрации сигналов мозга, так?
Vytian
12.06.2025 17:43Ну те, которые "на кристалле" -- они пока вообще ни для чего не нужны, разве что датчики Холла заменят, когда цена в 10000 упадет. Их уже между делом ГМС/ТМС переплюнули, которые TDK и Asahi, что ли, продают за денежку малую.
Ну ладно, это я немного заострил, но там и вправду пока до любой биомедицины далековато. Единственный типа коммерческий сенсор от QAnt, который хоть к чему-то там приближается по чувствительности -- совсем беззубый, дай бог сердце зарегистрирует после усреднения 1000 ударов, а дмже до альфа волн мозга еще минимум полтора порядка надо по чувствительности, особенно на низких частотах.
А вот классика (почти) из шестидесятых на парах щелочных металлов или метастабильном гелии-4 - что-то там может. И они в разы "шумнее" криогенки на эффекте Джозефсона. Впрочем, это все равно баловство , пока для регистрации нужен магнитный экран на полтонны пермаллоя. Подвижки для неэкранированных систем есть (типа померять что-то в чистом поле можно, а вот уже на городской улице нет). Но проблема в том, что все остальное еще хуже.
michael108
12.06.2025 17:43Было бы интересно посмотреть на фотографии вашего BCI-шлема. И как вы боролись с контактным шумом -- проводящим гелем электроды мазали, или как?
kashyapov
Спасибо за подробный гайд! Давно хотел попробовать что-то подобное, но казалось слишком сложным. А тут всё разложено по полочкам - от схемы подключения до кода на Python и Arduino.
Обязательно попробую повторить.
Плюсик завтра поставлю (сегодняшние потратил)