Далі буде лонгрід в стилі особистої драми з гарним кінцем (чи ні)
В нашій мові є афоризм "не вигадуй велосипед", що означає — не створюй те, що вже добре зроблено до тебе. Коли лікар порадив мені для лікування колін займатися їздою на велосипеді чи плаванням, я обрав саме велосипед (після операції на колінах через розрив меніску — таке собі задоволення). Але спочатку трохи передісторії.
Я розробник, який активно займається різними проєктами, пов'язаними з R&D, VR та AR. Так і заробляю на життя — колишнє хобі стало професією. Був розробником ігор та всякої такої всячини. Тож маю чималу колекцію різних девайсів: від старих шоломів Pico, картонних Google Cardboard та Google Glass до сучасних окулярів Nreal та Quest 3.
Маючи такий бекґраунд і обираючи домашній велосипед, я вже знав, що просто так кататися на ньому не буду — це ж нудно, правда? Перше, що спало на думку — знайти якийсь VR-симулятор і кататися просторами віртуальної реальності, хай навіть і не надто якісної. Натрапив на проєкт, де можна підключити велосипед до GTA V і кататися просторами Los Santos, керуючи поворотами через контролер. Від цього й почав відштовхуватися. Дочекався зарплати, щоб не чіпати заощадження, і пішов обирати собі "лісапєда". Головні критерії були прості: наявність Bluetooth для отримання даних і більш-менш пристойний вигляд.
Протоколів там чимало, і якщо вам цікаво, і у вас є старий велосипед, що давно припав пилом, а викидати шкода, бо потай мрієте знову бути "на коні" — маю гарну новину: ви все ще можете його осучаснити. На AliExpress чи будь-якому китайському маркетплейсі можна придбати кілька датчиків, прикріпити їх до велосипеда — і ось він уже передає показники швидкості куди завгодно.
Але я відійшов від теми. Отож, купив я велосипед, і за два дні величезна коробка з 50-кілограмовим вмістом уже чекала в мене на подвір'ї. Розпакувавши й зібравши його, я з нетерпінням чекав можливості ввімкнути та розібратися, як ця махіна працює. Під екраном велосипеда був цікавий виступ з гордим написом "iConsole+" — натяк на можливість встановити телефон чи планшет і ще більш явний натяк на елітарність через приставку "i" та знак "+" наприкінці. "+" це ж завжди краще, ніж без нього, правда?
Увімкнувши велосипед у розетку та навівшись на QR-код для завантаження додатка, я з подивом зрозумів, що цей додаток не працює в нашій країні. Оце так підтримка! Локально продавати пристрій, який навіть офіційно тут не підтримується. Ну, для мене це не вперше, тож, зрозумівши, що доведеться розбиратися з усім через реверс-інжиніринг, я пішов на GitHub. (офтоп, потім виявилось що qr код вів на додаток із китая, але це все одно мене б не зупинило)
Знайшов кілька проєктів, які описували, як витягнути дані з цього пристрою (не складно здогадатися, що через Bluetooth) і як їх декодувати. Скажу відверто: раніше я ніколи не стикався з потребою декодування Bluetooth-даних з велотренажерів — життя якось не змушувало. Але здавалося, що тут може бути складного? Колись давно я доводив Microsoft, що їхні шоломи Mixed Reality можуть працювати (хоча це й було помилкою так як ці пристрої не повинні існувати), тож із домашнім велосипедом точно впораюся. Коли я нашвидкуруч накидав пошук пристроїв за протоколом і витягування даних та отримав щось таке:
Raw bytes: 0x74 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0c 0x00
я подумав, що зараз за 15 хвилин усе зроблю. Це ж легко.
Ну, минуло не 15 хвилин, і не один підводний камінь трапився на цьому шляху. Першою і, мабуть, головною помилкою було вважати, що протоколи iConsole та iConsole+ ідентичні, і я можу просто повторити те, що вже розробили інші хлопці (чи дівчата — хтозна). Можу припустити, що в першому випадку виробник намагався вигадати щось своє, а в другому вже пішов за стандартами. Тож після кількох невдалих спроб і пари інфарктів від думок, що я зламав прошивку під час DDoS-атак бортового комп'ютера, я натрапив на інформацію про існування стандартів для виробників вело (і не тільки) тренажерів. Виявилося, це називається FTMS Protocol, і, о Боже, хай мене вдарить блискавка (чи шахєд), якщо я збрешу, сказавши, наскільки я зрадів, коли побачив у даних реальні цифри.
Далі вже все пішло як по маслу. Поступово декодуючи показник за показником, я зіставляв їх із показниками на екрані самого велотренажера, поки не розшифрував майже всі. Із проблем, які залишилися: показник RPM (revolutions per minute) явно був значно завищений, а дані, які надходили з велосипеда, завжди обнулялися після цифри 255 (особливості даних і типу протоколу). Тому методом експериментів я підібрав коефіцієнт RPM — як результат, поділив число на 2. Припускаю, що в кожного виробника та кожної моделі велотренажера, залежно від "заліза" всередині, різний коефіцієнт обчислення. Я поставив 2 — здається, досить близько до того, що показує екран. А щодо 255 — додав акумулятивність часу, калоріям та дистанції (а згодом ще й потужності, бо міг фізично підняти її до 300) і наче вирішив цю проблему. Як результат, у мене був повноцінний парсинг показників із пристрою та їх декодування в зрозумілий нам вигляд. А от чого вже на той момент не було, так це бажання інтегрувати це з GTA. По-перше, мені треба було купити її на ПК, а по-друге, якщо відверто (і не бийте мене за це), я не поціновувач цієї франшизи. Тут я залишу вам трохи часу написати про мене поганий коментар.
Так от, повернімося на початок цієї розповіді, а саме до вигадування своїх велосипедів. Звісно, я міг піти простим шляхом і просто встановити додаток через VPN чи взагалі користуватися виключно бортовим комп'ютером на велотренажері, але хіба це справжній шлях джедая? Я особисто вважаю, що ні. Хоча додам від себе, що франшиза "Зоряних війн" теж уже сильно перегріта, але це історія не про це.
Відкривши Cursor, який я обожнюю використовувати для швидкого прототипування, я почав накидати ідеї, чим це може бути. Що б я насамперед хотів від велотренажера? Звісно, спочатку з'явився автопошук пристроїв. У моєму випадку це було легко, оскільки виробник маркує Bluetooth-пристрій своєю назвою. Потім я вивів усі показники на екран. Наче круто. Далі додав можливість посекундного запису показників і їх збереження в JSON локально. На щастя, я обрав Electron, а він дозволяє легко це все робити кількома рядками коду. І вуаля — маю красивий інтерфейс і можливість записувати результати тренувань. До речі, цікавий момент: робити запис щосекунди необов'язково, з протоколу можна дізнатися, що оновлення інформації відбувається з інтервалом 1,5-2 секунди.
Але хіба цього достатньо? Мені точно ні! :) Далі я дізнався, що можу за допомогою команд керувати пристроєм. Арсенал команд для мого велотренажера не такий великий, як хотілося б, але достатній для інтеграції певної інтерактивності. Найпростіше і, мабуть, головне, що в мене є — це керування опором. От воно, подумав я! Спочатку я вивів в інтерфейс простий слайдер, а за кілька спроб навіть змусив його працювати. Знову ж таки, пішов за прикладом знайденого репозиторію і за їхнім зразком інтегрував команди. Але знову їхній приклад призвів до того, що я втратив багато часу, намагаючись зрозуміти, чому коли я надсилаю команду, перестає працювати передача параметрів, а коли отримую параметри — перестає працювати надсилання команд. Усе виявилося досить просто: у жодному разі не можна було використовувати пропрієтарний протокол. Тільки стандартизований. Один вимикав інший, надсилаючи різні режими роботи на велосипед. Режими роботи — це взагалі загадка: надсилаючи різні команди, я бачив на екрані велосипеда все дивніші символи. Але на цьому я зупинився, бо отримав бажаний результат. На екрані велосипеда, до речі, тепер відображається виключно величина опору. Фактично я встановив йому режим роботи через підключення до телефона.
Ну, і тут, як кажуть, Остапа понесло.
Поки я закінчував код із сетером опору, вже зрозумів, що треба додати в налаштування додатка збереження API-ключа для AI. Я обрав Claude, бо використовую його і в інших проєктах, та й сам Cursor теж працює на ньому. Ну і тепер, як на мене, я додав найкрутішу фічу — регуляцію опору велосипеда за допомогою AI-асистента. Штука доволі проста: я заздалегідь даю вибрати тип тренування та стиль поїздки, а також надсилаю асистенту кожні N секунд інформацію про мої показники за останніх 10 точок даних. Також прості промпти, які описують, що таке кожен тип поїздки. Ну і поради, куди ж без них :) Як результат, маю динамічну поїздку завдяки зміні опору (до речі, в мене він максимально 20 — не так круто, як у тренажерних залах, але згодиться) і ще інформацію про те, чи треба прискоритися, чи навпаки знизити темп для обраного стилю.
Ну і все, я катаюсь, штучний інтелект сам вигадує мені тренування, але постійно повертати голову до монітора дуже незручно. Тому я додав голосового асистента. Якщо грошей в кишені нема — використовую веб-синтезатор (жахливий, але дешевий), а коли отримую бонуси на роботі — можу дозволити собі красивий голос OpenAI. Вибір, як то кажуть, за мною.
Із цікавого: одне тренування (45-50 хвилин) без голосового асистента обходиться мені на момент написання статті десь у 0.02 долара. Це при інтервалі аналізу кожні 30 секунд. Можна оптимізувати, але я закинув 10 баксів і поки вистачає.
Опис тренувань для промта якщо прям дуже коротко приблизно такий:
TRAINING GOALS:
• CASUAL: R3-8, comfort first, gentle pace
• WEIGHT_LOSS: R6-12, HR 120-140, fat burning zone
• WARMUP: Start R1-3, +1-2 every 30s, gradual increase
• ENDURANCE: R8-15, steady sustained effort, build stamina
• HIIT: Alternate R12-18, intense intervals with recovery
• RECOVERY: R1-6, very light effort, active rest
• STRENGTH: R14-20, high resistance, muscle building
• SPRINT: R8-12, maximum RPM, short bursts
RIDE STYLES:
• CITY: Variable resistance, simulate stops/starts
• SUBURBAN: Moderate hills R6-12, steady climbs
• COUNTRYSIDE: Long gradual changes, scenic pace
• TRACK: Focus speed/RPM, minimal resistance changes
• MOUNTAIN: High resistance R12-20, climbing simulation
• BEACH: Relaxed R3-8, easy cruising pace
• FOREST: Natural variety R5-14, trail simulation
• HIGHWAY: Sustained effort R8-15, long distance pace
Добре-добре, ви вже, мабуть, здогадуєтесь, куди все йде. Але так, на цьому я не зупинився. Комусь із читачів може здатися, що я роблю все, аби не крутити педалі. Але насправді це не так! Чесно! Тільки тестування показників зайняло в мене 4 години крутіння :D
Так от, про що я? А, так! Я ж хочу знати статистику своїх тренувань. Тим паче, тепер на кожне тренування вже є готовий JSON із даними. Тому я швидко зібрав аналітику з усілякими графіками та показниками. Щоб було красиво. Але самі графіки — це добре, проте їхні значення та динаміку треба розуміти. Тому так, і тут AI: я підключив його до аналізу динаміки показників і попросив видавати поради щодо покращення тренувань. Як краще тримати пульс, швидкість чи щось таке. Графіки, до речі, вийшли реально крутими, а поради — взагалі бомба. Аби їх ще уважно читати й дотримуватися. Ну і додав скор якості тренування — це якщо поради зовсім лінь читати. Зараз у мене середнє тренування десь 70-80 зі 100. Є куди рости. Ну і кнопку "Скачати PDF" додав, бо як же без хизування перед кентами.
Після цього подумав, що треба якось запланувати тренування на майбутні тижні. Хтось любить блокноти, хтось — додатки, а я знову підключив AI, щоб він розпланував мені тижні, обираючи типи тренувань і навантажень відповідно до поставленої цілі. Так, каюсь, я раб AI — в такі часи живемо. Аби працювало. З'явився додатковий екран із плануванням. Поки не дуже зручний, але з чогось треба починати.
І от сиджу я такий впевнений у собі в AR-окулярах, кручу педалі й дивлюся кіно, коли розумію, що все це майже безкорисне, якщо не бачити його перед обличчям. Оце так несподіванка, так? Ну типу, я можу повернути голову, відволіктися на секунду й подивитися, що там на екрані комп'ютера, але втрачаю фокус і бажання крутити педалі. Ну все, яке рішення? Правильно — зробити ще один невеличкий клієнт для окулярів.
Окуляри працюють на Android, тому щось складне вигадувати не треба. Достатньо підняти невеличкий сервер на сокетах, а клієнт зібрати на чомусь на кшталт React Native. Просто, зручно, навіть Android Studio ставити не треба — все збереться в хмарі. Тому в додаток додав сокети й трансляцію даних. А для мінімальної безпеки — генерацію API-ключа, щоб сусіди не змогли побачити, як я погано кручу педалі. Також нам не треба робити фулскрін-додаток, тому на секунду я навіть відкрив Unity (для цих окулярів SDK тільки на Unity) і за хвилину закрив, зрозумівши, що це зайве. Я ж хочу паралельно дивитися Supernatural — я вже на 6-му сезоні. Як результат, маю невеликий додаток у стилі Nike, де постійно бачу показники й періодично отримую поради прискоритися чи сповільнитися. Ну прикольно ж!
Майже після кожного тренування я вношу невеличкі правки: у промпти, в роботу алгоритмів, у зручність користування додатком. Чи я на цьому зупинюся й буду далі просто крутити? Якщо ви дочитали до цього місця, то вже зрозуміли, що навряд чи.
У планах маю зробити історичний аналіз результатів із додаванням персональної інформації на кшталт ваги й прогнозу динаміки змін. Можливо, зроблю більш динамічні заняття завдяки покращенню промптів. Завжди можна знизити ціну через оптимізацію запитів. Додати контекстний чат-асистент. Хочу персоналізації — авжеж, це не Джарвіс (я, до речі, ненавиджу голосових асистентів, але переписуватися з ними — OK). Зробити план занять комплекснішим (можу ще додати свій walkpad). Ну а далі — всілякі приколи. Може, ачівки завести? Чи піти далі й зробити на Unreal Megascans красивий ліс і поле та все-таки повернутися до VR? Не знаю, який буде настрій.
Якщо ви дочитали до кінця, сподіваюся, вам була цікава ця подорож. Можливо, у вас є ідеї для покращення чи схожий досвід.
Сподіваюся, я надихнув вас на щось подібне. Проєкт абсолютно відкритий, і якщо є бажання, можу поділитися посиланням на вихідний код.
Топ коментарі (0)