跳到主要内容

01. 准备 ESP-IDF v5.5.4

学习形式环境实操
硬件要求电脑
配套 Demo
本课动作不涉及 CAN 总线

这节课要完成什么

完成这一课后,你应该能够:

  • 说清楚 ESP-IDF 是什么;
  • 解释为什么本课程固定使用 v5.5.4;
  • 根据网络情况,从 GitHub 或乐鑫下载服务器取得完整的 v5.5.4;
  • 在不删除旧版本的情况下并行安装 v5.5.4;
  • 确认当前终端真正加载了哪个 ESP-IDF;
  • 理解 IDF_PATHexport.sh 的作用。

这一课不连接 CAN,也不需要电机上电。

先打开乐鑫官方文档

本教程会把实际走过的安装过程拆开解释,但官方文档仍然是判断安装方法和版本要求的首要依据。下面把完整网址直接列出来,既可以在 Markdown 阅读器中点击,也可以复制到浏览器访问。

ESP-IDF v5.5.4:ESP32-C3 快速入门(中文)

ESP-IDF v5.5.4:ESP32-C3 快速入门

ESP-IDF v5.5.4:Linux 和 macOS 工具链标准设置(中文)

Linux 和 macOS 工具链标准设置

ESP-IDF v5.5.4 官方发布页面

ESP-IDF v5.5.4 发布页面

清华大学开源软件镜像站:PyPI 镜像使用帮助

清华大学 PyPI 镜像使用帮助

阅读官方页面时,确认页面顶部选择的是目标芯片 ESP32-C3 和版本 v5.5.4,不要误看成 ESP32latest 的说明。

官方安装示例通常把仓库克隆为 ~/esp/esp-idf。本教程为了让 v5.5.2 和 v5.5.4 并行存在,特意使用 ~/esp/esp-idf-v5.5.4 作为目录名。两种命名都可以,后续命令必须与自己的实际目录一致。

先说明教程中的路径

本教程把 ~/esp 作为示例工作目录。~ 和环境变量 $HOME 都表示当前登录用户的主目录:

# $HOME 会展开为当前用户的主目录,本教程统一把练习工程放在它下面。
echo "$HOME"

例如,登录用户为 student 时,~/esp 通常会展开为 /home/student/esp。你的用户名和安装位置可能不同,这完全正常。

后面的命令会尽量写成:

# 进入课程统一使用的 ~/esp 工作目录,后续相对路径都从这里计算。
cd "$HOME/esp"

不要把示例中的 /home/student/... 原样复制到自己的电脑。如果你没有把 ESP-IDF 放在 ~/esp,请把命令中的 "$HOME/esp" 替换成自己的实际工作目录。

命令仍使用双引号保护路径,但 ESP-IDF 源码目录和工程目录本身不要包含空格。ESP-IDF v5.5.4 官方文档明确说明构建系统不支持这两类路径中出现空格。

1. ESP-IDF 是什么

ESP-IDF(Espressif IoT Development Framework)是 Espressif 为 ESP32 系列芯片提供的官方开发框架。它不只是一个编译器,还包括:

芯片和外设驱动
FreeRTOS
构建系统
配置系统
烧录和串口监视工具
Python工具环境
组件管理器
交叉编译工具链

因此 ESP-IDF 版本变化可能同时带来:

  • API 名称和参数变化;
  • 驱动实现变化;
  • 组件最低版本要求变化;
  • Python 工具和编译器版本变化;
  • 默认配置变化。

这就是为什么教程不能只写“安装任意一个 IDF”。

2. 为什么固定使用 v5.5.4

本课程后半段使用官方组件:

espressif/canopennode 0.1.0

这个组件封装了 CANopenNode。CANopenNode 是一个开源的 CANopen 协议栈,也就是一套已经实现 CANopen 通信规则的软件库。后半段实验会让 ESP32 使用它处理完整的 CANopen 通信;现在不需要学习怎样调用它,只需要知道它也是工程的一项软件依赖。

这个组件自己的依赖声明要求:

