关于OpenMV学习与应用

关于OpenMV学习与应用

简单来说,OpenMv就是一个可编程的摄像头,通过使用python语言,专门用作嵌入式当中的视觉感光元件。下面将介绍Openmv使用过程中的常用知识。

image-20260729225150851

image-20260729225234834

image-20260729222032125

# 色块监测 例子
#
# 这个例子展示了如何通过find_blobs()函数来查找图像中的色块
# 这个例子查找的颜色是深绿色

import csi, image, time
csi0 = csi.CSI()

# 颜色追踪的例子,一定要控制环境的光,保持光线是稳定的。
green_threshold   = (   0,   80,  -70,   -10,   -0,   30)
#设置绿色的阈值,括号里面的数值分别是L A B 的最大值和最小值(minL, maxL, minA,
# maxA, minB, maxB),LAB的值在图像左侧三个坐标图中选取。如果是灰度图,则只需
#设置(min, max)两个数字即可。

csi0.reset()               # 初始化摄像头
csi0.pixformat(csi.RGB565) # 格式为 RGB565.
csi0.framesize(csi.QQVGA)  # 使用 QQVGA 速度快一些
csi0.snapshot(time = 2000) # 跳过2000s,使新设置生效,并自动调节白平衡
csi0.auto_gain(False)      # 关闭自动自动增益。默认开启的,在颜色识别中,一定要关闭白平衡。
csi0.auto_whitebal(False)  #关闭白平衡。白平衡是默认开启的,在颜色识别中,一定要关闭白平衡。
clock = time.clock()       # 追踪帧率

while(True):
    clock.tick()          # Track elapsed milliseconds between snapshots().
    img = csi0.snapshot() # 从感光芯片获得一张图像

    blobs = img.find_blobs([green_threshold])
    #find_blobs(thresholds, invert=False, roi=Auto),thresholds为颜色阈值,
    #是一个元组,需要用括号[ ]括起来。invert=1,反转颜色阈值,invert=False默认
    #不反转。roi设置颜色识别的视野区域,roi是一个元组, roi = (x, y, w, h),代表
    #从左上顶点(x,y)开始的宽为w高为h的矩形区域,roi不设置的话默认为整个图像视野。
    #这个函数返回一个列表,[0]代表识别到的目标颜色区域左上顶点的x坐标,[1]代表
    #左上顶点y坐标,[2]代表目标区域的宽,[3]代表目标区域的高,[4]代表目标
    #区域像素点的个数,[5]代表目标区域的中心点x坐标,[6]代表目标区域中心点y坐标,
    #[7]代表目标颜色区域的旋转角度(是弧度值,浮点型,列表其他元素是整型),
    #[8]代表与此目标区域交叉的目标个数,[9]代表颜色的编号(它可以用来分辨这个
    #区域是用哪个颜色阈值threshold识别出来的)。
    if blobs:
    #如果找到了目标颜色
        for b in blobs:
        #迭代找到的目标颜色区域
            # Draw a rect around the blob.
            img.draw_rectangle(b[0:4])   # rect
            #用矩形标记出目标颜色区域
            img.draw_cross((b[5], b[6])) # cx, cy
            #在目标颜色区域的中心画十字形标记

    print(clock.fps()) # 注意: 你的OpenMV连到电脑后帧率大概为原来的一半
    #如果断开电脑,帧率会增加

那么如何更改识别阈值呢?怎么知道物体的颜色阈值呢?

三个坐标图分别表示圈出的矩形区域内的颜色的LAB值,选取三个坐标图的最大最小值,如( 0, 60, -70, -10, -0, 30)

在工具栏里,点击将打开的脚本保存到OpenMV Cam(作为main.py), IDE就会自动将当前文件保存到main.py,实现脱机运行。

OpenMV Cam快速参考

文档地址:openmvcam快速参考 — MicroPython 1.22 文档

延时和时间

使用 time 模块:

import time

time.sleep(1)                                   # 睡眠 1秒
time.sleep_ms(500)                              # 睡眠 500毫秒
time.sleep_us(10)                               # 睡眠 10 微秒
start = time.ticks_ms()                         # 获取毫秒计数器
delta = time.ticks_diff(time.ticks_ms(), start) # 计算时间差值

虚拟定时器

周期以毫秒为单位,示例如下:

# 导入硬件定时器库,控制 MCU 内部定时器外设
from machine import Timer

# 定时器0:一次性定时器
tim0 = Timer(-1)
tim0.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(0))

# 定时器1:周期性定时器
tim1 = Timer(-1)
tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1))

# Timer(-1) = 软件定时器(不是硬件定时器)
#    -1:虚拟软件定时器,不限硬件通道
#    0/1/2…:指定硬件定时器(受硬件资源限制)

关闭定时器方法:

tim0.deinit()
tim1.deinit()

引脚和GPIO

使用 machine.Pin 类:

from machine import Pin
# 导入引脚控制模块,用来操作单片机GPIO

# 创建引脚P0,配置为输出模式
p0 = Pin('P0', Pin.OUT)
p0.on()                 # 引脚输出高电平
p0.off()                # 引脚输出低电平
p0.value(1)             # 写入电平,1=高电平,0=低电平

# 创建引脚P2,配置为输入模式(默认无上下拉)
p2 = Pin('P2', Pin.IN)
print(p2.value())       # 读取引脚电平,返回 0(低) 或 1(高)

