Симулятор MAX30102 онлайн — пульсоксиметр в браузере
MAX30102 это оптический датчик пульса и сатурации крови от Maxim. Два светодиода, красный и инфракрасный, светят сквозь палец, фотодиод ловит отражённый сигнал, а чип по изменению поглощения считает пульс. Интерфейс I2C, библиотека одна на MAX30102 и MAX30105.
В нашем симуляторе MAX30102 виртуальный: у него есть ползунки пульса от 40 до 180 уд/мин и сатурации от 90 до 100 процентов. Это позволяет написать скетч с порогами тревоги и проверить их, не покупая датчик и не разбирая его оптику.
Откройте симулятор, добавьте «Пульсоксиметр MAX30102» из палитры или напишите код с MAX30105 particle и вызовом particle.begin(). Дальше двигайте ползунки в карточке датчика, и getHeartRate с getSpO2 вернут эти значения.
Как работает MAX30102
Метод называется оптической плетизмографией. Кровь поглощает красный свет сильнее, чем инфракрасный, и при каждом сокращении сердца артериальная пульсация меняет это соотношение. Чип измеряет оба канала раздельно, а встроенный процессор ищет в сигнале пики, соответствующие сокращениям. Отсюда два числа: частота сокращений в уд/мин и насыщение крови кислородом в процентах.
Грабль: палец должен лежать неподвижно и с постоянным прижимом. Любое движение даёт артефакт, и пульс в этом случае скачет до нереальных значений. Реальные библиотеки умеют отсеивать motion artifacts по взаимной корреляции каналов, но полностью это не лечится. В симуляторе такой проблемы нет: там вы двигаете не палец, а ползунок, и значение всегда чистое.
Про сатурацию стоит понимать главное: это не самостоятельная медицинская величина, а оценка по соотношению поглощения. Норма 95-100 процентов, диапазон 91-94 процента называют лёгкой гипоксемией, а ниже 90 процентов это тяжёлая гипоксемия, при которой нужен кислород. У здорового некурящего человека обычно 97-99 процентов, у курящих хронически бывает 92-95.
Подключение и код
#include <Wire.h>#include "MAX30105.h"MAX30105 particle;void setup() { Serial.begin(9600); if (!particle.begin()) { Serial.println("Датчик не найден"); while(1); } particle.setup();}void loop() { int hr = particle.getHeartRate(); int spo2 = particle.getSpO2(); Serial.print("Пульс: "); Serial.print(hr); Serial.print(" уд/мин, SpO2: "); Serial.print(spo2); Serial.println(" %"); delay(1000);}Распиновка по I2C: VCC к 3.3 В, GND к GND, SDA к A4, SCL к A5. На платах с адаптером бывает стабилизатор, и тогда допустимо 5 В, но сам чип MAX30102 работает только в диапазоне от 1.8 до 3.6 В. Адрес на шине 0x57, и он единственный, так что конфликтов с другими I2C-устройствами не будет. Библиотека MAX30105 от SparkFun подходит и для MAX30102, в ней реализованы режимы RED и IR для пульса и SpO2, а у MAX30105 добавлен зелёный канал для более точного определения пульса.
Тонкость с begin(): метод проверяет готовность датчика и возвращает логическое значение. Если он вернул false, датчик не отвечает по I2C, и дальнейшая работа бессмысленна. Правильный шаблон: если begin вернул false, печатать сообщение и не идти дальше, а не читать нули из getHeartRate. В симуляторе begin всегда возвращает единицу, поэтому проверку ветки ошибки там придётся искусственно вызвать.
| Параметр | MAX30102 | В симуляторе |
|---|---|---|
| Каналы | RED + IR (пульс, SpO₂) | 2 значения с ползунков |
| I2C адрес | 0x57 | 0x57 (виртуально) |
| Частота семплирования | 50-3200 Гц | Не моделируется |
| Разрядность АЦП | 18 бит | Не моделируется |
| Ток | ~600 мкА активный, 0.7 мкА sleep | Не моделируется |
Что сначала не получилось
Первый скетч у меня печатал нули, и я полчаса искал проблему в I2C. Оказалось, дело было в том, что после создания объекта MAX30105 particle я не вызвал particle.setup(), а без него датчик не стартует из режима низкого потребления. Вызов begin проверяет связь, а setup именно запускает измерение.
Второй затык был с типом данных. Я сравнивал результат getHeartRate с числом 100 напрямую, а метод возвращает float, и при строгом сравнении условие никогда не выполнялось. Плюс я забыл про единицы: пульс это уд/мин, а SpO2 это проценты, и их нельзя сравнивать с одним и тем же порогом.
Личный опыт: тревога по SpO2
Первый полезный скетч на этом датчике у меня был сторожевым: когда пульс уходил выше 100 уд/мин или сатурация падала ниже 94 процентов, зажигался светодиод и в Serial уходило сообщение. Логику я отлаживал в симуляторе, и там же проверял границы: на 100 уд/мин тревога ещё не срабатывала, а на 101 срабатывала, и то же самое с сатурацией на 94 и 93 процентах.
Потом я добавил в скетч счётчик срабатываний и период в 10 секунд, чтобы не получить спам от одного плохого чтения. Правило получилось такое: если условие тревоги держится три чтения подряд, только тогда включаем сигнал, а при нормальном значении сразу сбрасываем счётчик в ноль. Такая задержка в несколько секунд совпадает с тем, как ведут себя настоящие медицинские приборы, и убирает ложные срабатывания от единичного артефакта.
Подключение по проводам
- VCC датчика к 3.3 В, GND к общей земле
- SDA к A4, SCL к A5 на Arduino Uno и Nano
- Подтягивающие резисторы 4.7 кОм на SDA и SCL, если их нет на модуле
- Общий GND обязателен, иначе I2C не заработает
- Проверка адреса: 0x57, в списке должен быть ровно один датчик
Про подтяжки стоит сказать отдельно. Шина I2C работает на открытом коллекторе, и без подтягивающих резисторов уровень на линии не определён. На большинстве модулей MAX30102 они уже распаяны, но на голом датчике или на плате, где выпаяли перемычку, их нужно поставить. Если плата работает через раз при разной длине проводов, первым делом проверьте именно их.
Ещё один приём, который сильно ускоряет отладку: выведите в Serial результат begin отдельной строкой. Если датчик не найден, вы увидите это сразу, а не будете гадать по нулям в показаниях. Второй полезный вывод: печатайте raw-значения, если библиотека это позволяет. По ним видно, что сигнал живой, даже когда рассчитанный пульс ещё считается.
Авторская позиция: что взять новичку
Для учебных задач MAX30102 удобен тем, что библиотека одна на оба чипа и примеры в ней уже написаны. Берите версию с адресом 0x57 и вынесенными SDA и SCL, чтобы её можно было повесить на макетку проводами. И начинайте с простого: выведите пульс в Serial раз в секунду и убедитесь, что число меняется. Только после этого добавляйте пороги и логику тревоги. Для реальных измерений нужно ещё и правильное положение датчика на пальце, а в этом помогает симулятор: в нём вы сразу видите, что код реагирует на значения, а не зависает.