任意位置积木分拣代码
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
父主题: 代码实现