# 创建引脚P4,输入模式,开启内部上拉电阻
# 外部悬空时,引脚默认读到高电平
p4 = Pin('P4', Pin.IN, Pin.PULL_UP)
# Pin.PULL_UP   内部上拉
# Pin.PULL_DOWN 内部下拉
# 不配置就是浮空输入,容易受干扰

# 创建引脚P5,输出模式,初始化直接输出高电平
p5 = Pin('P5', Pin.OUT, value=1)

还有一个更高级的抽象 machine.Signal ,可用于反转引脚。 用于使用 on()value(1) 点亮低电平激活的LED非常有用。

from machine import Pin, Signal
# 假设引脚0上接了一只高电平点亮的LED
led1_pin = Pin(0, Pin.OUT)
# 引脚1上接了一只低电平点亮的LED
led2_pin = Pin(1, Pin.OUT)

# 如果直接使用Pin类点亮这两个LED,需要给它们设置不同电平
led1_pin.value(1)
led2_pin.value(0)

# Signal类可以屏蔽【高有效/低有效】的硬件差异
led1 = Signal(led1_pin, invert=False)
led2 = Signal(led2_pin, invert=True)

# 现在点亮两个LED的调用方式统一了
led1.value(1)
led2.value(1)

# 更简洁的写法:
led1.on()
led2.on()

UART(串行通信)

参见 machine.UART

UART 实现了标准的 UART/USART 双工串行通信协议。在物理层面上,它由 2 条线组成:RX 和 TX。通信的单位是一个字符(不要与字符串字符混淆),可以是 8 位或 9 位宽。

可以使用以下方式创建和初始化 UART 对象:

from machine import UART

uart = UART(3, 9600)                          # 使用指定波特率初始化串口
uart.init(9600, bits=8, parity=None, stop=1)  # 完整参数初始化

参数说明:

bits 数据位:可选 7、8、9

stop 停止位:可选 1、2

parity=None(无校验)时,仅支持 8 位、9 位数据;

开启奇偶校验时,仅支持 7 位、8 位数据。

UART 对象类似数据流 (stream),可以使用标准流接口读写数据:

uart.read(10)      # 读取10个字节,返回bytes二进制对象
uart.read()        # 读取当前缓冲区所有可用数据
uart.readline()    # 读取一行数据(以换行符 \n 作为结束标志)
uart.readinto(buf) # 读取数据,存入预先开辟好的缓冲区buf
uart.write('abc')  # 发送3个字节数据

示例代码:

from machine import UART

uart1 = UART(1, baudrate=115200)
uart1.write('hello')              # write 5 bytes
uart1.read(5)                     # read up to 5 bytes

PWM(脉冲宽度调制)

PWM功能由 machine.PWM 类提供。它支持该类列出的所有基本方法以及一些额外方法来处理信号组。

from machine import Pin, PWM
# 导入引脚模块、PWM脉冲宽度调制模块

pwm2 = PWM("P6")        # 基于P6引脚创建PWM对象
pwm2.freq()             # 读取当前PWM频率
pwm2.freq(1000)         # 设置PWM频率为1000Hz
pwm2.duty_u16()         # 读取当前占空比,数值范围:0 ~ 65535
pwm2.duty_u16(200)      # 设置占空比,数值范围:0 ~ 65535
pwm2.deinit()           # 关闭该引脚的PWM功能,引脚恢复普通GPIO

# 在引脚6、7创建一对互补输出PWM信号(互补驱动)
pwm2 = PWM((6, 7), freq=2000, duty_ns=20000)

# 创建四路同步PWM信号组
# 先初始化模块0的Pin4,作为同步基准,产生同步脉冲
pwm4 = PWM(Pin(4), freq=1000, align=PWM.HEAD)
# 引脚5、6、9属于同一个定时器模块
pwm5 = PWM(Pin(5), freq=1000, duty_u16=10000, align=PWM.HEAD, sync=True)
pwm6 = PWM(Pin(6), freq=1000, duty_u16=20000, align=PWM.HEAD, sync=True)
pwm9 = PWM(Pin(9), freq=1000, duty_u16=30000, align=PWM.HEAD, sync=True)

pwm3                    # 在控制台打印PWM对象的参数属性
from machine import PWM
# 导入PWM脉冲调制模块

# 在指定引脚创建PWM对象,同时设置频率与占空比
pwm = PWM(pin, freq=50, duty_u16=8192)

pwm.duty_u16(32768)     # 设置占空比为50%

# 重新初始化:周期200微秒,高电平持续5微秒
pwm.init(freq=5000, duty_ns=5000)

pwm.duty_ns(3000)       # 设置脉冲高电平宽度为3微秒

pwm.deinit()            # 关闭引脚PWM功能,释放硬件资源

duty_u16

范围:0 ~ 65535

  • 0 → 0% 占空比

  • 32768 → 50% 占空比

  • 65535 → 100% 占空比

    duty_ns 1μs = 1000ns

    指定高电平持续时间,单位:纳秒 (ns)

    脉冲宽度不能超过 PWM 周期总时长,否则报错。

教程链接:Openmv简明使用教程 - ihuahua1415 - 博客园

posted @ 2026-08-24 08:47  Q&25  阅读(4)  评论(0)    收藏  举报