用进迭时空 K1 MUSE Pi Pro(SpacemiT M1,八核 RISC-V,融合 2 TOPS AI 算力)做一台感应风扇:USB 摄像头采集画面,Python 调用官方人脸识别例程做检测,一旦画面里出现人脸,就从 40Pin 扩展口的 GPIO73 输出 PWM 信号,驱动风扇电机模块转动;人离开画面超过设定时间,风扇自动停转。全部逻辑在板子上本地运行,不联网、不上云。
整个链路可以概括为:摄像头取帧 → YOLOv5n-face 检测人脸 → 检测结果映射为 PWM 占空比 → gpiozero 输出 → 风扇驱动板 → 风扇转动。

图 1 系统总体框图
硬件与软件清单
名称 | 规格 / 说明 | 用途 |
K1 MUSE Pi Pro | SpacemiT M1,8 核 RISC-V,LPDDR4X,Bianbu Desktop / Bianbu OS | 主控,跑 Python 与模型推理 |
USB 摄像头 | 支持 UVC 即可;也可用 MIPI CSI 摄像头 | 采集视频帧 |
风扇电机模块 | 商品页「风扇电机」SKU,带驱动板,5V 供电,PWM 调速 | 执行机构 |
杜邦线 | 母对母 / 公对母若干 | 连接 40Pin 与模块 |
电源与外设 | USB Type-C PD 5V/3A、HDMI 显示器、键鼠 | 供电与调试 |
Python 3.12 | venv 虚拟环境 | 运行环境 |
opencv-python / onnxruntime / gpiozero | 详见第一章依赖 | 视觉与 GPIO |
本文按「环境配置 → 人脸识别 → GPIO 控制 → 风扇模块功能 → 运行效果」的顺序展开,代码可以直接复制使用,版式留待在网页编辑器里再排。
一、环境配置:先把 Python 环境搭起来
1.1 为什么必须用虚拟环境
Bianbu OS 预装了 Python 3(推荐跟随系统版本,K1 平台推荐 Python 3.12)。官方文档明确说明:系统 Python 受 PEP 668 保护,直接 pip install 会报 error: externally-managed-environment。第三方库必须装进 venv 虚拟环境,或者用 apt install python3-xxx 安装系统预编译包。
另一个容易踩的坑是架构:K1 是 RISC-V,部分含 C/C++ 扩展的 Python 包在 PyPI 上没有预编译 wheel,pip 会拉源码本机编译,耗时且容易失败。进迭时空提供了适配 RISC-V 的 PyPI 镜像源,务必把它配成 extra-index-url。
1.2 安装系统依赖并创建虚拟环境
sudo apt update |
激活成功后,命令行提示符前会出现 (.venv)。用 python3 -c "import sys; print(sys.executable)" 可以确认解释器指向虚拟环境目录。
1.3 下载官方人脸识别例程
cd ~ |
requirements.txt 中的关键依赖:
onnxruntime==1.20.1+spacemit |
如果只想跑通检测、暂时不需要 NPU 加速,也可以按官方课程文档的最小依赖安装:pip install opencv-python pillow,其余由 requirements 一次装齐更省事。
1.4 安装 GPIO 库并放通权限
pip install "gpiozero>=2.0.5" lgpio |
官方说明里强调 gpiozero 版本必须 ≥ 2.0.5。chmod 每次重启会失效,做成 udev 规则更省心:
echo 'KERNEL=="gpiochip*", MODE="0666"' | sudo tee /etc/udev/rules.d/99-gpio.rules |
1.5 环境自检
python -c "import cv2, numpy, onnxruntime, gpiozero; print('env ok')" |
pinout 会打印板卡型号与 40Pin 的 GPIO 映射;ls /dev/video* 用来确认摄像头编号,后面代码里的 CAM_INDEX 要按实际结果填写。
二、人脸识别:官方例程怎么跑
2.1 例程做了什么
官方《人脸识别应用》课程用两个量化 ONNX 模型串成一条流水线:
l yolov5n-face_320_cut.q.onnx:YOLOv5n-face 人脸检测,输出人脸框 boxes 和裁剪出的人脸图 face_imgs;
l arcface_mobilefacenet_cut.q.onnx:ArcFace / MobileFaceNet 提取 512 维(量化版)特征向量,与人脸库里的 .npy 模板做点积/余弦相似度比较,阈值 0.6;
l 人脸库放在 faces/ 目录,每个 .npy 文件对应一个人名。
官方例程目录结构:
face_det_rec/ |
2.2 先注册人脸,再跑识别
cd ~/face_det_rec |
注册时尽量让正面人脸落在检测框内,终端提示「请输入人脸名」后输入名字回车即可。识别程序检测到人脸会画框,并把匹配到的名字标在框上方。

