将 Bambu Lab 的 BMCU(AMS控制器)集成到 Klipper 固件,实现:
- 使用BMCU硬件进行多色打印
- 不依赖原厂固件
- 完全开源的解决方案
- BMCU: Bambu Lab AMS/AMS Lite控制板
- 通信接口: RS485 (通过USB-485转换器)
- 测试设备: A1 mini 打印机(用于抓包参考)
成果:
- ✓ 完整解析BambuBus协议包结构
- ✓ 实现CRC8和CRC16校验算法
- ✓ 识别包头、长度、命令字段
- ✓ 理解长格式vs短格式包区别
关键发现:
// 短格式包(8字节)
[0x3D] [CMD] [LEN] [CRC8] [DATA] [CRC16_L] [CRC16_H] [END]
// 长格式包(17字节)
[0x3D] [CMD] [0x11] [CRC8] [SRC_H] [SRC_L] [DST_H] [DST_L]
[CMD] [PARAMS...] [CRC16_L] [CRC16_H]验证结果:
- CRC8 验证: 100% 通过
- CRC16 验证: 100% 通过
- 成功解析所有BMCU广播包
成果:
- ✓ 理解9位UART编码方式
- ✓ 成功接收BMCU数据(使用8N1 +
byte & 0x3F解码) - ✓ 识别第9位在第6、7位的编码规律
关键发现:
原始字节: 0xC5 (11000101)
解码字节: 0x05 (00000101)
第6-7位: 11 → 表示BMCU广播(从机)
原始字节: 0x05 (00000101)
解码字节: 0x05 (00000101)
第6-7位: 00 → 表示主机命令
统计分析 (来自18688字节抓包):
00(主机): 68.6%01: 9.1%10: 3.9%11(从机): 18.3%
成果:
- ✓ 成功抓取A1 mini与BMCU的完整通信数据
- ✓ 识别初始化序列
- ✓ 发现AMS Lite设备地址 (0x1200)
- ✓ 提取30个完整的A1命令包
关键数据:
初始化序列 (前4个命令):
1. 3D 05 00 00 13 00 8E 00 12 00 03 1A (含设备地址0x1200)
2. 3D 00 00 00 15 00 F4 00 03 00 12 1A (特殊握手命令)
3. 3D 05 00 00 13 00 8E 00 12 00 03 1A (重复)
4. 3D 05 00 00 13 00 8E 00 0F 00 03 1A (变体)
运行时命令 (最常见,26次出现):
RAW: 3D 05 01 02 68 FC 00 1C 01 24 08 E0 03 69 13 0C 20 C0 00 00
DEC: 3D 05 01 02 28 3C 00 1C 01 24 08 20 03 29 13 0C 20 00 00 00
C语言工具 (src/):
bmcu_comm.c- 主要交互式工具 (568行)test_ams_lite_init.c- AMS Lite初始化测试save_raw_stream.c- 二进制数据抓包capture_raw_realtime.c- 实时监听- 其他15+个诊断和测试工具
Python工具 (tools/):
analyze_9bit.py- 9位UART编码分析analyze_capture.py- 抓包数据分类extract_a1_commands.py- 提取A1命令
Shell脚本 (scripts/):
capture_a1.sh- 自动化抓包quick_test.sh- 快速测试
- 接口: RS485差分信号
- 波特率: 1,250,000 baud
- 帧格式: 9位UART (8数据位 + 1地址/数据位 + 偶校验)
包头: 0x3D (解码后)
第二字节:
0x00 - 0x3F: 主机命令0xC0 - 0xFF: 从机广播
长度字段:
- 短包:
0x08(8字节) - 长包:
0x11(17字节)
CRC校验:
- CRC8: poly=0x39, init=0x66 (用于前3字节)
- CRC16: poly=0x1021, init=0x913D (用于整个包)
0x0700 - AMS (标准四色换料器)
0x1200 - AMS Lite (双色换料器,A1 mini使用)
0x03 - 版本查询/设备注册
0x04 - 运动控制
0x05 - 状态查询
0x20 - 心跳包
问题: Linux标准termios不支持真正的9位UART
当前解决方案 (接收):
// 8N1模式接收,手动解码
uint8_t decoded = raw_byte & 0x3F; // 提取低6位作为数据
uint8_t bit67 = (raw_byte >> 6) & 0x03; // 提取高2位作为标志验证:
- ✓ 接收成功率: 100%
- ✓ CRC验证通过率: 100%
待解决 (发送):
- ❌ 8N1发送: BMCU不识别
- ❌ 8E1发送: BMCU不识别
⚠️ 可能需要真正的9位UART硬件支持
现象:
- LED始终保持红色(离线状态)
- 无论发送什么命令,BMCU无响应
- 在A1 mini上,同一BMCU的LED是绿色(在线)
已尝试的方案:
- ✗ 发送解码后的数据
- ✗ 发送原始RAW数据
- ✗ 使用8E1模式(8位+偶校验)
- ✗ 复制A1 mini的完整命令字节
- ✗ 按时间顺序发送初始化序列
- ✗ 设置AMS Lite设备地址(0x1200)
根本原因分析: 根据BMCU370源码 (BambuBus.cpp:1238-1283):
if (timex > time_set) {
stu = BambuBus_package_type::ERROR; // → LED RED
}BMCU需要每秒收到有效心跳包,否则标记为离线(LED红)。
我们发送心跳,但BMCU不认为是"有效"的。
可能原因:
-
9位UART发送问题:
- 我们用8位模式发送
- BMCU期望接收9位(8数据+1地址/数据位+1偶校验)
- 硬件层面可能拒绝了我们的数据
-
初始化流程缺失:
- 可能需要特定的握手序列
- 某些隐藏的注册步骤
-
硬件限制:
- USB-RS485转换器可能不支持9位模式
- 需要特殊硬件(Arduino, FTDI等)
问题:
- 我们能接收BMCU的数据 ✓
- 我们不知道BMCU是否收到我们的数据 ✗
建议方案:
- 使用示波器/逻辑分析仪验证波形
- 对比A1 mini发送 vs 我们发送的波形差异
问题: 当前抓包只能看到单向数据流(BMCU→A1或A1→BMCU),无法同时看到双向交互。
建议: 使用专业RS485监听设备或双通道逻辑分析仪。
使用支持9位UART的硬件桥接:
选项1: Arduino
// Arduino Mega支持9位UART
Serial1.begin(1250000, SERIAL_9N1); // 9位,无校验
// 或
Serial1.begin(1250000, SERIAL_9E1); // 9位,偶校验优势:
- ✓ 真正的9位UART支持
- ✓ 成本低(~$20)
- ✓ 可以精确控制第9位
实现步骤:
- Arduino连接BMCU(RS485)
- Arduino通过串口连接树莓派
- Klipper通过Arduino桥接控制BMCU
选项2: FTDI芯片 某些FTDI芯片支持9位模式,需要研究FT232H等型号。
尝试方向:
- 逐字节对比A1 mini发送的波形
- 尝试不同的termios配置组合
- 研究是否有Linux内核驱动可以支持9位UART
修改BMCU固件,支持8位UART通信:
- 需要BMCU的完整固件源码
- 或基于BMCU370开源固件修改
-
实现基础通信
- LED变绿(BMCU在线)
- 能发送运动命令
- BMCU正确响应
-
开发Klipper模块
# klipper/klippy/extras/bmcu.py class BMCU: def __init__(self, config): self.serial = serial.Serial('/dev/ttyUSB0', 1250000) def send_load_filament(self, slot): # 发送换料命令 pass
-
测试多色打印
- 单色换料
- 多色切换
- 自动换料逻辑
-
完整功能实现
- 支持AMS和AMS Lite
- 错误处理和恢复
- 断料检测
- 温度监控
-
开源发布
- 完善文档
- 制作教程视频
- 发布到GitHub
- 提交到Klipper主仓库
-
社区支持
- 建立Discord/论坛
- 收集用户反馈
- 持续改进
uint8_t crc8_calc(const uint8_t *data, size_t len) {
static uint8_t table[256];
static int initialized = 0;
if (!initialized) {
uint8_t poly = 0x39;
for (int i = 0; i < 256; i++) {
uint8_t crc = i;
for (int j = 0; j < 8; j++) {
crc = (crc & 0x80) ?
((crc << 1) ^ poly) & 0xFF :
(crc << 1) & 0xFF;
}
table[i] = crc;
}
initialized = 1;
}
uint8_t crc = 0x66; // 初始值
for (size_t i = 0; i < len; i++) {
crc = table[crc ^ data[i]];
}
return crc;
}uint16_t crc16_calc(const uint8_t *data, size_t len) {
static uint16_t table[256];
static int initialized = 0;
if (!initialized) {
uint16_t poly = 0x1021;
for (int i = 0; i < 256; i++) {
uint16_t val = i << 8;
for (int j = 0; j < 8; j++) {
val = (val & 0x8000) ?
((val << 1) ^ poly) & 0xFFFF :
(val << 1) & 0xFFFF;
}
table[i] = val;
}
initialized = 1;
}
uint16_t val = 0x913D; // 初始值
for (size_t i = 0; i < len; i++) {
val = table[((val >> 8) ^ data[i]) & 0xFF] ^
((val << 8) & 0xFFFF);
}
return val & 0xFFFF;
}struct termios tty;
memset(&tty, 0, sizeof(tty));
// 基础配置:8N1
tty.c_cflag = B38400 | CS8 | CREAD | CLOCAL;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 1;
tcsetattr(fd, TCSANOW, &tty);
// 设置自定义波特率
struct serial_struct serinfo;
ioctl(fd, TIOCGSERIAL, &serinfo);
serinfo.custom_divisor = serinfo.baud_base / 1250000;
serinfo.flags = (serinfo.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
ioctl(fd, TIOCSSERIAL, &serinfo);抓包统计 (18688字节,10秒):
- BMCU广播包: 307个 (
3D C5) - A1命令包: 149个 (
3D 05) - 包含0x1200 (AMS Lite地址): 6个
- 包含0x0700 (AMS地址): 0个
验证率:
- CRC8验证通过: 100%
- CRC16验证通过: 100%
- 包解析成功: 100%
// 简化的状态机逻辑
enum BambuBus_package_type {
NONE,
heartbeat, // 心跳
ERROR, // 错误/离线
// ... 其他状态
};
BambuBus_package_type BambuBus_run() {
static uint64_t time_set = 0;
if (BambuBus_have_data) {
switch (get_packge_type(buf_X, data_length)) {
case heartbeat:
time_set = timex + 1000; // 重置1秒超时
break;
// ...
}
}
// 超时检测
if (timex > time_set) {
return ERROR; // → LED变红
}
return current_state;
}关键点:
- 心跳包必须每秒发送
- 超过1秒无有效心跳 → 离线状态(LED红)
- 我们的问题:BMCU不认为我们的心跳包"有效"
-
BMCU370 (开源BMCU固件)
- GitHub: https://github.com/peng-zhihui/BMCU370
- 文件:
src/BambuBus.cpp,src/BambuBus.h - 关键函数:
BambuBus_run(),get_packge_type()
-
Klipper
- GitHub: https://github.com/Klipper3d/klipper
- 参考模块:
klippy/extras/(extras模块开发)
-
RS485通信
- 标准: TIA/EIA-485
- 差分信号: A、B两线
-
9位UART
- 格式: 8数据位 + 1地址/数据位 + 奇偶校验位
- 用途: 多机通信中区分地址和数据
-
逻辑分析仪 (推荐)
- Saleae Logic
- DSLogic
- 用于波形分析
-
串口调试
- minicom
- screen
- pyserial
- 2024-12-31: 初始版本,总结当前所有进展
- 待更新...
- tope - 项目发起人和主要开发者
- Claude (Anthropic) - 技术协助和代码开发
最后更新: 2024-12-31 项目状态: 早期开发阶段(原型验证) 下一个里程碑: 实现BMCU在线(LED绿)