Logo del proyecto fl3xbl0w

Controlador del Motor de la Trotadora - fl3xbl0w

Lanzado el 28 may 2022

Proyecto de ingeniería inversa. Comenzó con la trotadora Bowflex Treadmill 22 pero terminó generalizándose para cualquier máquina con Android vendida por Nautilus Inc. (Nautilus, Bowflex, Schwinn).

Esto aplica principalmente a la Treadmill 22 & Treadmill 56.

La placa de control del motor es fabricada por Electronics Way Industry.

Placa controladora del Motor B017D

Dado el manual de servicio proporcionado por Nautilus Inc. (respaldo en archive.org):

Diagrama eléctrico de la trotadora

Y enfocándonos específicamente en esta parte:

Camino de comunicación de la trotadora

Podemos identificar el “cable de comunicación” que conecta el controlador del motor como uno de 5 pines. Hay solo un conector de 5 pines. He etiquetado los cables con sus colores correspondientes (los datos & interruptor están optoaislados):

Color del cableEtiqueta
rojoGND
blancoRXD
negroTXD
amarillo+12
verdeSW

La placa no está conectada directamente a la consola Android.

El único conector de 5 pines es de la marca Molex. Una búsqueda en Google de “conectores Molex pequeños” me llevó a una imagen de lo que llaman Molex Micro-Fit 3.0 Single Row (5-Pin), que se utiliza para conectar la placa controladora del motor:

Conector Molex Micro-Fit 3.0

Enlace de AliExpress

Al echar un vistazo en NautilusLauncher.apk a través de jadx-gui, puedo ver que comunican la tablet Android con su “Consola Universal” usando Serial a 230400 Baudios (usando /dev/ttyS4). Eso NO es lo que estamos analizando aquí. Eso se refiere a la comunicación entre Android y la “Consola Universal”. Investigamos la comunicación entre la “Placa controladora de la botonera” y la “Placa controladora del motor”, así quitando tres placas como posibles puntos de falla.

Intentar conectar un ESP32 o un puente Serial basado en CH340 directamente a los cables entre la base de la trotadora y la placa controladora Bowflex hizo que la base de la trotadora no se inicializara correctamente, tras lo cual adquirí un analizador lógico para investigar más a fondo.

Actualización 2025

En las última semanas, y casi tres años después de que empecé con esto, varias personas se han comunicado conmigo para preguntar por avances respecto a esto, confirmando mi suposición inicial de que el sistema de la trotadora es horrible y sólo era cosa de tiempo para que máquinas comenzaran a fallar. Me pareció buen momento para poner en uso mi analizador lógico, que hasta ahora sólo estaba guardando polvo.

Conectando el analizador lógico a las líneas TXD y RXD (y GND, por supuesto), inmediatamente pude comenzar a interceptar mensajes entre ambas partes sin interrumpir la comunicación. Supongo que inicialmente no pude con un ESP32 por temas de impedancia. Tras algunos minutos de prueba y error, llegué a la siguiente configuración Serial:

- 2400 Bauds
- 8 Bits per Frame
- 1 Stop Bit
- No Parity Bit
- Least Significant Bit Sent First
- TXD: Inverted Signal
- RXD: Non Inverted Signal

Con esas configuraciones pude ver mensajes claramente definidos.

Interceptando mensajes UART

Interceptando mensajes UART en el proceso de encendido

Algunas cosas que me pude percatar de inmediato:

  • Todos los mensajes que envía la botonera comienzan con 0x68
  • Todos los mensajes que envía la placa controladora del motor comienzan con 0x73
  • Los mensajes de ambas partes terminan en 0x43
  • En general los mensajes de la botonera son enviados 100ms después de haber recibido un mensaje de la placa controladora del motor
    • A excepción del proceso de encendido, donde en una instancia tiene una diferencia de 300ms
  • El ruido que hay en las líneas de comunicación es increíble, dificultando la lectura de los mensajes

Con eso como base ya comienza el proceso de descifrar los mensajes y entender qué es lo que se está comunicando entre ambas partes, realizando cambios controlados en una rutina de ejercicios.

