Arduino CLI — 命令行驱动嵌入式全流程工具链
是什么
Arduino CLI 是 Arduino 官方用 Go 编写的全功能命令行工具,一个可执行文件覆盖从”检测开发板”到”上传固件”的完整嵌入式开发流程——无需打开 GUI 界面。
日常类比:想象你有一台洗衣机,以前只能按面板上的实体按钮;arduino-cli 就是把这些按钮全部变成”可以写进剧本的文字命令”——同样的操作,现在可以记进文件、定时自动跑、串到一长串任务里。以前 Arduino 开发必须打开图形 IDE,用鼠标点”编译”再点”上传”;arduino-cli 把这些操作变成终端命令,可以串进 CI/CD 管道和批处理脚本。
核心能力四件套:
- Board Manager:安装/更新开发板核心包(支持官方 AVR、ARM 及第三方 ESP8266、NRF52 等)
- Library Manager:搜索、安装、更新 Arduino 库
- 编译器(compile):调用底层 avr-gcc / arm-gcc(GCC 系列 C/C++ 编译器,专门针对嵌入式芯片)工具链,产出可上传的固件
- 上传器(upload):通过 avrdude / bossac(专门向单片机烧录固件的工具)把固件写入板子
最关键的是它还支持 gRPC daemon 模式——gRPC 是一种让两个程序之间”远程互相调用功能”的协议(类比:打电话给一个服务台,对方帮你执行操作)。arduino-cli 以后台服务形式运行,让 VSCode 插件、IDE、自动化脚本通过这个协议调用,免去每次都冷启动进程的开销。
为什么重要
不理解 arduino-cli,以下这些事都没法解释:
- 为什么在 GitHub Actions 里可以”推一次代码,自动编译并上传 Arduino 固件”——这整条管道的执行引擎就是 arduino-cli
- 为什么 Arduino IDE 2.x 比 1.x 快很多——因为 IDE 2.x 底层改用 arduino-cli 做后端引擎
- 为什么嵌入式 CI/CD 能对接 Docker 容器——arduino-cli 是静态单可执行文件,天然适合容器化
- 为什么跨平台嵌入式脚本能少踩 OS 差异坑——Go 编译产物一致性好,Windows/macOS/Linux 行为几乎相同
核心要点
-
FQBN — 开发板的”身份证号码”
每块 Arduino 兼容板子用一个 Fully Qualified Board Name(FQBN)精确标识,格式是
厂商:架构:型号,比如arduino:avr:uno(Arduino Uno)、esp32:esp32:esp32(ESP32 通用板)。FQBN 贯穿编译和上传两步——类比:机场登机牌,差一个字母就登错飞机。 -
注册表驱动的包管理
arduino-cli 的包管理逻辑与 npm/apt 相似:本地有一份”索引缓存”,记录所有可用的开发板核心包和库。
core update-index/lib update-index更新这份缓存,之后才能core install/lib install。第三方板(ESP8266 等)通过additional-urls在配置文件里注入额外注册表地址,和给 npm 加私有 registry 是同一个思路。 -
两种运行模式:CLI vs daemon
普通用法是每次调一条命令(
arduino-cli compile ...),适合脚本和 CI。daemon 模式下,arduino-cli daemon以 gRPC 服务常驻后台,客户端(如 VSCode 插件)复用同一进程,避免重复加载索引、重复启动工具链,显著减少冷启动开销。这两种模式共享同一套配置文件(~/.arduino15/arduino-cli.yaml),切换零成本。
实践案例
案例 1:GitHub Actions 全自动编译 + 上传固件
最典型的 CI/CD 用法:代码推到仓库,Action 自动编译,产出固件文件,可进一步触发上传或打 Release。
name: Build Arduino Firmwareon: [push]jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install arduino-cli run: | curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh sudo mv bin/arduino-cli /usr/local/bin/ - name: Update index & install core run: | arduino-cli core update-index arduino-cli core install arduino:avr - name: Compile sketch run: | arduino-cli compile \ --fqbn arduino:avr:uno \ --output-dir ./build \ ./sketch/blink - name: Upload artifact uses: actions/upload-artifact@v4 with: name: firmware path: ./build/*.hex逐部分解释:
core update-index更新注册表缓存,确保能找到最新版核心包core install arduino:avr安装 AVR 系列工具链(包含 avr-gcc 等)--fqbn arduino:avr:uno指定目标板子型号--output-dir指定输出目录,.hex文件可直接用 avrdude 上传或作为 Release 附件
案例 2:批量上传相同固件到多块开发板
测试场景或批量生产时,需要把同一份固件烧进多块板子。
#!/bin/bash# batch_upload.sh — 把 firmware.hex 上传到所有连接的 Arduino Uno
FQBN="arduino:avr:uno"SKETCH="./sketch/blink"
# 先编译一次,产出 .hexarduino-cli compile --fqbn "$FQBN" --output-dir ./build "$SKETCH"
# board list 列出所有连接的板,grep 过滤特定 FQBN,awk 取第一列(串口路径)arduino-cli board list | grep "$FQBN" | awk '{print $1}' | while read PORT; do echo "Uploading to $PORT ..." arduino-cli upload \ --fqbn "$FQBN" \ --port "$PORT" \ --input-dir ./build \ && echo " $PORT: OK" \ || echo " $PORT: FAILED"done逐部分解释:
board list列出所有当前连接的开发板及对应串口;board list命令本身不支持--fqbn过滤,需借助grep筛出目标型号- 编译只跑一次,上传复用同一份
.hex,效率更高 &&/||分支让每块板的结果独立报告,不因一块失败而中断整个流程
案例 3:daemon 模式供编辑器插件调用
当你在 VSCode 里装 Arduino 扩展时,插件后台就是通过这个模式与 arduino-cli 通信的。以下演示用 grpc-tools 直接调 daemon 接口(方便理解原理):
# 启动 daemon,监听 50051 端口arduino-cli daemon --port 50051 --log-level debug &
# 用 grpcurl 查已安装的 core(等价于 arduino-cli core list)grpcurl -plaintext \ -d '{"instance": {"id": 1}}' \ localhost:50051 \ cc.arduino.cli.commands.v1.ArduinoCoreService/PlatformList逐部分解释:
--port 50051指定 gRPC 监听端口,客户端(插件 / 脚本)连这个端口- daemon 启动后保持索引和工具链在内存,后续每次 compile/upload 请求响应更快
ArduinoCoreService是 arduino-cli 定义的 protobuf 服务,所有 CLI 功能都有对应的 RPC 方法
踩过的坑
-
FQBN 拼错导致
invalid FQBN报错:arduino:avr:uno每个段都不能多空格或大小写错误,用arduino-cli board listall查正确 FQBN,不要凭记忆猜。 -
忘了
core update-index就找不到板:装新开发板前如果不先更新索引,install会说”找不到该 core”,明明网上有却本地缓存过期,更新一次索引立即解决。 -
Linux 端口权限问题:
/dev/ttyACM0需要dialout组权限,用sudo usermod -aG dialout $USER后必须重新登录才生效,否则一直permission denied,重启也无效。 -
第三方 core 的
additional_urls只在配置文件设置不够:某些命令(如core search)还需每次加--additional-urls参数,或在~/.arduino15/arduino-cli.yaml的board_manager.additional_urls里永久配置,否则搜索结果里看不到第三方板。
适用 vs 不适用场景
适用:
- CI/CD 管道中自动编译 Arduino 固件,推代码即验证
- 批量管理多块开发板,脚本循环上传、自动化测试
- 嵌入式 IDE 扩展的后端引擎,通过 gRPC daemon 复用工具链
- 容器化嵌入式开发环境,arduino-cli 静态二进制天然适合 Docker 镜像
- 跨平台团队统一开发板管理,减少”在我机器上能跑”问题
不适用:
- 纯粹交互式的学生入门开发——Arduino IDE 图形界面更友好,直观性更强
- 不支持 Arduino 框架的嵌入式目标(如纯 ESP-IDF、Zephyr RTOS)——这些有自己的 CLI 工具
- 需要深度调试(GDB、断点、实时变量查看)——arduino-cli 没有集成调试适配器,需搭配 OpenOCD 等
历史小故事(可跳过)
- 2018 年:Arduino 官方宣布启动 arduino-cli 项目,目标是取代老旧的 Arduino Builder 和 IDE 内置工具链,选用 Go 语言是看中其跨平台静态编译和并发处理能力。
- 2019 年:发布 0.1.0,首次实现 board manager、library manager 和基本编译/上传功能,同时提供 gRPC daemon 接口草案。
- 2021–2022 年:Arduino IDE 2.x 正式切换到以 arduino-cli 为后端引擎,这意味着所有 IDE 2.x 用户实际上都在间接使用 arduino-cli,项目从”开发者工具”升格为”基础设施”。
- 现在:arduino-cli 已是 Arduino 生态的事实命令行标准,GitHub Actions Marketplace 里有多个专门封装它的官方 Action,让嵌入式 CI/CD 进入主流。
学到什么
- 把 GUI 操作变成命令是嵌入式开发进入 CI/CD 的关键门槛——arduino-cli 的本质贡献不是技术创新,而是”自动化可及性”
- FQBN 机制体现了”精确标识比模糊识别更可靠”——用结构化字符串而不是”尝试匹配”来指定板子,消除了一整类歧义错误
- daemon 模式是 CLI 工具演进的常见模式——Language Server Protocol(LSP)、buildkite-agent 都走同一条路:先做 CLI,再加 daemon,让编辑器/CI 复用进程
- 静态二进制 + 注册表索引是”可重现嵌入式构建”的标准答案——工具链版本锁定在
board_manager_additional_urls+core install arduino:avr@1.8.6,就像package-lock.json锁 npm
延伸阅读
- 官方文档:Arduino CLI Getting Started(最权威的入门手册,覆盖配置文件格式)
- GitHub Actions 官方 Action:arduino/setup-arduino-cli(CI 集成首选方案)
- gRPC API 参考:arduino-cli proto 定义(想写自定义客户端必读)
- act —— 本地模拟 GitHub Actions,搭配 arduino-cli 在本机跑嵌入式 CI
- actions-runner-controller —— K8s 上的 GitHub Actions Runner,配合 arduino-cli 做嵌入式大规模 CI
关联
- act —— 本地跑 GitHub Actions 的工具,arduino-cli + act 可以不推代码就调试 CI 流程
- actions-runner-controller —— K8s 上托管 Actions Runner,嵌入式 CI 规模扩大时搭档使用
- docker —— arduino-cli 静态二进制天然适合打进 Docker 镜像,实现可重现的嵌入式构建环境
- ansible —— 批量管理多台开发机时,Ansible 可以统一安装 arduino-cli 并保持版本一致
- buildroot —— 同为嵌入式构建工具链,buildroot 管 Linux 根文件系统,arduino-cli 管裸机 sketch;两者在物联网项目里经常共存
反向链接
- act —— act — 在本地用 Docker 跑 GitHub Actions
- ansible —— Ansible — 无 agent 配置管理
- buildroot —— Buildroot — 用 Make 给嵌入式板子烤一张完整 Linux 镜像
- circuitpython —— CircuitPython — 插上 USB 就能写 Python 的微控制器运行时
- micropython —— MicroPython — 在 MCU 上跑 Python 3 的精简实现
- platformio-core —— PlatformIO Core — 一套命令行,统管千块嵌入式开发板
- probe-rs —— probe-rs — Rust 写的嵌入式烧录与调试工具