以 Bumi 为例:Docker 镜像 + PR 自动构建 + 真机画布验证全流程

原创 · 具身智能 · 机器人驱动开发 

摘 要 机器人平台上的「卡片」本质上就是一段能被镜像拉起的功能代码:你在本地写逻辑,平台按 Dockerfile 帮你构建镜像,真机把镜像跑成容器,卡片便自动出现在仪表盘上。本文以 Bumi 机器人为例,把这条链路完整走一遍——Fork 仓库、克隆源码、编写 Morse 电码功能、提交 PR 触发自动构建、把镜像拉到真机、在画布上验证,最后关闭容器收尾;顺带记录 5 个我实际踩过的坑。全文配 29 张实拍截图,跟着做完,独立完成自己的第一张卡片大约只需要 1~2 小时。

标签: #具身智能  #Docker  #机器人驱动  #镜像构建  #CSDN

单位: 第四范式·海南具身智能实验室

本文目录 一、先搞懂三件事 二、整体流程 三、Fork 仓库 四、克隆源码 五、写功能代码 六、构建镜像 七、画布测试 八、关闭容器 九、踩坑记录 十、总结

写在前面

刚接触具身智能平台时,我最困惑的不是「功能代码怎么写」,而是「代码写完了,为什么机器人还是不会动」。折腾了两天才想明白:真机上根本没有你的 .py 文件,它只认镜像。代码写得再漂亮,只要没进镜像,对机器人来说就等于不存在。

这篇文章按我自己的开发顺序整理,尽量避免术语堆砌,每一步都给出对应的操作和验证方式。文中以 Bumi 机器人 + Morse(摩尔斯电码)功能为例,你把它换成自己的机器人名和功能即可;29 张截图全部来自真机与浏览器实际操作,可以对着一步步照做。

一、先搞懂三件事:Docker、镜像与容器

如果直接冲到「写代码」这一步,后面构建镜像时会非常痛苦。花五分钟把这三个概念理清楚,整条流程就只是一套固定动作了。

1.1 Docker:把「在我电脑上能跑」变成「在哪儿都能跑」

Docker 是一个开源的容器化平台,它把程序和程序需要的所有依赖、配置打包成一个标准化的「集装箱」,做到一次打包、到处运行。它解决的是一个经典问题:在我电脑上能跑,到了服务器上就跑不起来——因为两边的系统、库版本、环境变量不一样。集装箱装好之后,不管装上哪条船,里面的货都一样。

1.2 镜像、容器、仓库:一个模具的比喻

三个词经常被混着用,其实分工很清楚:

概念

是什么

类比

在本项目中的位置

镜像
Image

静态只读模板,包含代码、运行时、库和配置

模具 / 安装包

Fork 仓库里的代码 + Dockerfile 构建出来的产物

容器
Container

镜像运行起来的实例,进程相互隔离;一个镜像可以启动无数个容器

模具压出来的产品

真机上真正跑起来、出现在仪表盘的那张卡片

仓库
Registry

存放和分享镜像的地方,官方仓库叫 Docker Hub

代码仓库 GitHub

构建完成后存放镜像、供真机拉取的地方

Dockerfile

描述「怎么把源码做成镜像」的构建脚本

生产图纸

驱动仓库根目录,需要随功能代码一起修改

表 1 四个核心概念对照

1.3 Dockerfile:卡片从源码变成镜像的那道工序

这是整篇文章里最值得先记住的一句话:机器人上没有你的代码,它只会通过 Dockerfile 构建出的镜像,在容器里运行功能。 Dockerfile 里通常写清了四件事——用哪个基础镜像、把哪些文件拷进镜像、装哪些依赖、启动时执行什么命令。

所以写完 Morse.py 之后,如果不去改 Dockerfile,会发生一件很常见的事:镜像构建得很成功,容器也起来了,但卡片「什么也不会做」,因为你的功能代码压根没被打进镜像。

图 1 Dockerfile 在驱动仓库中的位置

注意 功能代码和 Dockerfile 是一对,必须一起改。我的习惯是让 AI 在写功能代码的同时顺手把 Dockerfile 补好,然后再自己核对一遍「新增文件有没有被 COPY 进去」这一行。

1.4 卡片、驱动、容器三者的关系

