[Перевод] Умная перчатка для велосипедистов

ed1c828378aee59e3db827ddef88f00e.jpg

Перевод с сайта instructables.com, автор проекта: Matlek

В данной статье я подробно расскажу процесс изготовления «умной перчатки» и её светодиодной панели, предназначенных для повышения безопасности велосипедистов и других людей, путешествующих по дорогам. Сначала можно посмотреть небольшую демонстрацию работы:

Как это работает


В перчатке находится плата Arduino, собирающая данные с гироскопа и акселерометра. Код использует модель «крохотного машинного обучения» tinyML и распознаёт жесты: каждое движение руки анализируется и превращается в сигнал (рука наклоняется влево, вправо, вперёд, назад, и т.п.). Сигнал отправляется по Bluetooth (BLE) на другой микроконтроллер, к которому подсоединена светодиодная матрица (которую, например, можно закрепить на рюкзак). Сообразно полученному сигналу матрица выводит определённые последовательности символов — так, чтобы другие водители и велосипедисты могли понимать, что собирается сделать велосипедист (к примеру, это могут быть стрелки влево, вправо, или текст).
df805bc7b579ebde0c106c350b72569a.jpg

a469344c9367e165c377a99ba3dd6b25.jpg

6ba718790f41540edb52a936cee16256.jpg

fc4729a733cc7d0db81c6c3a2067c5dc.jpg

Происхождение проекта


Во-первых, я езжу на велосипеде на работу, и провожу в седле более часа в день (проезжая порядка 22 км). Это всегда интересно, однако я живу в одном из самых густонаселённых городов Франции, где часто происходят происшествия с участием автомобилей и велосипедистов. Также Марсель — худший во Франции город для велосипедистов — там отчаянно не хватает велодорожек. Поэтому данный проект посвящён как увеличению безопасности велосипедистов, так и попыткам обратить внимание городских властей на эту проблему.

Во-вторых, этот проект поможет всем участникам движения пообщаться и лучше понимать друг друга. С моей точки зрения большая часть неприятностей, происходящих на дороге, связана с тем, что некоторые участники движения неправильно поняли других, что в результате привело к испугу, а потом к агрессии. Мне хочется, чтобы такое устройство помогло участникам движения лучше понимать друг друга. Стрелки показывают направление, а ещё можно выводить текст по буквам (однако я целиком и полностью выступаю за вежливые и конструктивные надписи, во избежание конфликтов).

Почему «умная перчатка»?


Я начал работу над проектом зимой, и холодная погода мотивировала меня на то, чтобы закрепить устройство на перчатке. Но я быстро понял, что идея была не очень хорошей, потому что в нашей местности летом довольно жарко. Поэтому я решил, что лучше всего будет поместить устройство в коробку и закрепить на руке. Но поскольку я не знал, как назвать его по-другому, я решил оставить слово «перчатка» в названии.

«Умная» происходит от техники машинного обучения, которую я использовал в данном проекте.

Вдохновение


Проект в основном является смесью двух других проектов. Я не начинал работу с нуля, а пользовался их наработками, которые потом развивал далее. Вот, чем я вдохновлялся при разработке:
— распознавание жестов при помощи Arduino Nano 33 BLE SENSE.
— не какой-то конкретный проект, а концепция использования светодиодных матриц для велосипедистов. Таких проектов полно — некоторые используют рюкзаки с интегрированными панелями, другие просто предлагают готовую матрицу, которую можно поместить куда угодно. В любом случае, эти светодиодные матрицы управляются при помощи пульта дистанционного управления, а не распознавания жестов.

Комплектующие


Для 3D-печати — 3D-принтер или доступ к таковому.

Электроника


  • Arduino Nano 33 BLE SENSE;
  • Ещё один МИ с BLE (Arduino Nano 33 BLE, Arduino 33 BLE SENSE, Arduino nano 33 IOT, ESP32, и т.д.). Я решил использовать плату на ESP32.
  • Светодиодная полоска (WS2812B). Я использовал 160 светодиодов, чтобы получить матрицу 20×8;
  • Четырёхуровневый буфер с 3 В до 5 В: 74AHCT125.
  • Конденсатор на 1000 мкФ.
  • Переключатели SPST, 3 шт.
  • Макетная плата.
  • Провода.
  • Батарейка 9 В.
  • Внешний аккумулятор.

