K210 chasing small ball program communicates with STM32 minimum system board (self-learning)

I first learned OPENMV, and then extended to K210. (Mainly because I haven't bought a screen for OPENMV, but K210 has it.) On OPENMV official website, there are functions related to chasing small balls, but it is debugged with OPENMV single-chip microcomputer. The relevant source code found on the Internet found that the frame rate was very slow after loading it into OPENMV.

The requirement of school training is to make a balance car that can chase a certain object. The mechanism of my car is controlled by STM32F1Z8T6, and K210 recognizes and transmits real-time data.

1. Through the function img.draw_rectangle(b[0:4]); you can get the X-axis coordinates of the center point in the rectangular frame of the drawn target and the size of the rectangular frame SIZE. The former of these two data can be used to judge the steering ring, and the latter can be used to judge forward and backward.

          x_pos = b[5]#Central position
          Size = b.area()

Through experimental testing, I got X: 2~320 range, SIZE: 2000~15000 

2. However, K210 sends a string to 32, and the number of digits in the string is uncertain, resulting in the length of the array stored by 32 for the received string is uncertain, and the data cannot be converted normally.

For the convenience of use, we modify it in the sending function of K210.

Coerce X and SIZE strings to fixed-digit numbers (in the PYthon environment)

          X = '%03d' % x_pos
          S  = '%05d' % Size

And set the sent frame header and frame tail to the final sent data DATA

 DATA = 'x' + X + S + 's'

The above situation is when the K210 'sees' the target.

3, What if the target is not found?

I do it like this:

Directly give him X=target value; SIZE=target value; send it to 32, and perform PID calculation respectively

In the PID program, X is the measured value of the steering ring SIZE is the measured value of the pursuit ring;

When the measured value = the expected value, the PID is equivalent to being equal all the time (my biased understanding is not to calculate)

At this point, only the upright ring and the speed ring are left

4. Going back to the previous question, what is the use of using the K210 screen?

For better and more convenient debugging, we directly display the data of X and SIZE on the screen 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)

In this way, it will be much more convenient to adjust the P in the PID of the steering loop and the pursuit loop.

Put the source code above: (for K210 with screen)

import sensor, lcd, time
import sensor, time
from machine import UART,Timer
from fpioa_manager import fm
from Maix import GPIO
from fpioa_manager import fm
fm.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,Timer
from 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 = 2000
max_Size = 10
def 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_blob

LED_B.value(0) #点亮LED
while(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显示图片

In the above function, we will find that a function is defined: find max

Why define this function??

Because when we ask to find the largest target color block, frame it. Otherwise, there will be many small target points. Multiple target rectangles will cause unusual jumps in the value sent by the serial port terminal.

The following is for OPENMV without a screen:

There are some differences between OPENMV and K210 in that:

(1) Serial port setting The serial port of OPENMV is fixed and does not require pin mapping. But K210 does.

(2) In OPENMV, the largest color block can be determined directly through Bolb[], and there is no need to establish the find max function.

OPENMV is modified in the routine program on the official website (ensure the frame rate, don't let him get stuck like this)

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)

Guess you like

Origin blog.csdn.net/qq_60043905/article/details/125655140