把上面几条串起来:一张 driver 卡片,本质上就是一个容器化服务。驱动仓库描述它、Dockerfile 打包它、镜像固化它、容器运行它。运行起来之后,平台自动把它注册成仪表盘上的一张卡片——你在画布上拖它、连线、触发,实际调用的是那个容器里的功能。

二、整体流程:一张表先看全局

把全流程拆成六步,第 4 步(构建镜像)是初学者最容易卡住的地方,也是本文的重点。

步骤

要做什么

关键产出

1 Fork

在平台上 Fork 一份驱动仓库到自己的账号下

属于你的仓库副本

2 克隆

把源码下载到本地任意目录

可编辑的本地工程

3 写代码

新建分支,加入功能代码,同步修改 Dockerfile

feat/bumi-driver 分支

4 构建镜像

提交 → 发起 PR → 评论触发 review bot → curl 拉到真机

可运行的镜像

5 画布测试

开隧道、登录仪表盘、连线、发指令验证

卡片跑通的证据

6 收尾

关闭智能体、停掉容器,把机器让给别人

干净的运行环境

表 2 卡片开发六步流程

三、Step 1|Fork:给自己的驱动仓库开个副本

进入要开发的驱动仓库,点击 Fork,一份副本就落到了你自己的账号下。Fork 是仓库的一个副本,你可以在这份副本上自由尝试各种改动,而不会影响原始项目——这也是为什么必须走 Fork:主仓库通常没有你的写权限,而 PR 只能从你自己的仓库发起。

图 2 Fork 之后的仓库

提示 Fork 之后的仓库和原仓库是两条线。原仓库更新了,你的副本不会自动同步,需要手动同步或重新 Fork。

四、Step 2|把源码克隆到本地

在任意路径下新建一个机器人驱动源码文件夹,右键选择在终端中打开,执行克隆命令。仓库地址在 Fork 后仓库页面的 Code 按钮里复制。

图 3 驱动仓库的源码地址

图 4 复制源码地址

# 1) 新建源码文件夹,右键 →「在终端中打开」
# 2) 把 fork 仓库下载到本地(地址在 Code → HTTPS 里复制)
git clone https://github.com/<你的GitHub用户名>/<驱动仓库名>.git
cd <驱动仓库名>

图 5 驱动仓库下载到本地的指令

克隆完成后,先花两分钟认一下目录结构。本例新增的功能文件放在 noetix/bumi 下,根目录的 Dockerfile 则负责把这些文件打进镜像。

<驱动仓库名>/
├── noetix/
│   └── bumi/                # Bumi 机器人驱动目录
│       ├── Morse.py         # 本例新增的功能代码
│       └── ...              # 该机器人已有的文件
├── Dockerfile               # 镜像构建脚本(必须一起改)
└── README.md

五、Step 3|写机器人功能代码

5.1 先建分支,再动手

在 VSCode 里新建并切换到一条功能分支,命名规范如下:

图 6 在 VSCode 上创建分支

feat/<你的机器人名>-driver      # 卡片描述

# 本项目 <你的机器人名> 为 bumi,因此分支名为:
git checkout -b feat/bumi-driver

每个新卡片都要建一条新分支,这是后面第九节会重点强调的一条纪律:同一条分支上反复改动,会把之前已经构建成功的镜像覆盖掉。

5.2 把功能代码写进驱动目录

选中 feat/bumi-driver 分支,打开机器人文件夹(本例为 noetix/bumi),在里面加入自己的功能代码。本例实现的是 Morse 摩尔斯电码:输入一段用点和划表示的电码,机器人把它解码后语音播报出来。

图 7 机器人代码文件(noetix/bumi 目录)

代码可以自己写,也可以让 AI 生成——但要交代清楚上下文:语言、框架、输入输出形式、以及「这是一个会被容器拉起的驱动卡片」。

5.3 顺手改掉 Dockerfile

这是最容易漏的一步。新文件要真正进入镜像,Dockerfile 里必须把它包含进来(拷贝目录、声明入口)。让 AI 写功能代码时,一并要求它更新 Dockerfile,然后自己再对着镜像构建日志确认一遍。

一句话记住 代码进仓库不等于代码进镜像。仓库是给人看的,镜像才是给机器人跑的。

六、Step 4|构建镜像:整条流程的分水岭

