下载
中文
注册

任意位置积木分拣代码

dofbot_garbage_yolov5功能包包含了训练好的yolov5模型及功能脚本。主要为通过yolov5进行色块的识别与定位,根据位置控制机械臂进行积木分类的代码。

“dofbot_garbage_yolov5/dofbot_garbage_yolov5/data_collect.py”为摄像头采集数据的逻辑代码。

# 打开摄像头
capture = cv.VideoCapture(0)
# 当摄像头正常打开的情况下循环执行
while capture.isOpened():

    # 读取相机的每一帧
    _, img = capture.read()
    # 统一图像大小
    img = cv.resize(img, (640, 480))

    try: 
        write_XYT(XYT_path, [93,130], 140)
    except Exception: 
        print("File XYT_config Error !!!") 

    dp = np.array([[86, 31], [18, 426], [609, 427], [537, 31]])
    img = calibration.Perspective_transform(dp, img)    

    # ----------  Get Image Index --------------
    img_idx = -1
    with open("/home/HwHiAiUser/RobotArmProject/ros2_dofbot_formal_ws/src/dofbot_garbage_yolov5/dofbot_garbage_yolov5/config/data_collect_idx.txt", "r") as f:
        contents = f.readline()
        # print(type(contents))        
        img_idx = int(contents)

    stored_path = "/home/HwHiAiUser/RobotArmProject/ros2_dofbot_formal_ws/src/dofbot_garbage_yolov5/dofbot_garbage_yolov5/data/" + str(img_idx) + ".png"
    cv.imwrite(stored_path, img)

    with open("/home/HwHiAiUser/RobotArmProject/ros2_dofbot_formal_ws/src/dofbot_garbage_yolov5/dofbot_garbage_yolov5/config/data_collect_idx.txt", "w") as f:
        img_idx += 1
        f.write(str(img_idx))
    # ---------- Done --------------------------
    break

“dofbot_garbage_yolov5/dofbot_garbage_yolov5/dofbot_config.py”为图像检测与机器视觉逻辑代码。

    def calibration_map(self, image,xy=None, threshold_num=130):
        '''
        放置方块区域检测函数
        :param image:输入图像
        :return:轮廓区域边点,处理后的图像
        '''
        if xy!=None: 
            self.xy=xy
        # 机械臂初始位置角度
        joints_init = [self.xy[0], self.xy[1], 0, 0, 90, 0] # REVISE
        # 将机械臂移动到标定方框的状态
        self.arm.Arm_serial_servo_write6_array(joints_init, 500)
        self.image = image
        self.threshold_num = threshold_num
        # 创建边点容器
        dp = []
        h, w = self.image.shape[:2]
        # print("h",h)
        # 获取轮廓点集(坐标)
        contours = self.Morphological_processing()
        # 遍历点集
        for i, c in enumerate(contours):
            # 计算轮廓区域。
            area = cv.contourArea(c)

            low_bound = None
            high_bound = None
            if self.use_other_cam:
                low_bound = h * w / 2 - 40000
            else:
                low_bound = h * w / 2
            high_bound = h * w

            # 设置轮廓区域范围
            if low_bound < area < high_bound:
                # 计算多边形的矩
                mm = cv.moments(c)
                if mm['m00'] == 0:
                    continue
                cx = mm['m10'] / mm['m00']
                cy = mm['m01'] / mm['m00']
                # 绘制轮廓区域
                cv.drawContours(self.image, contours, i, (255, 255, 0), 2)
                # 获取轮廓区域边点
                dp = np.squeeze(cv.approxPolyDP(c, 100, True))
                # 绘制中心
                if not self.data_collect:
                    cv.circle(self.image, (np.int_(cx), np.int_(cy)), 5, (0, 0, 255), -1)
        return dp, self.image

    def Morphological_processing(self):
        '''
        形态学及去噪处理,并获取轮廓点集
        '''
        # 将图像转为灰度图
        gray = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY)
        # 使用高斯滤镜模糊图像。
        gray = cv.GaussianBlur(gray, (5, 5), 1)
        # 图像二值化操作
        ref, threshold = cv.threshold(gray, self.threshold_num, 255, cv.THRESH_BINARY)
        # 获取不同形状的结构元素
        kernel = np.ones((3, 3), np.uint8)
        # 形态学开操作
        if self.use_other_cam:
            blur = cv.morphologyEx(threshold, cv.MORPH_OPEN, kernel, iterations=8)
        else:
            blur = cv.morphologyEx(threshold, cv.MORPH_OPEN, kernel, iterations=4)
        # 提取模式
        mode = cv.RETR_EXTERNAL
        # 提取方法
        method = cv.CHAIN_APPROX_NONE
        # 获取轮廓点集(坐标) python2和python3在此处略有不同
        # 层级关系 参数一:输入的二值图,参数二:提取模式,参数三:提取方法。
        contours, hierarchy = cv.findContours(blur, mode, method)
        return contours

    def Perspective_transform(self, dp, image):
        '''
        透视变换
        :param dp: 方框边点(左上,左下,右下,右上)
        :param image: 原始图像
        :return: 透视变换后图像
        '''
        if len(dp) != 4: 
            return
        upper_left = []
        lower_left = []
        lower_right = []
        upper_right = []
        for i in range(len(dp)):
            if dp[i][0]<320 and dp[i][1]<240:
                upper_left=dp[i]
            if dp[i][0]<320 and dp[i][1]>240:
                lower_left=dp[i]
            if dp[i][0]>320 and dp[i][1]>240:
                lower_right=dp[i]
            if dp[i][0]>320 and dp[i][1]<240:
                upper_right=dp[i]
        # 原图中的四个顶点
        pts1 = np.float32([upper_left, lower_left, lower_right, upper_right])
        # 变换后的四个顶点
        pts2 = np.float32([[0, 0], [0, 480], [640, 480], [640, 0]])
        # 根据四对对应点计算透视变换。
        M = cv.getPerspectiveTransform(pts1, pts2)
        # 将透视变换应用于图像。
        Transform_img = cv.warpPerspective(image, M, (640, 480))
        return Transform_img

