Mijn doel is om een oudere Tacx Flow ergotrainer om te bouwen naar een smart trainer die compatibel is met onder andere Zwift en BKOOL. De code voor mijn implementatie is beschikbaar op GitHub: https://github.com/krisc-informatica/arduino-smart-bike-trainer.
Deze ergotrainer werkt al digitaal, waardoor we de weerstand van het vliegwiel computergestuurd zouden moeten kunnen beheren.
De controller maken we met behulp van een Arduino Nano 33 BLE, die voorzien is van een ingebouwde Bluetooth Low Energy chip. De communicatie van de controller zal dus gebeuren via het BLE FTMS-profiel (FiTness Machine Service).
Documentatie op het web
De volgende websites of implementaties hebben geholpen bij het ontwikkelen van de trainer:
- Tacx Flow Ant+ Conversion op Hackaday.io
- Bicycle Odometer and Speedometer with 99 Lap/Period Recorder op Arduino Project Hub
- Developing a CIQ BLE Client for Treadmill and Fitness Equipment door Chris Hanger
- Arduino BLE Cycling Power Service op teaandtechtime.com
- Arduino BLE Cycle Power Service door Thomas Schuker
Tacx T1680 ergotrainer
Aan de hand van de informatie die we verkregen uit de eerste link en enkele experimenten kunnen we de technische details voor de ergotrainer als volgt samenvatten.
Rem-unit
In de rem-unit wordt weerstand opgewekt door de combinatie van permanente magneten en elektromagneten. Afhankelijk van de grootte en richting van de kracht van de elektromagneten worden de permanente magneten versterkt of tegengewerkt. Dit resulteert in een kleinere of grotere weerstand voor de trainer. De elektromagneten worden gecontroleerd door een PWM-signaal dat vanuit de controller gegenereerd wordt.
Kabel/Connector
De controller wordt verbonden met een 6-polige kabel met RJ12-stekker. De pinout van deze stekker is als volgt:
- Cadanssensor: 1 puls per trapomwenteling
- GND/Common
- Controle van de weerstand: PWM-signaal gesynchroniseerd aan de hand van 4.
- +23V AC stroomvoorziening en synchronisatiesignaal
- +18V
- Snelheidssensor: 4 pulsen per omwenteling van de as in de rem-unit. De diameter van de as in de rem-unit is 30mm.
Bluetooth FTMS profile
Om onze Smart Trainer via BLE te laten koppelen met training apps is het belangrijk dat we het juiste BLE-profiel implementeren. In dit geval zullen we het Fitness Machine Service-profiel implementeren. De UUID van deze service is vastgelegd op 0x1826.
De FTMS definieert de volgende procedures (characteristics) die door de toepassing geïmplementeerd moeten worden in het geval de toepassing een fietstrainer betreft:
- Fitness Machine Feature (0x2ACC)
- Indoor Bike Data (0x2AD2)
- Training Status (0x2AD3)
- Supported Resistance Level Range (0x2AD6)
- Fitness Machine Status (0x2ADA)
- Fitness Machine Control Point (0x2AD9)
De eerste vijf karakteristieken dienen om informatie over de trainer te verzamelen. De laatste (control point) dient om de trainer aan te passen aan de omstandigheden van de virtuele training, zoals de weerstand verhogen o.w.v. een helling.
De onderstaande Arduino-code definieert deze service en de bijhorende karakteristieken.
#include <ArduinoBLE.h>
BLEService fitnessMachineService("1826");
BLECharacteristic fitnessMachineFeatureCharacteristic("2ACC", BLERead, 8);
BLECharacteristic indoorBikeDataCharacteristic("2AD2", BLENotify, 6);
BLECharacteristic trainingStatusCharacteristic("2AD3", BLENotify | BLERead, 20);
BLECharacteristic supportedResistanceLevelRangeCharacteristic("2AD6", BLERead, 4);
BLECharacteristic fitnessMachineControlPointCharacteristic("2AD9", BLEWrite | BLEIndicate, 20);
BLECharacteristic fitnessMachineStatusCharacteristic("2ADA", BLENotify, 2);
void setup() {
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
BLE.setDeviceName("Arduino Smart Trainer");
BLE.setLocalName("AST");
BLE.setAdvertisedService(fitnessMachineService);
fitnessMachineService.addCharacteristic(fitnessMachineFeatureCharacteristic);
fitnessMachineService.addCharacteristic(indoorBikeDataCharacteristic);
fitnessMachineService.addCharacteristic(trainingStatusCharacteristic);
fitnessMachineService.addCharacteristic(supportedResistanceLevelRangeCharacteristic);
fitnessMachineService.addCharacteristic(fitnessMachineControlPointCharacteristic);
fitnessMachineService.addCharacteristic(fitnessMachineStatusCharacteristic);
BLE.addService(fitnessMachineService);
}