使用Arduino UNO Q开发一个桌面级机器人,通过设备内置的机器学习技术检测人脸,并实时朝向目标移动
该项目将计算机视觉与机器人技术集成于一块电路板上。摄像头捕捉视频,轻量级的人脸检测模型(由Edge Impulse提供支持)定位人脸,比例控制器则将该位置转换为差分轮子指令,整个过程每秒约10至15帧。
UNOQ的分体式结构使得这一点成为可能:
•MPU(高通,Linux)--> 用Python运行机器学习模型和控制逻辑
•MCU(STM32、Zephyr RTOS)用于以实时精度驱动舵机PWM
两个处理器通过桥接RPC通信,这是一种基于MessagePack的协议,通过内部串行链路传输。这种分离方式将复杂的推理任务从实时路径中移开,同时保持电机控制的确定性。
基于浏览器的Web界面可让您实时监控检测结果并调整转向参数,无需重新编译。
先决条件
硬件
软件
•Arduino App Lab v0.6 或更高版本(在浏览器中运行,无需本地安装)
•与UNO Q在同一网络中的计算机
•Edge Impulse Studio Studio Studio 账户
架构概览
该系统分为三层:
为什么要将MPU和MCU分开?机器学习推理计算量大且非确定性,应运行在Linux处理器上;而舵机PWM时序对安全性至关重要,必须无抖动,因此需部署在实时微控制器上。通过桥接RPC连接两者,往返延迟约为8毫秒。
硬件组装
底盘概览
机器人采用简单的差动驱动布局:
•两个安装在相对两侧的连续旋转伺服电机
•后轮转向或滑动点,用于提升稳定性
•用于UNO Q和相机的顶部安装平台
•USB移动电源放置在平台上方或下方作为镇流器使用。
连续旋转伺服电机简化了接线。1500微秒的脉冲表示停止,低于1500微秒时单向旋转,高于1500微秒时反向旋转。
布线
•在伺服电源和地线之间并联一个100微法的电容,以吸收电流尖峰。
•将网络摄像头连接到USB-C分线器上的USB-A接口。USB-C端为UNO Q供电。
注意:右侧伺服电机相对于左侧是镜像安装的。固件通过脉冲反转标志来处理此问题,无需交叉线。
App Lab 中的项目设置
文件结构
每个 App Lab 项目都遵循以下布局:
配置砖块
砖块是预构建的中间件包,运行在MPU上。它们无需编写样板代码即可提供高级功能。本项目使用了两个:
视频对象检测,捕获摄像头帧,运行人脸检测模型,并通过回调函数将结果传递给你的Python代码
web_ui 用于提供 HTML/JSJSJS 前端仪表盘,并配备 Socket.IO 服务器以实现实时通信。
模型:人脸检测线选择了一个内置的轻量级人脸检测模型,无需训练或 Edge Impulseulseulse 账户。
草图依赖项
在 sketch/sketch.yaml 中,主要的库是 Arduino_RouterBridge(桥接 RPC)和 Servo(PWM 输出):
MCU固件设计为极简,它通过Bridge RPC接收脉宽命令,并将这些命令写入PWM硬件。所有决策均由MPU完成。
Bridge RPC RPC RPC 端点
关键概念:
Arduino Servoo 库通过 attach(pin 和 writeMicroseconds()() 处理 PWM 输出。这比依赖于设备树索引映射的底层 Zephyr PWM API(pwm_set_dt)更具可移植性,因为后者在不同板型版本之间可能存在差异。
Bridge.provide_safe() 会注册该函数,使其在 Arduino 的 loop() 上下文中运行,从而确保 PWM PWM 写入等硬件操作的安全性。切勿使用 Bridge.provide()()() 调用 GPIO、舵机或电机相关功能,因为这些调用会在后台的 RPC RPC RPC 线程中执行,硬件 API API 可能在此时失败。
脉冲反转用于处理镜像的右舵机:反转时,脉冲值为3000减去脉冲数。这会将脉冲在1500微秒的停止点周围进行镜像,因此Python发出的相同“前进”指令会使两个轮子朝同一物理方向移动。
空的 loop() 是正确的,BridgeBridge 库会内部钩入 loop,以分发排队的 provide_safe_safe 回调。
连续旋转伺服基础
离1500越近,轮子转动越慢。本项目使用最大±125微秒的偏移量,实现响应灵敏且安全可靠的运动。
MPU应用:从检测到转向
MPU上的Python应用程序承担着三项职责:接收来自视觉模块的检测信息、计算转向指令,并与MCU和Web用户界面进行通信。
砖块初始化
VideoObjectDetectionDetectionDetection 块每次处理一帧时都会触发回调。on_detect_all_all 变体会为每一帧触发,包括没有检测到对象的帧,有助于保持看门狗时间戳的新鲜度:
检测格式
砖块以字典形式返回检测结果,每个标签对应一个检测实例列表:
每个实例包含一个置信度分数以及一个边界框坐标元组(x_min, y_min, x_max, y_max),单位为像素。TARGET_CLASS_CLASS_CLASS 常量必须与模型的标签完全匹配,内置人脸检测模型的标签为 "face"。
重要提示:每个标签的值始终是一个列表,即使只检测到一个对象。如果代码期望每个标签对应一个普通的字典(不包含列表包装),则会静默忽略所有检测结果。
比例转向控制器
控制器将面部的水平位置转换为差分轮子指令:
1. 找到人脸的边界框中心
2. 归一化到 0.0(左边缘)— 1.0(右边缘)
3. 计算偏移误差:(中心 - 0.5) × 2.0 → → → 范围为 -1.00 到 +1.0
4. 应用死区(忽略微小误差以抑制抖动)
5. 使用幂曲线进行形状响应(压缩大误差)
6. 按 STEER_GAIN → → → 转向速度调整
7. 转换为差分脉冲:左 = 1500 + + + 转数,右 = 1500 - - - 转数
功率曲线(STEER_CURVE = 0.4)使小误差时响应更激进,靠近车架边缘时响应更平缓,是一种适用于此场景的简单PID替代方案。
漂移与丢失目标
当面部短暂消失(遮挡、眨眼或短暂移开视线)时,控制器会在最后一个已知位置上保持一段时间(默认为0.5秒),即TRACKING_TIMEOUT秒后,宣布目标丢失。这可避免出现抖动的启停行为。
当目标真正丢失时,机器人会停止。可选的搜索模式(默认关闭)会缓慢旋转以扫描面部。
桥接通信与速率限制
UNO Q Q Q 桥接器没有内部队列,命令发送过快会导致串行链路崩溃。应用程序将桥接器调用限制在每 20 Hz(5000 毫秒间隔)以内:
Bridge.notify() 是“即发即忘”(无需等待响应),可避免阻塞推理循环。而 Bridge.call()() 则会等待返回值,从而减慢控制循环的运行速度。
安全提示:紧急停止功能完全绕过速率限制,以确保MCU能立即接收到停止指令。
看门狗
后台线程会检查检测回调是否已停止发送。如果在1.5秒内没有触发任何回调(表明相机或管道出现故障),看门狗将强制发出停止命令:
网页用户界面
仪表板可在同一网络中的任何浏览器上运行,提供实时监控和参数调优功能。
功能
所有滑块调整通过 Socket.IO.IO.IO 立即生效,无需重启。这使得调参变得快速:调整一个滑块,观察机器人的响应,重复操作即可。
部署并运行
App Lab 用户界面
1. 在浏览器中打开 Arduino App Lab
2. 创建一个新应用或导入项目文件
3. 点击运行,App Lab Lab 将代码编译后,闪存 MCU MCU 并启动 Python Python 应用程序
首次启动检查清单
1. 检查日志中的 sample_detectionsetections 行,它会在第一帧上打印原始检测数据。请验证:
标签为“face”(与TARGET_CLASS匹配)
边界框坐标与您的相机分辨率相匹配
2. 打开 Web UI,你应该能在“最近检测”中看到视频流和检测事件。
3. 验证舵机,请在用户界面中按下电机测试按钮。两个轮子应先向左转动,暂停,然后向右转动。如果不符合,请检查接线和舵机电源,然后再进行面向跟踪。
调校指南
转向方向
如果机器人转向远离你的脸而不是朝向它,请在 main.py 中翻转转向标志:
画幅宽度校准
检查 sample_detections 日志输出。如果 bounding_box_xyxy 中的最大 x x x 坐标与 FRAME_WIDTH_FALLBACK(默认为 640)有显著差异,请更新该常量使其匹配。错误的数值会导致转向不均匀或变弱。
增益调谐
从这些默认值开始,使用网页界面的滑块进行调整:
工作流程:将机器人放在桌面上,先设置初始参数。逐渐增大STEER_GAIN,直到机器人能平稳地对准你的面部。如果出现左右摆动(过冲),则需降低增益值。调校完成后,更新main.py中的默认参数,使机器人启动时使用合适的初始值。
本文编译自hackster.io





