Project architecture

从按下 Voice 到生成 UF2,这个项目怎样工作?

我们从首次可构建的五键原型出发,沿着“按钮输入”和“固件构建”两条链路,理解代码为什么存在,以及每个目录和文件负责什么。

历史基线:首次可构建的五键 ZMK 原型
01 · 系统全貌

这个仓库不是一个传统应用

仓库里没有自己编写的主循环,也没有一套 C/C++ 应用代码。它更像一组交给 的声明:选择哪块开发板、按钮接在哪些 GPIO、五个位置分别做什么,以及怎样构建和刷写。

按钮与 GPIO ZMK shield USB / BLE HID
Git push GitHub Actions ZMK 构建 UF2
运行时

设备上电以后

ZMK 扫描 D0–D4,识别按钮状态,再把对应的键盘事件通过 USB 或蓝牙发给电脑。

构建时

代码推送以后

GitHub Actions 读取构建矩阵和 shield 配置,调用 ZMK 官方工具链,最后产出可刷写的 UF2。

遥控器不采集语音 Voice 键只发送 F13。麦克风仍在电脑或耳机上,电脑端语音软件负责监听 F13 并开始或停止录音。
02 · Runtime flow

按下一颗按钮以后发生了什么?

运行链路依次经过物理电路、GPIO 扫描、位置顺序、键位绑定和 HID 传输。每层只回答一个问题。

  1. 电路:按钮把一个 XIAO GPIO 接到 GND。
  2. 扫描:ai_remote.overlay 告诉 ZMK 读取 D0–D4,并启用内部上拉与低电平有效。
  3. 位置:同一个 overlay 把五个 GPIO 排成从 0 到 4 的一行五列。
  4. 行为:ai_remote.keymap 按相同顺序绑定 F13、↑、Enter、↓ 和 BT_NXT。
  5. 输出:ZMK 根据配置通过 USB HID 或 BLE HID 把事件发给电脑。

硬件输入:ai_remote.overlay

boards/shields/ai_remote/ai_remote.overlay · D0–D4
input-gpios
    = <&xiao_d 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
    , <&xiao_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
    , <&xiao_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
    , <&xiao_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
    , <&xiao_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;

GPIO_PULL_UP 让松开状态保持为高电平;GPIO_ACTIVE_LOW 表示按下接地后读到低电平时,才算按钮激活。这样每颗按钮只需要 GPIO 和 GND 两根连接。

位置到行为:ai_remote.keymap

五个位置必须与 D0–D4 顺序一致
bindings = <
    &kp F13
    &kp UP_ARROW
    &kp RETURN
    &kp DOWN_ARROW
    &bt BT_NXT
>;

&kp 发送普通键盘按键;&bt BT_NXT 不发送字符,而是让 ZMK 切换到下一个 Bluetooth profile。五个 profile 的管理、配对信息保存和 BLE HID 传输由 ZMK 提供。

启用传输与持久设置:ai_remote.conf

USB、BLE 和 settings
CONFIG_ZMK_USB=y
CONFIG_ZMK_BLE=y
CONFIG_SETTINGS=y

USB 和 BLE 在原型期同时可用,便于先验证 USB 按键再排查蓝牙。CONFIG_SETTINGS 让配对等 ZMK 设置能够持久保存。

03 · Build flow

GitHub 怎样把这些声明变成 UF2?

构建链路的重点不是“执行一个神秘编译命令”,而是让 ZMK 能找到这个仓库作为额外模块,并知道要组合哪块 board 与哪套 shield。

  1. .github/workflows/build.yml 在 push、pull request 或手动触发时调用 ZMK 官方可复用工作流。
  2. config/west.yml 固定 ZMK v0.3,并导入 ZMK 自己的依赖清单。
  3. zephyr/module.yml 告诉 Zephyr:这个仓库根目录可以提供 board/shield 定义。
  4. build.yaml 声明两个构建目标:正常遥控器和 settings-reset 恢复固件。
  5. ZMK 根据 xiao_ble + ai_remote 找到 boards/shields/ai_remote/ 下的配置。
  6. 工具链合并 board、shield、Kconfig、Devicetree 和 keymap,生成 UF2 artifact。

.github/workflows/build.yml

只负责“什么时候构建”和“调用哪套官方流程”。它不重复实现 ZMK 的安装与编译步骤。

