关于openmv(部分常用函数的封装以及串口通信)(python)

本文基于本人在视觉学习中所遇到的问题以及所完成的题目所作

1.关于代码整体结构

以下是我为了让是自己使用更加方便所以写的一个比较简单实用的代码框架

​
#main.py -- put your code here!
import cpufreq
import pyb
import sensor,image, time,math,struct
from image import SEARCH_EX, SEARCH_DS
from pyb import LED,Timer,UART

sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)  # Set frame size to QVGA (320x240)
sensor.skip_frames(time=2000)     #延时跳过一些帧,等待感光元件变稳定
sensor.set_auto_gain(False)          #黑线不易识别时,将此处写False
sensor.set_auto_whitebal(False)
#sensor.set_auto_exposure(False, exposure_us=111000)#关闭自动曝光

clock = time.clock()                # Create a clock object to track the FPS.
#sensor.set_auto_exposure(True, exposure_us=5000) # 设置自动曝光sensor.get_exposure_us()

uart=UART(3,115200)
THRESHOLD = (0,100) # Grayscale threshold for dark things... (5, 70, -23, 15, -57, 0)(18, 100, 31, -24, -21, 70)
IMAGE_WIDTH=sensor.snapshot().width()
IMAGE_HEIGHT=sensor.snapshot().height()
IMAGE_DIS_MAX=(int)(math.sqrt(IMAGE_WIDTH*IMAGE_WIDTH+IMAGE_HEIGHT*IMAGE_HEIGHT)/2)


class target_check(object):
    x=0          #int16_t
    y=0          #int16_t
    pixel=0      #uint16_t
    flag=0       #uint8_t
    state=0      #uint8_t
    angle=0      #int16_t
    distance=0   #uint16_t
    apriltag_id=0#uint16_t
    img_width=0  #uint16_t
    img_height=0 #uint16_t
    reserved1=0  #uint8_t
    reserved2=0  #uint8_t
    reserved3=0  #uint8_t
    reserved4=0  #uint8_t
    fps=0        #uint8_t
    range_sensor1=0
    range_sensor2=0
    range_sensor3=0
    range_sensor4=0
    camera_id=0
    reserved1_int32=0
    reserved2_int32=0
    reserved3_int32=0
    reserved4_int32=0

class rgb(object):
    def __init__(self):
        self.red=LED(1)
        self.green=LED(2)
        self.blue=LED(3)

class uart_buf_prase(object):
    uart_buf = []
    _data_len = 0
    _data_cnt = 0
    state = 0

class singleline_check():
    rho_err = 0
    theta_err = 0
    state = 0

class mode_ctrl(object):
    work_mode = 0x01 #工作模式.默认是点检测,可以通过串口设置成其他模式
    check_show = 1   #开显示,在线调试时可以打开,离线使用请关闭,可提高计算速度

class KalmanFilter:
    def __init__(self):
        self.x = 0  # initial state
        self.p = 1  # initial state covariance
        self.q = 0.1  # process noise covariance
        self.r = 1  # measurement noise covariance
        self.k = 0  # kalman gain

    def update(self, measurement):
        # Prediction update
        self.p = self.p + self.q

        # Measurement update
        self.k = self.p / (self.p + self.r)
        self.x = self.x + self.k * (measurement - self.x)
        self.p = (1 - self.k) * self.p

        return self.x


ctr=mode_ctrl()
rgb=rgb()
R=uart_buf_prase()
target=target_check();
target.camera_id=0x01
target.reserved1_int32=65536
target.reserved2_int32=105536
target.reserved3_int32=65537
target.reserved4_int32=105537

f_x = (2.8 / 3.984) * 160 # 默认值
f_y = (2.8 / 2.952) * 120 # 默认值
c_x = 160 * 0.5 # 默认值(image.w * 0.5)
c_y = 120 * 0.5 # 默认值(image.h * 0.5)
last_send_time = pyb.millis()
k=21.62

