回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【创意智造组】逆天项目概念版1.0:目标检测检测辅助吸抛吸尘器 简单

头像 lordd 2026.04.06 19 0

目标检测检测辅助吸抛吸尘器,作为概念级项目目前可以吸走小纸片😭,目标检测也只训练了小纸片。但是作为小型玩具玩一玩还是可以的,所以本篇教程分为基础功能和概念进阶两个版本。只有完成了基础功能才可以进行进阶操作😊,但是别担心,基础版本主播也是拿随手可及的东西拼凑的,大家也可以根据实际情况进行修改。

步骤1 基础班材料准备

尼龙过滤网(主播在网上买的3元一米宽左右)

矿泉水瓶(0元)

6cm散热风扇 12V (4元)

4节5号电池盒带盖带开关(2.5元)

3.7V尖头大容量锂电池 4个(12元)

闲置旧舵机(0元)

以下内容可被替代

3D打印底座

3D打印通风道

3D打印滑轨与连杆

木制垫片

螺丝若干

步骤2 基础版组装过程

1.先连接风扇与通风管道,然后将整体连接到底板。3dc5b9006694414fae33efea1ae7fd1b.jpg

2.切割矿泉水瓶,用橡皮筋捆住滤网。afef461aa43f436a410883bd672897d6.jpg

3.连接矿泉水瓶和滑块连杆组合,并用螺丝锁住舵机臂。069020bdaf61d456246949079147b8b4.jpg

4.舵机连接垫块。d59cc9dba7cb550df5a03a9e4086ae55.jpg

5.选择合适位置,令风扇与矿泉水瓶平行。693b3c528caeca0d07eb95bc49a04d8c.jpg

6.风扇连接电池盒然后将电池盒粘贴到底板下方。782ae01dbc85075180952c73091b5fec.jpg

(风扇线与电池盒的连接处要用绝缘胶带缠一圈,防止直接连接正负极烧毁电路)

到目前为止,基本的功能就可以实现了。

步骤3 进阶版组装过程

进阶版需要用到以下材料

行空板m10

外接摄像头

100欧电阻

小灯泡

1.将摄像头和小灯泡连接矿泉水瓶和行空板,小灯泡连接小卡片p22接口,摄像头连接usb接口。31666907a0cc9a2f04137b68290b1f2d.jpg

2.用mind+上传程序和模型训练文件。

(想训练其他杂物识别可以用mind+目标检测训练模型)

image.png

3.如果想移动使用,可以用充电宝连接。

注意:1.不要将垃圾吹到他人身上,会引起他人不适。

2.不要用手碰运行中的风扇扇叶,会很疼。

代码
# -*- coding: UTF-8 -*-
#  MindPlus V2 - 优化识别速度 + 调试输出
import os
import time
import cv2
import threading
import queue
import sys
import traceback

os.environ["QT_QPA_FONTDIR"] = "/usr/share/fonts"
os.environ["OPENCV_LOG_LEVEL"] = "OFF"

from model_mp_io import ImageReader
from pinpong.board import Board, Pin
from model_mp_io import ImageWriter
from pinpong.extension.unihiker import *
from model_mp_core import ObjectDetectionInference

# ==================== 初始化 ====================
try:
    Board().begin()
    p_p22_out = Pin(Pin.P22, Pin.OUT)
    p_p22_out.write_digital(0)
    
    # 摄像头配置:分辨率 160x120(可手动调低为 128x96 或 96x72 以提升速度)
    image_reader = ImageReader(source=1)
    image_reader.set_resolution(320, 320)   # 可根据需要改为 128,96 或 96,72
    if hasattr(image_reader, 'cap'):
        image_reader.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
    
    # 加载模型
    inference = ObjectDetectionInference(
        get_asset_path_by_name("best.onnx"),
        get_asset_path_by_name("data.yaml")
    )
    
    detection_img_output = ImageWriter()
    
    # 设置显示窗口大小
    cv2.namedWindow("AI", cv2.WINDOW_NORMAL)
    cv2.resizeWindow("AI", 640, 480)
    print("初始化成功")
except Exception as e:
    print(f"初始化失败: {e}")
    traceback.print_exc()
    sys.exit(1)

