OpenMV3 M7在Linux下的使用(二)

4 脚本结构

请注意,这个 tutorial 假设你知道 python 语言是如何工作的。如果你不知道 python 是如何工作的,请研究它。有很多关于如何编写 python 代码的网络 tutorials(最后,如果你知道任何其他 C 类编程语言,你可以很容易地选择 python,因为它非常相似)。无论如何,你编写的任何脚本都有三个不同的部分:

import ...

... one time setup ...

while(True): # Loop
    ...

OpenMV Cam 代码的第一部分应该包括一些标题注释,import 模块将模块放入范围,最后是代码中的常量和全局变量。接下来,您将要执行一次性设置代码。这包括创建 I/O 引脚对象,设置相机,定义辅助函数等。

最后,您将创建一个 while(True): 循环,在该循环下,您将重复循环调用所有被调用的代码,直到关闭电源。

这是一个例子:

### 标题注释,导入语句等
# 你好世界的例子
#
# 欢迎来到OpenMV IDE!单击下面的绿色运行箭头按钮运行脚本!

import sensor, image, time

### 一次性设置

sensor.reset()                      # 重置并初始化传感器。
sensor.set_pixformat(sensor.RGB565) # 将像素格式设置为RGB565(或GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # 将帧大小设置为QVGA(320x240)
sensor.skip_frames(time = 2000)     # 等待设置生效。
clock = time.clock()                # 创建时钟对象以跟踪FPS。

### 无限循环

while(True):
    clock.tick()                    # 更新FPS时钟。
    img = sensor.snapshot()         # 拍照并返回图像。
    print(clock.fps())              # 注意:openmv运行速度一半到IDE。一旦断开连接,FPS应该增加。

请注意,如果您的代码中没有无限循环,那么一旦您的 OpenMV Cam 完成运行脚本,它就会坐在那里什么都不做。

5 I/O 教程

在进入机器视觉主题之前,我们将讨论 OpenMV Cam 上的 I/O 引脚控制。重要的是你知道如何切换 I/O 引脚,发送和接收串行数据,以及让你的 OpenMV Cam 处于睡眠状态,这样你就可以创建一个能够在一个包中”感知”、”计划”和”行动”的系统。首先,让我们来看看下面的 OpenMV Cam 的引脚: OpenMV Cam引脚

根据 OpenMV Cam 的型号,您可以使用 9-10 个通用 I/O 引脚,可用于低速数字输入和输出。请注意,我们使用具有 5V 容限 I/O 引脚的 STM32 处理器,因此您可以将 OpenMV Cam 直接连接到 Arduino 或其他 5V 器件而无需担心。I/O 引脚也非常强大,每个引脚或吸收电流高达 25 mA。

无论如何,不同的 I/O 引脚具有不同的特殊功能。例如,P0-P3 是您的 OpenMV Cam 的 SPI 总线引脚,可用于控制 SPI 器件。P4-P5 是您的 OpenMV Cam 的异步串行或 I2C 总线引脚,用于串行或 I2C 通话。P6 是您的 OpenMV Cam 的 ADC/DAC 引脚,用于 0V 至 3.3V 输入和输出。P7-P8(或 P7-P9)是您的 OpenMV Cam 的辅助 I/O 引脚。

5.1 PYB 模块

所有微控制器 I/O 功能都可以从 pyb(Python Board)模块获得。您只需在脚本中 import pyb 即可访问它。导入后,您可以访问 ADC,CAN,DAC,I2C,Pin,Servo,SPI 和 UART 类,同时还可以控制电路板的功耗。

6 系统架构

首先,OpenMV Cam 基于 STM32 微控制器架构,因为 MicroPython pyboard 基于 STM32 微控制器架构。如果项目是使用其他系统启动的,那么事情可能会完全不同。

接下来,我们选择不将 DRAM 与原始的 OpenMV Cam 一起使用,因为它使得系统太低而无法以低产量生产。

SDR DRAM(这是 STM32 支持的)在低制造量时并不是最便宜的,并且大大增加了电路板设计的复杂性(例如,您需要使用 8 层电路板来路由所有信号)。

随着我们用更快更快的主处理器加速 OpenMV Cam,SDR DRAM 速度也跟不上内部 RAM 速度。例如,在 STM32H7 上,内部 RAM 带宽为 3.2GB/s,最大 SDR RAM 带宽为 666MB/s,即使我们使用需要 50+ I/O 引脚的 32 位 DRAM 总线构建 8 层电路板系统对于 DRAM。

因此,由于我们建立在 STM32 架构上并且现在仅限于使用昂贵且速度慢的 SDR DRAM,我们还没有添加它,因为我们的内部 SRAM 速度更快。

随着产量的增加和技术的提高,我们可以在保持 OpenMV Cam 简单易用的同时获得更多内存。

6.1 存储器架构

鉴于上述存储器架构限制,我们构建了所有代码以在 STM32 微控制器存储器内部运行。但是,STM32 没有一个大的连续存储器映射。它针对不同情况提供不同的 RAM 段。

首先,有一段 RAM 包含全局变量,堆和堆栈。堆和全局变量的大小是固定的,因此只有堆栈增大和缩小。出于性能原因,不会不断检查堆/堆栈冲突,因此不要在 OpenMV Cam 上使用递归函数。

至于堆,它的大小是固定的,而不是向堆栈增长,并由 MicroPython 的垃圾收集器管理。MicroPython 自动释放堆内部未使用的块。但是,MicroPython 堆的设计不允许它像 PC 上的堆那样任意大(例如在兆字节范围内)。

因此,即使我们有 DRAM,也很难利用 MicroPython 的堆。接下来,帧缓冲区有一个更大的内存段来存储图像。在帧缓冲区的底部,当调用 sensor.snapshot() 之类的函数时,会存储新图像。然后,帧缓冲区中任何未使用的空间可用作”帧缓冲区堆栈”,从帧缓冲区的顶部向下构建。这种内存架构设计允许我们的许多计算机视觉方法执行而无需在 MicroPython 堆内部分配大型数据结构。

也就是说,帧缓冲堆栈仍然是堆栈,不支持随机分配和解除分配。幸运的是,大多数计算机视觉算法都具有非常可预测的内存分配。对于那些没有的人(如 AprilTags),我们在需要时在帧缓冲区堆栈内部分配一个临时堆(再次避免碎片化 MicroPython 堆)。

最后,视觉算法通过在 MicroPython 堆中分配对象来返回结果(通常很小)。然后,可以通过 MicroPython 轻松地收集结果,同时在任何计算机视觉算法完成执行后完全清除帧缓冲区堆栈。

现在虽然这很好用,但这意味着你只能在 RAM 中的帧缓冲区中拥有一个大图像。由于 MicroPython 堆针对存储大型 100KB 图像的小对象进行了优化,因此没有意义。为了使更多图像适合 RAM,我们允许使用 sensor.alloc_extra_fb() 将帧缓冲堆栈用于二次图像存储。通过在帧缓冲堆栈上分配辅助帧缓冲区,您现在可以在 RAM 中拥有两个或更多映像,但代价是减少更复杂算法的内存空间(如 AprilTags)。那就是内存架构。并且…我们允许将图像存储在帧缓冲区,堆和帧缓冲区堆栈中。

7 未完待续

Updated: