使用yolov8识别+深度相机+机械臂实现垃圾分拣机械臂(代码分享)

news2024/11/23 20:43:53

文章目录

  • 垃圾分拣机械臂
  • 视频演示
  • 程序主代码
  • 完整代码链接

垃圾分拣机械臂

在这里插入图片描述

在这里插入图片描述

视频演示

点击查看

  • 使用YoloV8做的目标检测,机械臂手眼标定使用Aruco的方式,通过深度相机获取三维坐标,与机械臂坐标系之间的转化,得到抓取的坐标
  • 深度相机是dabaipro
  • 机械臂自己打印

程序主代码

import ctypes
import os
import threading
import time

import cv2
import numpy as np
import serial
from openni import openni2
from ultralytics import YOLO

# 多进程
from multiprocessing import Process, Value, Queue, Array

from orbbec_init import initialize_openni, configure_depth_stream, convert_depth_to_xyz
from port_test import Ser


def orbbec_video(center_p_queue, robot_status):
    """
    使用相机进行视频捕捉和物体检测的函数。
    
    参数:
    - center_p_queue: 一个队列,用于存储检测到的物体中心点在相机坐标系下的坐标。
    - robot_status: 一个共享变量,用于指示机器人的工作状态(搜索或运行)。
    
    无返回值。
    """
    model = YOLO('best.pt')
    redist_path = "F:\study-python\dabeipro\OpenNI_2.3.0.86_202210111950_4c8f5aa4_beta6_windows\Win64-Release\sdk\libs"
    width, height, fps = 640, 400, 30
    fx, fy, cx, cy = 524.382751, 524.382751, 324.768829, 212.350189

    def mouse_callback(event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDBLCLK:
            print(x, y, img[y, x])
            print("三维坐标:", convert_depth_to_xyz(x, y, img[y, x], fx, fy, cx, cy))

    dev = initialize_openni(redist_path)
    print(dev.get_device_info())
    depth_stream = configure_depth_stream(dev, width, height, fps)
    cv2.namedWindow('depth')
    cv2.namedWindow('color')
    # cv2.setMouseCallback('depth', mouse_callback)
    cap = cv2.VideoCapture(0)
    fps = 0.0

    try:

        while True:
            t1 = time.time()

            # 开始读取深度视频流
            frame = depth_stream.read_frame()
            # intr = frame.profile.as_video_stream_profile().intrinsics
            # print(intr)
            frame_data = frame.get_buffer_as_uint16()
            # print(frame_data)
            img = np.ndarray((frame.height, frame.width), dtype=np.uint16, buffer=frame_data)
            dim_gray = cv2.convertScaleAbs(img, alpha=0.17)

            kernel_size = 5
            dim_gray = cv2.medianBlur(dim_gray, kernel_size)
            depth_colormap = cv2.applyColorMap(dim_gray, 2)
            # 开始读取彩色视频流
            ret, frame = cap.read()
            frame = cv2.resize(frame, (640, 400))
            frame = cv2.flip(frame, 1)
            # 开始推理
            results = model.predict(source=frame, **{'save': False, 'conf': 0.62, 'verbose': False}, )
            result = results[0].boxes.data.tolist()
            result_list = []
            max_score_bbox = [0, 0, 0, 0]
            category_dict = {
                'plastic bottle': 0,
                'glass bottle': 0,
                'mask': 1,
                'gauze': 1,
                'injector': 2
            }
            for idx in range(len(result)):
                xmin = int(result[idx][0])
                ymin = int(result[idx][1])
                xmax = int(result[idx][2])
                ymax = int(result[idx][3])
                conf = round(float(result[idx][4]), 2)
                cls_idx = int(result[idx][5])
                cls_name = model.names[cls_idx]
                result_list.append([ymin, xmin, ymax, xmax, conf, cls_idx, cls_name])
                cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)
                box_color = (0, 0, 255)

                x = int((xmax - xmin) / 2 + xmin)
                y = int((ymax - ymin) / 2 + ymin)
                # print(result_list, "中点:", x, y, conf, cls_name)
                if y > 400:
                    print("目标超出深度图像范围")
                    continue
                if conf > max_score_bbox[0]:
                    max_score_bbox[0] = conf
                    max_score_bbox[1:] = [x, y, category_dict[cls_name]]
                    # put text under box

                # center_p_queue.put([x_cam, y_cam, z_cam])
                # print("center_p_queue执行")
                x_cam, y_cam, z_cam = convert_depth_to_xyz(x, y, img[y, x], fx, fy, cx, cy)
                cv2.circle(frame, (x,y), 3, (0, 0, 255), -1)
                cv2.putText(frame, cls_name, (xmin, ymin + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8, box_color, 2)
                cv2.putText(frame, "x: {:.3f}".format(x_cam), (xmin, ymin + 40), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                            box_color, 2)
                cv2.putText(frame, "y: {:.3f}".format(y_cam), (xmin, ymin + 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                            box_color, 2)
                cv2.putText(frame, "z: {:.3f}".format(z_cam), (xmin, ymin + 80), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                            box_color, 2)
            # print("conf最大", max_score_bbox)
            x_cam, y_cam, z_cam = convert_depth_to_xyz(max_score_bbox[1], max_score_bbox[2],
                                                       img[max_score_bbox[2], max_score_bbox[1]], fx, fy, cx, cy)

            if robot_status.value == 0 and max_score_bbox[0] > 0.25:
                center_p_queue.put([x_cam, y_cam, z_cam, max_score_bbox[-1]])
                print(x_cam, y_cam, z_cam)
                print("center_p_queue执行")
                robot_status.value = 1
            #     # 处理深度图像,生成深度图的彩色版本
            #     depth_img = np.asanyarray(depth.get_data())
            #     depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_img, alpha=alpha_val), cv2.COLORMAP_JET)
            fps = (fps + (1. / (time.time() - t1))) / 2
            depth_colormap = cv2.putText(depth_colormap, "fps= %.2f" % (fps), (0, 40), cv2.FONT_HERSHEY_SIMPLEX, 1,(0, 255, 0), 2)
            # 根据机器人的状态,在图像上显示状态信息
            if robot_status.value == 0:
                status_text = "Status: Searching"
            else:
                status_text = "Status: Running"
            cv2.putText(frame, status_text, (400, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0) if robot_status == 0 else (0, 0, 255), 2)

            # 将颜色图像和深度图像叠加显示
            # images = np.vstack((color_image, depth_colormap))
            cv2.imshow('color', frame)
            cv2.imshow('depth', depth_colormap)

            key = cv2.waitKey(10)
            if int(key) == 113:
                break
    finally:
        # pipeline.stop()  # 关闭相机和视频写入器
        openni2.unload()
        dev.close()

def send_message(contunts):
    if ser.isOpen():  # 如果串口已经打开
        if contunts:
            # com1端口向com2端口写入数据 字符串必须译码
            # self.contunts = input("输入内容:")
            # 可以自定义输入Gcode命令,规划路径,例如 G1 X10 Y10 Z10 F30,其实就是三维坐标和速度
            ser.write((contunts + "\r").encode("utf-8"))
            time.sleep(1)
            # encode()函数是将字符串转化成相应编码方式的字节形式
            # 如str2.encode('utf-8'),表示将unicode编码的字符串str2转换成utf-8编码的字节数据。
            # 如果不转换,COM1发送到COM2的信息,COM2(调试助手)中文会识别不出来或者会出现乱码现象
    else:  # 如果没有读取到com1串口,则执行以下程序
        print("open failed")
def robot_grasp(center_p_queue, robot_status):
    """
    使用dobot机械臂进行抓取操作。

    参数:
    - center_p_queue: 队列,包含目标中心点的位置信息。
    - robot_status: 共享变量,用于控制机械臂的状态。
    """
    # 检查图像到机械臂转换参数文件是否存在
    if os.path.exists("./save_parms/image_to_arm.npy"):
        image_to_arm = np.load("./save_parms/image_to_arm.npy")
    else:
        print("image_to_arm.npy not exist")
        return

    #send_message("G28")
    ser.write("G28\r".encode("utf-8"))
    # send_message("M114")
    print("发送成功")
    # robot_status.value = 0

    while True:
        # 循环等待并处理目标中心点信息
        if robot_status.value:

            # 从队列获取中心点信息
            center_p = center_p_queue.get()
            center = center_p[0:3]

            # 计算机械臂需要移动到的位置
            img_pos = np.ones(4)
            img_pos[0:3] = center
            arm_pos = np.dot(image_to_arm, np.array(img_pos))
            print("arm_pos", arm_pos)
            # 如果目标位置超出机械臂可达范围,则跳过此次操作
            # if np.sqrt(arm_pos[0] * arm_pos[0] + arm_pos[1] * arm_pos[1]) > 320:
            #     print("Can not reach!!!!!!!!!!!!!!!, distance: {}".format(np.sqrt(arm_pos[0] * arm_pos[0] + arm_pos[1] * arm_pos[1])))

            send_message(f"G1 X{0} Y{185} Z{160}")  # 回原点

            send_message(f"G1 X{arm_pos[0]} Y{arm_pos[1]} Z{arm_pos[2]+80} ")  # 移动到目标上方50mm处

            send_message(f"G1 X{arm_pos[0]} Y{arm_pos[1]} Z{arm_pos[2]-25} ")  # 移动到目标上方处

            send_message("M5")  # 执行抓取
            time.sleep(5)
            send_message(f"G1 X{arm_pos[0]} Y{arm_pos[1]} Z{arm_pos[2]+80} ")  # 再次移动到目标上方20mm处
            if center_p[3] == 0:
                send_message(f"G1 X{170} Y{0} Z{160}")  # 病理性废物位置
            if center_p[3] == 2:
                send_message(f"G1 X{-170} Y{30} Z{160}")  # 损伤性废物位置
            if center_p[3] == 1:
                send_message(f"G1 X{170} Y{120} Z{160}")  # 感染性废物
            send_message("M3")  # 打开夹爪
            time.sleep(4)

            # action.send_message(f"G1 X{0} Y{185} Z{160} ")  # 返回原点
            print("another one")
            # 重置为搜索状态
            robot_status.value = 0

        else:
            # 如果没有检测到目标标记,重置为搜索状态
            print("no marker detected")
            time.sleep(3)
            # robot_status.value = 0
            continue


if __name__ == "__main__":
    center_arr = Array(ctypes.c_double, [0, 0, 0])  # 存储中心点坐标
    robot_status = Value(ctypes.c_int8, 0)
    center_p_queue = Queue()

    ser = serial.Serial("COM5", baudrate=115200, timeout=2, )
    time.sleep(2)

    process1 = Process(target=orbbec_video, args=(center_p_queue, robot_status,))
    # process2 = Process(target=robot_grasp, args=(center_p_queue, robot_status,))
    process1.start()
    # process2.start()
    robot_grasp(center_p_queue, robot_status)
    process1.join()
    # process2.join()

完整代码链接

点击下载
通过网盘分享的文件:robot-arm2
链接: https://pan.baidu.com/s/1GRImjGJQSKJ1_L6rph5LgA?pwd=cje5 提取码: cje5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2118407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

猜数游戏-Rust 入门经典案例

文章目录 发现宝藏1. 项目概述2. 项目结构3. 实现游戏4. 依赖管理5. 测试6. 改进和扩展7. 总结 发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。 在这篇博客中,我们将…

网站钓鱼——挂马技术手段介绍

更多网安实战内容,可前往无问社区查看http://wwlib.cn/index.php/artread/artid/10194.html 网站挂马目前已经成为流氓软件以及红队人员快速获取目标主机权限的常用手段之一,在长时间的实战中也是出现了层出不穷的钓鱼方法,这次分享一下实际…

酒茶香链接心灵——探寻现代人幸福生活

科技在飞速发展,人类社会以前所未有的速度向前跃进,物质世界的繁荣达到了前所未有的高度。 然而,这光鲜的背后,却无形中拉远了人与人之间的距离,割裂了传统文化的根脉。 传统文化势弱、“快餐文化”层出不穷&#xff0…

synchronized锁升级及CAS和AQS简述

概述 为什么会有锁升级的步骤呢,假设没有这个步骤,多个线程竞争时,抢到锁的线程直接运行,其他的都直接sleep/wait,然后等第一个线程运行完成后,再由操作系统唤醒接下来的线程。这个一套动作下来就很费调度…

【学习笔记】SSL密码套件之密钥交换

本篇将介绍密钥交换常用的协议,分别是ECDHE,DHE,ECDH,DH,RSA,PSK 密钥交换的目的:建立种子值(Seed Value) 种子值(二进制数字)用于生成额外的对称…

Python Opencv: 基于颜色提取的印章分割

利用Python实现了一个图像处理功能,即批量提取图像中的印章区域;使用了颜色聚类的方法来提取颜色。 本代码也发布到了github,欢迎大家试用(如果帮助,请star一下): GitHub - AICVHub/seal_seg_o…

讯鹏PDA扫码机一维/二维条码扫描轻松应对各种应用场景

在数字化系统集成中,选择合适的PDA手持机至关重要。然而,市场上许多PDA手持机存在扫码不灵敏精度差、屏幕小、系统卡、可靠性弱、易损坏等问题,给用户带来诸多困扰。针对这些痛点,讯鹏推出了一款5.72寸全面屏手持扫码PDA&#xff…

Unity6 + UE5.4 PSO缓存实践记录

题图(取自COD冷战的着色器编译提示) PSO(管线状态对象 Pipeline State Object)是伴随现代图形API(DirectX12、Vulkan、Metal)而出现的概念,它本质上是单次绘制时渲染管线所处的状态信息的集合&…

滁州皖东农商银行新任董事长未得官宣,年报涉嫌泄露股东隐私

撰稿|芋圆 近期,滁州皖东农商银行发布2024年半年报,其2024年上半年营业收入4.7亿元,同比增长72%,成功实现扭亏为盈;净利润1.37亿元,同比上涨10%,增速显著提升。但其利息净收入1.4亿元&#xff…

梨花声音研修院退费普通话学习初级方法

普通话作为中国的官方语言和国家通用语言,学习和掌握普通话不仅对中国人至关重要,对世界各地的学习者也具有重要意义。无论是为了工作、学术、旅游还是文化交流,掌握普通话都能带来巨大的好处。以下是一些行之有效的普通话学习方法&#xff0…

PMP–一、二、三模–分类–14.敏捷–技巧–敏捷项目章程

文章目录 技巧一模14.敏捷--项目章程--产品意愿--是指产品负责人对产品未来前景和方向的一个高度概括描述,它应符合公司或组织的战略目标。产品愿景声明发送给项目团队中的每个人,保证团队都理解并认可产品愿景。64、 [单选] 在一次会议上,产…

PHP体检信息管理系统-计算机毕业设计源码54850

目录 1 绪论 1.1 选题背景 1.2选题意义 1.3研究的主要内容 1.4论文结构与章节安排 2系统分析 2.1.1 技术可行性分析 2.1.2经济可行性分析 2.1.3操作可行性分析 2.2 系统流程分析 2.2.1 数据新增流程 2.2.2 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2…

线性代数|机器学习-P33卷积神经网络ImageNet和卷积规则

文章目录 1. ImageNet2. 卷积计算2.1 两个多项式卷积2.2 函数卷积2.3 循环卷积 3. 周期循环矩阵和非周期循环矩阵4. 循环卷积特征值4.1 卷积计算的分解4.2 运算量4.3 二维卷积公式 5. Kronecker Product 1. ImageNet ImageNet 的论文paper链接如下:详细请直接阅读相…

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"in…

奔驰 GLS450:后排电动遮阳帘升级,畅享私密与舒适

奔驰 GLS450&#xff1a;后排电动遮阳帘升级&#xff0c;畅享私密与舒适 奔驰 GLS450&#xff0c;作为豪华 SUV 的典范&#xff0c;一直致力于为乘客提供顶级的驾乘体验。此次升级后排电动遮阳帘&#xff0c;更是将舒适与私密提升到了新的高度。 升级后的电动遮阳帘&#xff…

第12章 第9节 Web应用测试(软件评测师)

1.web应用系统负载压力测试中&#xff0c;&#xff08;并发请求数&#xff09;不是衡量业务执行效率的指标。 【解析】并发请求数是考核系统能够承受的负载&#xff0c;交易执行吞吐量、交易执行相应时间、每秒点击率是衡量业务执行效率的指标 2.用户访问某web网站&#xff0…

你可能不知道的Activity启动的诡异现象探索

你可能不知道的Activity启动的诡异现象探索 这篇文章主要记录一下遇到的android启动过程中的一个有意思的探索过程&#xff0c;可能文章会比较长&#xff0c;相信我只要读下去一定会有所收获。这里说明一下&#xff0c;这篇文章肯定会涉及到activity的启动流程&#xff0c;很多…

JAVA社交新潮流同城组局搭子不愁系统小程序源码

社交新潮流——同城组局&#xff0c;搭子不愁系统 &#x1f389;【潮流前沿&#xff0c;社交新风向】&#x1f389; 在这个快节奏的城市生活中&#xff0c;你是否常常感到周末无聊&#xff0c;想找点乐子却苦于没有合适的搭子&#xff1f;别担心&#xff0c;今天我要给大家安…

【最经典的79个】软件测试面试题(内含答案)备战“金九银十”

001.软件的生命周期(prdctrm) 计划阶段(planning)-〉需求分析(requirement)-〉设计阶段(design)-〉编码(coding)->测试(testing)->运行与维护(running maintrnacne) 测试用例 用例编号 测试项目 测试标题 重要级别 预置条件 输入数据 执行步骤 预期结果 0002.问&…

RPG经典设计逻辑——DD系统简单拆解

RPG经典设计逻辑——D&D系统简单拆解 作为TGA2023年度游戏&#xff0c;身披数十项奖项及提名的《博德之门3》&#xff0c;近日又获得了2024雨果奖“最佳游戏或交互式作品”的奖项。“雨果奖”之名源于“科幻杂志之父”雨果・根斯巴克&#xff0c;是科幻及奇幻领域最负盛名…