# ==================== 线程间队列 ====================
frame_queue = queue.Queue(maxsize=2)
result_queue = queue.Queue(maxsize=1)
stop_event = threading.Event()

# ==================== 摄像头读取线程 ====================
def capture_thread():
    while not stop_event.is_set():
        try:
            img = image_reader.read_frame()
            if img is not None:
                if frame_queue.full():
                    try:
                        frame_queue.get_nowait()
                    except queue.Empty:
                        pass
                frame_queue.put(img)
        except Exception as e:
            print(f"摄像头读取异常: {e}")
            traceback.print_exc()
            time.sleep(0.01)

# ==================== 检测线程(高间隔,低频率) ====================
frame_counter = 0
detect_interval = 10   # 每10帧检测一次,大幅降低推理频率

def detect_thread():
    global frame_counter
    while not stop_event.is_set():
        try:
            img = frame_queue.get(timeout=1)
            if frame_counter % detect_interval == 0:
                # 执行推理
                result = inference.inference(img)
                if not isinstance(result, dict) or 'result' not in result:
                    print(f"推理结果格式错误: {result}")
                else:
                    # 打印检测结果(调试用)
                    detections = result.get('result', [])
                    if len(detections) > 0:
                        print(f"检测到 {len(detections)} 个物体")
                        for det in detections:
                            # 尝试获取标签和置信度
                            label = det.get('label') or det.get('class') or det.get('name', 'unknown')
                            conf = det.get('confidence') or det.get('score', 0)
                            print(f"  {label}: {conf:.2f}")
                    # 更新结果队列
                    while not result_queue.empty():
                        result_queue.get_nowait()
                    result_queue.put(result)
            frame_counter += 1
        except queue.Empty:
            continue
        except Exception as e:
            print(f"推理异常: {e}")
            traceback.print_exc()
            time.sleep(0.1)

threading.Thread(target=capture_thread, daemon=True, name="Capture").start()
threading.Thread(target=detect_thread, daemon=True, name="Detect").start()

# ==================== 自定义绘图函数(兼容多种键名) ====================
def draw_detections(img, result):
    """
    鲁棒的绘图函数,兼容不同键名
    """
    img_copy = img.copy()
    for det in result.get('result', []):
        # 获取边界框
        bbox = det.get('bbox')
        if bbox is None:
            continue
        x1, y1, x2, y2 = map(int, bbox)
        
        # 获取标签
        label = det.get('label') or det.get('class') or det.get('name', '?')
        # 获取置信度
        conf = det.get('confidence') or det.get('score', 0)
        
        # 绘制矩形框
        cv2.rectangle(img_copy, (x1, y1), (x2, y2), (0, 255, 0), 1)
        # 绘制标签文字
        text = f"{label}: {conf:.2f}" if conf else label
        cv2.putText(img_copy, text, (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 255, 0), 1)
    return img_copy

# ==================== 主线程:显示和控制 ====================
last_display_result = {'result': []}
frame_count = 0

try:
    while True:
        # 获取最新检测结果
        if not result_queue.empty():
            try:
                last_display_result = result_queue.get_nowait()
            except queue.Empty:
                pass
        
        # 获取最新帧
        try:
            img = frame_queue.get_nowait()
        except queue.Empty:
            time.sleep(0.001)
            continue
        
        # 使用自定义绘图函数(更稳定)
        try:
            img_with_boxes = draw_detections(img, last_display_result)
        except Exception as e:
            print(f"绘图异常: {e}")
            traceback.print_exc()
            img_with_boxes = img
        
        # 缩放显示
        display_size = (640, 480)
        img_to_show = cv2.resize(img_with_boxes, display_size, interpolation=cv2.INTER_NEAREST)
        cv2.imshow("AI", img_to_show)
        
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break
        
        # GPIO 控制
        try:
            p_p22_out.write_digital(1 if len(last_display_result.get('result', [])) > 0 else 0)
        except Exception as e:
            print(f"GPIO控制异常: {e}")
        
        frame_count += 1
        time.sleep(0.005)

except KeyboardInterrupt:
    print("用户中断")
except Exception as e:
    print(f"主循环异常: {e}")
    traceback.print_exc()
finally:
    stop_event.set()
    time.sleep(0.2)
    cv2.destroyAllWindows()
    print("程序退出")

评论

user-avatar