Interceptando cambios en la velocidad

Realizando cambios controlados a velocidades específicas, se puede observar los siguientes valores enviados hacia la placa controladora del motor:

Velocidad en la pantallaMensaje enviado
0,0 km/h (en espera o pausa)0x68 0x08 0x80 0x50 0x00 0x0A 0x00 0x00 0xE2 0x43
2,0 km/h0x68 0x08 0x80 0x50 0x14 0x0A 0x00 0x00 0xF6 0x43
3,0 km/h0x68 0x08 0x80 0x50 0x1D 0x0A 0x00 0x00 0xFF 0x43
5,0 km/h0x68 0x08 0x80 0x50 0x31 0x0A 0x00 0x00 0x13 0x43

Se puede observar que cambia el byte 5 y el byte 9. El byte 5 parece ser la velocidad en hexadecimal, y el byte 9 parece ser un checksum.

Pasando los valores del byte 5 a decimal:

Velocidad en la pantallaHexadecimalDecimal
0,0 km/h (en espera o pausa)0x000
2,0 km/h0x1420
3,0 km/h0x1D29
5,0 km/h0x3149

Habiendo decompilado algunas partes del sistema Android años atrás, recordé que al configurar la máquina en sistema métrico, internamente la aplicación de Bowflex realiza la conversión de sistema métrico a imperial para comunicarse con la “UCB”. La placa controladora de motor parece usar sistema métrico, y al parecer hay pérdida de precisión en la conversión de sistema métrico a imperial y después de vuelta a métrico (que es lo que la controladora del motor espera), ya que todo se maneja con 1 decimal de precisión. ¿Era tan difícil hacerlo bien, Nautilus?

Teniendo eso en consideración, y si se aplica un factor de escala de 10, coincide perfectamente con los valores enviados a la placa controladora del motor, por lo tanto la fórmula sería:

Valor en decimal = Velocidad en km/h × 10

Interceptando cambios en la inclinación

Siguiendo el mismo proceso que con la velocidad, se puede observar los siguientes valores enviados hacia la placa controladora del motor:

Inclinación en la pantallaMensaje enviado
-5°0x68 0x08 0x80 0x50 0x1D 0x00 0x00 0x00 0xF5 0x43
0x68 0x08 0x80 0x50 0x1D 0x32 0x00 0x00 0x27 0x43
0x68 0x08 0x80 0x50 0x1D 0x8C 0x00 0x00 0x81 0x43

En este caso el byte 6 parece ser la inclinación en hexadecimal, y me confirma que el byte 9 es un checksum.

Pasando los valores del byte 6 a decimal:

Inclinación en la pantallaHexadecimalDecimal
-5°0x000
0x3250
0x8C140

La fórmula que hace coindidir perfectamente los valores enviados a la placa controladora del motor es:

Valor en decimal = (Ángulo + 5) × 10

Checksum

Este parece ser un checksum simple y estándar en microcontroladores, sumando todos los bytes del mensaje y haciendo un overflow llegado a 256. Una representación sencilla sería algo como:

uint8_t calculateChecksum(uint8_t *msg) {
  return msg[1] + msg[2] + msg[3] + msg[4] + msg[5] + msg[6] + msg[7];
}

Al utilizar uint8_t como tipo de retorno, el overflow ocurre naturalmente. Podría utilizarse un for loop sumando los valores y retornar sum % 256, pero sería más lento para los microcontroladores sin ningún beneficio real.

Próximos pasos

  • Obtener un entendimiento lógico del proceso de encendido, o al menos replicarlo
  • Capturar interacciones de la llave de seguridad (la cosa roja que se coloca en la ropa)
  • Interpretar los mensajes que envía la placa controladora del motor, que no deben diferir mucho de los mensajes que envía la botonera

Teniendo eso ya se puede replicar el funcionamiento de la botonera, y con eso se puede controlar la trotadora desde un microcontrolador.

— Continuará —

©2022-2025 Sebastián Barrenechea. Todos los derechos reservados.

Construido con Astro v5.6.1.