- 项目介绍
使用MAX78000芯片开发一个具备自动人脸识别和人脸运动追踪功能的云台设备,该云台能够在自动跟拍等应用场景中发挥作用。
- 项目设计思路
项目框图如下:
为了实现这个项目,我们采用了两块开发板的方案。其中,MAX78000芯片负责图像捕捉和AI处理的任务。它能够捕捉到图像中的人脸,并通过AI处理,确定人脸所在的区域范围。一旦确定了人脸的位置,MAX78000芯片将该信息发送给第二块开发板。
第二块开发板负责运动控制部分。它接收到来自MAX78000芯片的人脸区域位置信息后,利用这些信息来驱动舵机,从而调整两轴云台的角度,以保持人脸始终处于画面的中心区域。
通过这种方式,两块开发板相互协作,实现了自动人脸识别和运动追踪的功能,使得云台能够自动跟随人脸,适用于自动跟拍等应用场景。
- 关键代码展示
这个项目的第一部分是基于官方的MAX78000 Feather Facial Recognition Demo中的face_detection进行改写,以实现人脸识别功能。首先,我们进行串口、摄像头和屏幕的初始化工作。一旦初始化完成,我们开始抓取摄像头图像。当图像抓取完成后,我们进行人脸识别,并获取到人脸所在区域的坐标数据。
接下来,我们将抓取到的源图像显示在LCD屏幕上,并且如果成功识别到人脸并获取到人脸位置的坐标数据,我们会根据这些数据在LCD屏幕上绘制一个方框,以显示人脸的区域。
最后,我们将获取到的坐标数据通过串口发送出去,作为第二部分的数据输入。这样,第一部分就完成了人脸识别的任务,并将所需的数据传递给第二部分,为接下来的运动控制提供准确的人脸位置信息。
其中,UART部分初始化的代码如下:
/* Initilize UART3 */
#define UART_BAUD 9600
#define BUFF_SIZE 4
int error, i;
uint8_t TxData[6];
TxData[0] = 254;
TxData[5] = 255;
if ((error = MXC_UART_Init(MXC_UART_GET_UART(3), UART_BAUD, MXC_UART_APB_CLK)) !=
E_NO_ERROR) {
printf("-->Error initializing UART: %d\n", error);
printf("-->Example Failed\n");
return error;
}
printf("-->UART Initialized\n\n");
mxc_uart_req_t write_req;
write_req.uart = MXC_UART_GET_UART(3);
write_req.txData = TxData;
write_req.txLen = BUFF_SIZE + 2;
write_req.rxLen = 0;
write_req.callback = NULL;
循环部分代码如下:
while (1)
{
face_detection();
if (face_detected)
{
// face_id();
LED_On(LED1);
face_detected = 0;
undetect_count = 0;
for (i = 0; i < BUFF_SIZE; i++)
{
TxData[i + 1] = box[i];
}
error = MXC_UART_Transaction(&write_req);
if (error != E_NO_ERROR)
{
printf("-->Error starting sync write: %d\n", error);
printf("-->Example Failed\n");
return error;
}
}
else
{
undetect_count++;
// PR_DEBUG("No Face!\n");
LED_Off(LED1);
}
#ifdef TFT_ENABLE
if (undetect_count > 5)
{
MXC_TFT_ClearArea(&area, 4);
undetect_count = 0;
}
#endif
}
在项目的第二部分中,我们使用树莓派PICO作为主控制器,它是基于RP2040芯片的开发板。该部分负责云台的控制算法。我们通过树莓派PICO来控制两轴舵机云台。
算法的实现方式是循环读取在第一部分中识别到的人脸位置信息。根据这些位置信息,我们会根据人脸在图像中的相对位置进行调整,以确保人脸始终位于图像的中心位置。这样就实现了人脸的追踪功能。
通过不断循环读取人脸位置并进行相应的调整,我们可以保持云台的舵机在不断地调整角度,以保持人脸在图像中心的位置。这样,云台能够自动追踪人脸的运动,确保人脸始终处于画面的中心位置。
代码是在circuitpython上完成的,UART接收部分增加了一步校验,更加确保了准确性:
if uart.in_waiting >= 6:
data = uart.read(6)
if data[0] == 254:
x1=data[1]
y1=data[2]
x2=data[3]
y2=data[4]
x = (x1 + x2) / 2
y = (y1 + y2) / 2
print(x)
print(y)
print()
接下来,根据人脸框的中心点与画布中心点比较,来决定xy舵机的运行方向。为了避免反复震荡,我在这里还添加了一定的死区。
if xs > 180: xs = 180
elif xs < 0: xs = 0
if ys > 180: ys = 180
elif ys < 0: ys = 0
print(xs)
print(ys)
print()
servo_x.angle = xs
servo_y.angle = ys
- 实现结果展示
在该项目中,使用了一块面包板进行电路搭建。由于接线较多且摄像头板载于MAX78000上,为避免杜邦线挡住摄像头,我选择了绕线的方式,将线路从面包板的后面引出。
硬件连接:
首先是LCD屏幕与MAX78000的连接:
CLK: P0.7
MISO: P0.6
MOSI: P0.5
CS: P0.11
DC: P0.8
VCC: 3V3
GND: GND
接下来是树莓派PICO的连线,先说PICO和MAX78000的连线。
GPIO5: P2.7
VBUS: VBUS
GND: GND
下面是PICO与两个舵机的连线
GPIO3: servo x signal
GPIO2: servo y signal
VCC: VBUS
GND: GND
然而,在项目初始阶段,遇到了系统莫名停止运行的问题,需通过复位才能继续工作。经过反复检查,最终发现了问题所在。由于使用USB作为系统的电源,并且在两个舵机同时工作时,瞬间的电流汲取会导致电压降的瞬间增大,导致系统异常。
为了解决这个问题,我在面包板上添加了一个大电解电容。该电容器能够平衡瞬间的电流需求,从而有效解决了电压降的问题。考虑到面包板空间有限,孔位不足的情况,我将电容器安装在了面包板的反面。
通过这个改进,成功解决了系统运行异常的问题。电解电容器的加入平衡了电流需求,确保了系统的正常工作。这个经验让我意识到在电路设计中,电源的稳定性是一个重要因素。
具效果体演示可以参考文章开头的视频。
- 遇到的主要难题及解决方法,或未来的计划或建议等
完成这个项目后,我发现其中一个遗憾是我没有亲自进行模型训练。由于我的技术水平有限,而且我的笔记本电脑的计算能力也不够强大,自己训练模型的成本太高。如果将来有机会使用云端训练,我会尝试进行模型训练。
这次的项目对个人的技术水平和硬件要求门槛相对较高,实现起来也比较困难。但无论结果如何,这个过程对我的个人成长非常有帮助。我不仅提高了自己的技能水平,还对硬件和软件的交互有了更深入的了解。
虽然我没有进行模型训练,但在其他方面我也取得了一些进展。通过克服各种困难,我获得了宝贵的经验。这个项目的挑战性为我的成长和发展提供了很多机会。
完成这个项目后,我对自己的能力和技术有了更深的认识。虽然有一些遗憾,但我对自己的努力感到骄傲。我期待着将来有机会进行云端训练,并进一步完善和提升项目的功能和性能。这个项目的经历让我更加坚定了在技术领域继续学习和成长的决心。