🤖 roboto_origin_03 Wiki
首页 / 固件 / 多仓库协同与子模块管理

人形机器人固件工程天然横跨异构计算域:MCU 上的实时 USB2CAN 适配器、基于 RK3588 的 ARM64 主控板、以及基于 RDK X5 的协处理单元。这三类子系统的源码规模、依赖深度与社区生态差异极大,若强行塞入单一 monorepo,将导致提交历史臃肿、权限边界模糊与工具链冲突。atom01_firmware 并未试图成为“大一统”的源码仓库,而是扮演**聚合器(Aggregator)**角色——通过 Git Submodule 绑定三个独立演进的子仓库,并允许每个子仓库在其内部采用最适合该领域生态的依赖管理工具。理解这种分层架构,是高效进行跨子系统联调与镜像集成的前提。

Sources: readme_cn.md

聚合层架构:Git Submodule 拓扑

根仓库的 .gitmodules 仅声明了三项子模块映射,自身不承载任何编译源码。这种“薄聚合层”设计使得各子系统可以独立维护版本标签、独立触发 CI、独立面向各自社区发布。

子模块路径 远程仓库 职责定位
roboto_usb2can/ wentywenty/roboto_usb2can Zephyr RTOS 固件,负责 USB↔CAN 协议转换
orangepi-build/ wentywenty/orangepi-build Armbian 风格构建系统,为主控板生成 Linux 镜像与内核 DEB
x5-rdk-gen/ wentywenty/x5-rdk-gen RDK X5 镜像生成器,输出协处理器固件与 Rootfs

克隆时需要显式拉取子模块,否则仅得到空目录。根仓库的 readme_cn.md 明确提示:所有编译产物(镜像、固件、工具)均发布在各子模块的 Release 页面中,主仓库本身不存储二进制分发件。

Sources: .gitmodules Sources: readme_cn.md

子系统内部的三套依赖管理范式

若将视角从聚合层下沉到每个子仓库内部,会发现它们采用了三种截然不同的源码同步策略。这种异构并非历史债务,而是对各子系统生态的主动适配。

flowchart TD
    A[atom01_firmware 聚合层<br/>Git Submodule] --> B[roboto_usb2can]
    A --> C[orangepi-build]
    A --> D[x5-rdk-gen]
    
    B --> B1[Zephyr West Manifest<br/>west.yml]
    B1 --> B2[zephyrproject-rtos/zephyr]
    B1 --> B3[CANnectivity/cannectivity]
    
    C --> C1[fetch_from_repo 动态拉取<br/>scripts/general.sh]
    C1 --> C2[内核/固件/工具源码<br/>external/cache/sources]
    C1 --> C3[CI 显式 clone<br/>igh-deb 等外围包]
    
    D --> D1[Google Repo 多仓库同步<br/>D-Robotics/x5-manifest.git]
    D1 --> D2[source/ 下数十个 BSP 仓库<br/>kernel/bootloader/hobot-*]

Zephyr West Manifest(roboto_usb2can)

roboto_usb2can 基于 Zephyr RTOS 构建。Zephyr 社区使用 West 作为元工具,其依赖声明集中在 west.yml。该 manifest 定义了两个远端(remote)与两个项目(project):

Sources: roboto_usb2can/west.yml

动态按需拉取 fetch_from_repo(orangepi-build)

orangepi-build 继承自 Armbian 构建框架,其依赖管理方式并非静态 submodule,而是构建脚本中的 fetch_from_repo 函数。该函数定义于 scripts/general.sh,支持四种引用类型:branch:tag:headcommit:。其核心逻辑为:

  1. external/cache/sources/ 下建立本地缓存目录;
  2. 通过 git ls-remote 比对远端哈希与本地 HEAD,仅在发生变更时才执行 git fetch --depth 200
  3. 若启用 OFFLINE_WORK=yes,则跳过所有网络操作,直接复用本地缓存;
  4. 若缓存目录本身是一个 Git 仓库且包含 .gitmodules,则递归调用 fetch_from_repo 更新嵌套子模块。

这种设计的优势在于延迟加载与离线复用:构建系统不会在克隆时一次性拉取所有内核源码、固件 blob 与第三方包,而是在首次执行对应构建目标时才按需下载。例如,内核源码、固件、oh-my-zsh、wiringOP 等均通过此机制获取。对于更外围的 Debian 包(如 igh-deb 用于 IgH EtherCAT),构建脚本或 CI 工作流会选择在运行时显式 git clone --recurse-submodules,而非硬编码到 fetch_from_repo 中,从而获得更灵活的版本控制。

Sources: orangepi-build/scripts/general.sh Sources: orangepi-build/scripts/compilation.sh

Google Repo 多仓库同步(x5-rdk-gen)

x5-rdk-gen 面向 D-Robotics RDK X5 平台,其 BSP 由数十个仓库组成(内核、Bootloader、多媒体驱动、示例代码等)。这种规模下,Git Submodule 会导致索引文件爆炸,而 West 并非 Linux BSP 的主流工具。因此项目采用 Google Repo 作为多仓库编排器:

Repo 的 manifest 仓库本身不包含源码,仅维护一份 XML 清单,描述各组件仓库的 URL、路径与修订版本。这意味着 x5-rdk-gen 作为 atom01_firmware 的一个 submodule,其内部再通过 Repo 展开为完整的 BSP 源码树。两层解耦使得 x5-rdk-gen 的构建脚本与具体的内核/驱动仓库版本解耦,版本锁定由 D-Robotics 官方 manifest 统一管理。

Sources: x5-rdk-gen/build.sh