Другое


  • Винты и гайки М3.
  • Застёжка-липучка.

Шаг 1: подготовка (МИ, код)


07a44e2e072851f0f339a397af103c42.jpg

bc741d2d1a288edc85e00b72bc5c2ba6.jpg

Прочитав статью про Arduino и машинное обучение, я решил тоже попробовать. Поскольку в последнее время появилось несколько новых плат Arduino Nano, я сделал сравнительную табличку, чтобы сделать наилучший выбор перед покупкой.

f1564867f352dd2048484af0b5be28dc.jpg

Все платы интересные, однако для распознавания жестов я мог использовать только одну — Arduino Nano 33 BLE SENSE. Лишь у неё есть нужные датчики и поддержка Tensorflow Lite. Ещё один интересный момент — на платах Arduino Nano 33 IOT, BLE и BLE SENSE есть собственный Bluetooth, поэтому любую из них можно использовать на светодиодной матрице для приёма BLE сигналов.

Загруженный в плату код основан на множестве различных программ для Arduino, найденных мною при разработке. Поэтому перед началом работы я решил проверить их с найденными мною примерами.

Поиграемся с BLE


В данном проекте связь по Bluetooth имеет решающее значение, поскольку именно так сигнал отправляется с датчиков на светодиодную матрицу. До этого я никогда не связывал две платы Arduino по BLE. Поэтому я практиковался со следующими примерами из библиотеки ArduinoBLE:

  • Скетч LedControl, используемый с платой Arduino Nano 33 BLE Sense и кнопкой с притягивающим резистором, подсоединённым к контакту 2. Пример опрашивает BLE-периферию, пока не найдёт сервис с UUID 19b10000-e8f2–537e-4f6c-d104768a1214. После его обнаружения и установления соединения он будет удалённо управлять периферийным светодиодом BLE по нажатию кнопки.
  • Скетч для светодиода и Arduino Nano 33 IoT.

К сожалению, со скетчем для светодиода у меня возникло множество проблем — 3 платы «сломались» при его загрузке. Понятия не имею, в чём там была проблема, но я решил заменить плату Arduino на другой МИ с BLE — плату ESP32. С новой платой я использовал следующее:

  • Скетч BLE_write из библиотеки BLE ESP32 ARDUINO. Я добавил несколько изменений, чтобы она работала с платой Arduino Nano 33 BLE SENSE. На шаге 10 вы сможете сравнить скетч BLE_write и скетч Smartglove_BLE_LED-matrix, который я написал и загрузил.

Поиграемся со встроенными RGB светодиодами


Вы знали, что у платы Arduino Nano 33 BLE SENSE есть встроенные RGB светодиоды? В данном проекте они пригодятся для проверки правильной работы распознавания жестов. Мы должны проверять, что сигнал был отправлен на светодиодную матрицу — однако поскольку панель, скорее всего, находится на спине велосипедиста, ему будет трудно понять, что распознавание жестов сработало и сигнал был отправлен.

Тут не было ничего сложного, я просто немного подправил пример Blink. Из кода видно, что красный светодиод находится на контакте 22, зелёный — на контакте 23, синий — на контакте 24. Входной сигнал LOW включает светодиод, HIGH — выключает.

const int LED_BUILTIN_RED = 22;
const int LED_BUILTIN_GREEN = 23;
const int LED_BUILTIN_BLUE = 24;

// функция setup запускается один раз после включения или перезагрузки платы
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN_RED, OUTPUT);
  pinMode(LED_BUILTIN_GREEN, OUTPUT);
  pinMode(LED_BUILTIN_BLUE, OUTPUT);
}

