0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

立创·梁山派开发板-21年电赛F题-送药小车-K210功能实现代码讲解

jf_31863339 来源:jf_31863339 作者:jf_31863339 2023-08-01 09:49 次阅读

送药小车代码仓库:https://gitee.com/lcsc/medical_car

更好的观看体验请去:https://lceda001.feishu.cn/wiki/ZDYbwqDfCiwVlckUEcScF0KSnRh

送药小车立创开源平台资料https://oshwhub.com/li-chuang-kai-fa-ban/21-dian-sai-f-ti-zhi-neng-song-yao-xiao-che

K210功能实现代码讲解

具体实现代码如下(在2_Code->application->sensor->k210->pyconde->main.py):

# Hello World Example
#
# Welcome to the CanMV IDE! Click on the green run arrow button below to run the script!

import sensor, image, time, lcd, struct, ustruct
import gc

from machine import UART,Timer,PWM
from board import board_info
from fpioa_manager import fm
import KPU as kpu
from Maix import GPIO,utils
import gc
import machine

lcd.init()                          # Init lcd display
lcd.clear(lcd.RED)                  # Clear lcd screen.

sensor.reset(freq=22000000, dual_buff=1)                # 设置摄像头频率 24M 开启双缓冲模式 会提高帧率 但内存占用增加
sensor.set_auto_exposure(0)         # 设置自动曝光
sensor.set_auto_gain(False) # 颜色跟踪必须关闭自动增益
sensor.set_auto_whitebal(False) # 颜色跟踪必须关闭白平衡
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)

#kpu = KPU()
#kpu.load_kmodel("/sd/KPU/mnist/uint8_mnist_cnn_model.kmodel")
sensor.skip_frames(time = 2000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.
sensor.set_auto_exposure(0)         # 设置自动曝光

sensor.set_vflip(1)
#______________________________________________________________________________________________________________________________
#打印内存分配情况
print(utils.gc_heap_size())
print("stack mem:"+str(gc.mem_free() / 1024)) # stack mem
print("heap mem:"+str(utils.heap_free() / 1024)) # heap mem

#第一次用执行一次下面这两个语句
#utils.gc_heap_size(800*1024)
#machine.reset()

#______________________________________________________________________________________________________________________________
#程序运行选择
is_need_debug = 0
is_patrol_line = 0
is_upacker_debug = 0
is_stack_heap_mem_debug = 0
is_upacker_recive_debug = 1
is_findflob_debug = 0

#______________________________________________________________________________________________________________________________
#程序运行状态
work_mode = 0  #0是巡线模式,1是数字识别模式

#______________________________________________________________________________________________________________________________
#串口配置区

fm.register(6, fm.fpioa.UART1_TX, force=True)
fm.register(7, fm.fpioa.UART1_RX, force=True)

k210_uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096)

uart_test_write_str = '1260808878'

#______________________________________________________________________________________________________________________________
#按键蜂鸣器配置区
#注册IO,注意高速GPIO口才有中断
fm.register(35, fm.fpioa.GPIO0)
fm.register(16, fm.fpioa.GPIOHS0)
#构建案件对象
KEY=GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)

#PWM通过定时器配置,接到IO15引脚
tim = Timer(Timer.TIMER1, Timer.CHANNEL0, mode=Timer.MODE_PWM)
beep = PWM(tim, freq=1000, duty=0, pin=9)

#按键标志位
key_node = 0
key_press_long = 0

#中断回调函数
def fun(KEY):
    global work_mode,key_node,key_press_long
    temp_count = 0

    time.sleep_ms(10) #消除抖动
    while KEY.value()== 0:
        key_node = 1
        time.sleep_ms(10) #长按延时
        #长按检测计数
        temp_count=temp_count+1
        print(temp_count)
    if temp_count >= 50:

        beep.duty(50)
        time.sleep_ms(500)
        beep.duty(0)
        time.sleep_ms(100)

        print(temp_count)
        key_node = 0
        key_press_long = 1

#开启中断,下降沿触发
KEY.irq(fun, GPIO.IRQ_FALLING)

#______________________________________________________________________________________________________________________________
#要传给梁山派的数据