singleline = singleline_check()
b=0


#标签测距
def degrees(radians):
    return (180 * radians) / math.pi


def uart_data_read():
    buf_len=uart.any()
    for i in range(0,buf_len):
        uart_data_prase(uart.readchar())

def time_callback(info):
    rgb.red.toggle()

timer=Timer(2,freq=4)
timer.callback(time_callback)

#找最大
def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[2] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[2]
    return max_blob

#找最小
def find_min(blobs):
    min_blob = None
    min_size = 0
    for blob in blobs:
        if blob[5] * blob[6] > min_size:
            min_blob = blob
            min_size = blob[5] * blob[6]
    return min_blob

'''
def find_min(blobs):
    min_size=10000
    for blob in blobs:
        if blob[2]*blob[2]<min_size:
            min_blob=blob
            min_size = blob[2]*blob[2]
    return min_blob
'''

# 绘制水平线
def draw_hori_line(img, x0, x1, y, color):
    for x in range(x0, x1):
        img.set_pixel(x, y, color)
# 绘制竖直线
def draw_vec_line(img, x, y0, y1, color):
    for y in range(y0, y1):
        img.set_pixel(x, y, color)
# 绘制矩形
def draw_rect(img, x, y, w, h, color):
    draw_hori_line(img, x, x+w, y, color)
    draw_hori_line(img, x, x+w, y+h, color)
    draw_vec_line(img, x, y, y+h, color)
    draw_vec_line(img, x+w, y, y+h, color)

#寻Apriltag
def opv_find_april_tag():
    img=sensor.snapshot()
    target.img_width=IMAGE_WIDTH
    target.img_height=IMAGE_HEIGHT
    apriltag_area=0
    apriltag_dis=IMAGE_DIS_MAX
    target.flag = 0
    for tag in img.find_apriltags(): # defaults to TAG36H11 without "families".
        img.draw_rectangle(tag.rect(), color = (255, 0, 0))
        b=(tag.rect()[2]/(abs(math.sin(tag.rotation()))+abs(math.cos(tag.rotation()))))
        #print(tag.rect()[2],b*b)
        #保存最大像素面积得apritag信息
        apriltag_dis_tmp=math.sqrt((tag.cx()-80)*(tag.cx()-80)+(tag.cy()-60)*(tag.cy()-60))
        apriltag_area_tmp=tag.w()*tag.h()
        if apriltag_dis>apriltag_dis_tmp:
            apriltag_area=tag.w()*tag.h()
            target.x = tag.cx()
            target.y = tag.cy()
            target.apriltag_id=tag.id()
            target.pixel=int(b*b)#apriltag_area
            apriltag_dis=apriltag_dis_tmp
            target.flag = 1
    if target.flag==1:
        img.draw_cross(target.x,target.y, color=127, size = 15)

#        img.draw_circle(target.x,target.y, 15, color = 127)
#    print(target.x,target.y,target.pixel,target.apriltag_id,apriltag_dis)


#识别条形码
def openmv_find_txm():
    sensor.set_framesize(sensor.QVGA)
    img = sensor.snapshot()
    #img.lens_corr(1.8)  # Adjust this parameter as needed
    # Find barcodes
    codes = img.find_barcodes()
    if codes:
        for code in codes:
            # Update Kalman Filter with measurementswd
            x_est = kf_x.update(code.rect()[0])
            y_est = kf_y.update(code.rect()[1])

            # Get barcode data
            barcode_data = code.payload()

            # Pack barcode data
            data_length = len(barcode_data)
            data_to_send = bytearray()
            data_to_send.extend(bytearray([0xAA, 0xAA]))  # frame header
            data_to_send.extend(struct.pack('<H', data_length))  # data length
            data_to_send.extend(barcode_data.encode('utf-8'))  # data content
            data_to_send.extend(bytearray([0x55, 0x55]))  # frame tail

            # Send data
            uart.write(data_to_send)
            print("Sent barcode data:", barcode_data, "Estimated position:", x_est, y_est)

