前言

AI 硬件这两年很热,但身边真正从一块裸板开始,自己焊、自己烧、自己调通一个能对话的 AI 设备的人,少之又少。原因无非是:环境搭建劝退、子模块下载卡死、Python 版本打架、引脚对不上……

本系列文章将基于我自己的实跑经历(一块 ESP32-S3、喇叭、麦克风,最终跑通小智固件,给孩子讲睡前故事),把从环境到成品的完整过程拆成若干篇写下来。本系列设计每篇聚焦一个难点,贴关键命令、与大家探讨一下原理、附实测结果,确保真实可复现验证,且知道为什么这样设计。

本文是系列第一篇,聚焦最劝退但也最该先搞定的:MacOS 下的 ESP-IDF 环境搭建,尤其是子模块卡死这个坑。

在这里插入图片描述

一、目标与前置

我想要的是一块 ESP32-S3 开发板,接上喇叭和麦克风,跑一套开源的语音对话固件(小智),让它本地或连云做 ASR/LLM/TTS,给孩子讲睡前故事。

在写第一行代码之前,得先把 ESP-IDF(乐鑫官方的 IoT 开发框架)装好。我的环境:

  • 硬件:MacBook Air(Apple Silicon / M1 )
  • 系统:macOS(shell = zsh)
  • 目标板:ESP32-S3(带 PSRAM 版本,如 N16R8)
  • ESP-IDF 版本:v5.3.2(我选了稳定版,没追 main)

二、先说清楚 ESP-IDF 为什么"难装":子模块机制

ESP-IDF 不是一个单独仓库,它是一个主仓库 + 一堆 git submodule(散在 components/ 下,比如 bt、wifi、mbedtls、lwip……)。官方安装命令长这样:

git clone -b v5.3.2 --recursive https://github.com/espressif/esp-idf.git

--recursive 会连带着把几十个子模块一起拉。问题来了:这些子模块的源全在 github.com,在国内终端里经常被卡死或半路断流。我第一次跑这条命令,卡在 lib_esp32 这个蓝牙子模块上,进度条一动不动,等了十几分钟也没动静。

这不是你操作的问题,是网络通道的问题。终端 git 走的是和浏览器不一样的链路,所以后面要用"浏览器下 ZIP"来绕过。

三、实操踩坑与破局

坑 1:git clone --recursive 卡死

破局方式 A(最快,适合只想先跑通例程):跳过子模块检查

如果你暂时只是想编译 hello_world 验证工具链,根本不需要把所有子模块补齐。ESP-IDF 提供了环境变量直接跳过检查:

cd ~/esp/esp-idf/examples/get-started/hello_world
export IDF_SKIP_CHECK_SUBMODULES=1
idf.py set-target esp32s3
idf.py build

5 秒搞定,cmake 不再纠结子模块完整性。代价:用得上蓝牙/BLE 时这个法子不够,得真补。

破局方式 B(彻底解决,手动下载 ZIP 补齐)

我不是只想跑通 helloworld,我想配置完整啊!!好难啊——所以走了手动补齐的路。思路是:终端 git 拉不动,就用浏览器(可挂代理)把 ZIP 下下来,再塞进对应目录。

以卡住的 lib_esp32 为例:

# 1. 先查这个子模块在 .gitmodules 里的真实地址
cd ~/esp/esp-idf
grep -A 3 "lib_esp32" .gitmodules
# 输出类似:
# [submodule "components/bt/controller/lib_esp32"]
#     path = components/bt/controller/lib_esp32
#     url = https://github.com/espressif/esp32-bt-lib.git

# 2. 浏览器打开上面的 url(注意不是主仓库!),Code → Download ZIP
# 3. 解压并进目录替换
cd ~/esp/esp-idf/components/bt/controller
rm -rf lib_esp32
unzip ~/Downloads/esp32-bt-lib-*.zip
mv esp32-bt-lib-* lib_esp32

坑 1.5:解压进去后 cmake 还是说子模块缺失**

光放文件不够。ZIP 解出来没有 .git,cmake 检查子模块完整性时依然认为它"没拉全"。得把这个子模块从 git 的 submodule 检查里移除:

cd ~/esp/esp-idf
git config -f .gitmodules --remove-section submodule.components/bt/controller/lib_esp32
git add .gitmodules
git rm --cached components/bt/controller/lib_esp32 2>/dev/null || true

这步做完,编译就不在它身上卡了。其余卡住的子模块(esp-wifi-lib、esp-protobuf-c、mbedtls 等)照方抓药,逐个浏览器下载、解压、移除检查即可。

小提示:有些仓库在 GitHub 上是 esp32-wifi-lib,.gitmodules 里写的却是 esp-wifi-lib,直接访问会 404。以你本地 .gitmodules 里的 url 字段为准,别照抄网上博客的地址。

坑 2:Python 版本打架(externally-managed + EIM 不认 3.13)

装好 IDF 代码后,要用乐鑫的图形化安装器(EIM,.dmg)来装工具链。这里又踩了 Python 的坑。

我的 Mac 上 python3 默认指向 3.15.x,而 EIM 向导要的是 3.13。直接 pip3 install 还会报经典的 error: externally-managed-environment(macOS 现在禁止裸 pip 改系统 Python)。

正确姿势是用 Homebrew 隔离装一个干净的 3.13,再把路径指给向导:

brew install python@3.13
# 确认装到哪了
brew --prefix python@3.13
# 通常输出:/opt/homebrew/opt/python@3.13

# 在 EIM 向导的"高级设置"里,手动指定解释器路径:
# /opt/homebrew/opt/python@3.13/bin/python3.13

如果终端里 python3 --version 仍显示旧版本,临时把它提前:

export PATH="/opt/homebrew/opt/python@3.13/bin:$PATH"

别直接把 export.sh 写死进 .zshrc 全局加载,会拖慢每个终端、还可能和你别的 Python 项目打架。用别名按需激活更稳。

坑 3:get_idf 别名配置

工具链装完后,配置按需激活的别名(只贴关键命令,原理见官方文档):

echo "alias get_idf='. \$HOME/esp/esp-idf/export.sh'" >> ~/.zshrc
source ~/.zshrc
get_idf   # 激活 ESP-IDF 环境

四、环境配置清单(实测可复现)

主机: MacBook Air,Apple Silicon
系统: macOS,shell = zsh
目标板: ESP32-S3(带 PSRAM)
ESP-IDF: v5.3.2(手动补齐子模块)
Python: 3.13(Homebrew 隔离,非系统默认)

五、验证:环境真的好了吗

新开终端,激活后跑一条:

get_idf
ls ~/esp/esp-idf/export.sh   # 能看到文件 = IDF 本体就位
idf.py --version             # 能输出版本 = 工具链通了

看到版本号,说明最难的"环境搭建"这关过了。后面才是硬件接线、音频、固件的事——那些坑更大,下一篇接着写。

小结

如果你也在 Mac 上折腾 ESP32,欢迎在评论区留下你的评论。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