# 组件管理器会在编译前检查当前 ESP-IDF 版本;低于 5.5.4 时会直接停止依赖解析。
idf:
version: '>=5.5.4'

实际依赖关系是:

课程后半段的 CANopenNode 实验工程

espressif/canopennode 0.1.0

要求 ESP-IDF >= 5.5.4

我们已经真实验证过:使用 ESP-IDF v5.5.2 时,idf.py set-target esp32c3 在组件依赖求解阶段失败,甚至还没有开始编译 C 代码。

关键理解:这不是 ESP32-C3 不支持 CAN,也不是应用源码写错了,而是组件声明的最低 ESP-IDF 版本没有满足。

理论上可以使用高于 5.5.4 的兼容版本,但课程固定到准确的 v5.5.4,保证 API、构建输出和依赖解析与已经验证的环境一致。学会以后再升级,会更容易判断差异来自哪里。

3. 已经有其他 ESP-IDF 怎么办

不需要删除。不同版本可以放在不同目录,例如:

~/esp/
├── esp-idf/ 旧的 v5.5.2
└── esp-idf-v5.5.4/ 本课程使用的版本 v5.5.4

它们的源码目录互不覆盖。当前终端使用哪一个版本,由你最后加载的 export.sh 决定。

4. 安装系统依赖并检查目标目录

本课程的国内网络安装路线已经在下面的环境完成验证:

项目验证环境
操作系统Ubuntu 24.04 LTS
CPU 架构x86_64
ShellBash
系统 PythonPython 3.12.3
目标芯片ESP32-C3
最终结果idf.py --version 输出 ESP-IDF v5.5.4

下面的系统软件包命令适用于 Ubuntu 和 Debian 系发行版。Windows、macOS、Arch Linux 等环境的软件包管理方式不同,应改用对应平台的官方安装步骤。

先确认系统和磁盘空间:

# 记录系统版本和剩余磁盘空间,空间不足时先不要开始安装。
cat /etc/os-release
uname -m
python3 --version
df -h "$HOME"

国内路线使用的完整压缩包约为 1.70 GiB,解压后的源码、交叉编译工具和 Python 环境还会继续占用空间。磁盘剩余空间如果只够存放压缩包,不要继续安装。

安装 ESP-IDF 构建依赖,以及国内路线需要的 unzip

# 安装 ESP-IDF 编译工具和本教程后续会用到的解压、串口工具。
sudo apt update

sudo apt install -y \
git wget flex bison gperf \
python3 python3-pip python3-venv \
cmake ninja-build ccache \
libffi-dev libssl-dev \
dfu-util libusb-1.0-0 unzip

检查后续一定会用到的命令:

# 把完整压缩包解压到固定版本目录。
git --version
wget --version | head -n 1
python3 --version
cmake --version | head -n 1
ninja --version
unzip -v | head -n 1

如果某一条显示 command not found,先处理 apt install 输出中的第一条错误,不要继续下载 ESP-IDF。

创建工作目录并检查目标路径:

# 先确认目标路径不存在,避免覆盖之前的工程或源码。
mkdir -p "$HOME/esp"
cd "$HOME/esp"
pwd

test -e "$HOME/esp/esp-idf-v5.5.4"
echo $?

输出含义:

0 = 路径已经存在,不能直接覆盖
1 = 路径不存在,可以创建

如果目录已经存在,先检查:

# 确认目录确实是完整 Git 仓库,并核对当前版本。
git -C "$HOME/esp/esp-idf-v5.5.4" status
git -C "$HOME/esp/esp-idf-v5.5.4" describe --tags --always

看到陌生内容时不要删除重装。先确认它是不是已经完成的 v5.5.4 安装。

5. 根据网络情况取得 ESP-IDF 源码

安装 ESP-IDF 时会下载三类内容。它们使用的地址并不相同:

国内网络环境下获取 ESP-IDF 源码、编译工具和 Python 包的三条路径

  • ESP-IDF 源码:从 GitHub 克隆,或者从乐鑫发布服务器下载包含子模块的完整压缩包;
  • 编译工具:由 install.sh 下载,国内网络可以通过 IDF_GITHUB_ASSETS 改写其中的 GitHub Release Assets 地址;
  • Python 包:由 install.sh 创建的 Python 环境安装,国内网络可以通过 PIP_INDEX_URL 指定镜像。

IDF_GITHUB_ASSETS 不会修改 Git 仓库地址,因此不能解决 git clone https://github.com/... 无法访问的问题。源码必须从下面两条路线中选择一条完整执行,不能把未完成的 Git 克隆目录与压缩包解压目录相互覆盖。

路线 A:国内网络下载乐鑫完整压缩包

GitHub 无法打开,或者 git clone 长时间没有进度时,使用这条已经在 Ubuntu 24.04 上完成验证的路线。

进入工作目录并保存固定下载地址:

# 进入课程统一使用的 ~/esp 工作目录,后续相对路径都从这里计算。
cd "$HOME/esp"

export IDF_ARCHIVE_URL="https://dl.espressif.com/github_assets/espressif/esp-idf/releases/download/v5.5.4/esp-idf-v5.5.4.zip"

先检查服务器能否访问:

# 只检查下载地址是否可访问,不下载文件。
wget --spider "$IDF_ARCHIVE_URL"

成功时会看到类似输出:

Remote file exists.

开始下载:

# 使用断点续传下载压缩包,网络中断后可以继续。
wget --continue "$IDF_ARCHIVE_URL"

--continue 表示断点续传。网络中断后,在同一终端回到 ~/esp 再执行这条命令即可继续。重新打开终端后,需要先重新设置 IDF_ARCHIVE_URL

下载结束后不要立即解压,先检查 ZIP 是否完整:

# 先校验压缩包完整性;出现 CRC 或文件结尾错误时不要解压。
ls -lh "$HOME/esp/esp-idf-v5.5.4.zip"
unzip -t "$HOME/esp/esp-idf-v5.5.4.zip"

最后应出现类似结果:

No errors detected in compressed data of esp-idf-v5.5.4.zip.

如果出现 End-of-central-directory signature not foundunexpected end of file 或 CRC 错误,不要解压。先续传;仍然报错时,保留错误并重新获取完整文件。

确认目标目录不存在后解压:

# 把完整压缩包解压到固定版本目录。
test ! -e "$HOME/esp/esp-idf-v5.5.4"
echo $?

cd "$HOME/esp"
unzip -q esp-idf-v5.5.4.zip

test 输出 0 才表示目标目录不存在。这里必须使用官方发布页单独提供的 esp-idf-v5.5.4.zip。GitHub 页面自动生成的 Source code (zip) 不包含可直接安装的完整子模块内容,不能替代它。

压缩包解压完成只代表 ESP-IDF 源码已经就位,国内路线还没有结束。继续完成第 6 节的源码检查,并在运行 install.sh 之前执行第 7.1 节:同时设置编译工具下载地址和 Python 包镜像。

路线 B:网络可以稳定访问 GitHub

只有目标目录不存在时才执行:

# 从指定标签克隆 ESP-IDF,并把目录名固定为课程使用的版本。
cd "$HOME/esp"
git clone -b v5.5.4 --recursive \
https://github.com/espressif/esp-idf.git \
esp-idf-v5.5.4

各部分含义:

参数含义
git clone下载一个 Git 仓库
-b v5.5.4检出 v5.5.4 标签
--recursive同时下载 ESP-IDF 使用的 Git 子模块
最后一个参数本地目录名称

ESP-IDF 包含子模块。遗漏 --recursive 可能导致后续安装或构建时缺少文件。

6. 检查版本和子模块

无论使用哪条下载路线,都从这里继续:

# 确认目录确实是完整 Git 仓库,并核对当前版本。
cd "$HOME/esp/esp-idf-v5.5.4"

test -x install.sh
echo $?

git describe --tags --always
git status --short
git submodule status

继续安装前应确认:

  • test 输出 0,说明 install.sh 存在并可执行;
  • git describe 显示 v5.5.4
  • 没有意外源码修改;
  • 子模块行首不出现表示未初始化的 -