跨仓库源码同步机制对比

维度 Zephyr West fetch_from_repo Google Repo
适用场景 RTOS 嵌入式固件 大型构建系统的按需依赖 Android/BSP 式多仓库
配置位置 west.yml 构建脚本内嵌参数 独立 manifest 仓库(XML)
本地缓存 ~/.west 或工作区 external/cache/sources/ .repo/source/
离线支持 有限(依赖网络初始化) 显式 OFFLINE_WORK=yes 可基于已 sync 的源码离线构建
深度抓取 默认全量克隆 --depth 200 浅克隆 默认全量克隆,可配置
子模块处理 递归导入 import: true 递归调用 fetch_from_repo Repo 自身管理,不混用 Git Submodule

Sources: roboto_usb2can/west.yml Sources: orangepi-build/scripts/general.sh Sources: x5-rdk-gen/build.sh

CI/CD 构建链的独立协同

由于三个子仓库的版本演进节奏不同,CI 流水线被设计为独立触发、独立发布,而非在主仓库层面进行统一构建。这种“去中心化”的构建策略降低了耦合,但也要求开发者明确各子仓库的产物边界。

flowchart LR
    subgraph roboto_usb2can_CI ["roboto_usb2can CI"]
        R1[zephyr-build.yml<br/>编译 ARM 固件]
        R2[build-tool-exe.yml<br/>编译 Windows 上位机]
    end
    
    subgraph orangepi_build_CI ["orangepi-build CI"]
        O1[build-kernel.yml<br/>内核/头文件/设备树 DEB]
        O2[CI 内嵌步骤<br/>clone igh-deb 并编译 EtherCAT DEB]
    end
    
    subgraph x5_rdk_gen ["x5-rdk-gen"]
        X1[无本地 CI Workflow<br/>依赖手动或外部触发]
    end
    
    R1 -->|Release .bin| Release1[GitHub Release]
    R2 -->|Release .exe| Release1
    O1 -->|Release .deb| Release2[GitHub Release]
    O2 -->|Release .deb| Release2
    X1 -->|本地输出 .img/.zip| Local[本地产物或外部 CI]

Sources: roboto_usb2can/.github/workflows/zephyr-build.yml Sources: roboto_usb2can/.github/workflows/build-tool-exe.yml Sources: orangepi-build/.github/workflows/build-kernel.yml

日常开发工作流与命令速查

以下表格汇总了在聚合仓库与各子仓库之间切换、同步、构建时最常用的命令。

场景 命令 说明
首次完整克隆 git clone --recursive <url> 一次性拉取聚合层与所有 submodule
补充拉取子模块 git submodule update --init --recursive 若初次遗漏,恢复空目录
更新所有子模块 git submodule update --remote 追踪子仓库远端最新提交(慎用,可能破坏锁定)
USB2CAN 构建准备 west init -m . && west update 在 roboto_usb2can 目录或其父工作区执行
OrangePi 离线构建 export OFFLINE_WORK=yes 避免 fetch_from_repo 重复访问网络
RDK X5 源码同步 ./build.sh setup 内部执行 repo initrepo sync
RDK X5 全量构建 sudo ./build.sh all 串行执行 setup → kernel → bootloader → rootfs → debs → pack

Sources: readme_cn.md Sources: roboto_usb2can/.github/workflows/zephyr-build.yml Sources: x5-rdk-gen/build.sh

设计权衡与最佳实践

为何 orangepi-build 不采用 Git Submodule 管理内核与工具源码?
Armbian 构建系统需要支持数十种板卡与多个内核分支,若将每个内核源码、固件仓库都声明为 submodule,.gitmodules 将膨胀到难以维护,且每次切换板卡配置都需切换 submodule 的 commit 指针。fetch_from_repo 的按需拉取策略将“需要哪些源码”的决策推迟到构建时,由板卡配置文件与脚本共同决定,保持了聚合层的轻量。

为何 x5-rdk-gen 不将 source/ 下的 BSP 仓库直接放入本仓库?
RDK X5 的 BSP 包含 kernel、bootloader、hobot-miniboot、hobot-multimedia 等数十个组件,且这些组件由 D-Robotics 官方独立迭代。使用 Repo 将版本清单(manifest)与源码仓库物理分离,使得 x5-rdk-gen 只需跟踪 manifest 仓库的一个修订,即可在 CI 或本地环境中复现完整的 BSP 快照,符合大型嵌入式平台的主流治理模式。

跨子仓库修改时的注意事项
若某次功能变更同时涉及 roboto_usb2can 的协议定义与 orangepi-build 的内核 CAN 驱动补丁,开发者需要分别在两个子仓库中提交 PR,并确保各自 CI 通过。主仓库的 Git Submodule 指针更新应当作为最后一步,通过一次独立的“指针升级”提交将两个已通过验证的 commit 锁定到聚合层。切勿在主仓库直接修改子模块目录内容后再反向提交,这将导致子仓库的提交历史与聚合层不同步。

Sources: orangepi-build/scripts/general.sh Sources: x5-rdk-gen/build.sh


理解 atom01_firmware 的“薄聚合层 + 厚子系统”架构后,开发者可以更精准地定位问题:固件编译异常首先检查 West 工作区与 Zephyr SDK;内核缺失驱动则审视 OrangePi 的 fetch_from_repo 缓存与 userpatches;RDK X5 镜像构建失败则优先确认 repo sync 完整性与 source/ 目录的交叉编译 sysroot 状态。如需深入特定子系统的构建细节,可继续阅读 构建流程与脚本编排全量构建与子命令解析Zephyr RTOS 与 USB 协议栈