#模板
def openmv_find_moban():
    sensor.reset()

    # Set sensor settings
    sensor.set_contrast(1)
    sensor.set_gainceiling(16)
    # Max resolution for template matching with SEARCH_EX is QQVGA
    sensor.set_framesize(sensor.QQVGA)
    sensor.set_pixformat(sensor.GRAYSCALE)
    templates = [ "/1.pgm", "/2.pgm", "/6.pgm"] #保存多个模板
    #加载模板图片

    clock = time.clock()

    # Run template matching
    while (True):
        clock.tick()
        img = sensor.snapshot()
        uart_data_read()
        if ctr.work_mode==0x07:#april测距ok
            for t in templates:
                template = image.Image(t)
                #对每个模板遍历进行模板匹配
                r = img.find_template(template, 0.70, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
                if r:
                    img.draw_rectangle(r)
                    print(t) #打印模板名字
        else:
            break



#数据包头和模式定义
HEADER=[0xFA,0xFB]
MODE=[0x01,0x02,0x03,0x04,0x05]
ENDER=[0x3B,0x2B]

def uart_data_prase(buf):
    if R.state==0 and buf==0xFA:#帧头1
        R.state=1
        R.uart_buf.append(buf)
    elif R.state==1 and buf==0xFB:#帧头2
        R.state=2
        R.uart_buf.append(buf)
    elif R.state==2 and buf<50:#数据长度小于50
        R.state=3
        R._data_len=buf  #有效数据长度
        R._data_cnt=buf+5#总数据长度
        R.uart_buf.append(buf)
    elif R.state==3 and R._data_len>0:#存储对应长度数据
        R._data_len=R._data_len-1
        R.uart_buf.append(buf)
        if R._data_len==0:
            R.state=4
    elif R.state==4 and buf==0x3B:#帧尾1
        R.state=5
        R.uart_buf.append(buf)
    elif R.state==5 and buf==0x2B:#帧尾2
        R.state=0
        R.uart_buf.append(buf)
        ctr.work_mode = R.uart_buf[3]
        R.uart_buf=[]#清空缓冲区,准备下次接收数据
    else:
        R.state=0
        R.uart_buf=[]#清空缓冲区,准备下次接收数据



b=0
ctr.work_mode=0x00 #0x0B
last_ticks=0
ticks=0
ticks_delta=0;

while True:

    #sensor.set_auto_exposure(False, exposure_us=111000)#关闭自动曝光
    clock.tick()

    if ctr.work_mode==0x00:#april测距ok
        find_apriltag_ceju()
        rgb.blue.toggle()

    elif ctr.work_mode==0x01:#识别圆环发送8个点ok
        find_circle_send_eight()
        rgb.blue.off()

    elif ctr.work_mode==0x02:#寻Apriltag
        opv_find_april_tag()
        rgb.blue.off()

    elif ctr.work_mode==0x03:#巡线模式
        found_line()
        rgb.blue.off()

    elif ctr.work_mode==0x04:#二维码识别ok
        send_ewm()
        rgb.blue.off()

    elif ctr.work_mode==0x05:#识别黑色矩形框ok
        find_rect_crop()
        rgb.blue.toggle()

    elif ctr.work_mode==0x06:#条形码识别
        openmv_find_txm()
        rgb.blue.toggle()

    elif ctr.work_mode==0x07:#模板识别
        openmv_find_moban()
        rgb.blue.toggle()

    elif ctr.work_mode==0x0B:

        rgb.blue.toggle()

    else:
        rgb.blue.toggle()
    #uart.write((ctr.work_mode))
    uart_data_read()

​

此代码为删减版(删除了部分函数定义),但整体结构不变

二.代码详解

 逻辑嵌套:我们直接看到while循环中所运行的代码,层层递进的分析使代码清晰易懂

while True:

    #sensor.set_auto_exposure(False, exposure_us=111000)#关闭自动曝光
    clock.tick()

    if ctr.work_mode==0x00:#april测距ok
        find_apriltag_ceju()
        rgb.blue.toggle()

    elif ctr.work_mode==0x01:#识别圆环发送8个点ok
        find_circle_send_eight()
        rgb.blue.off()

    elif ctr.work_mode==0x02:#寻Apriltag
        opv_find_april_tag()
        rgb.blue.off()

    elif ctr.work_mode==0x03:#巡线模式
        found_line()
        rgb.blue.off()

    elif ctr.work_mode==0x04:#二维码识别ok
        send_ewm()
        rgb.blue.off()

    elif ctr.work_mode==0x05:#识别黑色矩形框ok
        find_rect_crop()
        rgb.blue.toggle()

    elif ctr.work_mode==0x06:#条形码识别
        openmv_find_txm()
        rgb.blue.toggle()

    elif ctr.work_mode==0x07:#模板识别
        openmv_find_moban()
        rgb.blue.toggle()

    elif ctr.work_mode==0x0B:

        rgb.blue.toggle()

    else:
        rgb.blue.toggle()
    #uart.write((ctr.work_mode))
    uart_data_read()

​

可以看到,循环中一直在对ctr.work_mode的值进行判断并进行下一步动作,关于ctr.work_mode的定义如下:

def uart_data_prase(buf):
    if R.state==0 and buf==0xFA:#帧头1
        R.state=1
        R.uart_buf.append(buf)
    elif R.state==1 and buf==0xFB:#帧头2
        R.state=2
        R.uart_buf.append(buf)
    elif R.state==2 and buf<50:#数据长度小于50
        R.state=3
        R._data_len=buf  #有效数据长度
        R._data_cnt=buf+5#总数据长度
        R.uart_buf.append(buf)
    elif R.state==3 and R._data_len>0:#存储对应长度数据
        R._data_len=R._data_len-1
        R.uart_buf.append(buf)
        if R._data_len==0:
            R.state=4
    elif R.state==4 and buf==0x3B:#帧尾1
        R.state=5
        R.uart_buf.append(buf)
    elif R.state==5 and buf==0x2B:#帧尾2
        R.state=0
        R.uart_buf.append(buf)
        ctr.work_mode = R.uart_buf[3]
        R.uart_buf=[]#清空缓冲区,准备下次接收数据
    else:
        R.state=0
        R.uart_buf=[]#清空缓冲区,准备下次接收数据

可以看到,在这个函数中,我们对ctr.work_mode进行了赋值,这个函数是我们接收单片机数据的函数,通过解析数据对ctr.work_mode进行赋值

所以,这个代码整体的逻辑就是:

1.解析从单片机接收到的数据包

2.对ctr.work_mode进行赋值

3.执行函数

3.作者的话。。。。。。。。。

如果有想加的函数大家可以按照模板直接在循环之前def,然后在循环中加上相对应的ctr.work_mode的值,这样就算def的函数有问题也不会影响其他函数的执行,非常安全

其实我觉得最麻烦的部分是串口通信,因为大家可以看到我前面class了一段很长的函数却并没有用到,因为这一段函数发送的数据包过长,当然如果大家发送的数据很长也可以参考这个函数,不然就自己在定义的函数里面重新进行数据解析(一定要发送数据包,一定要发字节(取高八位,低八位))为了防止数据有问题最好设置帧头帧尾:


    if R.state==0 and buf==0xFA:#帧头1
        R.state=1
        R.uart_buf.append(buf)
    elif R.state==1 and buf==0xFB:#帧头2
        R.state=2
        R.uart_buf.append(buf)
 

就像是接收里面所进行的判断,要保证数据的准确性,当然,最好加一个校验位,好了,不多说了,差不多了,关于函数就不想讲了,注释还算比较清楚,希望大家有所收获

2024-8.17       by--leader.w

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值