fl3xbl0w 项目标志

跑步机电机控制器 - fl3xbl0w

发布于 2022年5月28日

逆向工程项目。它始于 Bowflex 跑步机 22,但最终被推广到 Nautilus Inc.(Nautilus、Bowflex、Schwinn)销售的任何由 Android 驱动的设备。

这主要适用于 Treadmill 22 和 Treadmill 56。

电机控制板由 Electronics Way Industry 制造。

电机控制板 B017D

根据 Nautilus Inc. 提供的 服务手册archive.org 的备份):

跑步机电气图

特别关注这一部分:

跑步机通信路径

我们可以识别出连接电机控制器的“通信电缆”是一个 5 针电缆。只有一个 5 针连接器。 我已经用相应的颜色标注了电缆(数据和开关是光隔离的):

电缆颜色标签
红色GND
白色RXD
黑色TXD
黄色+12
绿色SW

该板未直接连接到 Android 控制台。

唯一的 5 针连接器来自 Molex。谷歌搜索“小 Molex 连接器”让我看到了他们所说的 Molex Micro-Fit 3.0 Single Row (5-Pin) 的图片,用于连接电机控制器板:

Molex Micro-Fit 3.0 连接器

速卖通链接

通过 jadx-gui 查看 NautilusLauncher.apk,我可以看到他们使用 230400 波特率的串行通信将 Android 平板电脑与他们的“通用控制台”连接(使用 /dev/ttyS4)。这不是我们在这里分析的内容。那指的是 Android 与“通用控制台”之间的通信。我们正在调查“按钮面板控制器”和“电机控制板”之间的通信,从而排除了三个板作为潜在的故障点。

尝试将 ESP32 或基于 CH340 的串行桥直接连接到跑步机底座和 Bowflex 控制板之间的电缆导致跑步机底座无法正确初始化,之后我获取了一个逻辑分析仪以进一步调查。

更新 2025

在最近几周,几乎在我开始这个项目三年后,几个人联系我询问进展,确认了我最初的假设,即跑步机系统很糟糕,机器开始故障只是时间问题。看起来是时候使用我的逻辑分析仪了,它直到现在才被用上,此前它只是积灰。

将逻辑分析仪连接到 TXD 和 RXD 线路(当然还有 GND),我立即能够在不干扰通信的情况下拦截双方的消息。我猜我最初不能使用 ESP32 是由于阻抗问题。经过几分钟的试验和错误,我得出了以下串行配置:

- 2400 波特率
- 每帧 8 位
- 1 个停止位
- 无奇偶校验位
- 最低有效位先发送
- TXD:信号反转
- RXD:信号不反转

使用这些设置,我可以清晰地看到定义明确的消息。

拦截 UART 消息

引导过程中拦截 UART 消息

我立即注意到的一些事情:

  • 按钮面板发送的所有消息以 0x68 开头
  • 电机控制板发送的所有消息以 0x73 开头
  • 双方的消息都以 0x43 结尾
  • 通常,按钮面板在收到电机控制板的消息后 100 毫秒发送消息
    • 除了在引导过程中,有一次差异为 300 毫秒
  • 通信线路上的噪声非常大,导致消息读取困难

在此基础上,开始解读消息并理解双方之间传递的信息,进行有控制的锻炼程序更改。

拦截速度变化

通过对特定速度进行有控制的更改,可以观察到以下发送到电机控制板的值:

屏幕上的速度发送的消息
0.0 公里/小时(等待或暂停)0x68 0x08 0x80 0x50 0x00 0x0A 0x00 0x00 0xE2 0x43
2.0 公里/小时0x68 0x08 0x80 0x50 0x14 0x0A 0x00 0x00 0xF6 0x43
3.0 公里/小时0x68 0x08 0x80 0x50 0x1D 0x0A 0x00 0x00 0xFF 0x43
5.0 公里/小时0x68 0x08 0x80 0x50 0x31 0x0A 0x00 0x00 0x13 0x43

可以观察到,第 5 字节和第 9 字节发生了变化。第 5 字节似乎是十六进制的速度,第 9 字节似乎是校验和。

将第 5 字节的值转换为十进制:

屏幕上的速度十六进制十进制
0.0 公里/小时(等待或暂停)0x000
2.0 公里/小时0x1420
3.0 公里/小时0x1D29
5.0 公里/小时0x3149

回忆起几年前反编译 Android 系统的部分内容,我记得在配置机器为公制系统时,Bowflex 应用程序内部执行了从公制到英制的转换,以与“UCB”通信。电机控制板似乎使用公制系统,显然,在从公制转换到英制然后再转换回公制(电机控制板所期望的)时,精度有所损失,因为一切都是以 1 位小数的精度处理。Nautilus,难道这样做这么难吗?

考虑到这一点,如果应用缩放因子 10,正好与发送到电机控制板的值匹配。因此,公式如下:

十进制值 = 速度(公里/小时) × 10

拦截坡度变化

按照与速度相同的过程,可以观察到以下发送到电机控制板的值:

屏幕上的坡度发送的消息
-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

在这种情况下,第 6 字节似乎是十六进制的坡度,并且确认第 9 字节是校验和。

将第 6 字节的值转换为十进制:

屏幕上的坡度十六进制十进制
-5°0x000
0x3250
0x8C140

完全匹配发送到电机控制板的值的公式是:

十进制值 = (角度 + 5) × 10

校验和

这似乎是微控制器中一种简单且标准的校验和,将消息的所有字节相加并在达到 256 时发生溢出。一个简单的表示方式如下:

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

通过使用 uint8_t 作为返回类型,溢出会自然发生。可以使用 for 循环来求和并返回 sum % 256,但对于没有任何实际好处的微控制器来说,这会更慢。

下一步

  • 获得对引导过程的逻辑理解,或至少复制它
  • 捕捉与安全钥匙(放在衣物上的红色物品)的交互
  • 解释电机控制板发送的消息,这些消息应该与按钮面板发送的消息差别不大

通过这些,按钮面板的功能可以被复制,从而可以通过微控制器控制跑步机。

— 待续 —

内容翻译者 o1-mini

©2022-2025 Sebastian Barrenechea. 保留所有权利.

构建于 Astro v5.6.1.