#work_mode:0是巡线模式,1是数字识别模式
#recognition:0是未知(巡线状态下),1是药房门口区域(停车线),十字路口和T字路口由

class uart_send_data_t:
   def __init__( self, work_mode=0, recognition=0,top_block_offset=0,center_block_offset=0,left_block_offset=0,right_block_offset=0,left_number = 0,right_number = 0):
      self.work_mode = work_mode
      self.recognition = recognition
      self.top_block_offset = top_block_offset
      self.center_block_offset = center_block_offset
      self.left_block_offset = left_block_offset
      self.right_block_offset = right_block_offset
      self.left_number = left_number
      self.right_number = right_number


global_uart_send_data = uart_send_data_t()

#______________________________________________________________________________________________________________________________
#感兴趣区配置
roi_area_width = 30
roi_area_color = (0, 0, 200)
roi_area_thickness = 2


left_roi = [50,40,roi_area_width,sensor.height()-40]
right_roi = [sensor.width()-roi_area_width-50,40,roi_area_width,sensor.height()-40]
top_roi = [0,10,sensor.width(),roi_area_width]
center_roi = [0,int(sensor.height()/2)-int(roi_area_width/2),sensor.width(),roi_area_width]
#bottom_roi = [0,sensor.height()- roi_area_width,sensor.width(),roi_area_width]

black_block_roi = [0,100,sensor.width(),100]

def draw_roi(img):
    img.draw_rectangle(left_roi, color = roi_area_color, thickness = roi_area_thickness, fill = False)
    img.draw_rectangle(right_roi, color = roi_area_color, thickness = roi_area_thickness, fill = False)
    img.draw_rectangle(top_roi, color = roi_area_color, thickness = roi_area_thickness, fill = False)
    img.draw_rectangle(center_roi, color = roi_area_color, thickness = roi_area_thickness, fill = False)
    img.draw_rectangle(black_block_roi, color = (0, 255, 0), thickness = roi_area_thickness, fill = False)
    return

#______________________________________________________________________________________________________________________________
#寻找色块区配置
red_threshold =[12, 68, 11, 63, 5, 81]
black_threshold =[0, 50, -24,-1, -18, 6]

class red_blob_location_t:
   def __init__( self, x=0, y=0,area = 0):
      self.x = x
      self.y = y
      self.area = area


#______________
#左部blob位置信息
left_blob_location = red_blob_location_t()
left_pixels_threshold = 20     #若一个色块的像素数小于 pixel_threshold ,则会被过滤掉。
left_area_threshold = 20       #若一个色块的边界框区域小于 area_threshold ,则会被过滤掉。
left_x_stride = 20               #是查找某色块时需要跳过的x像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 x_stride 来提高查找色块的速度。
left_y_stride = 20               #是查找某色块时需要跳过的y像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 y_stride 来提高查找色块的速度。

#______________
#右部blob位置信息
right_blob_location = red_blob_location_t()
right_pixels_threshold = 20     #若一个色块的像素数小于 pixel_threshold ,则会被过滤掉。
right_area_threshold = 20       #若一个色块的边界框区域小于 area_threshold ,则会被过滤掉。
right_x_stride = 20               #是查找某色块时需要跳过的x像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 x_stride 来提高查找色块的速度。
right_y_stride = 20               #是查找某色块时需要跳过的y像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 y_stride 来提高查找色块的速度。

#______________
#顶部blob位置信息
top_blob_location = red_blob_location_t()
top_pixels_threshold = 20     #若一个色块的像素数小于 pixel_threshold ,则会被过滤掉。
top_area_threshold = 20       #若一个色块的边界框区域小于 area_threshold ,则会被过滤掉。
top_x_stride = 15               #是查找某色块时需要跳过的x像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 x_stride 来提高查找色块的速度。
top_y_stride = 20               #是查找某色块时需要跳过的y像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 y_stride 来提高查找色块的速度。

