MaixCAM实战:基于YOLOv5检测结果的MSPM0G3507联动控制
1. 项目背景与硬件准备最近在做一个智能家居安防的小项目需要实现当摄像头检测到有人时自动触发灯光效果。经过对比多种方案最终选择了MaixCAM搭配MSPM0G3507微控制器的组合。这个方案最大的优势在于MaixCAM可以直接运行YOLOv5模型进行实时目标检测而MSPM0G3507则负责接收检测结果并控制PWM呼吸灯。两者通过UART串口通信形成了一个完整的感知-决策-执行闭环。先说说硬件准备。我使用的是MaixCAM有屏幕版这个开发板自带摄像头和显示屏特别适合快速原型开发。微控制器方面选择了TI的MSPM0G3507这是一款基于Arm Cortex-M0的低功耗MCU内置PWM模块正好满足我们的需求。接线方面需要注意MaixCAM的UART0_TXA16引脚接MSPM0G3507的UART0_RXPA10MaixCAM的UART0_RXA17引脚接MSPM0G3507的UART0_TXPA11共地连接GND to GND这里有个坑我踩过一定要确认两边的UART端口对应正确。我第一次尝试时把MaixCAM的UART1接到了MSPM0G3507的UART0结果死活收不到数据。后来发现必须UART0对UART0才能正常通信这个在官方文档里其实有说明但很容易被忽略。2. MaixCAM端的YOLOv5模型部署在MaixCAM上运行YOLOv5模型出奇地简单。官方提供的nn模块已经封装好了常用功能我们只需要几行代码就能加载模型并开始检测。我使用的是yolov5s.mud这个预训练模型它已经在COCO数据集上训练过可以直接检测80类常见物体包括我们需要的person类别。模型加载的关键代码如下detector nn.YOLOv5(model/root/models/yolov5s.mud, dual_buffTrue) cam camera.Camera(detector.input_width(), detector.input_height(), detector.input_format())这里有个小技巧通过遍历detector.labels可以找到person对应的类别ID。因为不同版本的YOLOv5模型类别顺序可能不同所以最好不要硬编码这个ID。我的做法是person_id 0 for i, label in enumerate(detector.labels): if person in label.lower(): person_id i break检测逻辑也很直观。我们设置一个置信度阈值我测试下来0.7效果不错只有当检测到的人体置信度超过这个阈值时才触发后续操作current_detected False for obj in objs: if obj.class_id person_id and obj.score 0.7: current_detected True # 绘制检测框和标签 img.draw_rect(obj.x, obj.y, obj.w, obj.h, colorimage.COLOR_RED) msg fPerson: {obj.score:.2f} img.draw_string(obj.x, obj.y, msg, colorimage.COLOR_RED)3. UART串口通信实现检测到人后需要通过UART发送指令给MSPM0G3507。MaixCAM的UART配置需要注意以下几点首先要在代码开头设置引脚映射pinmap.set_pin_function(A17, UART0_RX) pinmap.set_pin_function(A16, UART0_TX)然后初始化UART我使用的是9600波特率这个速度对于简单的控制指令完全够用serial1 uart.UART(/dev/ttyS0, 9600)发送逻辑我做了优化不是每次检测到人都发送指令而是只在状态变化时发送比如从无人到有人if current_detected and not last_detected: print(Detected person with confidence 0.7) serial1.write_str(helloperson\n) print(UART sent: helloperson) last_detected current_detected这里有几个经验分享一定要在指令末尾加换行符\n这样接收端可以方便地判断指令结束指令内容不要太复杂简单的字符串即可减少传输错误概率实际测试时建议先单独测试UART通信确保两边能正常收发数据后再集成AI检测部分4. MSPM0G3507端的PWM呼吸灯控制MSPM0G3507端的代码主要分为三部分UART接收处理、PWM初始化和呼吸灯逻辑。先看UART接收部分这里使用了中断方式void UART_0_INST_IRQHandler(void) { uint8_t receivedChar; switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) { case DL_UART_MAIN_IIDX_RX: receivedChar DL_UART_Main_receiveData(UART_0_INST); if (rxIndex RX_BUFFER_SIZE - 1) { rxBuffer[rxIndex] receivedChar; rxIndex; rxBuffer[rxIndex] \0; } if (strstr((char*)rxBuffer, helloperson) ! NULL) { stringReceived true; rxIndex 0; memset((void*)rxBuffer, 0, RX_BUFFER_SIZE); } break; default: break; } }PWM呼吸灯的实现比较有趣。我使用了一个简单的算法PWM占空比从0逐渐增加到最大值然后再逐渐减小如此循环。通过调整breathingSpeed可以控制呼吸的快慢if (breathingEnabled) { timerCounter; if (timerCounter 1000) { timerCounter 0; pwmDutyCycle pwmDirection * breathingSpeed; if (pwmDutyCycle 1000) { pwmDutyCycle 1000; pwmDirection -1; } else if (pwmDutyCycle 0) { pwmDutyCycle 0; pwmDirection 1; } DL_TimerG_setCaptureCompareValue(PWM_0_INST, 1000 - pwmDutyCycle, DL_TIMER_CC_1_INDEX); } }这里有个细节需要注意PWM的占空比设置是反的。即设置值越大实际输出脉冲宽度越小灯越暗。所以代码中是1000 - pwmDutyCycle。5. 系统集成与调试技巧把各个模块集成到一起时我遇到了几个典型问题这里分享下解决方案问题1UART通信不稳定有时候会收到乱码或者丢数据。解决方法确认两边波特率完全一致检查接线是否牢固线长不要太长在代码中加入简单的校验机制比如固定指令格式问题2呼吸灯效果不流畅表现为灯光闪烁不均匀。解决方法调整PWM频率我最终使用的是1kHz优化呼吸灯算法避免占空比突变在main循环中加入适当延时避免MCU负载过高问题3误检测导致灯光频繁开关YOLOv5偶尔会把其他物体误检为人。解决方法提高置信度阈值从0.5提高到0.7在MCU端加入简单的防抖逻辑比如连续收到3次指令才真正切换状态对检测区域设置ROI只关注特定区域调试时可以分阶段进行先单独测试MaixCAM的物体检测功能然后测试UART通信最后测试PWM输出全部通过后再进行系统联调6. 性能优化与扩展思路这个基础版本跑起来后我又做了一些优化和扩展尝试性能优化在MaixCAM端将YOLOv5的输入分辨率从640x640降到320x320帧率从5fps提升到15fps在MSPM0G3507端将PWM频率从1kHz提高到10kHz灯光更加平滑优化通信协议将字符串指令改为二进制指令传输效率更高功能扩展增加多目标检测比如同时检测person和car根据检测到的人数控制灯光亮度人越多灯越亮添加蓝牙/WiFi模块实现手机远程监控和控制增加声音报警功能当检测到人时同时触发灯光和声音一个特别实用的扩展是添加了检测日志功能。当MaixCAM检测到人时除了控制灯光外还会把时间戳和检测置信度保存到SD卡方便后续分析。7. 实际应用中的注意事项经过一段时间的实际使用总结出以下几点经验电源管理MaixCAM功耗较高如果使用电池供电需要注意续航。可以考虑添加休眠模式当长时间未检测到人时自动进入低功耗状态。环境适应性在不同光照条件下YOLOv5的检测效果会有差异。可以考虑添加自动曝光控制针对特定场景微调模型使用红外摄像头在低光环境下工作抗干扰设计通信线上加磁环减少干扰在代码中加入CRC校验重要指令需要确认机制散热问题长时间运行时MaixCAM会发热。建议添加散热片确保通风良好避免阳光直射固件升级为两个设备都预留OTA升级功能方便后期维护和功能更新。这个项目最让我满意的是它的灵活性。基于这个框架可以很容易地替换不同的传感器和执行器实现各种智能交互场景。比如把人体检测换成火焰检测把呼吸灯换成报警器就是一个火灾预警系统。或者把YOLOv5换成专门的手势识别模型就能实现手势控制灯光。