| Датчик пульса: запуск (01.01.2026). |
|
| 2026 - Январь | |
| 01.01.2026 14:55 | |
Подготовка к тестированию датчика велась во много этапов: - изучение интерфейса I2C. У него даже при настройках "по умолчанию": глючность некоторых I2C-устройств - порождает жесточайший зашквар; - расчёт для I2C номиналов всех подтягивающих резисторов, определение максимальной длины провода. Тоже нетривиальная задачка, особенно с учётом огромной дезинформации в интернете; - компактная пайка на макетной плате и помещение всего в дорожную мыльницу. Печатные платы стоят непомерно дорого, корпуса РЭА - тоже. Но и этого оказалось мало: - продавец положил датчик без каких-либо надписей - что породило проблему: неизвестно напряжение питания. Общее для всех датчиков (в т.ч. 1 и тот же датчик может иметь разное напряжение питания от модели к модели) - 3.3В, оно и использовалось. Но оказалось ещё круче: продавец, по ошибке, вместо MAX30100 положил MAX30102 (и у него максимум напряжения - 3.3В). А для них - совершенно разные библиотеки, названия функций и алгоритм работы. Пока не догадался, неизвестно: сколько бы корячился с лучшей для MAX30100 прибалтийской библиотекой, - без какого-либо результата; - для MAX30102 существует также несколько библиотек. И прикол в том, что аж на самом гитхабе - глючная: даже не компилируется. Поиск библиотек привёл к 3 перлам: существует ещё и датчик MAX30105, для 102 и 105 - одинаковая библиотека, последняя библиотека (SparkFun MAX3010x Pulse and Proximity Sensor Library v.1.1.2) - датируется 06.2022 (что гораздо лучше 100 с его 201x годами). Возможно, она даже с 100 сможет работать; - с целью создания помехозащищённости I2C на большой дистанции - нужно линии VCC и SDA пустить по одной сдвоенной паре проводов, SCL и GND - по другой. Никогда в доме не было нормальных сдвоенных проводов - а тут ещё ультратонкий (чтобы паразитная ёмкость была меньше) и длинный нужен. Разбираясь в предновогодний день, решил всё из-под ванны запихнуть в нишу стены ванной комнаты - среди барахла обнаружился ЗИП для системы защиты от протечек. А в нём - моток почившего ныне сдвоенного провода ШТЛП 2(С) (теперь есть только ШТЛП 2 - и сильно дороже). Гибкий, тонкий, хорошо лудится, плохо припаивается, ломкий без изоляции, плохая кучность волосков - необходима жёсткая фиксация в месте пайки и рядом с ним. Что ж, провод найден - можно начинать работать: - отверстия в мыльнице для ШТЛП пришлось расширять сверлом 4мм: плоский, но широкий. Фиксация - в дальнейшем термоусадками: нет ни спичек, ни зажигалок (ни дома, ни на работе, ни ашан не привёз в заказе). Телом паяльника обжигать - чрезвычайно неудобно, бросил: пламя всю термоусадку разом стягивает - а тут не только подлезать с 4 сторон надо, но и двигать паяльник по длине медленнее. А если жалом жарким прижигать - то вообще зашквар получается; - провода размечаются 4 разными цветами: ошибки в пайке недопустимы; - самое сложное место, провод возле датчика, - обрабатывалось в 3 этапа: штырями в макетную плату, заламывание изоляции и лужёных частей проводов в отверстия платы, приклеивание термоусадки проводов к печатной плате. 4 этап: стянуть термоусадку дополнительно шпагатом - позже. Для проводов и шпагата - пришлось рассверливать отверстия сверлом 2мм. Далее - серия работ, краткий результат которых описывает голлум из Властелина колец: - включаю в сеть адаптер 12В - датчик не работает. На секунду показалось, что из Arduino вышло немного дыма, - но у Arduino лампочка горит. Принюхался - ничего - включаю в USB ПК. Монитор гаснет намертво. Вытаскиваю USB - монитор включается обратно. Отнёс обратно на кухню, быстро осмотрел всё, вернулся обратно, вставляю в USB ПК - норма. Ничего не понятно, уже подозрительно; - датчик не работает. Это означает: либо датчик сломан, либо длина провода 1м с помехами, либо какие-то из подтягивающих резисторов рассчитаны неверно, либо шина для подтягивающих резисторов I2C неверна, либо I2C вообще сгорел (в т.ч. из-за предыдущих проблем), либо иные причины; - начинается беготня комната-кухня, кухня-комната - в попытке понять ситуацию. Дело даже не в негодовании при разрушении настолько аккуратно припаянных резисторов: их, из-за компактности, ещё и разъединить сложно. Например, заземляющие резисторы A4 и A5 пришлось откусывать именно кухонными ножницами. При этом, 1 из резисторов откусывается совсем под корень (к слову, удалось его залудить прямо внутри оболочки: флюс волшебным образом припой затянул туда). Увеличиваешь номиналы подтягивающих резисторов I2C, переключаешь их на 3.3В, 5В - без толку; - взял другую плату Arduino, пустую. Существует сканер устройств I2C: I2C-сканер. Исходники опять везде различаются - удалось найти работоспособный вариант (минут через 200 размещу в полезных исходниках: дайте в себя прийти). Другая плата - сканируется за секунду, плата в мыльнице - зависает навсегда на первом же адресе 8. Всё, конец? Тут вступает в дело случай: - если хочешь найти какую-то мелкую деталь на полу - свети на неё в темноте горизонтально фонарём. Применил это к макетной плате - нормально, применил к датчику - нормально. Применил к кусочку макетной платы - между SDA и SCL одинокий волосок из ШТЛП (а волоски у него - ну совсем тонкие). Прозваниваю мультиметром - коротыш. И судя по тому, что волосок не сгорел, - низкоамперный коротыш. 1 проход канцелярского лезвия - сканер показал наличие устройства с адресом 0x57; - но датчик при этом - не горит; - также важно знать: сканер I2C - работает на 9600бод, 100 - на 9600бод, 102 - на 115200бод. Чтобы датчик показал красный свет и считал палец - нужно провести простые манипуляции (теперь простые - до этого, действительно, чуть не случился инфаркт жопы): - в глобальное. Подключение библиотек ( #include "MAX30105.h", #include "heartRate.h"). Объявление глобального объекта датчика (MAX30105 *oMAX30105); - в setup(). Инициализация объекта (oMAX30105 = new MAX30105();). Инициализация датчика (if (!oMAX30105->begin(Wire, 10000L) - где 10000L: номинал частоты I2C, можно и I2C_SPEED_FAST поставить - но пока стрёмно). Выставление настроек по умолчанию для сенсора (oMAX30105->setup();). Включить красный светодиод (oMAX30105->setPulseAmplitudeRed(0x0A);). Выключить зелёный светодиод (oMAX30105->setPulseAmplitudeGreen(0);); - в loop(). Получение значение с датчика (long lValue = oMAX30105->getIR();). Проверка числа на ударность (if (checkForBeat(lValue) == true)). Чуете, чем пахнет? Ненадёжностью: - и вот теперь - в дело вступают все подтягивающие резисторы, скрупулёзный расчёт которых делался ранее, и которые были все откусаны к хренам сейчас - припаивать их обратно: - когда были припаяны резисторы 1кОм SDA и SDL к линии 5В - всё опять не заработало. Зато когда были припаяны к линии 3.3В (что соответствует VCC датчика, а не платформы) - данные стали не просто более похожи, но и стали появляться чаще. Без подтягивающих резисторов - данные не просто искажались: часть из них терялась; - а когда к SDA и SCL подтягивающие резисторы 82кОм на GND припаялись - совсем шоколадно стало. А дальше - ложка дёгтя, которая может ошибочно поставить под сомнение необходимость подтягивающих резисторов. Как интерпретировать полученные значения? А никак: это просто число, отражённое значение с ИК-светодиода как эффект Доплера, - и его номинал не имеет никакого значения. Где-то внутри библиотеки, в checkForBeat: решается, что за число на датчике, - и является ли оно пульсом: вот она, индикация датчика. А время между ударами - изволь сам рассчитывать: хоть в мс, хоть в нс. К слову, скорость измерения как ТТХ датчика - 400мкс, то есть холтеры со своей частотой измерения 70-100-2000Гц - нервно курят в сторонке. Остаются вопросы: - как присобачить датчик к пальцу на постоянной основе: чтобы и не съезжал, чтобы палец не потел, чтобы палец не пережат был; - зелёный светодиод - датчик кислорода ли. И как получить этот кислород; - можно ли удлинить провод с 1м до 2м и более (уже поздно удлинять: монтажная ненадёжность паечных мест ШТЛП, запасов больше нет); - мешают ли друг другу зелёный и красный светодиоды датчика. Какой интервал надо выдерживать, чтобы они не исказили друг друга; - каким числом IR считать, что палец неплотно прижат или убирается; - когда закончится СВО, и нас разбанят, и мы получим возможность использовать качественные ресурсы вместо отечественного говна? (добавлено 02.01.2026) Разное: - датчик при "включении красного светодиода" - светит одновременно К- и ИК-светодиодами; - можно было лудить пару миллиметров ШТЛП вместо 5 - и проблемы КЗ бы не было; - число ИК - можно расценивать как силу биения сердца, при одинаковой силе прижима к пальцу; - датчик ещё температуру тела определять умеет (->setup(0), ->enableDIETEMPRDY(), ->readTemperature()); - в примерах часто упоминается ЧСС (которая должна вычисляться в диапазоне строго 1мин) - когда речь идёт о пульсе (вычисление за неизвестные точно Nсек); - в даташите регистр пульса соответствует 0x0C, во всех примерах интернета - используется число 0x0A (SpO2 Configuration). А пульс ли вообще был получен числом? Похоже, речь идёт о другом: силе свечения светодиодов (тогда почему не 0xFF?); - заглянул внутрь обоих пульсоксиметров. Красный светодиод светит сверху, считывающий датчик снизу - палец просвечивается. Это точно не просто подсветка: защемил свёрнутый вдвое лист бумаги вместе с пальцем - данных нет. Тогда что это за датчики? Ну вот, опять... (добавлено 03.01.2026) В примерах интернета есть 1 повсеместный баг (создаётся впечатление, что все друг у друга воровали одно и то же): - нельзя писать строку игнорирования биения, вида if (lValue < 50000), - пусть этим занимается только checkForBeat; - даже если палец соскальзывает с датчика - биения должны регистрироваться дальше. Потому что этот датчик нормально на продолжительное время - хрен зафиксируешь (и, похоже, не с той стороны кабель от датчика провёл: не обмотаешь ничем); - также, действительно, это число - сила удара сердца. И если при нормальном расположении датчика вдруг регистрируется 50000 - сердце что-то ослабло - и это тоже должно быть зафиксировано. (добавлено 04.01.2026) Да, 0xAA надо заменить на 0xFF (а точнее - на 255: не с адресами работа идёт): - светодиод светит очень ярко, как в пульсоксиметре (что может быть опасным для глаз); - данное повышение точности, понятно, увеличивает энергопотребление - но оно вторично; - получается, данный датчик лучше пульсоксиметра: в пульсоксиметре палец просвечивается насквозь, в датчике - достаточно первых миллиметров ткани; - числа с датчика увеличиваются с 119000 до 125000-140000; - сильного нагрева - не замечено. В интернете пишут про ток 50мА - не измерял. Датчик был прислонён к пальцу настолько, насколько получается без фиксации (несколько минут), - корректная частота выведения показаний в COM-порт (соответствует пульсу на шее). Часовое слежение за датчиком показало: при отсутствующем пальце - проскакивают значения до 5000 - их нужно отсеивать (не 50000, как в примерах интернета). Датчик меряет пульс, отражаясь от ЛДСП. Теперь понятно, почему банан имеет пульс и кислород: всё зависит от отражаемой поверхности. Страшно подумать, что будет, если датчик поднести к зеркалу. В Arduino IDE есть опция: "Инструменты - Плоттер по последовательному соединению". Лучше бы не включал: датчик чётко показал мою синусовую аритмию из ЭКГ (хоть и не это вообще нужно было изначально) - хорошая замена ЭКГ в этом вопросе. То есть, COM-порт сохраняет ещё и время (с точностью до мс). Вопрос в том, тормозит ли сам COM-порт: ведь это было бы чётким триггером сохранять телеметрию только на SD. (добавлено 13.01.2026) Шпагат удобнее продевать швейной иглой, увеличив размер отверстия до 2.5мм и выше. (добавлено 20.01.2026) Купленный MAX30100 - убожество, непригодное к использованию и сразу отправленное в мусорку: - отверстия для фиксации только на 1 стороне платы; - резисторы справа больше по высоте, чем сам датчик, - палец толком не положишь. Да и сам датчик к телу не приложишь, если не кончик пальца нужен. |
|
| Обновлено ( 20.01.2026 22:30 ) |