// функция loop повторяется вечно
void loop() {
  digitalWrite(LED_BUILTIN_RED, LOW);   // включить LED (HIGH – уровень напряжения)
  delay(1000);                       // подождать секунду
  digitalWrite(LED_BUILTIN_RED, HIGH);    // выключить LED, понизив напряжение до LOW
  delay(1000);                       // подождать секунду 

digitalWrite(LED_BUILTIN_GREEN, LOW);   // включить LED (HIGH – уровень напряжения)
  delay(1000);                       // подождать секунду
  digitalWrite(LED_BUILTIN_GREEN, HIGH);    // выключить LED, понизив напряжение до LOW
  delay(1000);   // подождать секунду
  
  digitalWrite(LED_BUILTIN_BLUE, LOW);   // включить LED (HIGH – уровень напряжения)
  delay(1000);                       // подождать секунду
  digitalWrite(LED_BUILTIN_BLUE, HIGH);    // выключить LED, понизив напряжение до LOW
  delay(1000);                       // подождать секунду
}

Поиграемся с распознаванием жестов и tinyML


Наконец, я изучил руководство по использованию машинного обучения на Arduino, и попрактиковался с примером распознавания жестов. Пример делится на три основные части:

  • Распознавание данных с программой IMU_Capture (и Arduino Nano 33 BLE sense);
  • Обучение модели на записанных данных на google colab (на компьютере);
  • Использование обученной модели на Arduino с IMU_Classifier для распознавания образов (опять на плате Arduino).

Шаг 2: перчатка 1/6 (электроника)


ba28cc2ac6149023e6d7ddea6cb5946b.jpg

0a2f76e8a7384532f64884d6d6bc4b45.jpg

61408eac67c8146c6c72d15ce8066b1d.jpg

2308e25f1bff5c5f8110da828db881ad.jpg

873130c9dd1d2e0c76be0a901fbd20fb.jpg

С шагов 2 по 7 я привожу одну и ту же схему, обозначая на ней шаги с тем, чтобы вам проще было понять процесс изготовления перчатки.

Схема электроники для перчатки очень простая:

  • Плата Arduino.
  • Батарейка на 9 В (я использую аккумулятор).
  • Переключатель SPST.

Шаг 3: перчатка 2/6 — корпус


94e191241b06a3ce56e73bb6b34ecf49.jpg

775d518c8518473ee3480f0f20f08ba2.jpg

e32d276dfe625ce6abc19ef071fd1fb5.jpg

e1cbe20eacec20b9d3d6daaf65dd7373.jpg

c3666a3f993f180519ec51ee44049271.jpg

6cceb12b18953b0497a29490213a2a0c.jpg

a935a5badecf69e2145547988ceb925b.jpg

6f723862f09c458ad4849541d3a18abd.jpg

f44209ea04dc63d76e4a660818f7eb8c.jpg

744d55a0302fd16bba2c05db82df6339.jpg

Корпус простой, и состоит всего из двух частей, распечатанных на 3D-принтере:

  • В жёлтой части находится плата Arduino, аккумулятор и переключатель. Отверстия в корпусе позволяют перезаряжать батарею и перепрограммировать плату Arduino без необходимости разбирать корпус.
  • Чёрная часть — это крышка, защищающая аккумулятор и плату.

На руку я креплю её полоской липучки.

Также я нарисовал логотип, который потом приклеил на крышку. Он обозначает велосипедиста, на которого смотрят сверху, и в нём есть три стрелочки — прямо, налево и направо. Четвёртая стрелочка отстоит от трёх остальных, потому что велосипеды не ездят назад.

Файлы


content.instructables.com/ORIG/FS2/L3M3/K9N93ZYW/FS2L3M3K9N93ZYW.stl

content.instructables.com/ORIG/F72/21NG/K9N93ZZG/F7221NGK9N93ZZG.stl

content.instructables.com/ORIG/FD3/NVS8/K9N93ZZI/FD3NVS8K9N93ZZI.stl

Шаг 4: перчатка 3/6: запись данных


d8e1150cb8ca714ad347dbb4f8aaa1ab.jpg

d79084da425e389fd936ce8d1d6f4a94.jpg