接下来这一步,初学者最容易迷路:界面里既没有一个叫「构建」的按钮,也不知道自己在等什么。其实整件事就是一句话——把你的代码推上去,让平台的机器人替你构建镜像。搞懂之后,它和写一份 Word 文档一样简单。

6.1 提交源代码

在 VSCode 左侧点击源代码管理。当有新代码或有代码被修改时,这个图标会出现数字角标,提示待提交的文件数量。

图 8 在 VSCode 上提交源代码

1. 点击暂存更改,把所有改动放进暂存区。

图 9 把所有改动暂存后的状态

2. 填写提交信息,点击提交。

3. 点击同步 / 推送,把提交推到 GitHub 上的 fork 仓库。

# 习惯用命令行的话,等价操作是:
git add .
git commit -m "feat(bumi): add Morse driver card"
git push origin feat/bumi-driver

提示 提交本质上是往 GitHub 推数据,受网速影响,有时候要等很久,也可能直接失败。失败时先别怀疑代码,多点几次提交/推送往往就好了;连续失败再检查网络和仓库权限。

6.2 发起 PR 并触发自动构建

推送完成后,回到 GitHub 上你的 fork 仓库,进入刚才那条分支。

图 10 进入 GitHub 上的分支

页面会出现分支推送提示,点击 Compare and pull request 跳转到 PR 页面。

图 11 进入 PR 请求界面

1. 先写清楚卡片的标题和描述:这张卡片叫什么、做什么、输入输出是什么。

图 12 撰写卡片标题与描述

2. 在 PR 页面评论区输入 /request_bot_review 并发送。

图 13 在 PR 评论区触发 review bot

3. 等待一段时间,review bot 会给出构建结果,以及创建好的镜像和对应指令。

/request_bot_review

6.3 拿到 curl,把镜像拉到真机

构建成功后,PR 里会出现一个 Try it 区块,里面是一条 curl 指令,把它复制下来。接下来通过 SSH 进入真机执行——不同项目的具体指令不一样,但框架相同:把 curl 连同「我在什么设备上、要做什么」一起丢给 AI,让它给出准确的登录与执行命令,通常比翻文档快得多。

图 14 Try it 区块里给出的 curl 指令

1. 登录机器人。

图 15 SSH 登录机器人

2. 执行 Try it 里的 curl 指令,拉取镜像。

图 16 在真机上拉取镜像

3. 命令执行完没有报错,说明镜像拉取成功。

图 17 镜像拉取成功后的输出

# 登录真机(示例:端口 2222,用户名 noetix,密码 bumi)
ssh -p 2222 noetix@192.168.3.22

# 在真机上执行 PR 页面 Try it 给出的 curl 指令
curl -sSL <Try it 中复制的地址> | sh

# 确认容器已经起来
docker ps

到这里,机器人就已经能执行你的卡片了。剩下的工作只有一件:去仪表盘上把它跑起来。

七、Step 5|画布测试:让机器人真的说一句 Hello World

本地开隧道,把真机的服务映射出来,然后登录仪表盘官网,输入 Token,进入画布。

1. 在本地开好隧道(具体命令交给 AI 生成即可)。

图 18 本地开隧道

2. 登录仪表盘官网,输入 Token。

图 19 登录仪表盘官网

3. 在画布上连好线,开启智能控制。

图 20 在画布上连线并输入电码

4. 在 morse 卡片中输入电码,例如:

.... . .-.. .-.. --- / .-- --- .-. .-.. -..

# 解码结果:HELLO WORLD

如果一切正常,机器人会语音播报 HelloWorld——卡片测试成功。

务必记住 测试完后关闭智能体、退出编辑。智能控制会长期占用通道,你挂着不走,别人就连不上、抢不到机器。

八、Step 6|关闭容器:把机器让出来

测试结束不等于收工。你启动的容器还在后台占着资源,需要手动停掉。这里用 VSCode 的远程开发最方便。

1. 在 VSCode 的扩展市场安装 Remote - SSH。

图 21 安装 Remote - SSH 扩展

2. 点击左下角按钮,打开远程窗口。

图 22 左下角的远程窗口入口

3. 选择「Connect to Host…」,再添加新的 SSH 主机。

图 23 选择 Connect to Host

4. 输入完整命令,并填写密码。

图 24 添加新的 SSH 主机

5. 在弹出的系统类型里选择 Linux,成功进入远程页面。

图 25 系统类型选择 Linux

图 26 成功进入远程页面