可复用工作流
jobs:
  build:
    uses: zmkfirmware/zmk/.github/workflows/
      build-user-config.yml@v0.3

build.yaml

它是构建矩阵。第一个目标生成日常固件,第二个目标生成清空 ZMK settings 的恢复固件。

board + shield
- board: xiao_ble
  shield: ai_remote
  artifact-name: ai-remote
- board: xiao_ble
  shield: settings_reset
  artifact-name: settings-reset
为什么需要两份 UF2? 正常固件负责使用;settings-reset 负责清空损坏或过期的持久配对信息。恢复后仍要重新刷回正常固件。
04 · Repository map

首次可构建原型的完整目录地图

下面展示首次可构建原型使用的历史路径。现有仓库中的 ai_voice_remote 对应这里的 ai_remote,各层职责相同。

仓库树 · 21 个受版本控制的文件
.
├── .github/workflows/build.yml       # 云端构建入口
├── boards/shields/ai_remote/         # 五键硬件与行为定义
│   ├── Kconfig.defconfig
│   ├── Kconfig.shield
│   ├── ai_remote.conf
│   ├── ai_remote.keymap
│   ├── ai_remote.overlay
│   └── ai_remote.zmk.yml
├── config/west.yml                   # ZMK 依赖清单
├── zephyr/module.yml                 # 把仓库注册为 Zephyr 模块
├── build.yaml                        # 云端构建矩阵
├── scripts/                          # 检查、构建、刷写
│   ├── check-config.py
│   ├── build-firmware.sh
│   └── flash-firmware.sh
├── docs/                             # 操作与验收文档
│   ├── firmware.md
│   ├── product-spec.md
│   └── wiring.md
├── hardware/README.md                # 接线证据与未来 PCB 边界
├── enclosure/README.md               # 未来外壳工作的进入条件
├── README.md                         # 项目入口
├── .gitignore                        # 排除本地和生成文件
└── LICENSE                           # MIT 许可
05 · File responsibilities

每个目录和文件分别负责什么?

这里按职责分组。文件之间真正重要的契约是:build.yaml 选择的 shield 名、目录名、Kconfig 条件和文件前缀必须互相匹配。

README.md

项目入口:产品边界、五键映射、当前阶段、构建方法和主要目录。

.github/workflows/build.yml

定义云端构建触发条件,并调用 ZMK 官方构建工作流。

build.yaml

列出 board、shield 与 artifact 名;决定云端要生成哪几份固件。

config/west.yml

West manifest:固定 ZMK v0.3、远程地址和需要导入的依赖。

zephyr/module.yml

把仓库根目录声明为 Zephyr 的 board_root,让构建系统能发现 shield。

.gitignore

排除 .build/、west workspace、缓存、日志以及生成的 UF2/HEX/BIN。

LICENSE

MIT 许可证,说明代码的使用、修改、分发条件和免责声明。

06 · Engineering boundaries

哪些东西已经存在,哪些仍然只是计划?

仓库已经具备
  • 五键 GPIO 与 keymap 声明;
  • USB HID 与 BLE HID 配置;
  • 多 profile 切换行为;
  • 正常与恢复固件构建目标;
  • 本地检查、构建和安全复制脚本;
  • 接线、刷写和验收文档。
尚未由代码证明
  • 真实按钮已经正确接线;
  • 五个键在主机上没有漏键或双击;
  • 三台电脑切换稳定;
  • 睡眠后的第一次按键不丢失;
  • PCB、电池和外壳尺寸可用;
  • 连续使用时的真实续航。
配置检查不等于真实编译,真实编译也不等于硬件成功 check-config.py 抓明显结构错误;ZMK 编译证明配置能被工具链接受;只有刷入真实 XIAO 并测量按键、BLE 和电源,才能证明设备行为。
07 · Check understanding

读完后,你应该能解释这些问题

一句话心智模型 这个仓库用 ZMK shield 描述五键硬件和行为,用 West/Zephyr 把描述接入工具链,用 GitHub Actions 或本地脚本生成 UF2,再通过真实硬件测试补上编译无法证明的部分。

内容依据首次可构建原型的 Git 历史快照 efd0458。这个 SHA 只用于固定证据版本,不是本课的学习目标。

术语解释