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



# 色块监测 例子
#
# 这个例子展示了如何通过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_ns1μs = 1000ns指定高电平持续时间,单位:纳秒 (ns)
脉冲宽度不能超过 PWM 周期总时长,否则报错。
浙公网安备 33010602011771号