图 7 人脸注册结果(官方)

图 8 人脸识别效果(官方)
2.3 本项目只取"检测到人脸"这一个信号
识别程序的核心接口是 det.infer_face(frame),返回 (face_imgs, boxes);没有检测到人脸时返回 (None, None)。官方主程序把推理放到独立线程,主线程只负责取帧和显示,这样模型推理的耗时不会卡住画面。
本项目要做的是"有人来就转风扇",所以触发条件取 boxes 非空,而不是"必须匹配到已注册的人":
face_imgs, boxes = det.infer_face(frame) |
这样做的好处是未注册的访客也能触发风扇;ArcFace 的识别结果仍然保留,只用于画面上显示姓名和相似度,不参与开关判断。如果想改成"只给认识的人吹风",把触发条件换成 any(not n.startswith("unknown") for n in names) 即可。
三、GPIO 控制:选哪个脚、怎么输出 PWM
3.1 引脚选择:GPIO73(40Pin 第 15 脚)
40Pin 排针的丝印编号和代码里用的 GPIO 编号不是同一个数,这是最容易出错的地方。本文选用 GPIO73 = 物理 PIN15,理由有两条:
1. 官方《Python 用户指南》的 PWMLED 呼吸灯示例就接在 GPIO73;
2. 官方《外设模块参考说明》里二维云台舵机的 PWM 信号线也接在 GPIO-73。
供电与地:5V 在 PIN2 / PIN4(最大 1A,官方标注可为散热风扇供电),GND 在 PIN6 / 9 / 14 / 20 / 25 / 30 / 34 / 39,3.3V 在 PIN1 / PIN17。整个 GPIO 电平域是 3.3V。

图 6 MUSE Pi Pro 40Pin 引脚定义(官方)

图 10 开发板 GPIO 接口(官方)
需要说明:gpiozero 输出的是软件 PWM(由 lgpio 在用户态模拟),官方也明确写了"即使某些 GPIO 引脚不支持硬件 PWM,只要支持基本输出功能,仍可通过 gpiozero 实现软件 PWM"。风扇调速对频率稳定性要求不高,软件 PWM 完全够用;若要驱动舵机或追求更稳的波形,可改用板上的硬件 PWM 脚:GPIO34/PWM4(PIN32)、GPIO35/PWM5(PIN36)、GPIO33/PWM3(PIN37)、GPIO46/PWM6(PIN38)、GPIO37/PWM7(PIN40),通过 /sys/class/pwm/pwmchipN/export、period、duty_cycle、enable 控制。
3.2 三行固定写法:显式指定引脚工厂
在 SpacemiT 板子上用 gpiozero,官方建议在程序开头固定加上这三行,显式指定底层使用 lgpio 的 /dev/gpiochip0:
from gpiozero.pins.lgpio import LGPIOFactory |
3.3 最小验证程序:让风扇按不同占空比转
先不接摄像头,单独写一个 fan_test.py 验证引脚、接线和 PWM 是否正常:
# fan_test.py —— 单测风扇 PWM,接线检查用 |
运行:
sudo chmod a+rw /dev/gpiochip0 |
PWMLED.value 从 0 到 1 线性对应占空比 0% 到 100%,占空比越高,驱动板给电机的平均电压越高,转速越快。

图 3 PWM 占空比与转速关系示意
注意:GPIO 的驱动能力很弱,官方文档明确不建议把 LED、电机等功率器件直接挂在引脚上。风扇必须由模块自带的驱动板(或外接 MOS 管/三极管)驱动,GPIO 只提供控制信号,电机电源从 5V 引脚取。 |

