CI/CD自动化——GitHub Actions/Jenkins在机器人项目中的应用
上篇聊了clang-tidy、cppcheck这些代码质量工具,最后提到要把它们串进CI流水线。今天就把CI/CD这件事展开讲透。
面试的时候被问:"你们代码提交之后,怎么保证编译通过、测试能跑?"
我当时说"本地跑一遍,没问题就push"。面试官又问:"那多人协作呢?每个人本地都跑一遍?"我想了想,好像确实不太对。
这就是CI/CD要解决的问题。CI是持续集成(Continuous Integration),CD是持续交付(Continuous Delivery)或者持续部署(Continuous Deployment)。说白了就是:代码一提交,自动跑编译、跑测试、跑代码检查,全过了才算合格。不用人盯着,机器帮你把关。
在机器人项目里,CI/CD特别重要。因为机器人软件依赖复杂(ROS2、各种第三方库)、编译时间长、测试需要仿真环境,如果没有自动化流程,光靠人工检查根本管不过来。
GitHub Actions:轻量级CI首选
GitHub Actions是目前最流行的CI方案之一。配置简单,和GitHub仓库深度集成,开源项目免费用。
在项目根目录创建.github/workflows/ci.yml:
name: CI
on: [push, pull_request]
jobs:
build-and-test:
runs-on: ubuntu-22.04
container: ros:humble
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update
rosdep update
rosdep install --from-paths src --ignore-src -y
- name: Build
run: |
source /opt/ros/humble/setup.bash
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
- name: Run tests
run: |
source /opt/ros/humble/setup.bash
source install/setup.bash
colcon test
colcon test-result --verbose
每次push或者创建PR,GitHub自动启动一个Ubuntu容器,装好ROS2 Humble,编译你的项目,跑测试。编译失败或者测试不通过,PR上会显示红叉,reviewer一看就知道。
GitHub Actions的优势在于配置简单、生态丰富。社区有大量现成的Action可以复用,比如checkout代码、缓存编译产物、上传测试报告等。
说说实际用的几个技巧。
Matrix策略:同时测试多个ROS2版本和Ubuntu版本。比如你的项目要支持Humble和Iron两个LTS版本,可以配成matrix:
strategy:
matrix:
ros_distro: [humble, iron]
ubuntu: [22.04, 24.04]
这样每次提交会同时跑4个job,确保代码在所有目标环境上都能编译通过。
缓存加速:ROS项目编译一次可能要10-20分钟,每次都从头编译太慢了。用ccache可以缓存编译结果,第二次编译只编译改动过的文件。配置大概是这样:
- uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ matrix.ros_distro }}
加上缓存以后,增量编译通常只要1-2分钟。这个优化对开发体验的提升是巨大的——你提一个PR,等2分钟就知道结果,和等20分钟完全是两种心态。
Artifact上传:编译产物可以上传为GitHub Artifact,方便下载和部署。测试报告也可以上传,在PR页面上直接看到哪些测试通过了、哪些失败了。
机器人项目中的CI实践
机器人项目的CI比纯软件项目复杂,主要因为几点。
依赖管理:ROS2项目依赖大量系统包,CI环境需要预装。常见做法是用Docker镜像,把ROS2和常用依赖都装好。
仿真测试:很多测试需要Gazebo仿真环境。CI里可以用gz sim -s跑无渲染模式,或用xvfb模拟显示。
测试分层很重要。单元测试(Google Test、pytest)每次提交都跑,几十秒出结果。集成测试(Gazebo仿真)在PR合并前跑一次。系统测试在真实硬件上跑,每天定时一次。硬件在环测试由测试工程师手动执行。
编译缓存:用ccache缓存编译结果,增量编译只要1-2分钟,比从零编译快好几倍。
一个实际的CI流水线
说一个我参与搭建的CI流程,供参考。
代码push到feature分支后,GitHub Actions自动触发:clang-format检查代码格式、clang-tidy静态分析、编译(用ccache加速)、跑单元测试。全部通过大概3-5分钟。
创建PR时,额外触发集成测试:在Docker容器里启动Gazebo无头模式,跑几个预定义的测试场景。通过后才允许合并。
合并到main分支后,Jenkins接手:交叉编译ARM版本、打包成deb包、推送到内部制品仓库。同时通知运维团队,由他们决定什么时候部署到现场机器人上。
这套流程跑了一年多,整体还不错。唯一的问题是Gazebo集成测试偶尔会超时——仿真环境启动太慢。后来我们把测试场景简化了,从5分钟缩短到2分钟,超时问题基本解决了。
CD:从代码到机器人
CI解决了"代码对不对"的问题,CD解决"怎么把代码部署到机器人上"的问题。
最简单的CD:CI编译测试通过后,自动把可执行文件scp到机器人上。正式的CD流程会更规范:编译→测试→打包(Docker镜像或deb包)→推送到制品仓库→机器人拉取更新。
在机器人产品中,OTA(Over-The-Air)更新是标配。关键要求是原子更新——更新要么完全成功,要么完全回滚。常见做法是A/B分区:当前运行在A分区,新版本写到B分区,写完后切换启动分区。启动失败则自动切回。
面试中怎么聊CI/CD
面试官问CI/CD,你可以说:"我们用GitHub Actions做CI,每次PR自动在Docker容器里编译和测试。容器镜像预装了ROS2 Humble和常用依赖。编译用了ccache加速,测试包括单元测试和集成测试。通过后自动打包成Docker镜像,部署时用docker-compose在机器人上启动。"
这种回答好在:有具体工具、有完整流程、有机器人特色。
CI/CD在机器人项目中的实践
机器人项目的CI/CD有个特殊挑战:编译时间长。一个完整的ROS2 workspace编译可能需要十几分钟。优化策略包括:用ccache缓存编译结果、用Docker镜像预装依赖、只编译改动的包。另外,单元测试在CI中很重要,可以用colcon test运行所有包的测试。一个实用的pipeline是:代码提交、lint检查、编译、单元测试、打包Docker镜像、部署到测试机器人。
补充一点:在CI中运行ROS2测试时,可以用launch_pytest框架来编写集成测试,验证多个节点之间的交互是否正确。
给你的建议
如果你还没用过CI,从GitHub Actions开始。创建一个仓库,写一个最简单的workflow:checkout代码、编译、跑测试。第一次看到绿色的对勾出现在PR上,你会觉得特别有成就感。
机器人项目的CI可以从简单开始:先保证每次提交能编译通过,再逐步加测试、加代码检查、加部署。不要一上来就搞复杂的流水线,团队维护不过来。
最后,CI的价值不只是自动化,是信任。有了CI,团队成员可以放心提交代码,因为机器会帮你检查。code review也能更专注在逻辑和架构上,不用操心编译能不能过。
上一篇:第104篇 代码质量工具——clang-tidy/cppcheck和机器人代码规范
下一篇预告:第106篇 ROS的前世今生——从ROS1到ROS2的进化逻辑
有任何问题欢迎评论区留言,我会尽量回复。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)