我在做21年电赛送药小车的题目。函数a是循迹,串口发送偏移角度;函数b是数字识别,串口发送识别到的数字。但是两者功能如何实现相互转化?硬件如何初始化才不会冲突?

Viewed 186

重现步骤
1.串口先发送a进入函数a
2.串口再发送b进入函数b(无法进入,报错)
image.png

期待结果和实际结果

希望可以实现两者功能的切换

软硬件版本信息

固件2.9.0

错误日志

RuntimeError: MediaManager, vb config failed(-1610317806), at now please reboot the board to fix it.

尝试解决过程

或者说可以通过逻辑代码实现按键的reset功能吗?
补充材料(完整代码)
见评论

3 Answers

你好,保证MeidaManager.init()仅执行一次,然后初始化工作在该函数前实现即可。

你可以直接帮我改动我的代码吗?

import time, os, utime, sys, math, gc, image, random, aicube
import ujson
from libs.PipeLine import PipeLine, ScopedTiming
from media.sensor import * #导入sensor模块,使用摄像头相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
from machine import UART
from machine import FPIOA
from machine import Pin # 导入Pin模块
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
import nncase_runtime as nn
import ulab.numpy as np
fpioa = FPIOA()

fpioa.set_function(3,FPIOA.UART1_TXD)
fpioa.set_function(4,FPIOA.UART1_RXD)

uart=UART(UART.UART1,115200) #设置串口号1和波特率

#3.5寸mipi屏分辨率定义
lcd_width = 800
lcd_height = 480

LED = Pin(52, Pin.OUT)
LED.value(0)

GRAYSCALE_THRESHOLD = [(0, 64)]

#采样图像为QVGA 320*240,列表把roi把图像分成3个矩形,越靠近的摄像头视野(通常为图像下方)的矩形权重越大。
ROIS = [ # [ROI, weight]
(0, 200, 320, 40, 0.7), # 可以根据不同机器人情况进行调整。
(0, 100, 320, 40, 0.3),
(0, 0, 320, 40, 0.1)
]

weight_sum = 0
for r in ROIS: weight_sum += r[4] # r[4] 为矩形权重值.

def a():
sensor = Sensor(width=1280, height=960) #构建摄像头对象,将摄像头长宽设置为4:3
sensor.reset() #复位和初始化摄像头
sensor.set_framesize(width=320, height=240) #设置帧大小,默认通道0
sensor.set_pixformat(Sensor.GRAYSCALE) #设置输出图像格式,默认通道0
Display.init(Display.ST7701, width=lcd_width, height=lcd_height, to_ide=True) #同时使用mipi屏和IDE缓冲区显示图像
#Display.init(Display.VIRT, sensor.width(), sensor.height()) #只使用IDE缓冲区显示图像
MediaManager.init() #初始化media资源管理器
sensor.run() #启动sensor
clock = time.clock()
while True:

    ################
    ## 这里编写代码 ##
    ################
    clock.tick()

    img = sensor.snapshot() #拍摄一张图片

    centroid_sum = 0

    for r in ROIS:
        blobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True) # r[0:4] 是上面定义的roi元组.

        if blobs:
            # Find the blob with the most pixels.
            largest_blob = max(blobs, key=lambda b: b.pixels())

            # Draw a rect around the blob.
            img.draw_rectangle(largest_blob.rect())
            img.draw_cross(largest_blob.cx(),
                           largest_blob.cy())

            centroid_sum += largest_blob.cx() * r[4] # r[4] 是每个roi的权重值.

    center_pos = (centroid_sum / weight_sum) # 确定直线的中心.

    # 将直线中心位置转换成角度,便于机器人处理.
    deflection_angle = 0

    # 使用反正切函数计算直线中心偏离角度。可以自行画图理解
    #权重X坐标落在图像左半部分记作正偏,落在右边部分记为负偏,所以计算结果加负号。

    #deflection_angle = -math.atan((center_pos-80)/60) #采用图像为QQVGA 160*120时候使用

    deflection_angle = -math.atan((center_pos-160)/120) #采用图像为QVGA 320*240时候使用

    # 将偏离值转换成偏离角度.
    deflection_angle = math.degrees(deflection_angle)

    # 计算偏离角度后可以控制机器人进行调整.
    print("Turn Angle: %d" % deflection_angle)

    # LCD显示偏移角度,scale参数可以改变字体大小
    img.draw_string_advanced(2,2,20, str('%.1d' % deflection_angle), color=(255,255,255))

    #Display.show_image(img) #显示图片

    #显示图片,仅用于LCD居中方式显示
    Display.show_image(img, x=round((lcd_width-sensor.width())/2),y=round((lcd_height-sensor.height())/2))

    #print(clock.fps()) #打印FPS
    uart.write("%d\n" % deflection_angle)#发送一条数据
    
    # 添加非阻塞模式切换检查
    new_text = uart.read(1)
    if new_text and new_text in [b'a', b'b']:
        print("退出巡线模式")
        sensor.stop()  # 停止摄像头
        MediaManager.deinit()  # 释放媒体资源
        break

