关于大神解答送药小车的程序,我有几个问题

Viewed 65

这是在问答社区找到关于送药小车的一篇很好的回答
但我对这个还有几个问题
1.双线程运行机制是什么
2.为什么我在巡线线程子函数结尾加个 print(1)串行终端并没有打印出“1”,但是我在子函数开头加上却能打印出,这是巡线线程子函数执行不到下半部分吗?
3.如何通过OSD层机制或者其他方式把不同线程“图像绘制”的结果一同显示到屏幕上
关于此问题的代码和问答链接附在下边了,感谢大佬们的解答!!!

https://www.kendryte.com/answer/questions/10010000000005607/10020000000005631

from media.sensor import *
from media.display import *
from media.media import *
from libs.PlatTasks import DetectionApp
from libs.Utils import *
from machine import UART, FPIOA, Pin
import image
import time, gc, _thread, ujson

# ---------- 全局配置 ----------
sensor=None
display_size=[800,480]
redline_img_size=[640,480]
rgb888p_size = [1280, 720]
det_stop=False
redline_stop=False
det_osd_img=None
redline_osd_img=None

# ---------- 串口 & 按键 ----------
fpioa = FPIOA()
fpioa.set_function(11, FPIOA.UART2_TXD)
fpioa.set_function(12, FPIOA.UART2_RXD)
fpioa.set_function(53, FPIOA.GPIO53)
KEY = Pin(53, Pin.IN, Pin.PULL_DOWN)
uart = UART(UART.UART2, baudrate=115200)

# ---------- 红线识别参数 ----------
thresholds = [(23, 57, 30, 127, -128, 127)]
ROIS1 = [(225, 0, 400, 160, 0.3), (225, 160, 400, 160, 0.35), (225, 320, 400, 160, 0.35)]
ROIS2 = [(0, 150, 250, 300), (550, 150, 250, 300)]

# ---------- 状态变量 ----------
key_flag = 0
flag = 0
turn_flag = 0
move_record = []
return_mode = False
current_index = 0
cross_detected = False
num = 1  # 模拟外部识别(1=左转, 2=右转, else 直行)

def media_init():
    global sensor,osd_img,rgb888p_size,display_size,det_osd_img,yolo_osd_img
    Display.init(Display.ST7701, width = display_size[0], height = display_size[1], to_ide = True, osd_num=3)
    sensor = Sensor(fps=30)
    sensor.reset()
    sensor.set_framesize(w = display_size[0], h = display_size[1],chn=CAM_CHN_ID_0)
    sensor.set_pixformat(Sensor.YUV420SP,chn=CAM_CHN_ID_0)
    sensor.set_framesize(w = redline_img_size[0], h = redline_img_size[1], chn=CAM_CHN_ID_1)
    sensor.set_pixformat(Sensor.RGB565,chn=CAM_CHN_ID_1)
    sensor.set_framesize(w = rgb888p_size[0], h = rgb888p_size[1], chn=CAM_CHN_ID_2)
    sensor.set_pixformat(Sensor.RGBP888,chn=CAM_CHN_ID_2)

    sensor_bind_info = sensor.bind_info(x = 0, y = 0, chn = CAM_CHN_ID_0)
    Display.bind_layer(**sensor_bind_info, layer = Display.LAYER_VIDEO1)

    Display.init(Display.ST7701, osd_num=2, to_ide=True)
    det_osd_img = image.Image(display_size[0], display_size[1], image.ARGB8888)
    redline_osd_img = image.Image(display_size[0], display_size[1], image.ARGB8888)
    MediaManager.init()
    sensor.run()

def media_deinit():
    global sensor
    os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
    sensor.stop()
    Display.deinit()
    time.sleep_ms(50)
    MediaManager.deinit()

# ---------- 红线线程 ----------
def calculate_error(blobs, rois):
    global flag, turn_flag
    detected_any = False
    weight_sum = 0
    centroid_sum = 0
    for i, roi in enumerate(rois):
        if blobs[i]:
            detected_any = True
            largest = max(blobs[i], key=lambda b: b.pixels())
            centroid_sum += largest.cx() * roi[4]
            weight_sum += roi[4]
    flag = 1 if detected_any else 0
    if weight_sum:
        center_x = centroid_sum / weight_sum
        dx = center_x - 400
        if dx > 0:
            turn_flag = 1
        else:
            dx = -dx
            turn_flag = 2
        return dx
    return 0

def filter_blob(blob):
    if blob.pixels() < 2000:
        return False
    if 140 < blob.cx() < 160 and 240 < blob.cy() < 260:
        return False
    if 640 < blob.cx() < 660 and 240 < blob.cy() < 260:
        return False
    return True

def redline_thread():
    global sensor,flag, turn_flag, return_mode, move_record, key_flag, cross_detected, current_index
    while True:
        if redline_stop:
            break
        img = sensor.snapshot(chn=CAM_CHN_ID_1)
        # ROI 红色检测
        mid_blobs = [img.find_blobs(thresholds, roi=roi[:4], merge=True) for roi in ROIS1]
        delta_pos_x = int(calculate_error(mid_blobs, ROIS1))
        # 按键切换
        if KEY.value() == 1:
            if flag == 0:
                return_mode = True
                current_index = len(move_record) - 1
                print("切换到回程模式")
            else:
                return_mode = False
                move_record.clear()
                print("切换到正常模式")
            key_flag = 1 - key_flag
            time.sleep_ms(300)

        if not key_flag:
            time.sleep_ms(50)
            continue
        # 左右色块检测
        left = img.find_blobs(thresholds, roi=ROIS2[0], merge=True)
        right = img.find_blobs(thresholds, roi=ROIS2[1], merge=True)
        left = [b for b in left if filter_blob(b)]
        right = [b for b in right if filter_blob(b)]
        is_cross = bool(left and right)
        # 自动回程切换
        if flag == 0 and not return_mode:
            return_mode = True
            current_index = len(move_record)-1
            print("自动切换到回程模式")

        move_prepare = 1 if num == 1 else (3 if num == 2 else 2)

        if is_cross and not cross_detected:
            print("检测到十字边沿,记录动作")
            if not return_mode:
                move_record.append(move_prepare)
                print("记录动作:", move_record)
            else:
                if current_index >= 0:
                    print(f"回程:准备执行动作 {move_record[current_index]}")
        if is_cross:
            if not return_mode:
                if move_prepare == 1:
                    delta_pos_x = 400
                    turn_flag = 2
                elif move_prepare == 3:
                    delta_pos_x = 400
                    turn_flag = 1
                else:
                    delta_pos_x = 0
                    turn_flag = 0
            else:
                if current_index >= 0:
                    m = move_record[current_index]
                    if m == 1:
                        delta_pos_x = 410
                        turn_flag = 1
                    elif m == 3:
                        delta_pos_x = 400
                        turn_flag = 2
                    else:
                        delta_pos_x = 0
                        turn_flag = 0

        cross_detected = is_cross
        uart.write(f"S:{num},{delta_pos_x},{flag},{turn_flag}\n".encode())
        time.sleep_ms(25)

.............................略.....................................
1 Answers

你好,线程运行机制就是同时处理两个任务,如果线程末尾的打印没有正常打印,可能是线程没有正常退出,正常的条件下应该是设置标志位,出现问题后修改标志位退出线程。另外OSD显示,只需要在不同的线程里调用Display.show_image并在参数指定显示的不同OSD层即可显示不同的结果。

哇!!!非常感谢大神!!!