STM32单片机RT Thread + Micropython + OpenMV + USB摄像头移植整合过程

按照之前设定的计划,利用业余时间做了这么一个项目。目标是基于RT Thread实时操作系统,将Micropython、OpenMV、USB摄像头+模拟摄像头+STM32本身自带的DVP摄像头,在OpenMV框架下,全部引入进来。这样的话,该软件平台同时具备了RTOS、Python脚本、USB OpenMV串口驱动、存储设备如SPI flash驱动,SD卡驱动、U盘驱动(和OpenMV串口组成一个USB Composite驱动,用来连电脑),其中U盘驱动可以用SD卡或者SPI flash作为介质。并实现了一个简单的FAT32文件系统,可以在SD卡或者SPI flash上使用。

USB摄像头和模拟摄像头的引入,使得带OpenMV算法的STM32H7等单片机硬件能够应用的范围大大拓展了。这种允许长连接线连接的摄像头,可以将摄像头模组和电路板分开,能够应用在网络摄像头,行车记录仪等场合。

RT-Thread 是一款完全由国内团队开发维护的嵌入式实时操作系统(RTOS),具有完全的自主知识产权。经过近 12 个年头的沉淀,伴随着物联网的兴起,它正演变成一个功能强大、组件丰富的物联网操作系统。相较于 Linux 操作系统,RT-Thread 体积小,成本低,功耗低、启动快速,除此以外 RT-Thread 还具有实时性高、占用资源小等特点,非常适用于各种资源受限(如成本、功耗限制等)的场合。在 RT-Thread 系统中,任务通过线程实现的,RT-Thread 中的线程调度器也就是以上提到的任务调度器。具体参考RT-Thread官网介绍

MicroPython运行的完整的Python编译器和运行时。 您将获得交互式提示(REPL),以便立即执行命令,以及从内置文件系统运行和导入脚本的功能。 REPL具有历史记录,选项卡完成,自动缩进和粘贴模式,以获得良好的用户体验。MicroPython致力于与普通Python(称为CPython)尽可能兼容,以便如果您会使用Python,就可以玩转MicroPython。除了实现一系列核心Python库之外,MicroPython还包括访问硬件的“machine”等模块。具体参考Micropython官网

OpenMV可以用来做:

  1. DIY相关的项目制作,比如追踪小球的车,云台,或者解魔方的机器人。
  2. 对成本要求很高的嵌入式工业方案,比如流水线物品的分拣。

OpenMV实现了画图, 寻找色块, AprilTag标记跟踪, 模板匹配, 多模板匹配, 特征点检测, 测距, 扫码识别, 颜色形状同时识别, 颜色模板匹配同时识别, 分辨不同人脸等算法,甚至还带了简单的TensorflowLite库。详情访问OpenMV国内官网:https://singtown.com/openmv/

下图是使用USB摄像头运行的效果:

 

USB摄像头驱动是基于我之前的STM32单片机实现连接USB摄像头,OpenMV及其模拟摄像头实现方法参考OpenMV增加支持模拟摄像头。另外移植解决了如下问题:

1、新版本OpenMV-3.5.1移植到RT thread,RTT官方目前没有成功移植的OpenMV版本供下载使用。这上面主要解决了RTT Micropython需要的8bit QSTR函数映射。当然参考的是OpenMV源码的映射方式,但是官方源码是16bit,需要小做修改。

2、我自己做的USB摄像头驱动优化了一下,目前优化后占用CPU可以做到更少。

3、OpenMV源码中JPEG压缩的实现采用查询的方式,改成了中断的方式实现,这种实现方式占用CPU更少一点。后期可以尝试采用DMA的方式,进一步减少对CPU资源的占用。

4、参考OpenMV串口功能,在RT Thread USB device驱动框架架构下实现了一个OpenMV串口,用来和OpenMV IDE实时算法调试时使用。

5、测试了一些简单的OpenMV算法如canny/Sobel边缘增强、颜色识别/追踪、人脸识别等,都没有问题。理论上其它算法正常跑起来,不会有任何问题。

结尾附上USB摄像头的测试python代码:

# Untitled - By: chummyhe - 周一 五月 11 2020

 

import sensor, image, time

 

sensor.reset()

sensor.set_pixformat(sensor.YUV422)

sensor.set_framesize(sensor.QVGA)

sensor.skip_frames(time = 2000)

 

clock = time.clock()

 

while(True):

    clock.tick()

    img = sensor.snapshot()

    print(clock.fps())