def b():
# 添加显示模式,支持"hdmi"和"lcd"
display_mode="lcd"
if display_mode=="hdmi":
display_size=[1920,1080]
else:
display_size=[800,480]
kmodel_path="/sdcard/app/Test/TEST.kmodel"
# 根据数据集设置,在线训练平台和AICube部署包的deploy_config.json文件中包含该字段
labels=["1","2","3","4","5","6","7","8","9"]
# 类别置信度阈值
confidence_threshold=0.5
# nms阈值
nms_threshold = 0.5
# 训练中使用的锚框,在线训练平台和AICube部署包的deploy_config.json文件中包含该字段,只有AnchorBaseDet需要该参数
anchors=[30,23,21,33,29,43,44,29,41,39,41,68,71,43,59,61,71,72]
# 初始化PipeLine,只关注传给AI的图像分辨率,显示的分辨率
pl=PipeLine(rgb888p_size=[1280,720],display_size=display_size,display_mode=display_mode)
pl.create()
# 检测类实例,关注模型输入分辨率,传给AI的图像分辨率,显示的分辨率
det=DetectionApp(kmodel_path,labels,model_input_size=[640,640],anchors=anchors,rgb888p_size=[1280,720],display_size=display_size,debug_mode=0)
# 配置预处理过程
det.config_preprocess()
try:
while True:
os.exitpoint()
with ScopedTiming("total",1):
# 获取当前帧
img=pl.get_frame()
# 获得检测框
det_boxes=det.run(img)
# 绘制检测框和类别信息
det.draw_result(pl,det_boxes)
# 显示当前的绘制结果
pl.show_image()
gc.collect()
except BaseException as e:
print("Exception:", e) # 使用通用异常打印方式
# sys.print_exception(e) # 如果环境支持可用此方式
finally:
det.deinit()
pl.destroy()

class DetectionApp(AIBase):
def init(self,kmodel_path,labels,model_input_size=[640,640],anchors=[10.13,16,30,33,23,30,61,62,45,59,119,116,90,156,198,373,326],model_type="AnchorBaseDet",confidence_threshold=0.5,nms_threshold=0.25,nms_option=False,strides=[8,16,32],rgb888p_size=[1280,720],display_size=[1920,1080],debug_mode=0):
super().init(kmodel_path,model_input_size,rgb888p_size,debug_mode)
# kmodel路径
self.kmodel_path=kmodel_path
# 类别标签
self.labels=labels
# 模型输入分辨率
self.model_input_size=model_input_size
# 检测任务的锚框
self.anchors=anchors
# 模型类型,支持"AnchorBaseDet","AnchorFreeDet","GFLDet"三种模型
self.model_type=model_type
# 检测框类别置信度阈值
self.confidence_threshold=confidence_threshold
# 检测框NMS筛选阈值
self.nms_threshold=nms_threshold
# NMS选项,如果为True做类间NMS,如果为False做类内NMS
self.nms_option=nms_option
# 输出特征图的降采样倍数
self.strides=strides
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]
# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]
# 调试模式
self.debug_mode=debug_mode
# 检测框预置颜色值
self.color_four=[(255, 220, 20, 60), (255, 119, 11, 32), (255, 0, 0, 142), (255, 0, 0, 230),
(255, 106, 0, 228), (255, 0, 60, 100), (255, 0, 80, 100), (255, 0, 0, 70),
(255, 0, 0, 192), (255, 250, 170, 30), (255, 100, 170, 30), (255, 220, 220, 0),
(255, 175, 116, 175), (255, 250, 0, 30), (255, 165, 42, 42), (255, 255, 77, 255),
(255, 0, 226, 252), (255, 182, 182, 255), (255, 0, 82, 0), (255, 120, 166, 157)]
# Ai2d实例,用于实现模型预处理
self.ai2d=Ai2d(debug_mode)
# 设置Ai2d的输入输出格式和类型
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)
# 配置预处理操作,这里使用了pad和resize,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看
def config_preprocess(self,input_image_size=None):
with ScopedTiming("set preprocess config",self.debug_mode > 0):
# 初始化ai2d预处理配置,默认为sensor给到AI的尺寸,您可以通过设置input_image_size自行修改输入尺寸
ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
# 计算padding参数
top,bottom,left,right=self.get_padding_param()
# 配置padding预处理
self.ai2d.pad([0,0,0,0,top,bottom,left,right], 0, [114,114,114])
# 配置resize预处理
self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)
# build预处理过程,参数为输入tensor的shape和输出tensor的shape
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]])
# 自定义当前任务的后处理,这里调用了aicube模块的后处理接口
def postprocess(self,results):
with ScopedTiming("postprocess",self.debug_mode > 0):
if self.model_type == "AnchorBaseDet":
# 修改所有labels为self.labels
det_boxes = aicube.anchorbasedet_post_process(results[0], results[1], results[2], self.model_input_size,
self.rgb888p_size, self.strides, len(self.labels), self.confidence_threshold,
self.nms_threshold, self.anchors, self.nms_option)

        elif self.model_type == "GFLDet":
            det_boxes = aicube.gfldet_post_process(results[0], results[1], results[2], self.model_input_size,
                self.rgb888p_size, self.strides, len(self.labels), self.confidence_threshold,
                self.nms_threshold, self.nms_option)
        
        elif self.model_type=="AnchorFreeDet":
            det_boxes = aicube.anchorfreedet_post_process(results[0], results[1], results[2], self.model_input_size,
                self.rgb888p_size, self.strides, len(self.labels), self.confidence_threshold,
                self.nms_threshold, self.nms_option)
        
        else:
            det_boxes=None
        return det_boxes