#______________
#中部blob位置信息
center_blob_location = red_blob_location_t()
center_pixels_threshold = 20     #若一个色块的像素数小于 pixel_threshold ,则会被过滤掉。
center_area_threshold = 20       #若一个色块的边界框区域小于 area_threshold ,则会被过滤掉。
center_x_stride = 20               #是查找某色块时需要跳过的x像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 x_stride 来提高查找色块的速度。
center_y_stride = 20               #是查找某色块时需要跳过的y像素的数量。找到色块后,直线填充算法将精确像素。 若已知色块较大,可增加 y_stride 来提高查找色块的速度。


blob_location=[0,0]

def find_blob(img):

    global global_uart_send_data
    #top_blob_location.x = -1
    #top_blob_location.y = -1
    #center_blob_location.x = -1
    #center_blob_location.y = -1
    left_blob_location.x = -1
    left_blob_location.y = -1
    right_blob_location.x = -1
    right_blob_location.y = -1
    center_blob_location.area = 0
    for blob in img.find_blobs([red_threshold], roi = left_roi, x_stride = left_x_stride, y_stride = left_y_stride, pixels_threshold=left_pixels_threshold, area_threshold=left_area_threshold, merge=False, margin=10):
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        left_blob_location.x = blob.cx()
        left_blob_location.y = blob.cy()
        left_blob_location.area = blob.area()

    for blob in img.find_blobs([red_threshold], roi = right_roi,x_stride = right_x_stride, y_stride = right_y_stride, pixels_threshold=right_pixels_threshold, area_threshold=right_area_threshold, merge=True, margin=10):
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        right_blob_location.x = blob.cx()
        right_blob_location.y = blob.cy()
        right_blob_location.area = blob.area()

    for blob in img.find_blobs([red_threshold], roi = top_roi,x_stride = top_x_stride, y_stride = top_y_stride, pixels_threshold=top_pixels_threshold, area_threshold=top_area_threshold, merge=True, margin=10):
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        #print("-------"+str(blob.area()))
        top_blob_location.x = blob.cx()
        top_blob_location.y = blob.cy()
        top_blob_location.area = blob.area()

    for blob in img.find_blobs([red_threshold], roi = center_roi,x_stride = center_x_stride, y_stride = center_y_stride, pixels_threshold=center_pixels_threshold, area_threshold=center_area_threshold, merge=True, margin=10):
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        center_blob_location.x = blob.cx()
        center_blob_location.y = blob.cy()
        center_blob_location.area = blob.area()
        #print(blob.pixels())


    #for blob in img.find_blobs([black_threshold], roi = black_block_roi, pixels_threshold=30,merge=True,margin=50):
        #img.draw_rectangle(blob.rect())
        #img.draw_cross(blob.cx(), blob.cy())
        ##print(blob.count())
        #if(blob.count() >= 5):
            #print("tinche"+str(blob.count()))
            #global_uart_send_data.recognition = 1
        #else:
            #global_uart_send_data.recognition = 0

    if(center_blob_location.area == 0):
        print("tinche")
        global_uart_send_data.recognition = 1
    else:
        global_uart_send_data.recognition = 0

    return

#______________________________________________________________________________________________________________________________
#色块连线区配置
lines_color = (0, 200, 0)
lines_thickness = 1

def draw_lines(img):
    img.draw_line(top_blob_location.x, top_blob_location.y, center_blob_location.x, center_blob_location.y, color = lines_color, thickness = lines_thickness)
    img.draw_line(left_blob_location.x, left_blob_location.y, right_blob_location.x, right_blob_location.y, color = lines_color, thickness = lines_thickness)
    return


#______________________________________________________________________________________________________________________________
#upacker python实现代码 :https://github.com/aeo123/upacker/blob/master/python/upacker.py
#介绍请看这里:https://github.com/aeo123/upacker