6. 找到属于自己的那个容器,把它停掉。

图 27 找到并停止自己的容器

# 1) 添加远程主机时输入的完整命令
ssh -p 2222 noetix@192.168.3.22

# 2) 密码
bumi

# 3) 进入远程终端后,找到并停掉自己的容器
docker ps                 # 查看正在运行的容器
docker stop <容器ID>       # 停掉你的那个
docker ps                 # 复查:列表里应该没有它了

有些面板里也提供直接停止容器的按钮,效果一样。原则只有一条:谁的容器谁负责关。

九、踩坑记录:五个让我卡住过的瞬间

这一节比前面的步骤更值钱,因为每一步我都真的卡过。

坑 1 容器会「抢线」

开发卡片时,需要关掉别人的容器、只保留自己的容器;真机测试完之后,也要关掉自己的容器(见第八节)。否则会出现「代码没问题、镜像也拉下来了,卡片就是不动」的诡异现象——其实是你连到了别人的容器上。

坑 2 新卡片必须开新分支

开发新卡片就要创建新分支,在新分支上写。如果图省事在同一条分支上改,会把之前构建好的镜像覆盖掉,PR 里出现的镜像也就不是你想要的那一个了。分支名建议直接带功能语义:feat/bumi-morse-driver。

坑 3 PR 构建失败,一定要看日志

PR 提交可能失败,失败时不要反复重试,先打开构建日志找报错行。我第一次提交就失败了,日志里写得清清楚楚:Dockerfile 少装了一个依赖插件。把日志整段丢给 AI,让它据此修改 Dockerfile,再构建就通过了。日志是唯一可信的证据,猜是没用的。

图 28 第一次提交 PR 时构建失败的日志

坑 4 改完要回到第 4 步,重新走一遍触发流程

同一个分支上修改代码之后,不是改完就生效:要回到「4. 构建镜像」重新提交源代码,再到 PR 里重新评论一次 /request_bot_review,让机器人用新代码重新构建。少这一步,你会拿着旧镜像测半天,然后怀疑人生。

坑 5 卡住时,去看别人的 PR

如果遇到问题不知道怎么解决,去翻别人的 PR 记录——那里有完整的日志和代码。如果有人踩过同样的坑并且解决了,直接参考他的做法,通常比从零排查快一个数量级。

图 29 参考他人的 PR 记录

十、总结:一张卡片的本质是什么

回头看,卡片开发其实是一条很标准的云原生流水线:本地写代码 → Git 分支管理 → PR 触发 CI 构建镜像 → 真机拉取镜像跑容器 → 业务侧验证。 只不过这里的「业务侧」是画布,是机器人,是会开口说话的物理实体。

● 卡片 = 功能代码 + Dockerfile + 一条 PR 流水线。 三者缺一,机器人就跑不起来。

● 改代码必须改 Dockerfile。 代码进仓库不等于代码进镜像。

● 一张卡片一条分支。 分支是隔离,也是可回滚的保险。

● 出问题先看日志。 PR 构建日志、容器日志,比任何猜测都有用。

● 用完把容器关掉。 这是共用真机的基本礼貌,也能避免自己下次踩坑。

三个最容易忘的动作,再复述一遍:改 Dockerfile、开新分支、测完关容器。 记住这三条,基本就不会在流程上翻车了。

十一、速查清单

场景

操作 / 命令

新建功能分支

git checkout -b feat/bumi-driver

提交并推送

git add . && git commit -m "feat(bumi): ..." && git push origin feat/bumi-driver

触发镜像构建

在 PR 评论区发送 /request_bot_review

登录真机

ssh -p 2222 noetix@192.168.3.22(密码:bumi)

拉取镜像

执行 PR 页面 Try it 区块中的 curl 指令

查看运行中的容器

docker ps

停掉自己的容器

docker stop <容器ID>

远程开发(可选)

VSCode 安装 Remote - SSH → Connect to Host… → 选 Linux

表 3 常用操作速查

参考资料

· 平台驱动卡片开发文档(Fork / PR / review bot 流程说明)

· Docker 官方文档:Get Started / Dockerfile reference

· GitHub 文档:Fork a repository / Creating a pull request

· 项目内其他开发者的 PR 记录(排查问题时最实用的资料)

— 如果这篇笔记帮你少踩一个坑,欢迎点赞、收藏、关注 —

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