7. 设置国内镜像并安装 ESP32-C3 工具

源码准备完成后,install.sh 还要下载编译工具和 Python 包。国内网络路线必须先完成下面两个镜像设置,不能直接跳到 ./install.sh esp32c3

7.1 设置编译工具和 Python 包镜像

  • IDF_GITHUB_ASSETS 用于改写安装脚本访问的 GitHub Release Assets 地址;
  • PIP_INDEX_URL 用于指定 ESP-IDF Python 依赖的包索引。

在即将运行安装脚本的同一个终端中执行:

# install.sh 读取这个变量后,会从乐鑫服务器取得交叉编译器等工具,避开 GitHub Assets。
export IDF_GITHUB_ASSETS="dl.espressif.cn/github_assets"

# ESP-IDF 创建自己的 Python 虚拟环境时,pip 会从这个国内镜像下载依赖包。
export PIP_INDEX_URL="https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"

马上读回两个变量,避免变量名或地址输入错误:

# 这里不是再次设置变量,而是读回当前终端保存的值;两行都正确后才能运行 install.sh。
printf 'IDF_GITHUB_ASSETS=%s\n' "$IDF_GITHUB_ASSETS"
printf 'PIP_INDEX_URL=%s\n' "$PIP_INDEX_URL"

应当看到:

IDF_GITHUB_ASSETS=dl.espressif.cn/github_assets
PIP_INDEX_URL=https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple

这两个变量只对当前终端及其随后启动的子进程生效。读回结果正确后,保持当前终端打开。

7.2 运行 ESP32-C3 工具安装脚本

进入 ESP-IDF 源码目录并执行安装脚本:

# 必须留在刚才设置两个镜像变量的同一个终端中,否则新终端读不到这些临时变量。
cd "$HOME/esp/esp-idf-v5.5.4"

# esp32c3 参数只安装当前课程目标芯片需要的工具,减少无关工具下载。
./install.sh esp32c3

esp32c3 参数让脚本只准备课程目标芯片需要的工具。脚本会安装交叉编译器和辅助程序,并在默认的 $HOME/.espressif 下创建 ESP-IDF Python 环境;它不会删除旧 ESP-IDF 源码目录。

成功结束时,末尾会提示下一步加载 export.sh。不要只根据下载进度条判断结果,应确认脚本正常回到 shell 提示符,并查看末尾是否出现完成提示。

常见失败判断:

现象先检查什么不要做什么
压缩包下载中断回到 ~/esp,重新设置下载变量并执行 wget --continue不要生成多个不同名称的残缺文件
unzip -t 报错确认下载是否完整,再续传或重新下载不要解压损坏的 ZIP
install.sh 仍访问 GitHubecho "$IDF_GITHUB_ASSETS" 检查当前终端变量不要把该变量误认为 Git 仓库代理
Python 包下载失败echo "$PIP_INDEX_URL" 检查索引,并保留第一条 pip 错误不要关闭证书校验掩盖问题
No space left on device再次运行 df -h "$HOME"不要反复重跑安装脚本
Permission denied检查源码目录和脚本权限不要使用 sudo ./install.sh 改变文件归属

排查时保留第一条真正的错误,不要只注意最后的 Installation failed。乐鑫服务器只镜像部分 GitHub Release Assets;某个资源仍然失败时,应记录其完整 URL 和第一条错误,再决定重试或切换网络。

8. 加载环境

打开一个尚未加载本课程 IDF 环境的终端后,执行:

# 在当前终端加载 ESP-IDF 环境;新开终端后需要重新执行。
source "$HOME/esp/esp-idf-v5.5.4/export.sh"

这里的 source 表示在当前 shell 中执行脚本。脚本会设置:

  • IDF_PATH
  • idf.py 搜索路径;
  • ESP32-C3 工具链搜索路径;
  • ESP-IDF 使用的 Python 环境。

更准确地说,这些变量保存在当前 shell 进程的环境中,并会传给它启动的子进程。source 不会自动修改其他已经打开的终端,也不会自动写入 .bashrc 等启动配置。