class Upacker():
    def __init__(self):
        self._STX_L = 0x55
        self._MAX_PACK_SIZE = 1024 + 4 + 128
        self._calc = 0
        self._check = 0
        self._cnt = 0
        self._flen = 0
        self._state = 0
        self._data = bytearray()

    def _decode(self, d):
        if (self._state == 0 and d == self._STX_L):
            self._state = 1
            self._calc = self._STX_L
        elif self._state == 1:
            self._flen = d & 0xff
            self._calc ^= d & 0xff
            self._state = 2
        elif self._state == 2:
            self._flen |= (d & 0xff) < < 8
            self._calc ^= d & 0x3F
            # 数据包超长得情况下直接丢包
            if ((self._flen & 0x3FFF) > self._MAX_PACK_SIZE):
                self._state = 0
                return -1
            else:
                self._data = bytearray(self._flen & 0x3FFF)
            self._state = 3
            self._cnt = 0
        elif self._state == 3:
            header_crc = ((d & 0x03) < < 4) | ((self._flen & 0xC000) >> 12)
            self._check = d
            if (header_crc != (self._calc & 0X3C)):
                self._state = 0
                return -1
            self._state = 4
            self._flen &= 0x3FFF
        elif self._state == 4:
            self._data[self._cnt] = d
            self._cnt += 1
            self._calc ^= d
            if self._cnt == self._flen:
                self._state = 0
                #接收完,检查check
                if ((self._calc & 0xFC) == (self._check & 0XFC)):
                    return 0
                else:
                    return -1
        else:
            self._state = 0

        return 1

    # 解包
    def unpack(self, bytes_data, callback):
        ret = 0
        for i in bytes_data:
            ret = self._decode(i)
            if ret == 0:
                callback(self._data)
                if(is_upacker_debug):
                    print(self._data)
            elif ret == -1:
                # callback(None)
                print("err")

    # 打包
    def enpack(self, data):
        tmp = bytearray(4)
        tmp[0] = 0x55
        tmp[1] = len(data) & 0xff
        tmp[2] = (len(data) >> 8) & 0xff
        crc = tmp[0] ^ tmp[1] ^ tmp[2]
        tmp[2] |= (crc & 0x0c) < < 4
        tmp[3] = 0x03 & (crc >> 4)

        for i in range(len(data)):
            crc ^= data[i]
        tmp[3] |= (crc & 0xfc)

        frame = struct.pack("BBBB%ds" % len(data), tmp[0], tmp[1], tmp[2],
                            tmp[3], data)
        #python3.5之前bytes数据没有hex()属性,所以修改了下面这个
        #print(frame.hex())
        if(is_upacker_debug):
            print(''.join(map(lambda x:('' if len(hex(x))>=4 else '/x0')+hex(x)[2:],frame)))

        return frame

#____________
#串口命令切换模式
uart_cmd_need_change_mode = 0

def print_hex(bytes):
    global work_mode,uart_cmd_need_change_mode

    hex_byte = [hex(i) for i in bytes]
    if is_upacker_recive_debug:
        print("-----"+" ".join(hex_byte))
    if bytes[0] == 0x00:
        work_mode = 0
    if bytes[0] == 0x01:
        work_mode = 1
    uart_cmd_need_change_mode = 1

#if __name__ == '__main__':
    #buf = bytearray([0x00, 0x01, 0x02,0x03,0x77])
    #pack = Upacker()
    #pkt = pack.enpack(buf)
    #pack.unpack(pkt, print_hex)

#______________________________________________________________________________________________________________________________
#upacker python实现代码结束



def upacker_init():
    pack = Upacker()

    return pack

yzh = 10

#______________________________________________________________________________________________________________________________
#发送数据到MCUgd32是小端字节序
#pack各字母对应类型
#x   pad byte        no value            1
#c   char            string of length 1  1
#b   signed char     integer             1
#B   unsigned char   integer             1
#?   _Bool           bool                1
#h   short           integer             2
#H   unsigned short  integer             2
#i   int             integer             4
#I   unsigned int    integer or long     4
#l   long            integer             4
#L   unsigned long   long                4
#q   long long       long                8
#Q   unsilong long   long                8
#f   float           float               4
#d   double          float               8
#s   char[]          string              1
#p   char[]          string              1
#P   void *          long

