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 公里/小时(等待或暂停) 0x00 0
2.0 公里/小时 0x14 20
3.0 公里/小时 0x1D 29
5.0 公里/小时 0x31 49

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

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

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

拦截坡度变化

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

屏幕上的坡度 发送的消息
-5° 0x68 0x08 0x80 0x50 0x1D 0x00 0x00 0x00 0xF5 0x43
0° 0x68 0x08 0x80 0x50 0x1D 0x32 0x00 0x00 0x27 0x43
9° 0x68 0x08 0x80 0x50 0x1D 0x8C 0x00 0x00 0x81 0x43

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

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

屏幕上的坡度 十六进制 十进制
-5° 0x00 0
0° 0x32 50
9° 0x8C 140

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

十进制值 = (角度 + 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-2026 Sebastian Barrenechea. 保留所有权利.

构建于 Astro v7.3.2.