新开的终端是否已经有 ESP-IDF 环境,要看你的系统配置:

  • 没有配置自动加载时,通常找不到 idf.py
  • .bashrc 等文件加载了旧 IDF 时,可能显示另一个版本;
  • 配置过 v5.5.4 自动加载,或者新 shell 继承了已有环境时,也可能直接显示 v5.5.4。

因此不要根据“是不是新终端”猜测版本,始终查看 IDF_PATHidf.py --version 的实际输出。

9. 必须进行的环境检查

# 确认目录确实是完整 Git 仓库,并核对当前版本。
echo "$IDF_PATH"
idf.py --version
python --version
git -C "$IDF_PATH" describe --tags --always

IDF_PATH 应指向你安装的 esp-idf-v5.5.4 目录。例如按照本教程的目录安装时,三项关键结果是:

IDF_PATH:<你的主目录>/esp/esp-idf-v5.5.4
idf.py --version:ESP-IDF v5.5.4
git describe:v5.5.4

Python 小版本由 ESP-IDF 安装环境决定,记录实际输出即可。

还可以让 shell 直接比较路径:

# 直接比较 IDF_PATH 与课程路径;返回 0 才表示两者完全一致。
test "$IDF_PATH" = "$HOME/esp/esp-idf-v5.5.4"
echo $?

输出 0 表示两边一致。如果你把 IDF 安装在其他目录,应把右侧改成自己的安装路径。

10. 新终端练习

打开一个新终端,先不要执行 export.sh,查看它原本使用什么环境:

# 逐项确认命令已经安装;没有输出的那一项需要先补装。
echo "$IDF_PATH"
command -v idf.py
idf.py --version

可能出现以下任意一种情况:

结果说明
idf.py: command not found这个 shell 还没有加载 ESP-IDF,属于正常现象
显示其他 IDF 版本PATH 或 shell 启动配置中已有另一个 ESP-IDF
已显示 v5.5.4当前环境已经加载了本课程版本,继续核对 IDF_PATH

然后在同一个终端中执行:

# 在当前终端加载 ESP-IDF 环境;新开终端后需要重新执行。
source "$HOME/esp/esp-idf-v5.5.4/export.sh"
echo "$IDF_PATH"
command -v idf.py
idf.py --version

最终应确认:

IDF_PATH 指向你安装的 esp-idf-v5.5.4 目录
idf.py --version 显示 ESP-IDF v5.5.4

这个练习真正要说明的是:ESP-IDF 的选择由 shell 环境决定,不能仅凭安装目录存在或终端是不是刚打开来判断。

这一课只需要记住五句话

  1. ESP-IDF 是一整套 SDK、工具链和构建环境,不只是一个头文件库。
  2. 官方 CANopenNode 0.1.0 要求 ESP-IDF 至少为 v5.5.4。
  3. GitHub 克隆和乐鑫完整压缩包都能得到课程需要的源码,但不能混用两个未完成的目录。
  4. 国内路线在运行 install.sh 前还必须设置 IDF_GITHUB_ASSETSPIP_INDEX_URL,压缩包只解决源码获取问题。
  5. 多个 IDF 可以并行存在,当前终端使用哪个版本由 source .../export.sh 决定。

完成检查

在实验记录中保存以下三条命令的实际输出:

# 确认目录确实是完整 Git 仓库,并核对当前版本。
echo "$IDF_PATH"
idf.py --version
git -C "$IDF_PATH" describe --tags --always

三项都指向 v5.5.4,这一课才算通过。

如果使用国内网络路线,还要在安装记录中保留下面两个变量的读回结果,证明工具下载地址和 Python 包镜像都在运行 install.sh 前生效:

# 让 ESP-IDF 的 Python 环境从国内镜像安装依赖包。
printf 'IDF_GITHUB_ASSETS=%s\n' "$IDF_GITHUB_ASSETS"
printf 'PIP_INDEX_URL=%s\n' "$PIP_INDEX_URL"