def send_data_to_mcu(pack,global_uart_send_data):
    hex_data = ustruct.pack("< bbhhhhbb",                        #小端字节序
                   global_uart_send_data.work_mode,
                   global_uart_send_data.recognition,
                   global_uart_send_data.top_block_offset,          #以屏幕中线为0点
                   global_uart_send_data.center_block_offset,
                   global_uart_send_data.left_block_offset,          #以屏幕中线为0点
                   global_uart_send_data.right_block_offset,
                   global_uart_send_data.left_number,
                   global_uart_send_data.right_number,)
    pkg_data =  pack.enpack(hex_data)
    k210_uart.write(pkg_data)

#______________________________________________________________________________________________________________________________
#pack解包后的回调函数
#def data_callback(bytes):
    #hex_byte = [hex(i) for i in bytes]
    #print(" ".join(hex_byte))

#______________________________________________________________________________________________________________________________
#定时发送串口数据的定时器
#构造函数
# 定时器回调
pack = upacker_init()

def on_timer(timer):
    global work_mode

    global_uart_send_data.work_mode = work_mode
    if(top_blob_location.x != -1):
        global_uart_send_data.top_block_offset = top_blob_location.x-int(sensor.width()/2)
    else:
        global_uart_send_data.top_block_offset = 0

    if(center_blob_location.x != -1):
        global_uart_send_data.center_block_offset = center_blob_location.x-int(sensor.width()/2)
    else:
        global_uart_send_data.center_block_offset = 0

    if(left_blob_location.y != -1):
        global_uart_send_data.left_block_offset = left_blob_location.y-int(sensor.height()/2)
    else:
        global_uart_send_data.left_block_offset = 0

    if(right_blob_location.y != -1):
        global_uart_send_data.right_block_offset = right_blob_location.y-int(sensor.height()/2)
    else:
        global_uart_send_data.right_block_offset = 0



    global_uart_send_data.top_block_offset = top_blob_location.x-int(sensor.width()/2)
    global_uart_send_data.center_block_offset = center_blob_location.x-int(sensor.width()/2)


    send_data_to_mcu(pack,global_uart_send_data)

# 配置定时器0通道0
tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PERIODIC, period=20, unit=Timer.UNIT_MS, callback=on_timer, arg=on_timer, start=False, priority=1, div=0)
#定时发送串口数据
tim.start()


#______________________________________________________________________________________________________________________________
#数字识别配置区域
anchors = [1.40625, 1.875, 1.09375, 1.1875, 1.25, 1.46875, 1.53125, 2.15625, 1.1875, 1.8125000000000002]
labels = ["1", "2", "3", "4", "5", "6", "7", "8"]

actual_number = [1,2,3,4,5,6,7,8]