图 9 PWM 信号接线示例(官方)
四、风扇模块功能:引脚定义、接线与联动代码
4.1 模块与引脚定义
商品页里选「风扇电机」这个 SKU,对应的是一片带驱动板的小风扇模块,典型规格是 5V 供电、板载驱动、三线接口,用一路 PWM 信号调速。本文按这类模块的通用三线定义接线:
模块丝印 | 线色(常见) | 功能 | 接到开发板 |
VCC | 红 | 5V 电源正 | 40Pin PIN2 或 PIN4(5V) |
GND | 黑 | 电源地 / 信号地 | 40Pin PIN30(或 PIN6、PIN9 等 GND) |
PWM / S / IN | 黄 / 白 | PWM 调速信号,3.3V 逻辑 | 40Pin PIN15(GPIO73) |
说明:淘宝商品页需要登录后才能查看详情,本文按该类风扇电机模块的通行引脚定义整理。接线前请以商品页「引脚定义」图和实物丝印为准,确认 VCC 是 5V 还是 3.3V、信号脚丝印是 PWM / S / IN 中的哪一个,再上电。 |

图 2 接线示意图
三条线里最容易漏的是共地:开发板 GND 必须和模块 GND 相连,否则 PWM 信号没有参考电平,风扇会出现不转、乱转或一直全速的现象。
4.2 两种常见变体的接法
l 四线 INA/INB 驱动(L9110S、MX1508 一类):INA 接 GPIO73 输出 PWM,INB 接一个普通 GPIO(例如 GPIO74 = PIN12)并固定输出低电平;也可以把 INB 直接接 GND。代码里加两行即可:
from gpiozero import LED |
l 两线裸电机(只有正负极):不能直接接 GPIO,必须外加 MOS 管或电机驱动板,GPIO 只控制 MOS 管栅极,5V 单独给电机供电,并在线圈两端并续流二极管。本文代码无需改动,只要 PWM 信号接到驱动级的控制端即可。
4.3 完整联动程序 fan_face_main.py
把下面代码保存为 ~/face_det_rec/fan_face_main.py,与官方的 base/、onnx_model/、faces/ 同级。它在官方例程的双线程结构上加了三件事:风扇控制器类、"有人开 / 无人延时关"的状态机、画面上的风扇状态显示。
# -*- coding: utf-8 -*- |
运行:
sudo chmod a+rw /dev/gpiochip0 |

图 4 主程序流程
4.4 几个参数的含义
参数 | 默认值 | 调整建议 |
FAN_PIN | 73 | 换脚时改这里;注意写 GPIO 号,不是排针号 |
FAN_DUTY | 0.70 | 风太大调小,风太小调大;低于约 0.3 部分电机可能起不来 |
START_DUTY / START_SEC | 0.90 / 0.25 | 低占空比启动不了电机时,把这两个值调大 |
HOLD_SEC | 3.0 | 人短暂离开就停转 → 调大;希望人走立刻停 → 设为 0 |
CAM_INDEX | 20 | MIPI 摄像头常用 20;USB 摄像头先 ls /dev/video*,多半是 0 |
SIM_THRES | 0.6 | 只影响姓名显示,不影响风扇开关 |
五、运行效果
程序启动后终端先打印初始化信息:
[init] camera=20 pwm_gpio=73 duty=0.70 hold=3.0s |
实际现象分三种状态:
1. 画面无人:PWM 占空比为 0,风扇静止,画面左上角显示红色 FAN OFF duty=0.00;
2. 有人进入画面:检测框出现,风扇先以 0.90 的占空比短促启动,0.25 秒后回落到 0.70 稳定转动,状态变成绿色 FAN ON duty=0.70;若人脸已注册,框上方还会显示姓名与相似度;
3. 人离开画面:last_seen 不再刷新,超过 3 秒后 tick() 把占空比归零,风扇停转,终端打印 [fan] OFF (timeout)。人还在画面内时每帧都会刷新时间戳,所以不会误停。