“dofbot_garbage_yolov5/dofbot_garbage_yolov5/garbage_grap.py”为机械臂抓取与移动分拣的逻辑代码。

    def move(self, joints, joints_down):
        '''
        移动过程
        :param joints: 移动到物体位置的各关节角度
        :param joints_down: 机械臂抬起各关节角度
        '''
        joints_uu = [90, 80, 50, 50, 265, self.grap_joint]
        # 抬起
        joints_up = [joints_down[0], 80, 50, 50, 265, 30]
        # 移动至物体位置上方
        self.arm.Arm_serial_servo_write6_array(joints_uu, 1000)
        sleep(1)
        # 开合夹爪
        # for i in range(5):
        #     self.arm.Arm_serial_servo_write(6, 180, 100)
        #     sleep(0.08)
        #     self.arm.Arm_serial_servo_write(6, 30, 100)
        #     sleep(0.08)
        # 松开夹爪
        self.arm.Arm_serial_servo_write(6, 0, 500)
        sleep(0.5)
        # 移动至物体位置
        self.arm.Arm_serial_servo_write6_array(joints, 500)
        sleep(0.5)
        # 进行抓取,夹紧夹爪
        self.arm.Arm_serial_servo_write(6, self.grap_joint, 500)
        sleep(0.5)
        # 架起
        self.arm.Arm_serial_servo_write6_array(joints_uu, 1000)
        sleep(1)
        # 抬起至对应位置上方
        self.arm.Arm_serial_servo_write(1, joints_down[0], 500)
        sleep(0.5)
        # 抬起至对应位置
        self.arm.Arm_serial_servo_write6_array(joints_down, 1000)
        sleep(1)
        # 释放物体,松开夹爪
        self.arm.Arm_serial_servo_write(6, 30, 500)
        sleep(0.5)
        # 抬起
        self.arm.Arm_serial_servo_write6_array(joints_up, 1000)
        sleep(1)

    def arm_run(self, name, joints):
        '''
        机械臂移动函数
        :param name:识别的垃圾名称
        :param joints: 反解求得的各关节角度
        '''
        # 有害垃圾--红色
        if name == "Syringe" or name == "Used_batteries" or name == "Expired_cosmetics" or name == "Expired_tablets" and self.move_status == True:
            # 此处设置,需执行完本次操作,才能向下运行
            self.move_status = False
            # print("有害垃圾")
            # print(joints[0], joints[1], joints[2], joints[3], joints[4])
            # 获得目标关节角
            joints = [joints[0], joints[1], joints[2], joints[3], 265, 30]
            # 移动到垃圾桶前对应姿态
            # joints_down = [45, 80, 35, 40, 265, self.grap_joint]
            # 移动到垃圾桶位置放下对应姿态
            joints_down = [45, 50, 20, 60, 265, self.grap_joint]
            # 移动
            self.move(joints, joints_down)
            # 移动完毕
            self.move_status = True
        # 可回收垃圾--蓝色
        if name == "Zip_top_can" or name == "Newspaper" or name == "Old_school_bag" or name == "Book" and self.move_status == True:
            self.move_status = False
            # print("可回收垃圾")
            # print(joints[0], joints[1], joints[2], joints[3], joints[4])
            joints = [joints[0], joints[1], joints[2], joints[3], 265, 30]
            # joints_down = [27, 110, 0, 40, 265, self.grap_joint]
            joints_down = [27, 75, 0, 50, 265, self.grap_joint]
            self.move(joints, joints_down)
            self.move_status = True
        # 厨余垃圾--绿色
        if name == "Fish_bone" or name == "Watermelon_rind" or name == "Apple_core" or name == "Egg_shell" and self.move_status == True:
            self.move_status = False
            # print("厨余垃圾")
            # print(joints[0], joints[1], joints[2], joints[3], joints[4])
            joints = [joints[0], joints[1], joints[2], joints[3], 265, 30]
            # joints_down = [152, 110, 0, 40, 265, self.grap_joint]
            joints_down = [147, 75, 0, 50, 265, self.grap_joint]
            self.move(joints, joints_down)
            self.move_status = True

        # 其他垃圾--灰色
        if name == "Yellow" or name == "Cigarette_butts" or name == "Toilet_paper" or name == "Peach_pit" or name == "Disposable_chopsticks" and self.move_status == True:
            self.move_status = False
            # print("其他垃圾")
            # print(joints[0], joints[1], joints[2], joints[3], joints[4])
            joints = [joints[0], joints[1], joints[2], joints[3], 265, 30]
            # joints_down = [137, 80, 35, 40, 265, self.grap_joint]
            joints_down = [133, 50, 20, 60, 265, self.grap_joint]
            self.move(joints, joints_down)
            self.move_status = True