Ошибаться полезно. Когда исправление одной ошибки уже не добавляет две новые, продукт начинает взрослеть. Мы третий год разрабатываем смарт-браслет для предприятий и решили написать лонгрид о его начинке и тех граблях, на которые наступили за это время. Возможно, вы вместе с нами зададитесь вопросом “как на эти грабли вообще можно было наступить?”. Или после прочтения расскажете о граблях, которые у нас впереди. Будем рады обсудить ваш и наш опыт в комментариях. Чтобы упорядочить лонгрид, мы разделили его на три смысловых блока: Зачем нужен ещё один смарт-браслет и что у него внутри? От реализации каких запросов заказчиков мы решили отказаться и почему. Какие ошибки мы совершили в процессе разработки и эксплуатации. Мы постарались, чтобы содержание блоков было независимым. Поэтому блоки можно читать в произвольном порядке. Меня зовут Даниил, я работаю в ГК НИИ СОКБ и отвечаю за разработку носимых устройств. Мы начинали с indoor-навигации, но поняли, что её дорого разрабатывать и сложно продавать. Параллельно нам поступали запросы на навигацию вне помещений (outdoor). Эта задача показалась нам проще. Координаты не нужно считать самим, их можно взять у GPS и ГЛОНАСС. Мобильный интернет есть практически везде, поэтому с передачей данных на сервер тоже не было проблем. Потенциальные клиенты сказали нам, что кроме треккинга местоположения им нужно знать, что происходит с работником – фиксировать падение и регистрировать пульс, чтобы понимать, к кому нужно отправлять помощь. Ещё было бы неплохо дать работнику возможность отправить сигнал SOS и поговорить с диспетчером, чтобы голосом сообщить о проблеме. Зная, что аппетит у B2B-заказчика приходит во время presale, мы сразу отказались от идеи взять готовый китайский браслет или детские смарт-часы. Обсуждать доработку прошивки и тем более начинки в этом случае можно в партиях от 1000 шт. на условиях предоплаты и сроках от полугода. В общем, не наш вариант. В итоге в 2019 году мы начали разрабатывать смарт-браслет SafeLife, и вот что у нас получилось. Для начала несколько слов о касдеве, дальше по технике. На первый взгляд может показаться, что смарт-браслеты – это очередная причуда работодателей, чтобы чаще штрафовать работников и мешать им работать. В духе китайских дворников, которым дали браслеты и начали штрафовать за неподвижность или выход за границы области уборки. Практически домашний арест на работе.  Касдев показывает, что экономия для заказчиков состоит не в контроле перемещений, когда, например, обходчик должен был сделать обход, но не сделал. Хотя это тоже важно. Ключевое – это снижение числа производственных травм и человеческих жертв. Чтобы работники не начали “случайно” ломать смарт-браслеты, нужно отнестись к ним с долей эмпатии и донести до них пользу, которую они могут принести. Вот несколько примеров: Работник потерялся в лесу, отправил сигнал SOS. Оператор позвонил и вызвал подмогу. Если работник потерялся не в лесу, а там, где нормально ловит GPS, оператор может помочь работнику дойти туда, куда ему нужно. Работник упал и потерял сознание. Оператор об этом узнал. Вызвал помощь. Человека спасли, а не нашли холодным через несколько суток.  На объекте произошла авария. Оператор по пульсу и последним координатам. определяет, кого нужно спасать в первую очередь. По телефону консультирует тех, кому нужна психологическая помощь. Работник случайно зашёл в зону, где сейчас находиться небезопасно. Например, скоро будут начаты взрывные работы или ездит крупногабаритная техника. Браслет на руке работника начинает пищать и вибрировать, предупреждая его об опасности. Внешний вид браслета – нейтральный. Размеры (54х46х18 мм) подобраны так, чтобы браслет на руке не мешал работе и вмещал аккумулятор максимально возможной ёмкости.  Мы смогли разместить в этом корпусе Li-Pol аккумулятор LP603030 емкостью 500 мА/ч. Для его зарядки используется микросхема STC4054 (ST). У неё есть режим предварительной зарядки сильно разряженного аккумулятора. Вообще сильный разряд – это плохо, потому что аккумулятор может начать терять свою ёмкость. Но если он всё таки разрядился, сначала нужна щадящая зарядка. Большой ток в этот момент может навредить батарейке.  Ещё один сценарий, когда можно навредить аккумулятору –  это постоянная зарядка. Если заряжать батарейку как только она немного разрядилась, со временем она начнёт терять свою ёмкость. Чтобы этого избежать, STC4054 позволяет определять приемлемый уровень разряда для начала подзарядки. Когда браслет лежит ночью на зарядке, мы не будем подзаряжать его каждую минуту.  Ещё к аккумулятору подключена микросхема MAX17055. С её помощью мы определяем эффективный % заряда с учётом прогноза деградации. Ещё схема может давать прогноз времени автономной работы. Пока не юзаем. Может быть, добавим в следующих версиях прошивки. Вокруг аккумулятора в браслете две системные платы. Одна с датчиками и питанием. Другая с модулем связи и навигации, микроконтроллером и энергонезависимой памятью. Такое решение позволяет упростить доработки под заказчика. Чтобы изменить канал передачи данных с мобильного интернета на LoRa или любую другую LPWAN, достаточно заменить плату управления, а плата с датчиками останется той же. Оказалось, мобильный интернет есть всё-таки не везде… С мобильным интернетом мы вообще наелись по полной. Оказалось, что доступные в продаже модули сотовой связи и геолокации достаточно громоздкие. В итоге мы остановились на 2G модуле MC60 (Quectel) со встроенными GPS и ГЛОНАСС. GPS и ГЛОНАСС работают одновременно, а не по очереди, как у некоторых других модулей.  Размер модуля связи и навигации 18.7х16.0х2.1мм. Ключевое ограничение – только 2G. Пропускной способности 2G нам хватает. Но оказалось, что сотовые операторы могут отдавать частоты 2G под 4G, чтобы людям с 4G доставалось больше трафика. Это вызывает проблемы на пресейлах. Сложно объяснить заказчику, что на объекте нет 2G, если там отлично работают смартфоны. С тем же сотовым оператором. Но в 4G…  Если подскажете компактные 3G или 4G модули, будем признательны. То, что нашли мы, нас не устраивает: 3G-модуль UG96. 22.5mm × 26.5mm × 2.2mm. 4G-модуль EG95. Размеры 29.0mm × 25.0mm × 2.3mm. Оба модуля больше MC60 и без GPS / ГЛОНАСС. Разместить эти модули и отдельно модуль геолокации в текущем корпусе нельзя. Если увеличить корпус, браслет будет неудобно носить. Поэтому пока 2G. Может быть нас удивит компактностью 5G. Хотя вряд ли… Ещё несколько слов о внутренностях браслетов и перейдем к кейсам. Честно-честно. В качестве микроконтроллера взяли STM32L4. У нас был опыт работы с устройствами STM, поэтому взяли их. Сначала взяли STM32L0, но в нём оказалось недостаточно памяти для расчёта пульса, поэтому взяли контроллер помощнее. У STM32L4 есть приятная особенность – он может получать прерывания от периферии в режиме низкого энергопотребления. Чтобы получить от акселерометра сигнал о падении, не нужно постоянно его опрашивать. В нужный момент датчик сформирует прерывание, и контроллер его получит, даже если практически спит.  Датчики внутри такие. Трехосевой акселерометр/гироскоп LSM6DSL (STMicroelectronics) определяет падение и продолжительную неподвижность. BMP280 (Bosch) измеряет атмосферное давление для определения высоты, на которой находится браслет. MAX30102 (Maxim Integrated) используется для определения пульса. Нам бы хотелось, чтобы датчик пульса на выходе выдавал пульс. Но не тут-то было. Это просто интегральная схема с двумя светодиодами и фотоприёмником. Причём это не проблема конкретного датчика. На рынке нет датчиков с готовыми алгоритмами определения пульса. Их нужно писать самим. Дальше расскажем как это сделали мы. А в завершении раздела расскажем вам о том, как с помощью барометра можно узнать, что работник полез куда ему не следует.  Однажды мы приехали на встречу с заказчиком, положили браслет на стол и он обнаружил у него пульс. После этого переговоры зашли в тупик, сделка не состоялась. Мы решили разобраться в чём дело.  Оказывается, мы не первые. В интернете легко найти видео, где Apple Watch измеряют пульс у рулона туалетной бумаги. Например, такое. Почему так происходит? Любой смарт-браслет измеряет пульс с помощью фотоплетизмографии. Когда сердце сокращается, оно накачивает кровь в сосуды по всему телу. Если светить на сосуд фонариком, в момент сокращения сердца сосуд станет темнее.  Чтобы определить пульсацию сердца, не нужно просвечивать руку насквозь, как на фото выше. Достаточно одного небольшого фотодиода. Светим, считываем данные, оцифровываем, считаем пульс. Делается это так. Сигнал после оцифровки имеет приблизительно такой вид. Приблизительно, потому что в исходном сигнале много шумов, которые мы убираем усреднением и различной фильтрацией. Любопытно, что сигнал отрицательный. Это происходит потому, что фотодиод ловит свет. В случае наливания сосуда кровью он становится темнее, а не светлее. На оси абсцисс - время в миллисекундах Казалось бы, 11 ударов за 10 секунд – это 66 ударов в минуты. Но мы считаем пульс по средней разнице между пиками. Так точнее. Пики выделены красным. На картинке сверху средняя разница примерно 942 мс. (10 с / 0,942) * 6 = 64 удара в минуту.   А это задание со звёздочкой: 84 удара в минуту  Дальше из сигнала датчика выбираются пиковые значения. По ним считается пульс. Чтобы не хранить кривую целиком, пики можно ловить по производной сигнала. В пике производная сигнала должна быть равна к нулю. Это в теории. На практике достаточно ловить изменение знака производной. Если знак поменялся, значит между отсчётами был ноль. Чтобы определить пульс, по нашему опыту достаточно данных за 10 с. К слову, врачи обычно измеряют пульс на запястье за 15 с, так что мы на 30% быстрее. Точность с врачом не сравнивали, но надевали на одну руку наш браслет, а на другую Mi Band. Разница была в несколько ударов в минуту. Близко к погрешности.  Что происходит с этим алгоритмом, когда браслет надет на рулон бумажных полотенец или лежит на столе? В этом случае фотодиод может вместо пульса считать отражение ламп освещения. Программно отличить его от реального пульса не смог даже Apple, поэтому мы пошли другим путём.  В составе пульсометра есть два диода – красный и ИК. Красный используется, чтобы считать пульс. ИК диод мы сначала не использовали, но после фиаско со столом стали с его помощью определять расстояние до поверхности, с которой соприкасается браслет. Теперь браслет измеряет пульс у стола, только если его плотно прижимать. Маленькая, но победа. От рулона туалетной бумаги ИК диод, увы, не спасает. Чтобы выполнять работы на высоте более 2 м, нужен допуск. Если у работника нет допуска, компания может получить штраф. Если у работника нет опыта высотных работ, и он самонадеянно полез наверх, это может закончиться трагично. Обычно в первый раз работник лезет осторожно и дело не заканчивается трагедией, поэтому важно зафиксировать этот факт и не дать ему полезть наверх в следующий раз.  Видеонаблюдение не всегда помогает определить, кто из работников полез наверх. Все выглядят одинаково. У всех каски, у всех спецодежда. Зато смарт-браслет у каждого свой. Если работник вдруг решит его снять и отдать другому, факт снятия будет обнаружен. Датчики пульсометра можно использовать не только для измерения пульса ;) Осталось дело за малым. Нужно научить браслет измерять высоту. Для этого мы встроили в браслет датчик давления BMP280. Производитель заявляет, что с его помощью можно измерять высоту с точностью до 1 метра. Брехня. Даже если достаточно точно измерять атмосферное давление, оценить по нему высоту над уровнем моря нельзя. На атмосферное давление сильно влияет география и погода. Если сейчас на Красной площади 740 мм.рт.ст., это не значит, что через полчаса на небе не появятся облака и давление не изменится. Также это не означает, что в Тулузе, которая находится на той же высоте над уровнем моря, будет 740 мм.рт.ст., даже если там такая же погода, как в Москве. Чтобы узнать абсолютную высоту, на которой находится работник, нужно постоянно делать поправки. Например, разместить в областях, где могут находится работники, устройства на определенной высоте и считать их показания эталонными. Сложно, но нужна ли нам абсолютная высота? Оказывается, что нет. Заказчику нужно знать, что работник полез, куда не следует. Для этого достаточно периодически измерять атмосферное давление. Если за 5 минут давление снизилось на десятые доли мм.рт.ст., то скорее всего сотрудник куда-то поднялся. Погода редко меняется так быстро. Две основные задача касдева – это выяснить, какая проблема стоит за хотелками заказчика (сокращённо ХЗ), и оценить, можно ли её решить с адекватными затратами. В этом разделе мы расскажем, какие хотелки мы не реализовали и почему.  ХЗ: защита от пыли и влаги по стандарту IP68, 6 – устройство должно быть защищено от пыли, 8 – устройство можно погружать на метр под воду на полчаса. По умолчанию наши браслеты защищены по стандарту IP65. Этого достаточно, чтобы комфортно использовать браслеты на улице, не боясь снега и дождя. Чтобы сделать IP68, нужно убрать микрофон и отказаться от голосовых вызовов. Микрофоны с IP68, как в iPhone, дорогие. Предложили заказчику выбрать что нужнее – голосовые вызовы или IP68. Выяснилось, что IP68 был нужен для регистрации падения человека в воду. Причём речь идёт не о том, чтобы сохранить в этом случае браслет, а о том, чтобы своевременно узнать о падении и помочь человеку выбраться. Если человек упал в очистные сооружения, он не всегда сможет выбраться сам.  Падение в воду определить сложно. Даже если акселерометр зафиксирует падение в полёте, факт падения нужно ещё передать на сервер. Сделать это, когда браслет находится под водой практически невозможно. Вода поглощает сигнал. Нужно или пытаться усиливать сигнал под водой, или отказаться от регистрации падения в воду. Заказчик выбрал последнее. Есть промышленные объекты, на которых фразу “из искры возгорится пламя” понимают буквально. На таких объектах женщинам запрещают носить капроновые колготки, а к оборудованию предъявляют требования к искробезопасности. Чтобы доказать, что оборудование искробезопасно, нужно пройти сертификацию.  Однажды мы прошли этот квест и получили сертификат на смарт-браслет для indoor-навигации. Сертификат позволял использовать браслеты во взрывоопасных зонах до 0 класса включительно. Только вряд ли бы кто захотел использовать браслеты после выполнения всех требований. Для сертификации от нас потребовали:  Залить все внутренности компаундом. После этого нельзя ни перепрошить браслет по проводу, ни заменить в нём аккумулятор.  Покрыть корпус антистатической краской, которая вместе с компаундом прилично поглощала сигнал.  До покраски антистатиком наш смарт-браслет выглядел так. Устройство получилось гармонично непригодным к использованию. Выглядит страшно. Не поддаётся ремонту (только замене). Регулярно теряет связь. Больше таких игрушек не делаем и вам не советуем. В одной из первых партий браслетов был обнаружен досадный баг. Когда аккумулятор разряжался ниже минимального уровня (бывает и так), попытки записи в файловую систему приводили к тому, что она разрушалась. В итоге после зарядки браслеты не могли пройти первоначальную инициализацию.  Самое смешное, что файловая система ломалась, когда браслет пытался записать в неё информацию о том, что он разрядился. Мы не ожидали такого поведения и, к сожалению, не отловили ошибку до передачи партии устройств заказчику. Партию пришлось отозвать и перепрошить. Но больше мы на эти грабли не наступали. Тестирование поведения при глубоком разряде включено в состав обязательных проверок при приёмке новых версий ПО.  Чтобы не защищать от пыли и влаги разъём для зарядки, мы реализовали зарядку браслета с помощью подпружиненных контактов (Pogo Pin). Нам казалось очевидным, что устройство нужно класть на зарядку, чтобы “гвоздики” на площадке совпали с металлическими контактами на корпусе браслета. В этом случае на лицевой стороне браслета загорится диод. “Уж это-то пользователи точно заметят!” – наивно думали мы.  Работники не заморачивались “огонёчками и гвоздиками” и клали браслет на зарядку не той стороной. Устройство не заряжалось, и на следующий день не было готово к работе. Работник инструкций не читает, на браслет не смотрит. А мы крайние. Чтобы больше не возвращаться к этим проблемам, мы добавили в зарядную станции магнит. Теперь браслет нельзя положить на зарядку неправильно.  Может возникнуть вопрос, почему мы не сделали беспроводную зарядку. Всё просто. Модули беспроводной зарядки больше и дороже. Плюс катушку беспроводной зарядки нужно отдельно и надёжно экранировать, иначе остальной браслет будет как кастрюля на индукционной плите. Проложить несколько слоёв фольги недостаточно. Например, у современных смартфонов многоступенчатая защита аккумуляторов от перегрева. Но даже она не всегда помогает. Можно вспомнить хотя бы историю c Samsung Galaxy Note 7.  Мы защитили аккумулятор в браслете самым простым и надёжным путём – ограничили ток зарядки, поэтому наши рукописи браслеты не горят. В первой версии прошивка не опрашивала датчик GPS/ГЛОНАСС, если акселерометр сообщал, что браслет неподвижен. Так мы хотели сэкономить батарейку. Вместо этого получили пробелы в треке.  Первое же тестирование показало, что трек браслета в машине выглядит так: точка, где сотрудник сел в машину, пару точек в пути при торможении на светофоре, и точка, где сотрудник припарковался. В промежутках между точками акселерометр сообщал, что устройство неподвижно. Посмотрели мы на этот трек. Вспомнили, как на уроках физики нам рассказывали про относительность состояния покоя. В итоге отказались от акслерометрозависимости - и трек стал лучше, и не дергаем GPS модуль при каждом чихе. Еще и модуль меньше потребляет при корректировке уже известной позиции. Мы решили, что работник не должен выключать или перезагружать браслет. Это было ошибкой. Собрав первые прототипы, мы решили проверить их на себе. Первая проблема, с которой мы столкнулись – это зависания при потере связи. Когда устройство лежит у разработчика на столе, потерь связи практически не бывает. В реальной жизни они встречаются сплошь и рядом – зашёл в метро, спустился на парковку и т.д. Прототипы устройств зависали при первой же потере связи. Сделать с ними что-либо было нельзя. Только ждать полной разрядки. Найти и исправить эту проблему было несложно. Но если устройства у заказчика по какой-то причине зависнут и их нельзя будет оперативно “привести в чувство”, со временем от наших устройств откажутся. Чтобы не наступать на такие грабли, мы добавили watchdog, который автоматически перезагружает браслет через несколько минут после зависания.  Ещё мы стали собирать с устройств логи, чтобы в случае зависаний понимать, по каким причинам они зависают. Логи позволяют нам исправлять проблемы заказчиков ещё до того, как они о них узнали.  Проблему с зависаниями нам удалось решить, не давая работнику выключать браслет самому. Но позже мы столкнулись с проблемой хранения браслетов и здесь без кнопки выключения, увы, не обошлось. Устройства нужно доставлять и хранить заряженными. Проблема здесь не в том, что пользователям лень заряжать браслеты перед первым использованием. Если хранить браслеты разряженными, их аккумуляторы начнут терять ёмкость и будут требовать более частой подзарядки. Чтобы не вредить аккумуляторам, мы добавили возможность выключения браслетов по длительному нажатию его двух кнопок. У браслетов стандартные часовые ремешки. Застежка, две силиконовые половины и две шпильки. Мы относимся к своим устройствам довольно бережно и не думали, что крепление ремешка нужно проверять на прочность. Оказалось, зря. После одного из пресейлов браслеты и ремешки вернулись к нам по отдельности. В дополнение потенциальный заказчик написал замечание про хлипкое крепление. Нам ничего не оставалось, как приложить всю свою молодецкую удаль и начать вырывать браслеты из креплений самим. Решение проблемы оказалось предельно простым. Мы сделали глубже отверстия для креплений в корпусе браслетов и начали ставить более длинные шпильки. Больше ремешки никто не вырывал – ни мы, ни заказчики. Мы решили, что не нужно поставлять вместе с браслетом USB-адаптер и micro-USB провод для зарядки. Дело не в жадности. Не было никаких проблем добавить 200-300 руб. к цене в прайсе и поставить всё вместе.  Мы искренне считали, что у каждого человека есть USB-адаптер и что у большинства наших пользователей есть micro-USB кабель для заряда телефона и второй кабель будет лишним. Наивно, правда?  Оказалось, что у части работников Type-C. Нашлись работники с айфонами и Lightning. Но даже те работники, у кого были micro-USB зарядки, не могли использовать их для зарядки наших браслетов.  Причина проста – большинство людей оставляет заряжать гаджеты на ночь. Если гаджетов несколько, нужно несколько зарядок. Никто не будет вставать посреди ночи, чтобы поменять гаджет на зарядке.  Нам оставалось только признать, что мы были неправы. Теперь в комплекте с каждым смарт-браслетом идёт полноценная зарядка с проводом и адаптером. Устройств и софта без ошибок не бывает. Лояльность заказчиков, как внешних, так и внутренних, зависит от того, как быстро ошибки исправляются и исправляются ли они вообще.  Спустя три года разработки смарт-браслетов многие ошибки кажутся нам глупыми. Но они дали нам необходимый опыт embedded-разработки, получить который иначе мы не могли. Начинающим и продолжающим embedded-разработчикам мы можем посоветовать не пренебрегать тестированием и тестировать нещадно. Придумывайте больше кейсов, даже таких, которые могут показаться вам фантастическими. Залезая в незнакомую предметную область, чаще устраивайте мозговые штурмы, где отпускайте фантазию на волю. Так вы сможете придумать кейс раньше, чем он произойдёт у заказчика.  N.B. Какими техниками мы пользуемся в тестировании ПО, можно прочитать в нашей прошлой статье.  Мы не станем утверждать, что в наших устройствах не осталось багов. Не исключено, что в одной из следующих версий прошивки найдётся какая-нибудь противная “детская болячка”. Но мы скорее всего вылечим её до того, как она попадёт заказчику.  Давайте обсудим в комментариях, с какими типовыми проблемами вы сталкивались в embedded-разработке и как вы их решили. Будем благодарны обратной связи по тем проблемам, которые мы уже решили – вместе посмеемся какие мы дураки или обсудим как эти проблемы можно решить лучше. До встречи в комментах! P.S. Если после прочтения не стало клонить в сон и появилось желание попробовать наши устройства на своих (или чужих) работников, оставьте заявку на нашем сайте. Мы свяжемся с вами в течение двух дней.  Инженер-разработчик