KPU = kpu.load("/sd/mx.kmodel")
xy = [0,0]
kpu.init_yolo2(KPU,0.7,0.01,len(anchors)//2,anchors)

#______________________________________________________________________________________________________________________________
#主循环
while (True):
    gc.collect()
    img = sensor.snapshot()  # Take a picture and return the image.
    # img.draw_cross(sensor.width()//2, sensor.height()//2, color = (0, 255, 0), size = 10, thickness = 2)
    clock.tick()
    #手动切换
    if key_press_long ==1:
        key_press_long = 0
        #长按后切换K210工作模式
        if work_mode == 0:
            work_mode =1
            print("work mode to 1")
            sensor.set_windowing((224, 224))
        else:
            work_mode =0
            print("work mode to 0")
            img = img.resize(320, 240)
            sensor.set_windowing((320, 240))
    #GD32控制切换
    if uart_cmd_need_change_mode == 1:
        uart_cmd_need_change_mode = 0
        #串口命令来切换K210工作模式
        if work_mode == 1:
            print("work mode to 1")
            sensor.set_windowing((224, 224))
        else:
            print("work mode to 0")
            img = img.resize(320, 240)
            sensor.set_windowing((320, 240))

    if work_mode == 0:  # 巡线模式
        find_blob(img)
        draw_roi(img)
        draw_lines(img)
        if is_findflob_debug:
            print(clock.fps(), top_blob_location.x,center_blob_location.x, left_blob_location.y, right_blob_location.y)  # Note: CanMV Cam runs about half as fast when connected,int(top.x),int(top.y)
            print(clock.fps(), global_uart_send_data.top_block_offset,global_uart_send_data.center_block_offset, global_uart_send_data.left_block_offset, global_uart_send_data.right_block_offset)
            print(global_uart_send_data.recognition)
        fps = clock.fps()  # Update the FPS clock.
        img.draw_string(2, 2, ("%2.1ffps" % (fps)), color=(0, 128, 0), scale=2)
        lcd.display(img)

    else:  # 数字识别模式

        img = sensor.snapshot()  # Take a picture and return the image.
        code = kpu.run_yolo2(KPU, img)
        fps = clock.fps()  # Update the FPS clock.
        img.draw_string(2, 2, ("%2.1ffps" % (fps)), color=(0, 128, 0), scale=2)
        #print(clock.fps())
        if bool(code):
            for i in code:
                img = img.draw_rectangle(i.rect(), (0, 255, 0), 2, 0)
                xy[0] = i.x()
                xy[1] = (i.y() - 20)
                img = img.draw_string(xy[0], xy[1], (labels[i.classid()]), (0, 255, 0), scale=2)
                img = img.draw_string(xy[0], xy[1] + 24, '%.3f' % i.value(), color=(255, 0, 0), scale=2)
            if(code[0].x()< code[-1].x()):
                global_uart_send_data.left_number = actual_number[code[0].classid()]
                global_uart_send_data.right_number = actual_number[(code[-1].classid())]
            else:
                global_uart_send_data.left_number = actual_number[(code[-1].classid())]
                global_uart_send_data.right_number = actual_number[(code[0].classid())]
            #print(global_uart_send_data.left_number,global_uart_send_data.right_number)
        lcd.display(img)
    read_data = k210_uart.read()
    if read_data:
        read_str = pack.unpack(read_data, print_hex)
    lcd.display(img)  # Display image on lcd.
    if is_stack_heap_mem_debug:
        print("stack mem:"+str(gc.mem_free() / 1024)) # stack mem
        print("heap mem:"+str(utils.heap_free() / 1024)) # heap mem

关键的注释都添加了,可以帮助理解代码,这段代码同时实现了寻红线和数字识别,但是还做不到同时运行,在寻红线的时候没法数字识别,这两个状态之间的切换可以通过长按K210上的用户按键或者由立创梁山派来控制切换。当送药小车到达数字识别处时就控制K210进入数字识别模式,识别到数字后再控制K210进入寻红线模式。

首先初始化LCD屏幕、配置摄像头、配置UART通信,并配置一个具有中断的按钮。然后,定义了感兴趣区域(ROIs)和一些用于在图像中查找色块的参数(具体可以去MaixPy的API文档中查找)。

设置了在图像中检测色块和在里面绘制连线的参数。共定义了四个感兴趣区域(ROI):左侧、右侧、顶部和中心。每个ROI都有自己的色块检测参数,如pixel_threshold、area_threshold、x_stride和y_stride。这些参数用于过滤掉过小的色块或者通过跳过一些像素来提高检测速度,避免一些微小噪声小色块的影响。

find_blob函数处理输入图像(img),使用img.find_blobs方法在每个ROI中检测红色的色块。然后在色块周围绘制矩形并在其中心绘制十字标记来方便调试。检测到的色块的位置和面积信息存储在left_blob_location、right_blob_location、top_blob_location和center_blob_location结构中。如果在中心ROI中没有检测到色块,则将global_uart_send_data.recognition变量设置为1,否则设置为0,当红色线没了的时候就代表该停车了。draw_lines函数用于在上下和左右ROI的红色块之间绘制连线(上下左右ROI都识别到红色块就是一个交叉的十字),方便调试使用。

定义了一个名为send_data_to_mcu的函数,用于将数据发送到立创梁山派。这里使用了ustruct.pack函数将数据打包为字节序列,然后调用pack.enpack方法将数据打包,最后通过k210_uart.write将数据发送出去。

定义了一个名为on_timer的定时回调函数,用于定时发送串口数据。在这个函数中,根据图像中的各个位置计算出相应的偏移量,并将这些偏移量存储在global_uart_send_data对象中。然后,调用send_data_to_mcu函数将数据发送到立创梁山派的串口里面。然后,配置定时器0通道0,设置定时器的模式、周期、单位、回调函数等参数,并启动定时器。

进行数字识别的相关配置,用init_yolo2加载模型并初始化KPU

在主循环中,根据工作模式选择执行巡线模式还是数字识别模式。在巡线模式下,调用find_blobdraw_roidraw_lines等函数来处理摄像头采集到图像,并将处理后的图像显示在LCD上方便调试。在数字识别模式下,使用KPU运行模型并获取识别结果,将识别到的数字绘制在图像上,并将处理后的图像显示在LCD上。最后,程序会读取来自立创梁山篇串口发送来的数据,并使用pack.unpack方法解包数据。如果有数据,会执行解包,解包成功后会更新K210模式控制的标志位(巡线模式还是数字识别模式)。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 开发板
    +关注

    关注

    25

    文章

    5033

    浏览量

    97375
  • 代码
    +关注

    关注

    30

    文章

    4779

    浏览量

    68527
收藏 人收藏

    评论

    相关推荐

    梁山的华秋DFM解析讲解(上)

    可制造性设计(DFM)就是从产品开发设计时起,就考虑到可制造性和可测试性,使设计和制造之间紧密联系,实现从设计到制造一次成功的目的。这是保证PCB设计质量的最有效方法。基于华秋DFM来看一下
    的头像 发表于 12-12 09:07 3952次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b><b class='flag-5'>梁山</b><b class='flag-5'>派</b>的华秋DFM解析<b class='flag-5'>讲解</b>(上)

    ·梁山开发板-21F-送药小车-K210更换固件-运行基础颜色识别例程

    K210更换固件,他的IDE叫CanMV,看起来应该是官方合作出品的。但是实际使用的时候发现他里面的函数都比较老旧,连接IDE的时候经常性出现连不上或者连上很久之后才有反应。而且对机器视觉的适配没有Maixpy好,所以开始之前我们先给这个K210
    的头像 发表于 07-28 11:27 1471次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b>·<b class='flag-5'>梁山</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b>-<b class='flag-5'>21</b><b class='flag-5'>年</b><b class='flag-5'>电</b><b class='flag-5'>赛</b><b class='flag-5'>F</b><b class='flag-5'>题</b>-<b class='flag-5'>送药</b><b class='flag-5'>小车</b>-<b class='flag-5'>K210</b>更换固件-运行基础颜色识别例程

    ·梁山开发板-21F-送药小车-K210的KPU数字识别训练

    数字的数据量尽可能相等。但 k210 的算力也是有限的,他所能运行的模型也是有限的,对于 k210:运行 c 代码时最大可以加载 6MB 左右的模型,运行 maixpy 的最小固件时,能加载 3MB 左右
    的头像 发表于 07-31 10:29 1178次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b>·<b class='flag-5'>梁山</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b>-<b class='flag-5'>21</b><b class='flag-5'>年</b><b class='flag-5'>电</b><b class='flag-5'>赛</b><b class='flag-5'>F</b><b class='flag-5'>题</b>-<b class='flag-5'>送药</b><b class='flag-5'>小车</b>-<b class='flag-5'>K210</b>的KPU数字识别训练

    开发板-21F-送药小车-小车寻红线环的调试与实现

    PID控制来说,测量值是红线相较屏幕中线的偏移,目标值是想让红线偏移为0,输出值是电机的速度。 根据14_梁山K210串口通信协议
    的头像 发表于 08-03 10:10 1360次阅读

    ·梁山开发板-21F-送药小车实现思路

    基本要求 1. 根据走廊上的标识信息自动识别,寻径将药品送到指定病房,投影要在门口区域内, 2. 到了指定病房后,点亮红色指示灯,等待卸载药品。 3. 人工卸掉药品后,小车自动熄灭红色指示灯,开始返回。 4. 自动返回药房,点亮绿色指示灯。
    的头像 发表于 08-08 09:44 892次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b>·<b class='flag-5'>梁山</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b>-<b class='flag-5'>21</b><b class='flag-5'>年</b><b class='flag-5'>电</b><b class='flag-5'>赛</b><b class='flag-5'>F</b><b class='flag-5'>题</b>-<b class='flag-5'>送药</b><b class='flag-5'>小车</b><b class='flag-5'>实现</b>思路

    怎样去设计一个智能送药小车

    2021F智能送药小车原文链接:openmv巡线代码
    发表于 01-07 08:19

    梁山-21F-智能送药小车-按键检测的消抖和实现

    按键检测的消抖和实现送药小车中,预留了三个按键,药品装载检测是通过一个轻触开关来实现的,也可以把他理解成一个按键。 按键的实际电路如下: 我们通常用的按键内部都是机械弹性开关,当
    发表于 08-04 09:48

    求助,求K210开发板测试参考程序,MDK5开发

    您好,本人小白一枚,想学习一下K210开发板的使用。求K210开发板测试参考程序,MDK5开发的。顺带能否发一下包括
    发表于 09-15 07:42

    Kendryte K210开发板使用说明书

    本文档是 Kendryte K210 开发板使用说明书,型号是 KD233,描述了开发板资源、建立软件开发环境、使用 SDK 在开发板上执行
    发表于 05-28 10:09 64次下载

    亚博智能K210开发板学习笔记

    亚博智能K210开发板学习笔记
    发表于 12-08 15:06 46次下载
    亚博智能<b class='flag-5'>K210</b><b class='flag-5'>开发板</b>学习笔记

    梁山的华秋DFM解析讲解(下)

    开源的梁山开发板已经大批量生产,其中一些细节和布线布局规则还是很值得我们学习的。上期已经介绍电气信号,最小线宽,最小间距,SMD间距的
    的头像 发表于 12-12 13:17 2027次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b><b class='flag-5'>梁山</b><b class='flag-5'>派</b>的华秋DFM解析<b class='flag-5'>讲解</b>(下)

    梁山开发板-21F-送药小车-分析

    全国产开源开发板,基于GD32F4系列,21F
    的头像 发表于 07-31 10:13 1242次阅读
    <b class='flag-5'>梁山</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b>-<b class='flag-5'>21</b><b class='flag-5'>年</b><b class='flag-5'>电</b><b class='flag-5'>赛</b><b class='flag-5'>F</b><b class='flag-5'>题</b>-<b class='flag-5'>送药</b><b class='flag-5'>小车</b>-<b class='flag-5'>赛</b><b class='flag-5'>题</b>分析

    梁山开发板-21F-送药小车-小车角度环的调试与实现

    来达到目标值。 第二种是在实现小车轮子位置环的基础上,控制两边轮子同时向不同的方向旋转一定的圈数(编码器脉冲),在小车轮子不打滑的情况下转过的角度就是一个确定的值,在送药
    的头像 发表于 07-27 10:18 933次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b><b class='flag-5'>梁山</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b>-<b class='flag-5'>21</b><b class='flag-5'>年</b><b class='flag-5'>电</b><b class='flag-5'>赛</b><b class='flag-5'>F</b><b class='flag-5'>题</b>-<b class='flag-5'>送药</b><b class='flag-5'>小车</b>-<b class='flag-5'>小车</b>角度环的调试与<b class='flag-5'>实现</b>

    ·梁山开发板-21F-送药小车-与K210串口通信协议框架搭建

    K210可以识别到色块和识别数字后,就需要把这些信息传递给梁山派了。而立梁山
    的头像 发表于 08-02 10:57 750次阅读

    ·梁山开发板-21F-送药小车数据的发布与订阅

    可维护性和调试困难:使用全局变量传递信息可能导致代码的可维护性和调试的困难。由于全局变量可以被任何任务修改,追踪问题的根源和调试错误可能会变得更加困难。
    的头像 发表于 08-07 09:55 478次阅读
    <b class='flag-5'>立</b><b class='flag-5'>创</b>·<b class='flag-5'>梁山</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b>-<b class='flag-5'>21</b><b class='flag-5'>年</b><b class='flag-5'>电</b><b class='flag-5'>赛</b><b class='flag-5'>F</b><b class='flag-5'>题</b>-<b class='flag-5'>送药</b><b class='flag-5'>小车</b>数据的发布与订阅