bb8af278f427f066737ec3899f59b887.jpg

e44fb0fd7ff1d774408af9dc0e06048e.jpg

24ae0cec33de1af49d4c6c340bbe4710.jpg

828fb43b8c0fd45ded3c264d0e595c77.jpg

a5e1c047e3b06d8278b576ec8f648e81.jpg

После сборки устройства приходит время записи данных. Цель — записать каждый жест многократно. Я установил порог для гироскопа, и когда он выходит за это значение, Arduino начинает выводить записанные данные на монитор.

Я записал следующие жесты:

  • Рука указывает влево (стандартный жест велосипедистов, обозначающий поворот налево).
  • Торможение (жест пальцами, тянущимися к рычагу тормоза).
  • Рука наклоняется назад.
  • Рука наклоняется вперёд.
  • Рука наклоняется влево.
  • Рука наклоняется вправо.

Естественно, вы можете записывать свои жесты.

Для записи данных я написал программку, переключающую на светодиоде цвета после каждых 20 движений. Это помогало мне понимать, когда нужно переходить к другому жесту. Я подсоединил Arduino к компьютеру, открыл программу для отслеживания порта и положил ноутбук в рюкзак.

Записав все жесты, я перешёл к последнему этапу — скопировал данные, выведенные в программу, и сохранил их в формате csv.

content.instructables.com/ORIG/FC7/B0JT/K9UEA78V/FC7B0JTK9UEA78V.ino

Шаг 5: перчатка 4/6: обучение


14b7051318a2bcf6c56879dea170983c.jpg

9fe23297eb990e91cdbd8fb52c3117f0.jpg

ced7f703da0d18ba283e5487770de40e.jpg

Для обучения я использовал следующий пример, исправив в нём всего несколько строк. Перед обучением стоит проверить, что для каждого жеста у вас есть свой csv-файл, и данные в каждом файле относятся именно к этому жесту.

На сайте Google Colab по ссылке в разделе «Upload data» загрузите свои данные.

В разделе «Graph Data (optional)» добавьте имя одного из файлов.

filename = «Arm_left.csv»

Затем исправьте эту строчку, чтобы выводить только данные с гироскопа:

#index = range (1, len (df['aX']) + 1)
index = range (1, len (df['gX']) + 1)

Закомментируйте следующие строки — данные акселерометра мы не используем:

#plt.plot (index, df['aX'], 'g.', label='x', linestyle='solid', marker=',')
#plt.plot (index, df['aY'], 'b.', label='y', linestyle='solid', marker=',')
#plt.plot (index, df['aZ'], 'r.', label='z', linestyle='solid', marker=',')
#plt.title («Acceleration»)
#plt.xlabel («Sample #»)
#plt.ylabel («Acceleration (G)»)
#plt.legend ()
#plt.show ()

В разделе «Parse and prepare the data» добавьте все названия файлов:

#GESTURES = [«punch», «flex»,]
GESTURES = [«Arm_left», «Brake», «Hand_back-tilt», «Hand_front-tilt», «Hand_left-tilt», «Hand_right-tilt»]

Измените количество образцов на один жест, если меняли их в коде для Arduino:

#SAMPLES_PER_GESTURE = 119
SAMPLES_PER_GESTURE = 64

Осталось только закомментировать ускорение:

# normalize the input data, between 0 to 1:
# — acceleration is between: -4 to +4
# — gyroscope is between: -2000 to +2000
tensor += [
#(df['aX'][index] + 4) / 8,
#(df['aY'][index] + 4) / 8,
#(df['aZ'][index] + 4) / 8,
(df['gX'][index] + 2000) / 4000,
(df['gY'][index] + 2000) / 4000,
(df['gZ'][index] + 2000) / 4000
]

После прохода всей программы вы сможете скачать обученную модель.

Файлы


content.instructables.com/ORIG/F7A/GLEK/K9UEA8Z5/F7AGLEKK9UEA8Z5.csv

content.instructables.com/ORIG/FV1/853G/K9UEA8Z6/FV1853GK9UEA8Z6.csv