图 5 运行效果示意
由于模型推理放在独立线程,画面帧率会比纯摄像头预览低一些,属于正常现象;把检测输入分辨率调小、或使用量化模型(例程默认已是 .q.onnx)可以改善。本文没有给出具体帧率数值,因为它与摄像头分辨率、系统负载和散热条件相关,建议以自己板子上的实测为准。
还可以继续扩展:按识别到的人名给不同风速、按画面里人脸数量线性提高占空比、叠加温度阈值做"又热又有人"才转,或者把 HOLD_SEC 做成网页端可调参数。
六、踩过的坑与注意事项
1. pip 装不进系统 Python:报 externally-managed-environment 是 PEP 668 保护,必须用 venv,不要加 --break-system-packages。
2. GPIO 报 Permission denied:忘记 sudo chmod a+rw /dev/gpiochip0,重启后又会失效,建议写 udev 规则。
3. 排针号 ≠ GPIO 号:PIN15 对应 GPIO73,PIN32 对应 GPIO34/PWM4。代码里一律写 GPIO 后面的数字,接线时才看排针号。
4. 电平与供电:GPIO 是 3.3V 电平域,5V 只能从 PIN2/PIN4 取;电机绝不能由 GPIO 直接驱动,且必须共地。
5. 低占空比不转:直流电机有静摩擦,0.2~0.3 的占空比可能只让驱动板"嗡嗡响"。代码里加了 START_DUTY 启动脉冲,若仍不转就调大它或调大 FAN_DUTY。
6. 摄像头打不开:官方例程用 cv2.VideoCapture(20),那是 MIPI CSI 的节点;插 USB 摄像头时先 ls /dev/video*,把 CAM_INDEX 改成对应编号。
7. 人脸库是空的:不影响"有人就转",但画面只会画框、显示不出姓名。想显示姓名先跑一次 save_face.py。
8. 软件 PWM 的边界:gpiozero 用的是软件 PWM,驱动舵机会抖;风扇调速没问题。要求严格时序时改用硬件 PWM 脚与 sysfs 接口。
9. 模块引脚以实物为准:不同批次的风扇电机模块丝印可能是 PWM、S、IN、INA/INB 或只有两根线。上电前核对商品页引脚定义图,必要时按 4.2 节的变体接法调整。
七、总结
这个项目把进迭时空官方的人脸识别例程和 gpiozero 的 PWM 输出拼在一起,用的都是板子自带能力:Bianbu OS + Python 3.12 虚拟环境跑 YOLOv5n-face 与 ArcFace 量化模型,40Pin 的 GPIO73(PIN15)输出 PWM,5V 引脚给风扇模块供电。核心逻辑其实只有一句判断——boxes 非空就 fan.on(),再配一个 HOLD_SEC 的延时关断,就实现了"看到有人来就转风扇"。
工程文件只有一个新脚本 fan_face_main.py,其余全部复用官方 face_det_rec 源码包,方便复现和二次修改。接线时记住三件事:5V 供电、必须共地、信号脚接 PIN15。
参考资料
l K1 MUSE Pi Pro 用户使用指南:https://www.spacemit.com/community/document/info?lang=zh&nodepath=ecohardware/k1_series/k1_muse_pi_pro/pi_pro_user_guide.md
l 人脸识别应用(AI 综合应用案例):https://www.spacemit.com/community/document/info?lang=zh&nodepath=courses/AI/02_AI综合应用案例/02_人脸识别应用.md
l Python 使用指南(Bianbu OS 环境配置与 gpiozero):https://www.spacemit.com/community/document/info?lang=zh&nodepath=software/SDK/bianbu/development/python.md
l MUSE Pi / MUSE Pi Pro 扩展 IO 定义:https://www.spacemit.com/community/document/info?lang=zh&nodepath=software/SDK/bianbu/user_guide/LXQt/MUSEPi_and_MUSEPiPro_expansion_IO_pinout.md
l gpiozero 使用说明 / 外设模块参考说明(竞赛教程)
l 风扇电机模块(SKU 与引脚定义商品页):https://item.taobao.com/item.htm?id=1086825104957 ;https://item.taobao.com/item.htm?id=1085516335983
l 华秋开源硬件社区文章格式参考:https://p.eda.cn/d-1436671834299826176 ;https://p.eda.cn/d-1435260630108995584
