Skip to content

Latest commit

 

History

History
510 lines (398 loc) · 11.7 KB

File metadata and controls

510 lines (398 loc) · 11.7 KB

BMCU Klipper 技术总结文档

📋 目录

  1. 项目背景
  2. 技术成果
  3. 协议分析
  4. 待解决问题
  5. 下一步计划
  6. 技术细节

项目背景

目标

将 Bambu Lab 的 BMCU(AMS控制器)集成到 Klipper 固件,实现:

  • 使用BMCU硬件进行多色打印
  • 不依赖原厂固件
  • 完全开源的解决方案

硬件环境

  • BMCU: Bambu Lab AMS/AMS Lite控制板
  • 通信接口: RS485 (通过USB-485转换器)
  • 测试设备: A1 mini 打印机(用于抓包参考)

技术成果

✅ 已完成的工作

1. BambuBus协议逆向工程

成果:

  • ✓ 完整解析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广播包

2. 9位UART通信研究

成果:

  • ✓ 理解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%

3. A1 mini通信抓包

成果:

  • ✓ 成功抓取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

4. 工具开发

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 - 快速测试

协议分析

BambuBus协议规范

物理层

  • 接口: 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 - 心跳包

9位UART编码机制

问题: 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硬件支持

待解决问题

🔴 关键问题

1. BMCU不识别我们发送的命令

现象:

  • 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不认为是"有效"的。

可能原因:

  1. 9位UART发送问题:

    • 我们用8位模式发送
    • BMCU期望接收9位(8数据+1地址/数据位+1偶校验)
    • 硬件层面可能拒绝了我们的数据
  2. 初始化流程缺失:

    • 可能需要特定的握手序列
    • 某些隐藏的注册步骤
  3. 硬件限制:

    • USB-RS485转换器可能不支持9位模式
    • 需要特殊硬件(Arduino, FTDI等)

2. 缺乏双向通信验证

问题:

  • 我们能接收BMCU的数据 ✓
  • 我们不知道BMCU是否收到我们的数据 ✗

建议方案:

  • 使用示波器/逻辑分析仪验证波形
  • 对比A1 mini发送 vs 我们发送的波形差异

3. 缺少BMCU响应抓包

问题: 当前抓包只能看到单向数据流(BMCU→A1或A1→BMCU),无法同时看到双向交互。

建议: 使用专业RS485监听设备或双通道逻辑分析仪。


下一步计划

短期目标(1-2周)

方案A: 硬件方案 (推荐)

使用支持9位UART的硬件桥接:

选项1: Arduino

// Arduino Mega支持9位UART
Serial1.begin(1250000, SERIAL_9N1);  // 9位,无校验
//
Serial1.begin(1250000, SERIAL_9E1);  // 9位,偶校验

优势:

  • ✓ 真正的9位UART支持
  • ✓ 成本低(~$20)
  • ✓ 可以精确控制第9位

实现步骤:

  1. Arduino连接BMCU(RS485)
  2. Arduino通过串口连接树莓派
  3. Klipper通过Arduino桥接控制BMCU

选项2: FTDI芯片 某些FTDI芯片支持9位模式,需要研究FT232H等型号。

方案B: 继续调试软件方案

尝试方向:

  1. 逐字节对比A1 mini发送的波形
  2. 尝试不同的termios配置组合
  3. 研究是否有Linux内核驱动可以支持9位UART

方案C: 固件修改(长期)

修改BMCU固件,支持8位UART通信:

  • 需要BMCU的完整固件源码
  • 或基于BMCU370开源固件修改

中期目标(1-2个月)

  1. 实现基础通信

    • LED变绿(BMCU在线)
    • 能发送运动命令
    • BMCU正确响应
  2. 开发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
  3. 测试多色打印

    • 单色换料
    • 多色切换
    • 自动换料逻辑

长期目标(3-6个月)

  1. 完整功能实现

    • 支持AMS和AMS Lite
    • 错误处理和恢复
    • 断料检测
    • 温度监控
  2. 开源发布

    • 完善文档
    • 制作教程视频
    • 发布到GitHub
    • 提交到Klipper主仓库
  3. 社区支持

    • 建立Discord/论坛
    • 收集用户反馈
    • 持续改进

技术细节

CRC算法实现

CRC8 (poly=0x39, init=0x66)

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;
}

CRC16 (poly=0x1021, init=0x913D)

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;
}

串口配置 (Linux)

自定义波特率1250000

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%

BMCU状态机 (参考BMCU370)

// 简化的状态机逻辑
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不认为我们的心跳包"有效"

参考资料

源码参考

  1. BMCU370 (开源BMCU固件)

  2. Klipper

硬件资料

  1. RS485通信

    • 标准: TIA/EIA-485
    • 差分信号: A、B两线
  2. 9位UART

    • 格式: 8数据位 + 1地址/数据位 + 奇偶校验位
    • 用途: 多机通信中区分地址和数据

工具

  1. 逻辑分析仪 (推荐)

    • Saleae Logic
    • DSLogic
    • 用于波形分析
  2. 串口调试

    • minicom
    • screen
    • pyserial

文档修订历史

  • 2024-12-31: 初始版本,总结当前所有进展
  • 待更新...

贡献者

  • tope - 项目发起人和主要开发者
  • Claude (Anthropic) - 技术协助和代码开发

最后更新: 2024-12-31 项目状态: 早期开发阶段(原型验证) 下一个里程碑: 实现BMCU在线(LED绿)