content.instructables.com/ORIG/FQH/OAZD/K9UEA8Z7/FQHOAZDK9UEA8Z7.csv

content.instructables.com/ORIG/F7N/P7AG/K9UEA8Z9/F7NP7AGK9UEA8Z9.csv

content.instructables.com/ORIG/FD4/WZRM/K9UEA8ZA/FD4WZRMK9UEA8ZA.csv

content.instructables.com/ORIG/F6W/7SO2/K9UEA8ZB/F6W7SO2K9UEA8ZB.csv

Шаг 6: перчатка 5/6: код для Arduino

a3576ebefa5bc68272aa7c4f40ac4c0e.jpg

Итоговый мой код для умной перчатки — это смесь следующих программ:

  • пример «LED» из библиотеки «ArduinoBLE» (Peripheral>LED).
  • «IMU_Classifier» отсюда.

Подробно тут я распространяться о них не буду, просто рекомендую прочитать оригинальные программы, чтобы лучше понимать происходящее.

Добавьте свою модель в код, и её можно будет испытывать!

Файлы


content.instructables.com/ORIG/F9N/4SBK/K9UEA98M/F9N4SBKK9UEA98M.h

content.instructables.com/ORIG/FKZ/ODO9/KB52VXZK/FKZODO9KB52VXZK.ino

Шаг 7: перчатка 6/6: испытания


ff8ca2705cf9abd4bbc553c958ea607e.jpg

4fa24c7f1fc3d74897f176aef5dbc4f9.jpg

9422a019b8a5e662225d573c5641d972.jpg

fe067bb390f9f18d328c51692861563c.jpg

Как видно из видеоролика, светодиод загорается по-разному в зависимости от распознанного жеста:

Шаг 8: светодиодная матрица ¼: электроника


5cc9a14a4ee57d98e891c50b0ec3ea30.jpg

c15405624c1854e5e9f6f7679e31dfbb.jpg

fc1a6a5a1451412ff3a40aaf3f564c07.jpg

078898330a89aed27706287ed6c9c0d7.jpg

14cf3eb682ec29577fd873f1653e7fa1.jpg

Как я уже упоминал, при закачке скетча из библиотеки ArduinoBLE для светодиода на Arduino Nano 33 BLE SENSE я столкнулся с некоторыми проблемами. Поэтому я решил вместо этой платы использовать ESP32. Поэтому на приведённых фотографиях вы можете увидеть обе платы.

Поскольку обе платы, Arduino Nano 33 BLE SENSE и ESP32, работают с логикой на 3,3 В, я добавил четырёхуровневый буфер с 3 В до 5 В (74AHCT125), как рекомендуется в инструкции от Adafruit.

Также я добавил конденсатор на 100 мкФ для защиты светодиода от резких перепадов напряжения.

Всю схему я собрал на макетной плате.

Видно, что я задействовал оба разъёма внешнего источника питания, поскольку испугался, что светодиодной матрице потребуется слишком большой ток. Поэтому матрица и МИ питаются от разных разъёмов внешнего источника питания.

Шаг 9: светодиодная матрица 2/4: корпус


e1048bbbc3d5ea32b48832614feb7852.jpg

fed818416a82872572e495162de6c261.jpg

3208b0af71cc6d5e9a4b15222e9952f8.jpg

8a2051cd13c285c86a00b5f82f2874ea.jpg

6763f51a7d19ff1c8aef271605165eb2.jpg

33d6130b544a68a7191cb4eade960062.jpg

56c330f0ebef5be6abaf82bbd4727857.jpg

f32d400bda2554e6f6f8faea659f30df.jpg

50a8a2e91945a7d82e5576c83728ce90.jpg

511479bfc69e4a3d9e4484b5c186e9ff.jpg

8c8293d8dfbbf7f7a382a6827e407c6b.jpg

bf0309981e99f607434cedbd3fb9bb12.jpg

3e249bf9655e5a25e6bd0235891dce9a.jpg