# 将结果绘制到屏幕上
def draw_result(self,pl,det_boxes):
    global uart
    
    with ScopedTiming("draw osd",self.debug_mode > 0):
        if det_boxes:
            pl.osd_img.clear()
            # 收集所有检测到的标签数字
            detected_labels = [self.labels[b[0]] for b in det_boxes]
            # 发送逗号分隔的数字字符串
            uart.write(f"{','.join(detected_labels)}\n".encode())
            
            for det_boxe in det_boxes:
                # 获取每一个检测框的坐标,并将其从原图分辨率坐标转换到屏幕分辨率坐标,将框和类别信息绘制在屏幕上
                x1, y1, x2, y2 = det_boxe[2],det_boxe[3],det_boxe[4],det_boxe[5]
                sx=int(x1 * self.display_size[0] // self.rgb888p_size[0])
                sy=int(y1 * self.display_size[1] // self.rgb888p_size[1])
                w = int(float(x2 - x1) * self.display_size[0] // self.rgb888p_size[0])
                h = int(float(y2 - y1) * self.display_size[1] // self.rgb888p_size[1])
                pl.osd_img.draw_rectangle(sx , sy , w , h , color=self.get_color(det_boxe[0]))
                label = self.labels[det_boxe[0]]
                score = str(round(det_boxe[1],2))
                pl.osd_img.draw_string_advanced(sx, sy-50,32, label + " " + score , color=self.get_color(det_boxe[0]))
        else:
            pl.osd_img.clear()
            pl.osd_img.draw_rectangle(0, 0, 128, 128, color=(0,0,0,0))
            # 无检测时发送"None"
            uart.write("None\n".encode())

# 计算padding参数
def get_padding_param(self):
    ratiow = float(self.model_input_size[0]) / self.rgb888p_size[0];
    ratioh = float(self.model_input_size[1]) / self.rgb888p_size[1];
    ratio = min(ratiow, ratioh)
    new_w = int(ratio * self.rgb888p_size[0])
    new_h = int(ratio * self.rgb888p_size[1])
    dw = float(self.model_input_size[0]- new_w) / 2
    dh = float(self.model_input_size[1] - new_h) / 2
    top = int(round(dh - 0.1))
    bottom = int(round(dh + 0.1))
    left = int(round(dw - 0.1))
    right = int(round(dw - 0.1))
    return top,bottom,left,right

# 根据当前类别索引获取框的颜色
def get_color(self, x):
    idx=x%len(self.color_four)
    return self.color_four[idx]    

while True:
gc.collect()
text = uart.read(1)
if text == b'a':
print("进入巡线模式")
LED.value(1)
time.sleep(1)
LED.value(0)
a() # 执行巡线函数
elif text == b'b':
print("进入目标检测模式")
LED.value(1)
time.sleep(1)
LED.value(0)
b() # 执行检测函数

你好,想问一下你串口发送数据时会自动发送total time吗?