本人先通过学习OPENMV,再延申到K210中。(主要是OPENMV我还没买屏幕,但是K210有)在OPENMV官网中,有相关追小球的函数,但是是用OPENMV单片机来进行调试的。在网上找到的相关源码,加载到OPENMV后发现帧数很慢。
学校实训的要求是要做出能追一定物体的平衡小车,我的小车的机构通过STM32F1Z8T6来进行控制,K210进行识别传输实时数据。
1,通过函数img.draw_rectangle(b[0:4]) ;可以得到画出目标的矩形框中的中心点X轴坐标和矩形框的大小SIZE。这两个数据前者可以用来判断转向环,后者可以用来判断前进和后退。
x_pos = b[5]#中心位置
Size = b.area()
通过实验测试,我得到了X:2~320范围,SIZE:2000~15000
2,但是K210给32发送的是字符串,并且字符串的位数不确定,导致32用于接收到的字符串所存放的数组长度不确定,无法正常的转化数据。
为了方便的使用,我们在K210的发送函数中修改。
将X和SIZE字符串强制转化为固定位数的(在PYthon环境中)
X = '%03d' % x_pos
S = '%05d' % Size
并设置发送出的帧头和帧尾给最终发送的数据DATA
DATA = 'x' + X + S + 's'
以上情况是当K210'看到'目标的时候进行的操作.
3,若没有找到目标的时候呢??
我是这样操作的:
直接给他X=目标值;SIZE=目标值; 发送到32内部,分别进行了PID计算
在PID程序中 X是转向环的测量值 SIZE是追求环的测量值;
当测量值=期望值的时候,PID相当于一直相等(我的偏见理解就是不计算)
此时就只剩下 直立环和速度环
4,回到之前的问题 用K210的屏幕有什么用呢?
为了更好更方便的调试,我们直接把X和SIZE的数据直接在屏幕LCD中显示出来.
img.draw_string(2,2, ("X:%03d" %(b[5])), color=(255,255,255), scale=2)
img.draw_string(2,25, ("S:%04d" %(b.area())), color=(255,255,255), scale=2)
这样在调转向环和追求环的PID中的P时候就会方便很多.
以上放置源码:(针对有屏幕的K210)
import sensor, lcd, timeimport sensor, timefrom machine import UART,Timerfrom fpioa_manager import fmfrom Maix import GPIOfrom fpioa_manager import fmfm.register(12, fm.fpioa.GPIO0)LED_B = GPIO(GPIO.GPIO0, GPIO.OUT) #构建LED对象LED_B.value(0) #点亮LED#摄像头初始化sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.set_vflip(1) #后置模式,所见即所得sensor.run(1)sensor.skip_frames(30)from machine import UART,Timerfrom fpioa_manager import fm#映射串口引脚fm.register(7 , fm.fpioa.UART1_RX, force=True)fm.register(30, fm.fpioa.UART1_TX, force=True)#初始化串口uart = UART(UART.UART1, 115200, read_buf_len=4096)#lcd初始化lcd.init()clock=time.clock()color_threshold = (23, 100, 31, 51, 6, 43)size_threshold = 2000max_Size = 10def find_max(blobs): max_size=0 for blob in blobs: if blob[2]*blob[3] > max_size: max_blob=blob max_size = blob[2]*blob[3] return max_blobLED_B.value(0) #点亮LEDwhile(1): clock.tick() img = sensor.snapshot() blobs = img.find_blobs([color_threshold],area_threshold=50,pixels_threshold=50) if blobs: #for b in blobs: b = find_max(blobs) img.draw_rectangle(b[0:4]) # circle img.draw_cross(b[5], b[6], color=(0, 0, 255)) x_pos = b[5]#中心位置 Size = b.area() X = '%03d' % x_pos S = '%05d' % Size DATA = 'x' + X + S + 's' img.draw_string(2,2, ("X:%03d" %(b[5])), color=(255,255,255), scale=2) img.draw_string(2,25, ("S:%04d" %(b.area())), color=(255,255,255), scale=2) uart.write(DATA) print(DATA) else uart.write('x') uart.write('1') uart.write('6') uart.write('0') uart.write('0') uart.write('2') uart.write('0') uart.write('0') uart.write('0') uart.write('s') img.draw_string(2,2, ("X:%03d" %(160)), color=(255,255,255), scale=2) img.draw_string(2,25, ("S:%04d" %(2000)), color=(255,255,255), scale=2) lcd.display(img) #LCD显示图片
在以上的函数中 我们会发现 定义了一个函数:find max
为什么要定义这个函数呢??
因为 当我们要求找到最大的目标色块,给它进行画框.不然会出现很多目标小点点.多个目标矩形框会导致串口终端发送的数值有不寻常的跳变.
下面针对没有屏幕的OPENMV:
OPENMV中与K210有些不同在于:
(1) 串口的设置 OPENMV的串口是固定的,不需要引脚映射.但是K210需要.
(2) 在OPENMV中,最大的色块可以直接通过Bolb[]来确定,不需要find max函数建立.
OPENMV是在官网的例程程序中修改的(确保帧速,不让他这么卡)
uart = UART(3, 115200)uart.init(115200, bits=8, parity=None, stop=1, timeout_char=1000) # 使用给定参数初始化# Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are# returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the# camera resolution. "merge=True" merges all overlapping blobs in the image.while(True): clock.tick() img = sensor.snapshot() for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=200, merge=True): # These values depend on the blob not being circular - otherwise they will be shaky. if blob.elongation() > 0.5: img.draw_edges(blob.min_corners(), color=(255,0,0)) img.draw_line(blob.major_axis_line(), color=(0,255,0)) img.draw_line(blob.minor_axis_line(), color=(0,0,255)) # These values are stable all the time. #画框 img.draw_rectangle(blob.rect()) #画十字 img.draw_cross(blob.cx(), blob.cy()) # Note - the blob rotation is unique to 0-180 only. #特征点识别 img.draw_keypoints([(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20) #返回x轴中心点位置,blob.cx() 返回色块的外框的中心x坐标(int),也可以通过blob[5]来获取 x = blob[5] #blob.area() 返回色块的外框的面积。应该等于(w * h) s = blob.area() #发送数据 #data = bytearray([0x11,x,s,0x00]) X = '%03d'%(x) S = '%05d'%(s) data = 'x' + X + S+ 's' #串口发送 uart.write(data) # print(clock.fps()) print(data)
来源地址:https://blog.csdn.net/qq_60043905/article/details/125655140