Мне нужен был сборный корпус для светодиодной матрицы. Поэтому он состоит из нескольких частей (а ещё потому, что мой 3D-принтер очень крохотный), и я предусмотрел в них отверстия для болтов.

Для подсоединения панели я снова воспользовался липучкой.

Файлы


content.instructables.com/ORIG/FH6/TB4H/K9N93ZZJ/FH6TB4HK9N93ZZJ.stl

content.instructables.com/ORIG/FK3/BZPC/K9N93ZZK/FK3BZPCK9N93ZZK.stl

content.instructables.com/ORIG/FMU/ZRTY/K9N93ZZL/FMUZRTYK9N93ZZL.stl

content.instructables.com/ORIG/F38/BF1P/K9N93ZZM/F38BF1PK9N93ZZM.stl

content.instructables.com/ORIG/FJC/DQMY/K9N93ZZN/FJCDQMYK9N93ZZN.stl

content.instructables.com/ORIG/F43/ELQV/K9N93ZZQ/F43ELQVK9N93ZZQ.stl

content.instructables.com/ORIG/FJE/C5FG/K9N93ZZR/FJEC5FGK9N93ZZR.stl

content.instructables.com/ORIG/F55/1×43/K9N93ZZS/F551×43K9N93ZZS.stl

Шаг 10: светодиодная матрица ¾: код для Arduino


edfecce697ebae5907f4368be75e7fc4.jpg

66de8d01bb5a93dfebfbf3220636cd5e.jpg

5b50bd95c3fd7a7711ce03eaeb659acf.jpg

89186ac360c6809b966813552d421d8c.jpg

848c46b2c53dfa2a9fad080044a1b70a.jpg

9f6634d79f45f880b2cc5c45a0284864.jpg

Итоговый код — смесь следующих кодов (и их модификация):

  • Пример BLE_Write из библиотеки BLE ESP32 ARDUINO.
  • Пример MatrixGFXDemo64 из библиотеки FastLED NeoMatrix.

Подробно тут я распространяться о них не буду, просто рекомендую прочитать оригинальные программы, чтобы лучше понимать происходящее.

content.instructables.com/ORIG/FIR/RETZ/KB52VXP4/FIRRETZKB52VXP4.ino

Шаг 11: светодиодная матрица 4/4: испытания


8eefd33e49b5bce2415717e1a76ce48b.jpg

1e4d6ded7b0c57f0a9a5713c15442d3a.jpg

Настало время всё проверить! После распознавания каждого жеста на светодиодную матрицу отправляется сигнал, и она показывает определённый узор. Видно, что на перчатке светодиоды зажигаются соответственно распознанному жесту.

Шаг 12: итоговые испытания и заключение


aa656b64d873c18655e0b691b109915b.jpg

ab5a9ed009c1669951b9a02540fee196.jpg

Вот как это выглядит вживую:

Я очень доволен получившимся устройством. Благодаря проекту я гораздо увереннее чувствую себя с tinyML и BLE. С тех пор я купил ещё Arduino Nano 33 IOT, и сейчас занимаюсь весьма интересным проектом, о котором напишу позже. Что бы я изменил во второй версии описанного мною устройства:

  • Крышка для «перчатки». Сейчас она держится на корпусе только за счёт того, что туго надевается. Однако как-то во время поездки я задел что-то рукой, крышка соскочила и разбилась. В следующей версии прикручу её винтами.
  • Корпус для светодиодной матрицы. Я почти сразу понял, что в моём корпусе отсутствует быстрый доступ к USB МИ. А мне хотелось бы иметь доступ, чтобы отлаживать код или менять его. Также без раскручивания корпуса нельзя зарядить внешний источник питания.
  • Больше данных для обучения. Иногда некоторые из жестов не распознаются, а иногда распознаются ошибочно. Думаю, не хватает данных (всего 20 движений для каждого жеста). Больше движений — лучше модель, меньше ошибок.

На завершение проекта и написание этого текста у меня ушло несколько месяцев. Если что-то неясно, или какого-то файла не хватает, пишите в комментариях к оригинальной статье.

© Habrahabr.ru