From 7e49274e04cfc4b3ffec3724cad17d8862da3f2a Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Wed, 16 Nov 2022 16:05:13 +0800 Subject: [PATCH 01/12] update new aikit code --- .../scripts/mecharm_topics.py | 2 + .../ai_mecharm_270/launch/vision_wio.launch | 8 +- .../scripts/advance_detect_obj_color.py | 493 +++++++++++++ .../scripts/advance_detect_obj_img_folder.py | 644 +++++++++++++++++ mycobot_ai/ai_mycobot_280/res/blue/goal9.jpeg | Bin 0 -> 3533 bytes .../ai_mycobot_280/res/gray/goal10.jpeg | Bin 0 -> 3416 bytes .../ai_mycobot_280/res/green/goal12.jpeg | Bin 0 -> 3572 bytes mycobot_ai/ai_mycobot_280/res/red/goal8.jpeg | Bin 0 -> 4012 bytes mycobot_ai/ai_mycobot_280/res/red/goal9.jpeg | Bin 0 -> 3616 bytes mycobot_ai/ai_mycobot_280/res/takephoto.jpeg | Bin 64540 -> 42627 bytes .../scripts/advance_detect_obj_color.py | 479 +++++++++++++ .../scripts/advance_detect_obj_img_folder.py | 660 ++++++++++++++++++ mycobot_ai/ai_mycobot_280/scripts/test.py | 17 +- .../launch/vision_wio.launch | 6 +- .../ai_mypalletizer_260/res/blue/goal9.jpeg | Bin 0 -> 2808 bytes .../ai_mypalletizer_260/res/gray/goal9.jpeg | Bin 0 -> 3155 bytes .../ai_mypalletizer_260/res/green/goal12.jpeg | Bin 0 -> 4376 bytes .../ai_mypalletizer_260/res/green/goal14.jpeg | Bin 0 -> 2451 bytes .../ai_mypalletizer_260/res/red/goal8.jpeg | Bin 0 -> 2991 bytes .../ai_mypalletizer_260/res/takephoto.jpeg | Bin 46764 -> 48769 bytes .../scripts/advance_detect_obj_color.py | 550 +++++++++++++++ .../scripts/advance_detect_obj_img_folder.py | 628 +++++++++++++++++ .../ai_mypalletizer_260/scripts/test.py | 31 +- .../mypalletizer_260/config/mypal_260.rviz | 247 +------ .../launch/communication_topic.launch | 2 +- .../scripts/mypal_topics.py | 16 +- 26 files changed, 3548 insertions(+), 235 deletions(-) create mode 100644 mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py create mode 100644 mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py create mode 100644 mycobot_ai/ai_mycobot_280/res/blue/goal9.jpeg create mode 100644 mycobot_ai/ai_mycobot_280/res/gray/goal10.jpeg create mode 100644 mycobot_ai/ai_mycobot_280/res/green/goal12.jpeg create mode 100644 mycobot_ai/ai_mycobot_280/res/red/goal8.jpeg create mode 100644 mycobot_ai/ai_mycobot_280/res/red/goal9.jpeg create mode 100644 mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py create mode 100644 mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py create mode 100644 mycobot_ai/ai_mypalletizer_260/res/blue/goal9.jpeg create mode 100644 mycobot_ai/ai_mypalletizer_260/res/gray/goal9.jpeg create mode 100644 mycobot_ai/ai_mypalletizer_260/res/green/goal12.jpeg create mode 100644 mycobot_ai/ai_mypalletizer_260/res/green/goal14.jpeg create mode 100644 mycobot_ai/ai_mypalletizer_260/res/red/goal8.jpeg create mode 100644 mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py create mode 100644 mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py diff --git a/mecharm/mecharm_communication/scripts/mecharm_topics.py b/mecharm/mecharm_communication/scripts/mecharm_topics.py index 02c3934..5039b0d 100755 --- a/mecharm/mecharm_communication/scripts/mecharm_topics.py +++ b/mecharm/mecharm_communication/scripts/mecharm_topics.py @@ -71,6 +71,8 @@ class MycobotTopics(object): rospy.init_node("mycobot_topics") rospy.loginfo("start ...") port = rospy.get_param("~port", os.popen("ls /dev/ttyUSB*").readline()[:-1]) + if not port: + port = rospy.get_param("~port", os.popen("ls /dev/ttyACM*").readline()[:-1]) baud = rospy.get_param("~baud", 115200) rospy.loginfo("%s,%s" % (port, baud)) self.mc = MyCobot(port, baud) diff --git a/mycobot_ai/ai_mecharm_270/launch/vision_wio.launch b/mycobot_ai/ai_mecharm_270/launch/vision_wio.launch index 51eb78b..6b6f132 100644 --- a/mycobot_ai/ai_mecharm_270/launch/vision_wio.launch +++ b/mycobot_ai/ai_mecharm_270/launch/vision_wio.launch @@ -2,8 +2,8 @@ - - + + @@ -14,13 +14,13 @@ - + - + diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py new file mode 100644 index 0000000..ec46a57 --- /dev/null +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py @@ -0,0 +1,493 @@ +#!/usr/bin/env python2 +# -*- coding:utf-8 -*- +import cv2 +import numpy as np +import time +import os,sys +import rospy +from visualization_msgs.msg import Marker +from pymycobot.mycobot import MyCobot +from moving_utils import Movement + + +IS_CV_4 = cv2.__version__[0] == '4' +__version__ = "1.0" +# Adaptive seeed + + +class Object_detect(Movement): + + def __init__(self, camera_x = 140, camera_y = 5): # m5 + # def __init__(self, camera_x = 140, camera_y = -5): # pi + # inherit the parent class + super(Object_detect, self).__init__() + # get path of file + dir_path = os.path.dirname(__file__) + + # declare 270 + self.mc = None + + # 移动角度 + self.move_angles = [ + [0, 0, 0, 0, 90, 0], # point to grab + [-33.31, 2.02, -10.72, -0.08, 95, -54.84], # init the point + ] + + # 移动坐标 + self.move_coords = [ + [92.3, -104.9, 211.4, -179.6, 28.91, 131.29], # above the red bucket + [165.0, -93.6, 201.4, -173.43, 46.23, 160.65], # above the green bucket + [88.1, 126.3, 193.4, 162.15, 2.23, 156.02], # above the blue bucket + [-5.4, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket + ] + + # which robot: USB* is m5; ACM* is wio; AMA* is raspi + self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] + self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] + self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] + self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] + self.raspi = False + if "dev" in self.robot_m5: + self.Pin = [2, 5] + # self.Pin = [5] + elif "dev" in self.robot_wio: + # self.Pin = [20, 21] + self.Pin = [2, 5] + for i in self.move_coords: + i[2] -= 20 + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + import RPi.GPIO as GPIO + GPIO.setwarnings(False) + self.GPIO = GPIO + GPIO.setmode(GPIO.BCM) + GPIO.setup(20, GPIO.OUT) + GPIO.setup(21, GPIO.OUT) + GPIO.output(20, 1) + GPIO.output(21, 1) + self.raspi = True + if self.raspi: + self.gpio_status(False) + # choose place to set cube + self.color = 0 + # parameters to calculate camera clipping parameters + self.x1 = self.x2 = self.y1 = self.y2 = 0 + # set cache of real coord + self.cache_x = self.cache_y = 0 + # set color HSV + self.HSV = { + "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], + "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], + "green": [np.array([35, 43, 46]), np.array([77, 255, 255])], + "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], + "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], + } + # use to calculate coord between cube and 270 + self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 + # The coordinates of the grab center point relative to the 270 + self.camera_x, self.camera_y = camera_x, camera_y + # The coordinates of the cube relative to the 270 + self.c_x, self.c_y = 0, 0 + # The ratio of pixels to actual values + self.ratio = 0 + # Get ArUco marker dict that can be detected. + self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) + # Get ArUco marker params. + self.aruco_params = cv2.aruco.DetectorParameters_create() + + # init a node and a publisher + rospy.init_node("marker", anonymous=True) + self.pub = rospy.Publisher('/cube', Marker, queue_size=1) + # init a Marker + self.marker = Marker() + self.marker.header.frame_id = "/joint1" + self.marker.ns = "cube" + self.marker.type = self.marker.CUBE + self.marker.action = self.marker.ADD + self.marker.scale.x = 0.04 + self.marker.scale.y = 0.04 + self.marker.scale.z = 0.04 + self.marker.color.a = 1.0 + self.marker.color.g = 1.0 + self.marker.color.r = 1.0 + + # marker position initial + self.marker.pose.position.x = 0 + self.marker.pose.position.y = 0 + self.marker.pose.position.z = 0.03 + self.marker.pose.orientation.x = 0 + self.marker.pose.orientation.y = 0 + self.marker.pose.orientation.z = 0 + self.marker.pose.orientation.w = 1.0 + + # publish marker + def pub_marker(self, x, y, z=0.03): + self.marker.header.stamp = rospy.Time.now() + self.marker.pose.position.x = x + self.marker.pose.position.y = y + self.marker.pose.position.z = z + self.marker.color.g = self.color + self.pub.publish(self.marker) + + # pump_control pi + def gpio_status(self, flag): + if flag: + # self.GPIO.output(20, 0) + self.GPIO.output(21, 0) + else: + # self.GPIO.output(20, 1) + self.GPIO.output(21, 1) + + # 开启吸泵 m5 + def pump_on(self): + # 让2号位工作 + # self.mc.set_basic_output(2, 0) + # 让5号位工作 + self.mc.set_basic_output(5, 0) + + # 停止吸泵 m5 + def pump_off(self): + # 让2号位停止工作 + # self.mc.set_basic_output(2, 1) + # 让5号位停止工作 + self.mc.set_basic_output(5, 1) + + # Grasping motion + def move(self, x, y, color): + # send Angle to move 270 + print(color) + self.mc.send_angles(self.move_angles[0], 30) + time.sleep(4) + + # send coordinates to move 270 + self.mc.send_coords([x, y, 140, 179.12, -0.18, 179.46], 30, 0) + time.sleep(3) + self.pub_marker(x/1000.0, y/1000.0, 140/1000.0) + + + self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 + # self.mc.send_coords([x, y, 90, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi + time.sleep(3) + self.pub_marker(x/1000.0, y/1000.0, 90/1000.0) + + + # open pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_on() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(True) + time.sleep(1.5) + + tmp = [] + while True: + if not tmp: + tmp = self.mc.get_angles() + else: + break + time.sleep(0.5) + + # print(tmp) + self.mc.send_angles([tmp[0], 17.22, -32.51, tmp[3], 97, tmp[5]],30) + time.sleep(3) + + + + self.mc.send_coords(self.move_coords[color], 30, 1) + self.pub_marker(self.move_coords[color][0]/1000.0, + self.move_coords[color][1]/1000.0, + self.move_coords[color][2]/1000.0) + time.sleep(3) + + # close pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_off() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(False) + time.sleep(6) + + if color == 1: + self.pub_marker( + self.move_coords[color][0]/1000.0+0.04, self.move_coords[color][1]/1000.0-0.02) + elif color == 0: + self.pub_marker( + self.move_coords[color][0]/1000.0+0.03, self.move_coords[color][1]/1000.0) + + self.mc.send_angles(self.move_angles[1], 30) + time.sleep(1.5) + + # decide whether grab cube + def decide_move(self, x, y, color): + print(x, y, self.cache_x, self.cache_y) + # detect the cube status move or run + if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm + self.cache_x, self.cache_y = x, y + return + else: + self.cache_x = self.cache_y = 0 + # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 + self.move(x, y, color) + + # init 270 + def run(self): + if "dev" in self.robot_m5: + self.mc = MyCobot(self.robot_m5, 115200) + elif "dev" in self.robot_wio: + self.mc = MyCobot(self.robot_wio, 115200) + elif "dev" in self.robot_raspi: + self.mc = MyCobot(self.robot_raspi, 1000000) + if not self.raspi: + self.pub_pump(False, self.Pin) + self.mc.send_angles([-33.31, 2.02, -10.72, -0.08, 95, -54.84], 30) + time.sleep(3) + + # draw aruco + def draw_marker(self, img, x, y): + # draw rectangle on img + cv2.rectangle( + img, + (x - 20, y - 20), + (x + 20, y + 20), + (0, 255, 0), + thickness=2, + lineType=cv2.FONT_HERSHEY_COMPLEX, + ) + # add text on rectangle + cv2.putText(img, "({},{})".format(x, y), (x, y), + cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (243, 0, 0), 2,) + + # get points of two aruco + def get_calculate_params(self, img): + # Convert the image to a gray image + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + # Detect ArUco marker. + corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( + gray, self.aruco_dict, parameters=self.aruco_params + ) + + """ + Two Arucos must be present in the picture and in the same order. + There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. + Determine the center of the aruco by the four corners of the aruco. + """ + if len(corners) > 0: + if ids is not None: + if len(corners) <= 1 or ids[0] == 1: + return None + x1 = x2 = y1 = y2 = 0 + point_11, point_21, point_31, point_41 = corners[0][0] + x1, y1 = int((point_11[0] + point_21[0] + point_31[0] + point_41[0]) / 4.0), int( + (point_11[1] + point_21[1] + point_31[1] + point_41[1]) / 4.0) + point_1, point_2, point_3, point_4 = corners[1][0] + x2, y2 = int((point_1[0] + point_2[0] + point_3[0] + point_4[0]) / 4.0), int( + (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / 4.0) + return x1, x2, y1, y2 + return None + + # set camera clipping parameters + def set_cut_params(self, x1, y1, x2, y2): + self.x1 = int(x1) + self.y1 = int(y1) + self.x2 = int(x2) + self.y2 = int(y2) + print(self.x1, self.y1, self.x2, self.y2) + + # set parameters to calculate the coords between cube and 270 + def set_params(self, c_x, c_y, ratio): + self.c_x = c_x + self.c_y = c_y + self.ratio = 220.0/ratio + + # calculate the coords between cube and 270 + def get_position(self, x, y): + return ((y - self.c_y)*self.ratio + self.camera_x), ((x - self.c_x)*self.ratio + self.camera_y) + + """ + Calibrate the camera according to the calibration parameters. + Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. + If two ARuco values have been calculated, clip the video. + """ + def transform_frame(self, frame): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), fx=fx, fy=fy, + interpolation=cv2.INTER_CUBIC) + if self.x1 != self.x2: + # the cutting ratio here is adjusted according to the actual situation + frame = frame[int(self.y2*0.78):int(self.y1*1.1), + int(self.x1*0.86):int(self.x2*1.08)] + return frame + + # detect cube color + def color_detect(self, img): + # set the arrangement of color'HSV + x = y = 0 + for mycolor, item in self.HSV.items(): + # print("mycolor:",mycolor) + redLower = np.array(item[0]) + redUpper = np.array(item[1]) + + # transfrom the img to model of gray + hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + # print("hsv",hsv) + + # wipe off all color expect color in range + mask = cv2.inRange(hsv, item[0], item[1]) + + # a etching operation on a picture to remove edge roughness + erosion = cv2.erode(mask, np.ones((1, 1), np.uint8), iterations=2) + + # the image for expansion operation, its role is to deepen the color depth in the picture + dilation = cv2.dilate(erosion, np.ones( + (1, 1), np.uint8), iterations=2) + + # adds pixels to the image + target = cv2.bitwise_and(img, img, mask=dilation) + + # the filtered image is transformed into a binary image and placed in binary + ret, binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY) + + # get the contour coordinates of the image, where contours is the coordinate value, here only the contour is detected + contours, hierarchy = cv2.findContours( + dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + if len(contours) > 0: + # do something about misidentification + boxes = [ + box + for box in [cv2.boundingRect(c) for c in contours] + if min(img.shape[0], img.shape[1]) / 10 + < min(box[2], box[3]) + < min(img.shape[0], img.shape[1]) / 1 + ] + if boxes: + for box in boxes: + x, y, w, h = box + # find the largest object that fits the requirements + c = max(contours, key=cv2.contourArea) + # get the lower left and upper right points of the positioning object + x, y, w, h = cv2.boundingRect(c) + # locate the target by drawing rectangle + cv2.rectangle(img, (x, y), (x+w, y+h), (153, 153, 0), 2) + # calculate the rectangle center + x, y = (x*2+w)/2, (y*2+h)/2 + # calculate the real coordinates of 270 relative to the target + + if mycolor == "red": + self.color = 0 + elif mycolor == "green": + self.color = 1 + elif mycolor == "cyan": + self.color = 2 + else: + self.color = 3 + + if abs(x) + abs(y) > 0: + return x, y + else: + return None + +if __name__ == "__main__": + + # open the camera + cap_num = 0 + cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) + if not cap.isOpened(): + cap.open() + # init a class of Object_detect + detect = Object_detect() + # init 270 + detect.run() + + _init_ = 20 + init_num = 0 + nparams = 0 + num = 0 + real_sx = real_sy = 0 + while cv2.waitKey(1) < 0: + # read camera + _, frame = cap.read() + # deal img + frame = detect.transform_frame(frame) + if _init_ > 0: + _init_ -= 1 + continue + + # calculate the parameters of camera clipping + if init_num < 20: + if detect.get_calculate_params(frame) is None: + cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + init_num += 1 + continue + elif init_num == 20: + detect.set_cut_params( + (detect.sum_x1)/20.0, + (detect.sum_y1)/20.0, + (detect.sum_x2)/20.0, + (detect.sum_y2)/20.0, + ) + detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 + init_num += 1 + continue + + # calculate params of the coords between cube and 270 + if nparams < 10: + if detect.get_calculate_params(frame) is None: + cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + nparams += 1 + continue + elif nparams == 10: + nparams += 1 + # calculate and set params of calculating real coord between cube and 270 + detect.set_params( + (detect.sum_x1+detect.sum_x2)/20.0, + (detect.sum_y1+detect.sum_y2)/20.0, + abs(detect.sum_x1-detect.sum_x2)/10.0 + + abs(detect.sum_y1-detect.sum_y2)/10.0 + ) + print("ok") + continue + + # get detect result + detect_result = detect.color_detect(frame) + if detect_result is None: + cv2.imshow("figure", frame) + continue + else: + x, y = detect_result + # calculate real coord between cube and 270 + real_x, real_y = detect.get_position(x, y) + if num == 20: + detect.pub_marker(real_sx/20.0/1000.0, real_sy/20.0/1000.0) + detect.decide_move(real_sx/20.0, real_sy/20.0, detect.color) + num = real_sx = real_sy = 0 + + else: + num += 1 + real_sy += real_y + real_sx += real_x + + cv2.imshow("figure", frame) + + # close the window + if cv2.waitKey(1) & 0xFF == ord('q'): + cap.release() + cv2.destroyAllWindows() + sys.exit() \ No newline at end of file diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py new file mode 100644 index 0000000..f2bc2c1 --- /dev/null +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py @@ -0,0 +1,644 @@ +#!/usr/bin/env python2 +# encoding:utf-8 +from multiprocessing import Process, Pipe +import cv2 +import numpy as np +import time +import os,sys +import rospy +from visualization_msgs.msg import Marker +from moving_utils import Movement +from pymycobot.mycobot import MyCobot + +IS_CV_4 = cv2.__version__[0] == '4' +__version__ = "1.0" # Adaptive seeed + + +class Object_detect(Movement): + + def __init__(self, camera_x = 145, camera_y = -5): + # inherit the parent class + super(Object_detect, self).__init__() + # get path of file + dir_path = os.path.dirname(__file__) + + # declare 270 + self.mc = None + # 移动角度 + self.move_angles = [ + [0, 0, 0, 0, 90, 0], # point to grab + [-33.31, 2.02, -10.72, -0.08, 95, -54.84], # init the point + ] + + # 移动坐标 + self.move_coords = [ + [92.3, -104.9, 211.4, -179.6, 28.91, 131.29], # above the red bucket + [165.0, -93.6, 201.4, -173.43, 46.23, 160.65], # above the green bucket + [88.1, 126.3, 193.4, 162.15, 2.23, 156.02], # above the blue bucket + [-5.4, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket + ] + + # 判断连接设备:ttyUSB*为M5,ttyACM*为seeed + self.raspi = False + self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] + self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] + self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] + self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] + if "dev" in self.robot_m5: + self.Pin = [2, 5] + elif "dev" in self.robot_wio: + # self.Pin = [20, 21] + self.Pin = [2, 5] + for i in self.move_coords: + i[2] -= 20 + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + import RPi.GPIO as GPIO + GPIO.setwarnings(False) + self.GPIO = GPIO + GPIO.setmode(GPIO.BCM) + GPIO.setup(20, GPIO.OUT) + GPIO.setup(21, GPIO.OUT) + GPIO.output(20, 1) + GPIO.output(21, 1) + self.raspi = True + if self.raspi: + self.gpio_status(False) + + # choose place to set cube + self.color = 0 + # parameters to calculate camera clipping parameters + self.x1 = self.x2 = self.y1 = self.y2 = 0 + # set cache of real coord + self.cache_x = self.cache_y = 0 + + # use to calculate coord between cube and mycobot + self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 + # The coordinates of the grab center point relative to the mycobot + self.camera_x, self.camera_y = camera_x, camera_y + # The coordinates of the cube relative to the mycobot + self.c_x, self.c_y = 0, 0 + # The ratio of pixels to actual values + self.ratio = 0 + # Get ArUco marker dict that can be detected. + self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) + # Get ArUco marker params. + self.aruco_params = cv2.aruco.DetectorParameters_create() + + # init a node and a publisher + rospy.init_node("marker", anonymous=True) + self.pub = rospy.Publisher('/cube', Marker, queue_size=1) + # init a Marker + self.marker = Marker() + self.marker.header.frame_id = "/joint1" + self.marker.ns = "cube" + self.marker.type = self.marker.CUBE + self.marker.action = self.marker.ADD + self.marker.scale.x = 0.04 + self.marker.scale.y = 0.04 + self.marker.scale.z = 0.04 + self.marker.color.a = 1.0 + self.marker.color.g = 1.0 + self.marker.color.r = 1.0 + + # marker position initial + self.marker.pose.position.x = 0 + self.marker.pose.position.y = 0 + self.marker.pose.position.z = 0.03 + self.marker.pose.orientation.x = 0 + self.marker.pose.orientation.y = 0 + self.marker.pose.orientation.z = 0 + self.marker.pose.orientation.w = 1.0 + + self.cache_x = self.cache_y = 0 + + # publish marker + def pub_marker(self, x, y, z=0.03): + self.marker.header.stamp = rospy.Time.now() + self.marker.pose.position.x = x + self.marker.pose.position.y = y + self.marker.pose.position.z = z + self.marker.color.g = self.color + self.pub.publish(self.marker) + + # pump_control pi + def gpio_status(self, flag): + if flag: + # self.GPIO.output(20, 0) + self.GPIO.output(21, 0) + else: + # self.GPIO.output(20, 1) + self.GPIO.output(21, 1) + + # 开启吸泵 m5 + def pump_on(self): + # 让2号位工作 + # self.mc.set_basic_output(2, 0) + # 让5号位工作 + self.mc.set_basic_output(5, 0) + + # 停止吸泵 m5 + def pump_off(self): + # 让2号位停止工作 + # self.mc.set_basic_output(2, 1) + # 让5号位停止工作 + self.mc.set_basic_output(5, 1) + + # Grasping motion + def move(self, x, y, color): + # send Angle to move 270 + self.mc.send_angles(self.move_angles[0], 30) + time.sleep(7) + + print("x %s ,y %s" % (x,y)) + # send coordinates to move 270 根据不同底板机械臂,调整吸泵高度 + self.mc.send_coords([x, y, 140, 179.12, -0.18, 179.46], 30, 0) + time.sleep(7) + print("ntm") + + self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 + # self.mc.send_coords([x, y, 90, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi + # self.mc.send_coords([x, y, 92, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 + time.sleep(6) + + # open pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_on() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(True) + time.sleep(1.5) + + tmp = [] + while True: + if not tmp: + tmp = self.mc.get_angles() + else: + break + time.sleep(0.5) + + # print(tmp) + self.mc.send_angles([tmp[0], 17.22, -32.51, tmp[3], 97, tmp[5]],30) + time.sleep(6) + + + self.mc.send_coords(self.move_coords[color], 30, 1) + self.pub_marker(self.move_coords[color][0] / 1000.0, + self.move_coords[color][1] / 1000.0, + self.move_coords[color][2] / 1000.0) + time.sleep(6) + + # close pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_off() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(False) + time.sleep(6) + + self.mc.send_angles(self.move_angles[1], 30) + time.sleep(6) + + # decide whether grab cube + def decide_move(self, x, y, color): + print(x, y, self.cache_x, self.cache_y) + # detect the cube status move or run + if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm + self.cache_x, self.cache_y = x, y + return + else: + self.cache_x = self.cache_y = 0 + # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 + self.move(x, y, color) + + # init 270 + def run(self): + if "dev" in self.robot_wio : + self.mc = MyCobot(self.robot_wio, 115200) + elif "dev" in self.robot_m5: + self.mc = MyCobot(self.robot_m5, 115200) + elif "dev" in self.robot_raspi: + self.mc = MyCobot(self.robot_raspi, 1000000) + if not self.raspi: + self.pub_pump(False, self.Pin) + self.mc.send_angles([-33.31, 2.02, -10.72, -0.08, 95, -54.84], 30) + time.sleep(3) + + # draw aruco + def draw_marker(self, img, x, y): + # draw rectangle on img + cv2.rectangle( + img, + (x - 20, y - 20), + (x + 20, y + 20), + (0, 255, 0), + thickness=2, + lineType=cv2.FONT_HERSHEY_COMPLEX, + ) + # add text on rectangle + cv2.putText( + img, + "({},{})".format(x, y), + (x, y), + cv2.FONT_HERSHEY_COMPLEX_SMALL, + 1, + (243, 0, 0), + 2, + ) + + # get points of two aruco + def get_calculate_params(self, img): + # Convert the image to a gray image + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + # Detect ArUco marker. + corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( + gray, self.aruco_dict, parameters=self.aruco_params) + + """ + Two Arucos must be present in the picture and in the same order. + There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. + Determine the center of the aruco by the four corners of the aruco. + """ + if len(corners) > 0: + if ids is not None: + if len(corners) <= 1 or ids[0] == 1: + return None + x1 = x2 = y1 = y2 = 0 + point_11, point_21, point_31, point_41 = corners[0][0] + x1, y1 = int( + (point_11[0] + point_21[0] + point_31[0] + point_41[0]) / + 4.0), int( + (point_11[1] + point_21[1] + point_31[1] + point_41[1]) + / 4.0) + point_1, point_2, point_3, point_4 = corners[1][0] + x2, y2 = int( + (point_1[0] + point_2[0] + point_3[0] + point_4[0]) / + 4.0), int( + (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / + 4.0) + return x1, x2, y1, y2 + return None + + # set camera clipping parameters + def set_cut_params(self, x1, y1, x2, y2): + self.x1 = int(x1) + self.y1 = int(y1) + self.x2 = int(x2) + self.y2 = int(y2) + print(self.x1, self.y1, self.x2, self.y2) + + # set parameters to calculate the coords between cube and mycobot + def set_params(self, c_x, c_y, ratio): + self.c_x = c_x + self.c_y = c_y + self.ratio = 220.0 / ratio + + # calculate the coords between cube and mycobot + def get_position(self, x, y): + return ((y - self.c_y) * self.ratio + + self.camera_x), ((x - self.c_x) * self.ratio + self.camera_y) + + """ + Calibrate the camera according to the calibration parameters. + Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. + If two ARuco values have been calculated, clip the video. + """ + + def transform_frame(self, frame): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), + fx=fx, + fy=fy, + interpolation=cv2.INTER_CUBIC) + if self.x1 != self.x2: + # the cutting ratio here is adjusted according to the actual situation + frame = frame[int(self.y2 * 0.2):int(self.y1 * 1.15), + int(self.x1 * 0.7):int(self.x2 * 1.15)] + return frame + + # according the class_id to get object name + def id_class_name(self, class_id): + for key, value in self.labels.items(): + if class_id == int(key): + return value + + # detect object + def obj_detect(self, img, goal, kp_img, desc_img, kp_list, desc_list, connection): + i = 0 + MIN_MATCH_COUNT = 5 + # sift = cv2.xfeatures2d.SIFT_create() + + # find the keypoints and descriptors with SIFT + # kp = [] + # des = [] + kp = kp_list + des = desc_list + + # for i in goal: + # kp0, des0 = sift.detectAndCompute(i, None) + # kp.append(kp0) + # des.append(des0) + + # kp1, des1 = sift.detectAndCompute(goal, None) + # kp2, des2 = sift.detectAndCompute(img, None) + kp2, des2 = kp_img, desc_img + + # FLANN parameters + FLANN_INDEX_KDTREE = 0 + index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) + search_params = dict(checks=50) # or pass empty dictionary + flann = cv2.FlannBasedMatcher(index_params, search_params) + + x, y = 0, 0 + try: + for i in range(len(des)): + matches = flann.knnMatch(des[i], des2, k=2) + # store all the good matches as per Lowe's ratio test. 根据Lowe比率测试存储所有良好匹配项。 + good = [] + for m, n in matches: + if m.distance < 0.7 * n.distance: + good.append(m) + + # When there are enough robust matching point pairs 当有足够的健壮匹配点对(至少个MIN_MATCH_COUNT)时 + if len(good) > MIN_MATCH_COUNT: + + # extract corresponding point pairs from matching 从匹配中提取出对应点对 + # query index of small objects, training index of scenarios 小对象的查询索引,场景的训练索引 + src_pts = np.float32([kp[i][m.queryIdx].pt + for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([kp2[m.trainIdx].pt + for m in good]).reshape(-1, 1, 2) + + # Using matching points to find homography matrix in cv2.ransac 利用匹配点找到CV2.RANSAC中的单应矩阵 + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, + 5.0) + matchesMask = mask.ravel().tolist() + # Calculate the distortion of image, that is the corresponding position in frame 计算图1的畸变,也就是在图2中的对应的位置 + h, w, d = goal[i].shape + pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], + [w - 1, 0]]).reshape(-1, 1, 2) + dst = cv2.perspectiveTransform(pts, M) + coord = (dst[0][0] + dst[1][0] + dst[2][0] + + dst[3][0]) / 4.0 + connection.send((DRAW_COORDS, coord)) + # cv2.putText(img, "{}".format(coord), (50, 60), + # fontFace=None, fontScale=1, + # color=(0, 255, 0), lineType=1) + print(format(dst[0][0][0])) + x = (dst[0][0][0] + dst[1][0][0] + dst[2][0][0] + + dst[3][0][0]) / 4.0 + y = (dst[0][0][1] + dst[1][0][1] + dst[2][0][1] + + dst[3][0][1]) / 4.0 + + # bound box 绘制边框 + # img = cv2.polylines(img, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) + connection.send((DRAW_RECT, dst)) + # cv2.polylines(mixture, [np.int32(dst)], True, (0, 255, 0), 2, cv2.LINE_AA) + except Exception as e: + pass + + if x + y > 0: + return x, y + else: + return None + +# The path to save the image folder +def parse_folder(folder): + restore = [] + # path = '' + path1 = '/home/ubuntu/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mecharm_270/' + folder + path2 = '/home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mecharm_270/' + folder + + if os.path.exists(path1): + path = path1 + elif os.path.exists(path2): + path = path2 + + # print("path:",path) + for i, j, k in os.walk(path): + for l in k: + restore.append(cv2.imread(folder + '/{}'.format(l))) + return restore + +def compute_keypoints_and_descriptors(sift, images_lists): + kp_list = [] + desc_list = [] + for images in images_lists: + kp_tmp = [] + desc_tmp = [] + for img in images: + kp, desc = sift.detectAndCompute(img, None) + kp_tmp.append(kp) + desc_tmp.append(desc) + kp_list.append(kp_tmp) + desc_list.append(desc_tmp) + + return kp_list, desc_list + +GET_FRAME = 1 +STOP_PROCESSING = 2 +DRAW_COORDS = 3 +DRAW_RECT = 4 +CLEAR_DRAW = 5 +CROP_FRAME = 6 + +def get_frame(connection): + connection.send(GET_FRAME) + frame = connection.recv() + return frame + +def process_transform_frame(frame, x1, y1, x2, y2): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), + fx=fx, + fy=fy, + interpolation=cv2.INTER_CUBIC) +# if x1 != x2: + # the cutting ratio here is adjusted according to the actual situation +# frame = frame[int(y2 * 0.2):int(y1 * 1.15), +# int(x1 * 0.7):int(x2 * 1.15)] + return frame + +def process_display_frame(connection): + cap_num = 0 + coord = None + dst = None + x1 = 0 + y1 = 0 + x2 = 0 + y2 = 0 + cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) + if not cap.isOpened(): + cap.open() + while cv2.waitKey(1) < 0: + _, frame = cap.read() + frame = process_transform_frame(frame, x1, y1, x2, y2) + if connection.poll(): + request = connection.recv() + if request == GET_FRAME: + connection.send(frame) + elif request == CLEAR_DRAW: + coord = None + dst = None + elif type(request) is tuple: + if request[0] == DRAW_COORDS: + coord = request[1] + elif request[0] == DRAW_RECT: + dst = request[1] + elif request[0] == CROP_FRAME: + x1 = request[1] + y1 = request[2] + x2 = request[3] + y2 = request[4] + + if not coord is None: + cv2.putText(frame, "{}".format(coord), (50, 60), fontFace=None, + fontScale=1, color=(0, 255, 0), lineType=1) + if not dst is None: + frame = cv2.polylines(frame, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) + cv2.imshow("figure", frame) + time.sleep(0.04) + connection.send(STOP_PROCESSING) + +def run(): + parent_conn, child_conn = Pipe() + child = Process(target = process_display_frame, args=(child_conn,)) + child.start() + + res_queue = [[], [], [], []] + res_queue[0] = parse_folder('res/red') + res_queue[1] = parse_folder('res/green') + res_queue[2] = parse_folder('res/blue') + res_queue[3] = parse_folder('res/gray') + + + sift = cv2.xfeatures2d.SIFT_create() + kp_list, desc_list = compute_keypoints_and_descriptors(sift, res_queue) + + # init a class of Object_detect + detect = Object_detect() + + # init mycobot + detect.run() + + # _init_ = 20 # + init_num = 0 + nparams = 0 + # num = 0 + # real_sx = real_sy = 0 + while True: + start_time = time.time() + if parent_conn.poll(): + data = parent_conn.recv() + if data == STOP_PROCESSING: + break + # read camera + frame = get_frame(parent_conn) + # deal img + #frame = detect.transform_frame(frame) + + # if _init_ > 0: + # _init_ -= 1 + # continue + # calculate the parameters of camera clipping + if init_num < 20: + if detect.get_calculate_params(frame) is None: + # cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + init_num += 1 + continue + elif init_num == 20: + detect.set_cut_params( + (detect.sum_x1) / 20.0, + (detect.sum_y1) / 20.0, + (detect.sum_x2) / 20.0, + (detect.sum_y2) / 20.0, + ) + parent_conn.send((CROP_FRAME, + (detect.sum_x1) / 20.0, + (detect.sum_y1) / 20.0, + (detect.sum_x2) / 20.0, + (detect.sum_y2) / 20.0)) + detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 + init_num += 1 + continue + + # calculate params of the coords between cube and mycobot + if nparams < 10: + if detect.get_calculate_params(frame) is None: + # cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + nparams += 1 + print ("ok") + continue + elif nparams == 10: + nparams += 1 + # calculate and set params of calculating real coord between cube and mycobot + detect.set_params((detect.sum_x1 + detect.sum_x2) / 20.0, + (detect.sum_y1 + detect.sum_y2) / 20.0, + abs(detect.sum_x1 - detect.sum_x2) / 10.0 + + abs(detect.sum_y1 - detect.sum_y2) / 10.0) + print("ok") + continue + + # get detect result + kp_img, desc_img = sift.detectAndCompute(frame, None) + frame = get_frame(parent_conn) + for i, v in enumerate(res_queue): + # HACK: to update frame every time + detect_result = detect.obj_detect(frame, v, kp_img, desc_img, kp_list[i], desc_list[i], parent_conn) + if detect_result: + x, y = detect_result + # calculate real coord between cube and mycobot + real_x, real_y = detect.get_position(x, y) + detect.color = i + detect.pub_marker(real_x / 1000.0, real_y / 1000.0) + detect.decide_move(real_x, real_y, detect.color) + # if num == 5: + # detect.color = i + # detect.pub_marker(real_sx / 5.0 / 1000.0, + # real_sy / 5.0 / 1000.0) + # detect.decide_move(real_sx / 5.0, real_sy / 5.0, + # detect.color) + # num = real_sx = real_sy = 0 + # else: + # num += 1 + # real_sy += real_y + # real_sx += real_x + parent_conn.send(CLEAR_DRAW) + + # cv2.imshow("figure", frame) + time.sleep(0.05) + end_time = time.time() + print("loop_time = ", end_time - start_time) + + # close the window + if cv2.waitKey(1) & 0xFF == ord('q'): + # cap.release() + cv2.destroyAllWindows() + sys.exit() + + child.join() + + +if __name__ == "__main__": + run() + # Object_detect().take_photo() + # Object_detect().cut_photo() diff --git a/mycobot_ai/ai_mycobot_280/res/blue/goal9.jpeg b/mycobot_ai/ai_mycobot_280/res/blue/goal9.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3eaf44f4207b6dc74c1fd61ab2ee18e9e1870a15 GIT binary patch literal 3533 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 HFvtG|JlUUL literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mycobot_280/res/gray/goal10.jpeg b/mycobot_ai/ai_mycobot_280/res/gray/goal10.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..df419e2d177a462d960b3fc2f80bc328a1c3f138 GIT binary patch literal 3416 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 literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mycobot_280/res/green/goal12.jpeg b/mycobot_ai/ai_mycobot_280/res/green/goal12.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..19f703f7559bb49e516cc4f58fca5b7da7f243e7 GIT binary patch literal 3572 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 literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mycobot_280/res/red/goal8.jpeg b/mycobot_ai/ai_mycobot_280/res/red/goal8.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e8dfcbb8e6afbc3972062ce2a3197aa8e2ecf089 GIT binary patch literal 4012 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 literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mycobot_280/res/takephoto.jpeg b/mycobot_ai/ai_mycobot_280/res/takephoto.jpeg index 4d761e6edcff945101e6faabbe7de7846586af75..348b385a73f81d87b184a8c1dabf2d8abfc0fa9e 100644 GIT binary patch delta 42344 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�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 z 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 5: # mm + self.cache_x, self.cache_y = x, y + return + else: + self.cache_x = self.cache_y = 0 + # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 + self.move(x, y, color) + + # init mycobot + def run(self): + if "dev" in self.robot_wio : + self.mc = MyCobot(self.robot_wio, 115200) + elif "dev" in self.robot_m5: + self.mc = MyCobot(self.robot_m5, 115200) + elif "dev" in self.robot_raspi: + self.mc = MyCobot(self.robot_raspi, 1000000) + if not self.raspi: + self.pub_pump(False, self.Pin) + self.mc.send_angles([-7.11, -6.94, -55.01, -24.16, 0, -15], 20) + time.sleep(3) + + # draw aruco + + def draw_marker(self, img, x, y): + # draw rectangle on img + cv2.rectangle( + img, + (x - 20, y - 20), + (x + 20, y + 20), + (0, 255, 0), + thickness=2, + lineType=cv2.FONT_HERSHEY_COMPLEX, + ) + # add text on rectangle + cv2.putText(img, "({},{})".format(x, y), (x, y), + cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (243, 0, 0), 2,) + + # get points of two aruco + def get_calculate_params(self, img): + # Convert the image to a gray image + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + # Detect ArUco marker. + corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( + gray, self.aruco_dict, parameters=self.aruco_params + ) + + """ + Two Arucos must be present in the picture and in the same order. + There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. + Determine the center of the aruco by the four corners of the aruco. + """ + if len(corners) > 0: + if ids is not None: + if len(corners) <= 1 or ids[0] == 1: + return None + x1 = x2 = y1 = y2 = 0 + point_11, point_21, point_31, point_41 = corners[0][0] + x1, y1 = int((point_11[0] + point_21[0] + point_31[0] + point_41[0]) / 4.0), int( + (point_11[1] + point_21[1] + point_31[1] + point_41[1]) / 4.0) + point_1, point_2, point_3, point_4 = corners[1][0] + x2, y2 = int((point_1[0] + point_2[0] + point_3[0] + point_4[0]) / 4.0), int( + (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / 4.0) + return x1, x2, y1, y2 + return None + + # set camera clipping parameters + def set_cut_params(self, x1, y1, x2, y2): + self.x1 = int(x1) + self.y1 = int(y1) + self.x2 = int(x2) + self.y2 = int(y2) + print(self.x1, self.y1, self.x2, self.y2) + + # set parameters to calculate the coords between cube and mycobot + def set_params(self, c_x, c_y, ratio): + self.c_x = c_x + self.c_y = c_y + self.ratio = 220.0/ratio + + # calculate the coords between cube and mycobot + def get_position(self, x, y): + return ((y - self.c_y)*self.ratio + self.camera_x), ((x - self.c_x)*self.ratio + self.camera_y) + + """ + Calibrate the camera according to the calibration parameters. + Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. + If two ARuco values have been calculated, clip the video. + """ + + def transform_frame(self, frame): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), fx=fx, fy=fy, + interpolation=cv2.INTER_CUBIC) + if self.x1 != self.x2: + # the cutting ratio here is adjusted according to the actual situation + frame = frame[int(self.y2*0.78):int(self.y1*1.1), + int(self.x1*0.86):int(self.x2*1.08)] + return frame + + # detect cube color + def color_detect(self, img): + # set the arrangement of color'HSV + x = y = 0 + for mycolor, item in self.HSV.items(): + redLower = np.array(item[0]) + redUpper = np.array(item[1]) + # transfrom the img to model of gray + hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + # wipe off all color expect color in range + mask = cv2.inRange(hsv, item[0], item[1]) + # a etching operation on a picture to remove edge roughness + erosion = cv2.erode(mask, np.ones((1, 1), np.uint8), iterations=2) + # the image for expansion operation, its role is to deepen the color depth in the picture + dilation = cv2.dilate(erosion, np.ones( + (1, 1), np.uint8), iterations=2) + + + # adds pixels to the image + target = cv2.bitwise_and(img, img, mask=dilation) + # the filtered image is transformed into a binary image and placed in binary + ret, binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY) + # get the contour coordinates of the image, where contours is the coordinate value, here only the contour is detected + contours, hierarchy = cv2.findContours( + dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + if len(contours) > 0: + # do something about misidentification + boxes = [ + box + for box in [cv2.boundingRect(c) for c in contours] + if min(img.shape[0], img.shape[1]) / 10 + < min(box[2], box[3]) + < min(img.shape[0], img.shape[1]) / 1 + ] + if boxes: + for box in boxes: + x, y, w, h = box + # find the largest object that fits the requirements + c = max(contours, key=cv2.contourArea) + # get the lower left and upper right points of the positioning object + x, y, w, h = cv2.boundingRect(c) + # locate the target by drawing rectangle + cv2.rectangle(img, (x, y), (x+w, y+h), (153, 153, 0), 2) + # calculate the rectangle center + x, y = (x*2+w)/2, (y*2+h)/2 + # calculate the real coordinates of mycobot relative to the target + if mycolor == "red": + self.color = 0 + + elif mycolor == "green": + self.color = 1 + + elif mycolor == "cyan": + self.color = 2 + + else: + self.color = 3 + + + if abs(x) + abs(y) > 0: + return x, y + else: + return None + + +if __name__ == "__main__": + # open the camera + cap_num = 0 + cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) + + if not cap.isOpened(): + cap.open() + # init a class of Object_detect + detect = Object_detect() + # init mycobot + detect.run() + + _init_ = 20 # + init_num = 0 + nparams = 0 + num = 0 + real_sx = real_sy = 0 + while cv2.waitKey(1) < 0: + # read camera + _, frame = cap.read() + # deal img + frame = detect.transform_frame(frame) + + if _init_ > 0: + _init_ -= 1 + continue + # calculate the parameters of camera clipping + if init_num < 20: + if detect.get_calculate_params(frame) is None: + cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + init_num += 1 + continue + elif init_num == 20: + detect.set_cut_params( + (detect.sum_x1)/20.0, + (detect.sum_y1)/20.0, + (detect.sum_x2)/20.0, + (detect.sum_y2)/20.0, + ) + detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 + init_num += 1 + continue + + # calculate params of the coords between cube and mycobot + if nparams < 10: + if detect.get_calculate_params(frame) is None: + cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + nparams += 1 + continue + elif nparams == 10: + nparams += 1 + # calculate and set params of calculating real coord between cube and mycobot + detect.set_params( + (detect.sum_x1+detect.sum_x2)/20.0, + (detect.sum_y1+detect.sum_y2)/20.0, + abs(detect.sum_x1-detect.sum_x2)/10.0 + + abs(detect.sum_y1-detect.sum_y2)/10.0 + ) + print ("ok") + continue + + # get detect result + detect_result = detect.color_detect(frame) + if detect_result is None: + cv2.imshow("figure", frame) + continue + else: + x, y = detect_result + # calculate real coord between cube and mycobot + real_x, real_y = detect.get_position(x, y) + if num == 20: + detect.pub_marker(real_sx/20.0/1000.0, real_sy/20.0/1000.0) + detect.decide_move(real_sx/20.0, real_sy/20.0, detect.color) + num = real_sx = real_sy = 0 + + else: + num += 1 + real_sy += real_y + real_sx += real_x + + cv2.imshow("figure", frame) diff --git a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py new file mode 100644 index 0000000..68a1432 --- /dev/null +++ b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py @@ -0,0 +1,660 @@ +# encoding:utf-8 +#!/usr/bin/env python2 + +from multiprocessing import Process, Pipe +import cv2 +import numpy as np +import time +import os,sys +import rospy +from visualization_msgs.msg import Marker +from pymycobot.mycobot import MyCobot +from moving_utils import Movement + +IS_CV_4 = cv2.__version__[0] == '4' +__version__ = "1.0" # Adaptive seeed + + +class Object_detect(Movement): + + def __init__(self, camera_x = 155, camera_y = 10): + # inherit the parent class + super(Object_detect, self).__init__() + # get path of file + dir_path = os.path.dirname(__file__) + self.mc = None + + # 移动角度 + self.move_angles = [ + [-7.11, -6.94, -55.01, -24.16, 0, -15], # init the point + [18.8, -7.91, -54.49, -23.02, -0.79, -14.76], # point to grab + ] + + # 移动坐标 + self.move_coords = [ + [132.2, -136.9, 200.8, -178.24, -3.72, -107.17], # above the red bucket + [238.8, -124.1, 204.3, -169.69, -5.52, -96.52], # green + [115.8, 177.3, 210.6, 178.06, -0.92, -6.11], # blue + [-6.9, 173.2, 201.5, 179.93, 0.63, 33.83], # gray + ] + # 判断连接设备:ttyUSB*为M5,ttyACM*为seeed + self.raspi = False + self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] + self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] + self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] + self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] + if "dev" in self.robot_m5: + self.Pin = [2, 5] + elif "dev" in self.robot_wio: + self.Pin = [2, 5] + for i in self.move_coords: + i[2] -= 20 + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + import RPi.GPIO as GPIO + GPIO.setwarnings(False) + self.GPIO = GPIO + GPIO.setmode(GPIO.BCM) + GPIO.setup(20, GPIO.OUT) + GPIO.setup(21, GPIO.OUT) + GPIO.output(20, 1) + GPIO.output(21, 1) + self.raspi = True + if self.raspi: + self.gpio_status(False) + + # choose place to set cube + self.color = 0 + # parameters to calculate camera clipping parameters + self.x1 = self.x2 = self.y1 = self.y2 = 0 + # set cache of real coord + self.cache_x = self.cache_y = 0 + # load model of img recognition + # self.model_path = os.path.join(dir_path, "frozen_inference_graph.pb") + # self.pbtxt_path = os.path.join(dir_path, "graph.pbtxt") + # self.label_path = os.path.join(dir_path, "labels.json") + # # load class labels + # self.labels = json.load(open(self.label_path)) + + # use to calculate coord between cube and mycobot + self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 + # The coordinates of the grab center point relative to the mycobot + self.camera_x, self.camera_y = camera_x, camera_y + # The coordinates of the cube relative to the mycobot + self.c_x, self.c_y = 0, 0 + # The ratio of pixels to actual values + self.ratio = 0 + # Get ArUco marker dict that can be detected. + self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) + # Get ArUco marker params. + self.aruco_params = cv2.aruco.DetectorParameters_create() + + # if IS_CV_4: + # self.net = cv2.dnn.readNetFromTensorflow(self.model_path, self.pbtxt_path) + # else: + # print('Load tensorflow model need the version of opencv is 4.') + # exit(0) + # init a node and a publisher + rospy.init_node("marker", anonymous=True) + self.pub = rospy.Publisher('/cube', Marker, queue_size=1) + # init a Marker + self.marker = Marker() + self.marker.header.frame_id = "/joint1" + self.marker.ns = "cube" + self.marker.type = self.marker.CUBE + self.marker.action = self.marker.ADD + self.marker.scale.x = 0.04 + self.marker.scale.y = 0.04 + self.marker.scale.z = 0.04 + self.marker.color.a = 1.0 + self.marker.color.g = 1.0 + self.marker.color.r = 1.0 + + # marker position initial + self.marker.pose.position.x = 0 + self.marker.pose.position.y = 0 + self.marker.pose.position.z = 0.03 + self.marker.pose.orientation.x = 0 + self.marker.pose.orientation.y = 0 + self.marker.pose.orientation.z = 0 + self.marker.pose.orientation.w = 1.0 + + self.cache_x = self.cache_y = 0 + + # publish marker + def pub_marker(self, x, y, z=0.03): + self.marker.header.stamp = rospy.Time.now() + self.marker.pose.position.x = x + self.marker.pose.position.y = y + self.marker.pose.position.z = z + self.marker.color.g = self.color + self.pub.publish(self.marker) + + def gpio_status(self, flag): + if flag: + # self.GPIO.output(20, 0) + self.GPIO.output(21, 0) + else: + self.GPIO.output(20, 1) + # self.GPIO.output(21, 1) + + # 开启吸泵 m5 + def pump_on(self): + # 让2号位工作 + # self.mc.set_basic_output(2, 0) + # 让5号位工作 + self.mc.set_basic_output(5, 0) + + # 停止吸泵 m5 + def pump_off(self): + # 让2号位停止工作 + # self.mc.set_basic_output(2, 1) + # 让5号位停止工作 + self.mc.set_basic_output(5, 1) + + # Grasping motion + def move(self, x, y, color): + # send Angle to move mycobot + print (color) + self.mc.send_angles(self.move_angles[1], 25) + time.sleep(3) + + # send coordinates to move mycobot + self.mc.send_coords([x, y, 190.6, 179.87, -3.78, -62.75], 25, 1) # usb :rx,ry,rz -173.3, -5.48, -57.9 + time.sleep(3) + + # self.mc.send_coords([x, y, 150, 179.87, -3.78, -62.75], 25, 0) + # time.sleep(3) + + # self.mc.send_coords([x, y, 105, 179.87, -3.78, -62.75], 25, 0) + self.mc.send_coords([x, y, 103, 179.87, -3.78, -62.75], 25, 0) + + time.sleep(3) + + # open pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_on() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(True) + time.sleep(1.5) + + tmp = [] + while True: + if not tmp: + tmp = self.mc.get_angles() + else: + break + time.sleep(0.5) + + # print(tmp) + self.mc.send_angles([tmp[0], -0.71, -54.49, -23.02, -0.79, tmp[5]],25) # [18.8, -7.91, -54.49, -23.02, -0.79, -14.76] + time.sleep(5) + + + + self.mc.send_coords(self.move_coords[color], 25, 1) + self.pub_marker(self.move_coords[color][0]/1000.0, self.move_coords[color] + [1]/1000.0, self.move_coords[color][2]/1000.0) + time.sleep(4) + + # close pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_off() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(False) + time.sleep(4) + + self.mc.send_angles(self.move_angles[0], 25) + time.sleep(3) + + # decide whether grab cube + def decide_move(self, x, y, color): + print(x, y, self.cache_x, self.cache_y) + # detect the cube status move or run + if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm + self.cache_x, self.cache_y = x, y + return + else: + self.cache_x = self.cache_y = 0 + # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 + self.move(x, y, color) + + # init mycobot + def run(self): + if "dev" in self.robot_wio : + self.mc = MyCobot(self.robot_wio, 115200) + elif "dev" in self.robot_m5: + self.mc = MyCobot(self.robot_m5, 115200) + elif "dev" in self.robot_raspi: + self.mc = MyCobot(self.robot_raspi, 1000000) + if not self.raspi: + self.pub_pump(False, self.Pin) + self.mc.send_angles([-7.11, -6.94, -55.01, -24.16, 0, -15], 20) + time.sleep(3) + + # draw aruco + def draw_marker(self, img, x, y): + # draw rectangle on img + cv2.rectangle( + img, + (x - 20, y - 20), + (x + 20, y + 20), + (0, 255, 0), + thickness=2, + lineType=cv2.FONT_HERSHEY_COMPLEX, + ) + # add text on rectangle + cv2.putText( + img, + "({},{})".format(x, y), + (x, y), + cv2.FONT_HERSHEY_COMPLEX_SMALL, + 1, + (243, 0, 0), + 2, + ) + + # get points of two aruco + def get_calculate_params(self, img): + # Convert the image to a gray image + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + # Detect ArUco marker. + corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( + gray, self.aruco_dict, parameters=self.aruco_params) + """ + Two Arucos must be present in the picture and in the same order. + There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. + Determine the center of the aruco by the four corners of the aruco. + """ + if len(corners) > 0: + if ids is not None: + if len(corners) <= 1 or ids[0] == 1: + return None + x1 = x2 = y1 = y2 = 0 + point_11, point_21, point_31, point_41 = corners[0][0] + x1, y1 = int( + (point_11[0] + point_21[0] + point_31[0] + point_41[0]) / + 4.0), int( + (point_11[1] + point_21[1] + point_31[1] + point_41[1]) + / 4.0) + point_1, point_2, point_3, point_4 = corners[1][0] + x2, y2 = int( + (point_1[0] + point_2[0] + point_3[0] + point_4[0]) / + 4.0), int( + (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / + 4.0) + return x1, x2, y1, y2 + return None + + # set camera clipping parameters + def set_cut_params(self, x1, y1, x2, y2): + self.x1 = int(x1) + self.y1 = int(y1) + self.x2 = int(x2) + self.y2 = int(y2) + print(self.x1, self.y1, self.x2, self.y2) + + # set parameters to calculate the coords between cube and mycobot + def set_params(self, c_x, c_y, ratio): + self.c_x = c_x + self.c_y = c_y + self.ratio = 220.0 / ratio + + # calculate the coords between cube and mycobot + def get_position(self, x, y): + return ((y - self.c_y) * self.ratio + + self.camera_x), ((x - self.c_x) * self.ratio + self.camera_y) + + """ + Calibrate the camera according to the calibration parameters. + Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. + If two ARuco values have been calculated, clip the video. + """ + + def transform_frame(self, frame): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), + fx=fx, + fy=fy, + interpolation=cv2.INTER_CUBIC) + if self.x1 != self.x2: + # the cutting ratio here is adjusted according to the actual situation + frame = frame[int(self.y2 * 0.2):int(self.y1 * 1.15), + int(self.x1 * 0.7):int(self.x2 * 1.15)] + return frame + + # according the class_id to get object name + def id_class_name(self, class_id): + for key, value in self.labels.items(): + if class_id == int(key): + return value + + # detect object + def obj_detect(self, img, goal, kp_img, desc_img, kp_list, desc_list, connection): + i = 0 + MIN_MATCH_COUNT = 5 + # sift = cv2.xfeatures2d.SIFT_create() + + # find the keypoints and descriptors with SIFT + # kp = [] + # des = [] + kp = kp_list + des = desc_list + + # for i in goal: + # kp0, des0 = sift.detectAndCompute(i, None) + # kp.append(kp0) + # des.append(des0) + + # kp1, des1 = sift.detectAndCompute(goal, None) + # kp2, des2 = sift.detectAndCompute(img, None) + kp2, des2 = kp_img, desc_img + + # FLANN parameters + FLANN_INDEX_KDTREE = 0 + index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) + search_params = dict(checks=50) # or pass empty dictionary + flann = cv2.FlannBasedMatcher(index_params, search_params) + + x, y = 0, 0 + try: + for i in range(len(des)): + matches = flann.knnMatch(des[i], des2, k=2) + # store all the good matches as per Lowe's ratio test. 根据Lowe比率测试存储所有良好匹配项。 + good = [] + for m, n in matches: + if m.distance < 0.7 * n.distance: + good.append(m) + + # When there are enough robust matching point pairs 当有足够的健壮匹配点对(至少个MIN_MATCH_COUNT)时 + if len(good) > MIN_MATCH_COUNT: + + # extract corresponding point pairs from matching 从匹配中提取出对应点对 + # query index of small objects, training index of scenarios 小对象的查询索引,场景的训练索引 + src_pts = np.float32([kp[i][m.queryIdx].pt + for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([kp2[m.trainIdx].pt + for m in good]).reshape(-1, 1, 2) + + # Using matching points to find homography matrix in cv2.ransac 利用匹配点找到CV2.RANSAC中的单应矩阵 + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, + 5.0) + matchesMask = mask.ravel().tolist() + # Calculate the distortion of image, that is the corresponding position in frame 计算图1的畸变,也就是在图2中的对应的位置 + h, w, d = goal[i].shape + pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], + [w - 1, 0]]).reshape(-1, 1, 2) + dst = cv2.perspectiveTransform(pts, M) + coord = (dst[0][0] + dst[1][0] + dst[2][0] + + dst[3][0]) / 4.0 + connection.send((DRAW_COORDS, coord)) + # cv2.putText(img, "{}".format(coord), (50, 60), + # fontFace=None, fontScale=1, + # color=(0, 255, 0), lineType=1) + print(format(dst[0][0][0])) + x = (dst[0][0][0] + dst[1][0][0] + dst[2][0][0] + + dst[3][0][0]) / 4.0 + y = (dst[0][0][1] + dst[1][0][1] + dst[2][0][1] + + dst[3][0][1]) / 4.0 + + # bound box 绘制边框 + # img = cv2.polylines(img, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) + connection.send((DRAW_RECT, dst)) + # cv2.polylines(mixture, [np.int32(dst)], True, (0, 255, 0), 2, cv2.LINE_AA) + except Exception as e: + pass + + if x + y > 0: + return x, y + else: + return None + +# The path to save the image folder +def parse_folder(folder): + restore = [] + path = '' + path1 = '/home/ubuntu/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/' + folder + path2 = '/home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/' + folder + if os.path.exists(path1): + path = path1 + elif os.path.exists(path2): + path = path2 + + # print("path:",path) + + for i, j, k in os.walk(path): + for l in k: + restore.append(cv2.imread(folder + '/{}'.format(l))) + return restore + +def compute_keypoints_and_descriptors(sift, images_lists): + kp_list = [] + desc_list = [] + for images in images_lists: + kp_tmp = [] + desc_tmp = [] + for img in images: + kp, desc = sift.detectAndCompute(img, None) + kp_tmp.append(kp) + desc_tmp.append(desc) + kp_list.append(kp_tmp) + desc_list.append(desc_tmp) + + return kp_list, desc_list + +GET_FRAME = 1 +STOP_PROCESSING = 2 +DRAW_COORDS = 3 +DRAW_RECT = 4 +CLEAR_DRAW = 5 +CROP_FRAME = 6 + +def get_frame(connection): + connection.send(GET_FRAME) + frame = connection.recv() + return frame + +def process_transform_frame(frame, x1, y1, x2, y2): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), + fx=fx, + fy=fy, + interpolation=cv2.INTER_CUBIC) +# if x1 != x2: + # the cutting ratio here is adjusted according to the actual situation +# frame = frame[int(y2 * 0.2):int(y1 * 1.15), +# int(x1 * 0.7):int(x2 * 1.15)] + return frame + +def process_display_frame(connection): + cap_num = 0 + coord = None + dst = None + x1 = 0 + y1 = 0 + x2 = 0 + y2 = 0 + cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) + if not cap.isOpened(): + cap.open() + while cv2.waitKey(1) < 0: + _, frame = cap.read() + frame = process_transform_frame(frame, x1, y1, x2, y2) + if connection.poll(): + request = connection.recv() + if request == GET_FRAME: + connection.send(frame) + elif request == CLEAR_DRAW: + coord = None + dst = None + elif type(request) is tuple: + if request[0] == DRAW_COORDS: + coord = request[1] + elif request[0] == DRAW_RECT: + dst = request[1] + elif request[0] == CROP_FRAME: + x1 = request[1] + y1 = request[2] + x2 = request[3] + y2 = request[4] + + if not coord is None: + cv2.putText(frame, "{}".format(coord), (50, 60), fontFace=None, + fontScale=1, color=(0, 255, 0), lineType=1) + if not dst is None: + frame = cv2.polylines(frame, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) + cv2.imshow("figure", frame) + time.sleep(0.04) + connection.send(STOP_PROCESSING) + +def run(): + parent_conn, child_conn = Pipe() + child = Process(target = process_display_frame, args=(child_conn,)) + child.start() + + # Object_detect().take_photo() + # Object_detect().cut_photo() + # goal = Object_detect().distinguist() + + res_queue = [[], [], [], []] + res_queue[0] = parse_folder('res/red') + res_queue[1] = parse_folder('res/green') + res_queue[2] = parse_folder('res/blue') + res_queue[3] = parse_folder('res/gray') + + # res_queue = [] + # res_queue.extend(parse_folder('res/red')) + # res_queue.extend(parse_folder('res/green')) + # res_queue.extend(parse_folder('res/gray')) + # res_queue.extend(parse_folder('res/blue')) + + sift = cv2.xfeatures2d.SIFT_create() + kp_list, desc_list = compute_keypoints_and_descriptors(sift, res_queue) + + # init a class of Object_detect + detect = Object_detect() + # init mycobot + detect.run() + + # _init_ = 20 # + init_num = 0 + nparams = 0 + # num = 0 + # real_sx = real_sy = 0 + while True: + start_time = time.time() + if parent_conn.poll(): + data = parent_conn.recv() + if data == STOP_PROCESSING: + break + # read camera + frame = get_frame(parent_conn) + # deal img + #frame = detect.transform_frame(frame) + + # if _init_ > 0: + # _init_ -= 1 + # continue + # calculate the parameters of camera clipping + if init_num < 20: + if detect.get_calculate_params(frame) is None: + # cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + init_num += 1 + continue + elif init_num == 20: + detect.set_cut_params( + (detect.sum_x1) / 20.0, + (detect.sum_y1) / 20.0, + (detect.sum_x2) / 20.0, + (detect.sum_y2) / 20.0, + ) + parent_conn.send((CROP_FRAME, + (detect.sum_x1) / 20.0, + (detect.sum_y1) / 20.0, + (detect.sum_x2) / 20.0, + (detect.sum_y2) / 20.0)) + detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 + init_num += 1 + continue + + # calculate params of the coords between cube and mycobot + if nparams < 10: + if detect.get_calculate_params(frame) is None: + # cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + nparams += 1 + print ("ok") + continue + elif nparams == 10: + nparams += 1 + # calculate and set params of calculating real coord between cube and mycobot + detect.set_params((detect.sum_x1 + detect.sum_x2) / 20.0, + (detect.sum_y1 + detect.sum_y2) / 20.0, + abs(detect.sum_x1 - detect.sum_x2) / 10.0 + + abs(detect.sum_y1 - detect.sum_y2) / 10.0) + print("ok") + continue + + # get detect result + kp_img, desc_img = sift.detectAndCompute(frame, None) + frame = get_frame(parent_conn) + for i, v in enumerate(res_queue): + # HACK: to update frame every time + detect_result = detect.obj_detect(frame, v, kp_img, desc_img, kp_list[i], desc_list[i], parent_conn) + if detect_result: + x, y = detect_result + # calculate real coord between cube and mycobot + real_x, real_y = detect.get_position(x, y) + detect.color = i + detect.pub_marker(real_x / 1000.0, real_y / 1000.0) + detect.decide_move(real_x, real_y, detect.color) + # if num == 5: + # detect.color = i + # detect.pub_marker(real_sx / 5.0 / 1000.0, + # real_sy / 5.0 / 1000.0) + # detect.decide_move(real_sx / 5.0, real_sy / 5.0, + # detect.color) + # num = real_sx = real_sy = 0 + # else: + # num += 1 + # real_sy += real_y + # real_sx += real_x + parent_conn.send(CLEAR_DRAW) + + # cv2.imshow("figure", frame) + time.sleep(0.05) + end_time = time.time() + # print("loop_time = ", end_time - start_time) + + # close the window + if cv2.waitKey(1) & 0xFF == ord('q'): + # cap.release() + cv2.destroyAllWindows() + sys.exit() + child.join() + + +if __name__ == "__main__": + run() + # Object_detect().take_photo() + # Object_detect().cut_photo() diff --git a/mycobot_ai/ai_mycobot_280/scripts/test.py b/mycobot_ai/ai_mycobot_280/scripts/test.py index 816215a..0e4aead 100755 --- a/mycobot_ai/ai_mycobot_280/scripts/test.py +++ b/mycobot_ai/ai_mycobot_280/scripts/test.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- from pymycobot.mycobot import MyCobot from pymycobot.genre import Angle -from pymycobot import PI_PORT, PI_BAUD # 当使用树莓派版本的mycobot时,可以引用这两个变量进行MyCobot初始化 + # 当使用树莓派版本的mycobot时,可以引用这两个变量进行MyCobot初始化 import time mc = MyCobot("/dev/ttyACM0", 115200) # mc = MyCobot("/dev/ttyUSB0", 115200) # mc = MyCobot("/dev/ttyAMA0", 1000000) -mc.send_angles([0,0,0,0,0,0], 25) +# mc.send_angles([0,0,0,0,0,0], 25) # print(mc.get_angles()) # mc.send_angles([-7.11, -6.94, -55.01, -24.16, 0.0, -15], 30) # time.sleep(4) @@ -42,3 +42,16 @@ mc.send_angles([0,0,0,0,0,0], 25) # print("angles:%s"% mc.get_angles()) # print("coords:%s"% mc.get_coords()) # print("\n") +move_coords = [ + [132.2, -136.9, 200.8, -178.24, -3.72, -107.17], # above the red bucket + [232.5, -124.6, 212.8, -169.94, -5.88, -97.63], # green + [115.8, 177.3, 210.6, 178.06, -0.92, -6.11], # blue + [-6.9, 173.2, 201.5, 179.93, 0.63, 33.83], # gray + ] + +# mc.send_coords(move_coords[1],20, 1) +# mc.send_angles([-13.44, -57.3, 0.7, -22.76, -4.74, -6.76], 20) +mc.send_coords([238.8, -124.1, 204.3, -169.69, -5.52, -96.52], 20, 1) +time.sleep(3) +print(mc.get_angles()) +print(mc.get_coords()) \ No newline at end of file diff --git a/mycobot_ai/ai_mypalletizer_260/launch/vision_wio.launch b/mycobot_ai/ai_mypalletizer_260/launch/vision_wio.launch index 51eb78b..5548425 100644 --- a/mycobot_ai/ai_mypalletizer_260/launch/vision_wio.launch +++ b/mycobot_ai/ai_mypalletizer_260/launch/vision_wio.launch @@ -2,8 +2,8 @@ - - + + @@ -14,7 +14,7 @@ - + diff --git a/mycobot_ai/ai_mypalletizer_260/res/blue/goal9.jpeg b/mycobot_ai/ai_mypalletizer_260/res/blue/goal9.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a370eb450b5da6e1725713ab30a77b69e6ca3c7d GIT binary patch literal 2808 zcmbV}c{J2*|Hr>$%#5w9BfC2kvUJ&f*`OUXs-*9W#@$aj>iuBk3bw?P6!mn zj={@rAPTVKgTd_35O!jAcLMt!;1q-i9o8^|3L|}Bau^ZKq^uGydGm%2IBIZRLCg2* z4Q?LMLt^3*M~*5gDIe3;(bdy8Ftj*nX=Q!N#@5lv*#+%-&du+Fe?Z{HpkQoxL}XNS zOzh3%TPdlx@8Gg?a`W;F3hx({mX%jjRz0bH+W4%A_`I3a()zlytGkEtrnhfscw}^J z{Nn_bMxUKy%r7i1Ei=DuY;J9TXZ`(Sp9=(l|G{GWzvU8Sb8+m?0JhHs;)r4wSdbHP zSOY3#hJ^WGgyl4oxJ1meN*X%2<+V`jaNnzgJfaHPv?I)YwBKa^8Q6{giR}Nt{-28q z@PR?>;eiDK6JS^W)R}i=hgp0d;b@kC`=9;o=pnowAd^?q(h7E3!z?=*BJwqT#n-yI z%Rb`&j&eX?&|$iPQp2F>EL>#kh^1YI;Slv`MA9{64;2yxx10gli6E z=AcMS)KbV5KK~XYL+5st*NF$zb)rTt)4U8)k)O&BU4snih>}EA77lkLv}i*M5GJR& zu|ZN~*SG4YC})oa+&Pr-7!3|(=69Gir%aG89fuD^qr21SfOSFB&jBsJH=MhJTa`9k zN)`l5S02|HWK#A4wEFcJ`>w?t`_T>uz=zuKb*&NjOnpu^6vbVv0-ufBBcEzt6xDVI)6kQ-0P{ehdjg>-L!wXX#voIeG2-RWnb9Lg&*u+|#`nNmV zBvuHmhPY8XYs$}5H>gWI813@;q(S;j3|lQj`OknX8{FALv3Y{|JzccC=O$*-_V^wlxb6 zEXG8w02-I>nzX6B->iPqV?FDc^V7oWY+*8m2vg60jxRpheo3rc!=z{+uHQAV03foL17OKANyUCC#?E@$0;VZFT1M1z5u%r z$HfTZ_O-tna#q|$y6nVAWd4UTu9oe(%e~Gm3hvcc+>346J z7{?CIx)v~syloIFqeobmPdqPaYt&y=$z&=f6I5+vkdihF@M6hBW+M%*PvNLmgXt5! zA~gCXxP0|)$k+Oh3q4U1pHrX@!oIqJnzAYIZ_>q?21d_|$$4A$U+qiWspsBC9MddW z%JQ^6WSjnNeqy>axJ^rBj54UNFEx~_kPx(!Fc6e+&lb0nzH4(S2EW29?jfN2iB+#K z*vThzqdjMK$Jd@;Yc>nV+*Rc;0~ftpF0Thinvjfhow6=i!K4vNkKJoGcTaG>wEj+L z*IjXze+=(EfAq@0!Gp}5FE!5{8P$GNf|0n>RL(`t;+7RpyPv3dEg9YQ@Wu{-xHL?w zCNOh1WQ^ig|J1cRF<|}d^%Rsr-TKx-O1(tZv=j*^(1i>uaHM5|cM$C(in`xkPv)-3 zOKW&m%p@jfij*p=-R?J#dx7xlEDF57W2W|Yf^jsS0K=lS`$fIngOx=eRSKjV(#fsl z2(&OiW-*?~SE?PjR_euaMjGR9aw*isjCaW<$2mWrl(F~mGQYSz?l>{;-}xsD-p8VJ ze)^+`d9D8-<3ns@y%ukgOU3zf(yWJ#xl8I!(Qtf6+U>7-)X~(!sS6SHrN4Nh%}uzY z-6S2#HN@rNj~)kokD@+|y*vlL6sU;XGzzgK-ttT5Q+g#<`|R`>LD%?w`+>%(MzM20 z&z9fsr`b-EbLSiY1r*-LQz!~imdyGrVMnWiTh?105&m%O$HzNH*;WSc^*867%e2r&c+s-tap=%{`1;E;ays{ zKMQ-N2_k0xxC+LYe_=3S2UZE6bf1!O*Q*zjk{-pxy52=;K(&`*C_e7`PPFg9WU zPW&51+s7rXw=+atnGfq?y7M1eNIm(o8!W@UYGI{ z7S2zS;oQ(2PBt7MdL*9CetUMrbLu4|cU*R64@faqSZ}HwTK0^bSKA<*5zH@*T#ki2 zCsYFvZu*nxDmUfI7jl2SF5Zo&2ku;R${ZmvzF4VaIMv*vysO4NJJacbrg+<*$Hhzw3X@AT4zoz}vD&OA(he JZCM literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mypalletizer_260/res/gray/goal9.jpeg b/mycobot_ai/ai_mypalletizer_260/res/gray/goal9.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8f63e9173f483d3749829aa72ce624314d83d721 GIT binary patch literal 3155 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 NjfJHU7MYCi{{e$4h64Zq literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mypalletizer_260/res/green/goal14.jpeg b/mycobot_ai/ai_mypalletizer_260/res/green/goal14.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7778ecbe638e96bc385dea23fb9e70b1de8039f3 GIT binary patch literal 2451 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 PZzp2S(O=ei>)k&A_LNvP literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mypalletizer_260/res/red/goal8.jpeg b/mycobot_ai/ai_mypalletizer_260/res/red/goal8.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..abb5652b485b33a89726ce488aa3dbe8201fd3a9 GIT binary patch literal 2991 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 literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mypalletizer_260/res/takephoto.jpeg b/mycobot_ai/ai_mypalletizer_260/res/takephoto.jpeg index 179878563033396af49f45910d5ea44154fbde3a..e529be284af7f353a7022c4a18b9361f98d86424 100644 GIT binary patch delta 48535 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

q8#cASpD+PJA4y^$)uihee^~@ zIzZ=8r?9RKA*iZ$-!OZ`^Abt7(tn_71M9d*+Covj-dDjvSI+R&Nvv&KQe5h6`m52A z<+a$C9-J9qpoII=w|jXq`PfE0KdkCi3^$*$CN>#Hf&M)yg5}7?{jf1lP%k|Y_5jrB z9P!W%KJ8+;t&Nf{{!-}Kw(5jMS)uv$0!0n_NyA5#(~k55Min1!-u-m3&!TxUFzzLE zKY_Ny9uzM@$)s^AGv!oeK($vOfHlDN{HGj;RGl4UM$^d3kiuVG*%*3+(lW?}~u zfAwd1lF6?MjQg68Nk{mpivzPZ6^?E%cblA0_8a4KOv+7Gx>Ymh-(x#$JGrWO0AnsI zRzd7i_MWZbp3pN&1y0A0O-#67y?dr3air&CAG;73H_2=7ycX+SoHaxdJBU4YwVKt9 zt(O~@7gG%d!)#^_cZV7EzBo!t_$Qwc`57z8Yuw!0%LgL6DFeGWm_-9c2k$_jZ%TS$ zzo~)o<7$rRhV!^ENqZDSnGm!Yn9d}dl2?CJbq!9Rejm9oL{etsB4OsRZC-m-nBowT zZqR&$x72C&Q}H4C;z4HifWve3)A`u~E>F z7bR{yxV9L#xT-Xi_k&D+U*%MHV+IS(3M&sp(DN*QrA~G;#?}XGYfkM07MxsJ5Wpj= z`j7EL)ro15s*?L{bd-HX(l#QB?e&-f2GbO_QYU|B%(i(1mQ6$Z8@U+dz%9)G`)hIf zr(Fpj)umkFl&|bYui zT(Ow3b3$?ODzLT9=;R0N<0tG3#oH&*ewswzSl^JwAx&0>5Ru1j{J-(!0_x`zsDtNX zbAP{YJ*vcS&gULm=QC^`zvnNIZOl9bljGYDf2^1y;-wPEmb2z!q};ZT1Cb!;9&T9N zZ~T%eQ^I(rJ<>BT_&((>J83I8X^{RVTM&~v!Y!ZslT**^j|Tufe&{z>>tI0EYR*Iz zI07#litHzHB~>Zoo!2Cv+;Z2>YjN|URoQSW7L5ezwy((xOLTUp-kw+(bLh^mG4e=y zQbX9;@XR^$N)9!t3=5P~&LjF_7lj?{#PM zXz&|Az5gXKCHA}Cu-bG)yGr%?A4qYcp)|$44P0YMj0O$6u$=cDUn1wXLo&16)P`)C zJW Ot1fC=@>c2oTl_zOg9c;( delta 46514 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 {=Z$qdjgvTSK{lDH^>Q}hP1cd( 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 b69W|9hd^{${tR@}1~uQm`hv+*|IPn@nA=1D diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py new file mode 100644 index 0000000..6d3e902 --- /dev/null +++ b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py @@ -0,0 +1,550 @@ +# -*- coding:utf-8 -*- +#!/usr/bin/env python2 +import cv2 +import numpy as np +import time +import os,sys +import rospy +from visualization_msgs.msg import Marker +from pymycobot.mypalletizer import MyPalletizer +from moving_utils import Movement + + +IS_CV_4 = cv2.__version__[0] == '4' +__version__ = "1.0" +# Adaptive seeed + + +class Object_detect(Movement): + + def __init__(self, camera_x = 160, camera_y = 10): + # inherit the parent class + super(Object_detect, self).__init__() + # get path of file + dir_path = os.path.dirname(__file__) + + # declare mypal260 + self.mc = None + + # 移动角度 + self.move_angles = [ + [0, 0, 0, 0], # init the point + [-29.0, 5.88, -4.92, -76.28], # point to grab + [17.4, -10.1, -87.27, 5.8, -2.02, 15], # point to grab + ] + + # 移动坐标 + self.move_coords = [ + [132.6, -155.6, 211.8, -20.9], # above the red bucket + [232.5, -134.1, 197.7, -45.26], # above the green bucket + [111.6, 159, 221.5, -120], # above the blue bucket + [-15.9, 164.6, 217.5, -119.35], # above the gray bucket + ] + + # which robot: USB* is m5; ACM* is wio; AMA* is raspi + self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] + self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] + self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] + self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] + self.raspi = False + if "dev" in self.robot_m5: + self.Pin = [2, 5] + elif "dev" in self.robot_wio: + # self.Pin = [20, 21] + self.Pin = [2, 5] + for i in self.move_coords: + i[2] -= 20 + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + import RPi.GPIO as GPIO + GPIO.setwarnings(False) + self.GPIO = GPIO + GPIO.setmode(GPIO.BCM) + GPIO.setup(20, GPIO.OUT) + GPIO.setup(21, GPIO.OUT) + GPIO.output(20, 1) + GPIO.output(21, 1) + self.raspi = True + if self.raspi: + self.gpio_status(False) + # choose place to set cube + self.color = 0 + # parameters to calculate camera clipping parameters + self.x1 = self.x2 = self.y1 = self.y2 = 0 + # set cache of real coord + self.cache_x = self.cache_y = 0 + + self.HSV = { + "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], + "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], + "green": [np.array([70, 100, 100]), np.array([90, 255, 255])], # [77, 255, 255] + "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], + "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], # np.array([78, 43, 46]), np.array([99, 255, 255]) + } + + # set color HSV + # self.HSV = { + # # "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], + # "yellow": [np.array([22, 93, 70]), np.array([45, 255, 245])], + # "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], + # # "green": [np.array([35, 43, 46]), np.array([77, 255, 255])], + # "green": [np.array([35, 55, 30]), np.array([88, 255, 255])], + # "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], + # # "blue": [np.array([-10, 100, 100]), np.array([10, 255, 255])], + # "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], + # } + # self.HSV = { + # # "yellow": [np.array([11, 85, 70]), np.array([59, 255, 245])], + # "yellow": [np.array([22, 93, 0]), np.array([45, 255, 245])], + # "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], + # "green": [np.array([35, 43, 35]), np.array([90, 255, 255])], + # # "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], + # "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], + # } + # use to calculate coord between cube and mypal260 + self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 + # The coordinates of the grab center point relative to the mypal260 + self.camera_x, self.camera_y = camera_x, camera_y + # The coordinates of the cube relative to the mypal260 + self.c_x, self.c_y = 0, 0 + # The ratio of pixels to actual values + self.ratio = 0 + # Get ArUco marker dict that can be detected. + self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) + # Get ArUco marker params. + self.aruco_params = cv2.aruco.DetectorParameters_create() + + # init a node and a publisher + rospy.init_node("marker", anonymous=True) + self.pub = rospy.Publisher('/cube', Marker, queue_size=1) + # init a Marker + self.marker = Marker() + self.marker.header.frame_id = "/joint1" + self.marker.ns = "cube" + self.marker.type = self.marker.CUBE + self.marker.action = self.marker.ADD + self.marker.scale.x = 0.04 + self.marker.scale.y = 0.04 + self.marker.scale.z = 0.04 + self.marker.color.a = 1.0 + self.marker.color.g = 1.0 + self.marker.color.r = 1.0 + + # marker position initial + self.marker.pose.position.x = 0 + self.marker.pose.position.y = 0 + self.marker.pose.position.z = 0.03 + self.marker.pose.orientation.x = 0 + self.marker.pose.orientation.y = 0 + self.marker.pose.orientation.z = 0 + self.marker.pose.orientation.w = 1.0 + + # publish marker + def pub_marker(self, x, y, z=0.03): + self.marker.header.stamp = rospy.Time.now() + self.marker.pose.position.x = x + self.marker.pose.position.y = y + self.marker.pose.position.z = z + self.marker.color.g = self.color + self.pub.publish(self.marker) + + # pump_control pi + def gpio_status(self, flag): + if flag: + # self.GPIO.output(20, 0) + self.GPIO.output(21, 0) + else: + # self.GPIO.output(20, 1) + self.GPIO.output(21, 1) + + # 开启吸泵 m5 + def pump_on(self): + # 让2号位工作 + # self.mc.set_basic_output(2, 0) + # 让5号位工作 + self.mc.set_basic_output(5, 0) + + # 停止吸泵 m5 + def pump_off(self): + # 让2号位停止工作 + # self.mc.set_basic_output(2, 1) + # 让5号位停止工作 + self.mc.set_basic_output(5, 1) + + # Grasping motion + def move(self, x, y, color): + # send Angle to move mypal260 + print(color) + self.mc.send_angles(self.move_angles[0], 20) + time.sleep(3) + + # send coordinates to move mypal260 + self.mc.send_coords([x, y, 160, 0], 20, 0) + time.sleep(1.5) + self.mc.send_coords([x, y, 101, 0], 20, 0) + time.sleep(1.5) + + # open pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_on() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(True) + time.sleep(1.5) + + self.mc.send_angle(2, 0, 20) + time.sleep(0.3) + self.mc.send_angle(3, -20, 20) + time.sleep(2) + + self.mc.send_coords(self.move_coords[color], 20, 1) + self.pub_marker(self.move_coords[color][0]/1000.0, self.move_coords[color] + [1]/1000.0, self.move_coords[color][2]/1000.0) + time.sleep(3) + + # close pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_off() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(False) + time.sleep(6) + + if color == 1: + self.pub_marker( + self.move_coords[color][0]/1000.0+0.04, self.move_coords[color][1]/1000.0-0.02) + elif color == 0: + self.pub_marker( + self.move_coords[color][0]/1000.0+0.03, self.move_coords[color][1]/1000.0) + + self.mc.send_angles(self.move_angles[1], 20) + time.sleep(1.5) + + # decide whether grab cube + def decide_move(self, x, y, color): + print(x, y, self.cache_x, self.cache_y) + # detect the cube status move or run + if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm + self.cache_x, self.cache_y = x, y + return + else: + self.cache_x = self.cache_y = 0 + # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 + self.move(x, y, color) + + # init mypal260 + def run(self): + if "dev" in self.robot_m5: + self.mc = MyPalletizer(self.robot_m5, 115200) + elif "dev" in self.robot_wio: + self.mc = MyPalletizer(self.robot_wio, 115200) + elif "dev" in self.robot_raspi: + self.mc = MyPalletizer(self.robot_raspi, 1000000) + if not self.raspi: + print('start pump') + self.pub_pump(False, self.Pin) + print('end') + self.mc.send_angles([-29.0, 5.88, -4.92, -76.28], 20) + time.sleep(3) + + # draw aruco + def draw_marker(self, img, x, y): + # draw rectangle on img + cv2.rectangle( + img, + (x - 20, y - 20), + (x + 20, y + 20), + (0, 255, 0), + thickness=2, + lineType=cv2.FONT_HERSHEY_COMPLEX, + ) + # add text on rectangle + cv2.putText(img, "({},{})".format(x, y), (x, y), + cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (243, 0, 0), 2,) + + # get points of two aruco + def get_calculate_params(self, img): + # Convert the image to a gray image + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + # Detect ArUco marker. + corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( + gray, self.aruco_dict, parameters=self.aruco_params + ) + + """ + Two Arucos must be present in the picture and in the same order. + There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. + Determine the center of the aruco by the four corners of the aruco. + """ + if len(corners) > 0: + if ids is not None: + if len(corners) <= 1 or ids[0] == 1: + return None + x1 = x2 = y1 = y2 = 0 + point_11, point_21, point_31, point_41 = corners[0][0] + x1, y1 = int((point_11[0] + point_21[0] + point_31[0] + point_41[0]) / 4.0), int( + (point_11[1] + point_21[1] + point_31[1] + point_41[1]) / 4.0) + point_1, point_2, point_3, point_4 = corners[1][0] + x2, y2 = int((point_1[0] + point_2[0] + point_3[0] + point_4[0]) / 4.0), int( + (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / 4.0) + return x1, x2, y1, y2 + return None + + # set camera clipping parameters + def set_cut_params(self, x1, y1, x2, y2): + self.x1 = int(x1) + self.y1 = int(y1) + self.x2 = int(x2) + self.y2 = int(y2) + print(self.x1, self.y1, self.x2, self.y2) + + # set parameters to calculate the coords between cube and mypal260 + def set_params(self, c_x, c_y, ratio): + self.c_x = c_x + self.c_y = c_y + self.ratio = 220.0/ratio + + # calculate the coords between cube and mypal260 + def get_position(self, x, y): + return ((y - self.c_y)*self.ratio + self.camera_x), ((x - self.c_x)*self.ratio + self.camera_y) + + """ + Calibrate the camera according to the calibration parameters. + Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. + If two ARuco values have been calculated, clip the video. + """ + def transform_frame(self, frame): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), fx=fx, fy=fy, + interpolation=cv2.INTER_CUBIC) + if self.x1 != self.x2: + # the cutting ratio here is adjusted according to the actual situation + # frame = frame[int(self.y2*0.2):int(self.y1*1.15), + # int(self.x1*0.7):int(self.x2*1.15)] + frame = frame[int(self.y2*0.78):int(self.y1*1.1), + int(self.x1*0.86):int(self.x2*1.08)] + return frame + + # detect cube color + def color_detect(self, img): + # set the arrangement of color'HSV + x = y = 0 + for mycolor, item in self.HSV.items(): + # print("mycolor:",mycolor) + redLower = np.array(item[0]) + redUpper = np.array(item[1]) + + # transfrom the img to model of gray + hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + # print("hsv",hsv) + + # wipe off all color expect color in range + mask = cv2.inRange(hsv, item[0], item[1]) + + # a etching operation on a picture to remove edge roughness + erosion = cv2.erode(mask, np.ones((1, 1), np.uint8), iterations=2) + + # the image for expansion operation, its role is to deepen the color depth in the picture + dilation = cv2.dilate(erosion, np.ones( + (1, 1), np.uint8), iterations=2) + + # adds pixels to the image + target = cv2.bitwise_and(img, img, mask=dilation) + + # the filtered image is transformed into a binary image and placed in binary + ret, binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY) + + # get the contour coordinates of the image, where contours is the coordinate value, here only the contour is detected + contours, hierarchy = cv2.findContours( + dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + if len(contours) > 0: + # do something about misidentification + boxes = [ + box + for box in [cv2.boundingRect(c) for c in contours] + if min(img.shape[0], img.shape[1]) / 10 + < min(box[2], box[3]) + < min(img.shape[0], img.shape[1]) / 1 + ] + if boxes: + for box in boxes: + x, y, w, h = box + # find the largest object that fits the requirements + c = max(contours, key=cv2.contourArea) + # get the lower left and upper right points of the positioning object + x, y, w, h = cv2.boundingRect(c) + # locate the target by drawing rectangle + cv2.rectangle(img, (x, y), (x+w, y+h), (153, 153, 0), 2) + # calculate the rectangle center + x, y = (x*2+w)/2, (y*2+h)/2 + # calculate the real coordinates of mypal260 relative to the target + if mycolor == "red": + self.color = 0 + break + elif mycolor == "blue": + self.color = 2 + break + elif mycolor == "green": + self.color = 1 + break + elif mycolor == "cyan": + self.color = 2 + break + + elif mycolor == "yellow": + self.color = 3 + break + + # elif mycolor == "green": + # self.color = 1 + + # if mycolor == "red": + # self.color = 0 + # break + # elif mycolor == "green": + # self.color = 1 + # print('green') + # break + # elif mycolor == "cyan": + # self.color = 2 + # break + # elif mycolor == "blue": + # self.color = 2 + # break + # elif mycolor == "yellow": + # self.color = 3 + # break + # if mycolor == "yellow": + + # self.color = 3 + # print(mycolor) + # break + + # elif mycolor == "red": + # self.color = 0 + # print(mycolor) + # break + + # elif mycolor == "cyan" or mycolor == "blue": + # self.color = 2 + # print(mycolor) + # break + + # # elif mycolor == "blue": + # # self.color =2 + # # break + # else: + # self.color = 1 + # print(mycolor) + # # break + + if abs(x) + abs(y) > 0: + return x, y + else: + return None + +if __name__ == "__main__": + + # open the camera + cap_num = 0 + cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) + if not cap.isOpened(): + cap.open() + # init a class of Object_detect + detect = Object_detect() + # init mypal260 + detect.run() + + _init_ = 20 + init_num = 0 + nparams = 0 + num = 0 + real_sx = real_sy = 0 + while cv2.waitKey(1) < 0: + # read camera + _, frame = cap.read() + # deal img + frame = detect.transform_frame(frame) + if _init_ > 0: + _init_ -= 1 + continue + + # calculate the parameters of camera clipping + if init_num < 20: + if detect.get_calculate_params(frame) is None: + cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + init_num += 1 + continue + elif init_num == 20: + detect.set_cut_params( + (detect.sum_x1)/20.0, + (detect.sum_y1)/20.0, + (detect.sum_x2)/20.0, + (detect.sum_y2)/20.0, + ) + detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 + init_num += 1 + continue + + # calculate params of the coords between cube and mypal260 + if nparams < 10: + if detect.get_calculate_params(frame) is None: + cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + nparams += 1 + continue + elif nparams == 10: + nparams += 1 + # calculate and set params of calculating real coord between cube and mypal260 + detect.set_params( + (detect.sum_x1+detect.sum_x2)/20.0, + (detect.sum_y1+detect.sum_y2)/20.0, + abs(detect.sum_x1-detect.sum_x2)/10.0 + + abs(detect.sum_y1-detect.sum_y2)/10.0 + ) + print("ok") + continue + + # get detect result + detect_result = detect.color_detect(frame) + if detect_result is None: + cv2.imshow("figure", frame) + continue + else: + x, y = detect_result + # calculate real coord between cube and mypal260 + real_x, real_y = detect.get_position(x, y) + if num == 20: + detect.pub_marker(real_sx/20.0/1000.0, real_sy/20.0/1000.0) + detect.decide_move(real_sx/20.0, real_sy/20.0, detect.color) + num = real_sx = real_sy = 0 + + else: + num += 1 + real_sy += real_y + real_sx += real_x + + cv2.imshow("figure", frame) + + # close the window + if cv2.waitKey(1) & 0xFF == ord('q'): + cap.release() + cv2.destroyAllWindows() + sys.exit() \ No newline at end of file diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py new file mode 100644 index 0000000..01a7153 --- /dev/null +++ b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py @@ -0,0 +1,628 @@ +#!/usr/bin/env python2 +# encoding:utf-8 +from multiprocessing import Process, Pipe +import cv2 +import numpy as np +import time +import os,sys +import rospy +from visualization_msgs.msg import Marker +from moving_utils import Movement +from pymycobot.mypalletizer import MyPalletizer + +IS_CV_4 = cv2.__version__[0] == '4' +__version__ = "1.0" # Adaptive seeed + + +class Object_detect(Movement): + + def __init__(self, camera_x = 160, camera_y = 10): + # inherit the parent class + super(Object_detect, self).__init__() + # get path of file + dir_path = os.path.dirname(__file__) + + # declare mypal260 + self.mc = None + # 移动角度 + self.move_angles = [ + [0, 0, 0, 0], # init the point + [-29.0, 5.88, -4.92, -76.28], # point to grab + [17.4, -10.1, -87.27, 5.8, -2.02, 15], # point to grab + ] + + # 移动坐标 + self.move_coords = [ + [132.6, -155.6, 211.8, -20.9], # above the red bucket + [232.5, -134.1, 197.7, -45.26], # above the green bucket + [111.6, 159, 221.5, -120], # above the blue bucket + [-15.9, 164.6, 217.5, -119.35], # above the gray bucket + ] + # 判断连接设备:ttyUSB*为M5,ttyACM*为seeed + self.raspi = False + self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] + self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] + self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] + self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] + if "dev" in self.robot_m5: + self.Pin = [2, 5] + elif "dev" in self.robot_wio: + self.Pin = [2, 5] + for i in self.move_coords: + i[2] -= 20 + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + import RPi.GPIO as GPIO + GPIO.setwarnings(False) + self.GPIO = GPIO + GPIO.setmode(GPIO.BCM) + GPIO.setup(20, GPIO.OUT) + GPIO.setup(21, GPIO.OUT) + GPIO.output(20, 1) + GPIO.output(21, 1) + self.raspi = True + if self.raspi: + self.gpio_status(False) + # choose place to set cube + self.color = 0 + # parameters to calculate camera clipping parameters + self.x1 = self.x2 = self.y1 = self.y2 = 0 + # set cache of real coord + self.cache_x = self.cache_y = 0 + + # use to calculate coord between cube and mycobot + self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 + # The coordinates of the grab center point relative to the mycobot + self.camera_x, self.camera_y = camera_x, camera_y + # The coordinates of the cube relative to the mycobot + self.c_x, self.c_y = 0, 0 + # The ratio of pixels to actual values + self.ratio = 0 + # Get ArUco marker dict that can be detected. + self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) + # Get ArUco marker params. + self.aruco_params = cv2.aruco.DetectorParameters_create() + + + # init a node and a publisher + rospy.init_node("marker", anonymous=True) + self.pub = rospy.Publisher('/cube', Marker, queue_size=1) + # init a Marker + self.marker = Marker() + self.marker.header.frame_id = "/joint1" + self.marker.ns = "cube" + self.marker.type = self.marker.CUBE + self.marker.action = self.marker.ADD + self.marker.scale.x = 0.04 + self.marker.scale.y = 0.04 + self.marker.scale.z = 0.04 + self.marker.color.a = 1.0 + self.marker.color.g = 1.0 + self.marker.color.r = 1.0 + + # marker position initial + self.marker.pose.position.x = 0 + self.marker.pose.position.y = 0 + self.marker.pose.position.z = 0.03 + self.marker.pose.orientation.x = 0 + self.marker.pose.orientation.y = 0 + self.marker.pose.orientation.z = 0 + self.marker.pose.orientation.w = 1.0 + + self.cache_x = self.cache_y = 0 + + # publish marker + def pub_marker(self, x, y, z=0.03): + self.marker.header.stamp = rospy.Time.now() + self.marker.pose.position.x = x + self.marker.pose.position.y = y + self.marker.pose.position.z = z + self.marker.color.g = self.color + self.pub.publish(self.marker) + + # pump_control pi + def gpio_status(self, flag): + if flag: + self.GPIO.output(20, 0) + self.GPIO.output(21, 0) + else: + self.GPIO.output(20, 1) + self.GPIO.output(21, 1) + + # 开启吸泵 m5 + def pump_on(self): + # 让2号位工作 + # self.mc.set_basic_output(2, 0) + # 让5号位工作 + self.mc.set_basic_output(5, 0) + + # 停止吸泵 m5 + def pump_off(self): + # 让2号位停止工作 + # self.mc.set_basic_output(2, 1) + # 让5号位停止工作 + self.mc.set_basic_output(5, 1) + + # Grasping motion + def move(self, x, y, color): + print(color) + # send Angle to move mypal260 + self.mc.send_angles(self.move_angles[0], 20) + time.sleep(3) + + # send coordinates to move mypal260 根据不同底板机械臂,调整吸泵高度 + self.mc.send_coords([x, y, 160, 0], 20, 0) + time.sleep(1.5) + self.mc.send_coords([x, y, 101, 0], 20, 0) + time.sleep(1.5) + + # open pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_on() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(True) + time.sleep(1.5) + + self.mc.send_angle(2, 0, 20) + time.sleep(0.3) + self.mc.send_angle(3, -18, 20) + time.sleep(2) + + self.mc.send_coords(self.move_coords[color], 20, 1) + self.pub_marker(self.move_coords[color][0] / 1000.0, + self.move_coords[color][1] / 1000.0, + self.move_coords[color][2] / 1000.0) + time.sleep(3) + + # close pump + if "dev" in self.robot_m5 or "dev" in self.robot_wio: + self.pump_off() + elif "dev" in self.robot_raspi or "dev" in self.robot_jes: + self.gpio_status(False) + time.sleep(6) + + self.mc.send_angles(self.move_angles[1], 20) + time.sleep(1.5) + + # decide whether grab cube + def decide_move(self, x, y, color): + print(x, y, self.cache_x, self.cache_y) + # detect the cube status move or run + if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm + self.cache_x, self.cache_y = x, y + return + else: + self.cache_x = self.cache_y = 0 + # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 + self.move(x, y, color) + + # init mypal260 + def run(self): + if "dev" in self.robot_m5: + self.mc = MyPalletizer(self.robot_m5, 115200) + elif "dev" in self.robot_wio: + self.mc = MyPalletizer(self.robot_wio, 115200) + elif "dev" in self.robot_raspi: + self.mc = MyPalletizer(self.robot_raspi, 1000000) + if not self.raspi: + self.pub_pump(False, self.Pin) + self.mc.send_angles([-29.0, 5.88, -4.92, -76.28], 20) + time.sleep(3) + + # draw aruco + def draw_marker(self, img, x, y): + # draw rectangle on img + cv2.rectangle( + img, + (x - 20, y - 20), + (x + 20, y + 20), + (0, 255, 0), + thickness=2, + lineType=cv2.FONT_HERSHEY_COMPLEX, + ) + # add text on rectangle + cv2.putText( + img, + "({},{})".format(x, y), + (x, y), + cv2.FONT_HERSHEY_COMPLEX_SMALL, + 1, + (243, 0, 0), + 2, + ) + + # get points of two aruco + def get_calculate_params(self, img): + # Convert the image to a gray image + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + # Detect ArUco marker. + corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( + gray, self.aruco_dict, parameters=self.aruco_params) + + """ + Two Arucos must be present in the picture and in the same order. + There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. + Determine the center of the aruco by the four corners of the aruco. + """ + if len(corners) > 0: + if ids is not None: + if len(corners) <= 1 or ids[0] == 1: + return None + x1 = x2 = y1 = y2 = 0 + point_11, point_21, point_31, point_41 = corners[0][0] + x1, y1 = int( + (point_11[0] + point_21[0] + point_31[0] + point_41[0]) / + 4.0), int( + (point_11[1] + point_21[1] + point_31[1] + point_41[1]) + / 4.0) + point_1, point_2, point_3, point_4 = corners[1][0] + x2, y2 = int( + (point_1[0] + point_2[0] + point_3[0] + point_4[0]) / + 4.0), int( + (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / + 4.0) + return x1, x2, y1, y2 + return None + + # set camera clipping parameters + def set_cut_params(self, x1, y1, x2, y2): + self.x1 = int(x1) + self.y1 = int(y1) + self.x2 = int(x2) + self.y2 = int(y2) + print(self.x1, self.y1, self.x2, self.y2) + + # set parameters to calculate the coords between cube and mycobot + def set_params(self, c_x, c_y, ratio): + self.c_x = c_x + self.c_y = c_y + self.ratio = 220.0 / ratio + + # calculate the coords between cube and mycobot + def get_position(self, x, y): + return ((y - self.c_y) * self.ratio + + self.camera_x), ((x - self.c_x) * self.ratio + self.camera_y) + + """ + Calibrate the camera according to the calibration parameters. + Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. + If two ARuco values have been calculated, clip the video. + """ + + def transform_frame(self, frame): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), + fx=fx, + fy=fy, + interpolation=cv2.INTER_CUBIC) + if self.x1 != self.x2: + # the cutting ratio here is adjusted according to the actual situation + frame = frame[int(self.y2 * 0.2):int(self.y1 * 1.15), + int(self.x1 * 0.7):int(self.x2 * 1.15)] + return frame + + # according the class_id to get object name + def id_class_name(self, class_id): + for key, value in self.labels.items(): + if class_id == int(key): + return value + + # detect object + def obj_detect(self, img, goal, kp_img, desc_img, kp_list, desc_list, connection): + i = 0 + MIN_MATCH_COUNT = 5 + # sift = cv2.xfeatures2d.SIFT_create() + + # find the keypoints and descriptors with SIFT + # kp = [] + # des = [] + kp = kp_list + des = desc_list + + # for i in goal: + # kp0, des0 = sift.detectAndCompute(i, None) + # kp.append(kp0) + # des.append(des0) + + # kp1, des1 = sift.detectAndCompute(goal, None) + # kp2, des2 = sift.detectAndCompute(img, None) + kp2, des2 = kp_img, desc_img + + # FLANN parameters + FLANN_INDEX_KDTREE = 0 + index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) + search_params = dict(checks=50) # or pass empty dictionary + flann = cv2.FlannBasedMatcher(index_params, search_params) + + x, y = 0, 0 + try: + for i in range(len(des)): + matches = flann.knnMatch(des[i], des2, k=2) + # store all the good matches as per Lowe's ratio test. 根据Lowe比率测试存储所有良好匹配项。 + good = [] + for m, n in matches: + if m.distance < 0.7 * n.distance: + good.append(m) + + # When there are enough robust matching point pairs 当有足够的健壮匹配点对(至少个MIN_MATCH_COUNT)时 + if len(good) > MIN_MATCH_COUNT: + + # extract corresponding point pairs from matching 从匹配中提取出对应点对 + # query index of small objects, training index of scenarios 小对象的查询索引,场景的训练索引 + src_pts = np.float32([kp[i][m.queryIdx].pt + for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([kp2[m.trainIdx].pt + for m in good]).reshape(-1, 1, 2) + + # Using matching points to find homography matrix in cv2.ransac 利用匹配点找到CV2.RANSAC中的单应矩阵 + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, + 5.0) + matchesMask = mask.ravel().tolist() + # Calculate the distortion of image, that is the corresponding position in frame 计算图1的畸变,也就是在图2中的对应的位置 + h, w, d = goal[i].shape + pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], + [w - 1, 0]]).reshape(-1, 1, 2) + dst = cv2.perspectiveTransform(pts, M) + coord = (dst[0][0] + dst[1][0] + dst[2][0] + + dst[3][0]) / 4.0 + connection.send((DRAW_COORDS, coord)) + # cv2.putText(img, "{}".format(coord), (50, 60), + # fontFace=None, fontScale=1, + # color=(0, 255, 0), lineType=1) + print(format(dst[0][0][0])) + x = (dst[0][0][0] + dst[1][0][0] + dst[2][0][0] + + dst[3][0][0]) / 4.0 + y = (dst[0][0][1] + dst[1][0][1] + dst[2][0][1] + + dst[3][0][1]) / 4.0 + + # bound box 绘制边框 + # img = cv2.polylines(img, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) + connection.send((DRAW_RECT, dst)) + # cv2.polylines(mixture, [np.int32(dst)], True, (0, 255, 0), 2, cv2.LINE_AA) + except Exception as e: + pass + + if x + y > 0: + return x, y + else: + return None + +# The path to save the image folder +def parse_folder(folder): + restore = [] + path1 = '/home/ubuntu/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mypalletizer_260/' + folder + path2 = '/home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mypalletizer_260/' + folder + + if os.path.exists(path1): + path = path1 + elif os.path.exists(path2): + path = path2 + + for i, j, k in os.walk(path): + for l in k: + restore.append(cv2.imread(folder + '/{}'.format(l))) + return restore + +def compute_keypoints_and_descriptors(sift, images_lists): + kp_list = [] + desc_list = [] + for images in images_lists: + kp_tmp = [] + desc_tmp = [] + for img in images: + kp, desc = sift.detectAndCompute(img, None) + kp_tmp.append(kp) + desc_tmp.append(desc) + kp_list.append(kp_tmp) + desc_list.append(desc_tmp) + + return kp_list, desc_list + +GET_FRAME = 1 +STOP_PROCESSING = 2 +DRAW_COORDS = 3 +DRAW_RECT = 4 +CLEAR_DRAW = 5 +CROP_FRAME = 6 + +def get_frame(connection): + connection.send(GET_FRAME) + frame = connection.recv() + return frame + +def process_transform_frame(frame, x1, y1, x2, y2): + # enlarge the image by 1.5 times + fx = 1.5 + fy = 1.5 + frame = cv2.resize(frame, (0, 0), + fx=fx, + fy=fy, + interpolation=cv2.INTER_CUBIC) +# if x1 != x2: + # the cutting ratio here is adjusted according to the actual situation +# frame = frame[int(y2 * 0.2):int(y1 * 1.15), +# int(x1 * 0.7):int(x2 * 1.15)] + return frame + +def process_display_frame(connection): + cap_num = 0 + coord = None + dst = None + x1 = 0 + y1 = 0 + x2 = 0 + y2 = 0 + cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) + if not cap.isOpened(): + cap.open() + while cv2.waitKey(1) < 0: + _, frame = cap.read() + frame = process_transform_frame(frame, x1, y1, x2, y2) + if connection.poll(): + request = connection.recv() + if request == GET_FRAME: + connection.send(frame) + elif request == CLEAR_DRAW: + coord = None + dst = None + elif type(request) is tuple: + if request[0] == DRAW_COORDS: + coord = request[1] + elif request[0] == DRAW_RECT: + dst = request[1] + elif request[0] == CROP_FRAME: + x1 = request[1] + y1 = request[2] + x2 = request[3] + y2 = request[4] + + if not coord is None: + cv2.putText(frame, "{}".format(coord), (50, 60), fontFace=None, + fontScale=1, color=(0, 255, 0), lineType=1) + if not dst is None: + frame = cv2.polylines(frame, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) + cv2.imshow("figure", frame) + time.sleep(0.04) + connection.send(STOP_PROCESSING) + +def run(): + parent_conn, child_conn = Pipe() + child = Process(target = process_display_frame, args=(child_conn,)) + child.start() + + res_queue = [[], [], [], []] + res_queue[0] = parse_folder('res/red') + res_queue[1] = parse_folder('res/green') + res_queue[2] = parse_folder('res/blue') + res_queue[3] = parse_folder('res/gray') + + sift = cv2.xfeatures2d.SIFT_create() + kp_list, desc_list = compute_keypoints_and_descriptors(sift, res_queue) + + # init a class of Object_detect + detect = Object_detect() + + # init mycobot + detect.run() + + # _init_ = 20 # + init_num = 0 + nparams = 0 + # num = 0 + # real_sx = real_sy = 0 + while True: + start_time = time.time() + if parent_conn.poll(): + data = parent_conn.recv() + if data == STOP_PROCESSING: + break + # read camera + frame = get_frame(parent_conn) + # deal img + #frame = detect.transform_frame(frame) + + # if _init_ > 0: + # _init_ -= 1 + # continue + # calculate the parameters of camera clipping + if init_num < 20: + if detect.get_calculate_params(frame) is None: + # cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + init_num += 1 + continue + elif init_num == 20: + detect.set_cut_params( + (detect.sum_x1) / 20.0, + (detect.sum_y1) / 20.0, + (detect.sum_x2) / 20.0, + (detect.sum_y2) / 20.0, + ) + parent_conn.send((CROP_FRAME, + (detect.sum_x1) / 20.0, + (detect.sum_y1) / 20.0, + (detect.sum_x2) / 20.0, + (detect.sum_y2) / 20.0)) + detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 + init_num += 1 + continue + + # calculate params of the coords between cube and mycobot + if nparams < 10: + if detect.get_calculate_params(frame) is None: + # cv2.imshow("figure", frame) + continue + else: + x1, x2, y1, y2 = detect.get_calculate_params(frame) + detect.draw_marker(frame, x1, y1) + detect.draw_marker(frame, x2, y2) + detect.sum_x1 += x1 + detect.sum_x2 += x2 + detect.sum_y1 += y1 + detect.sum_y2 += y2 + nparams += 1 + print ("ok") + continue + elif nparams == 10: + nparams += 1 + # calculate and set params of calculating real coord between cube and mycobot + detect.set_params((detect.sum_x1 + detect.sum_x2) / 20.0, + (detect.sum_y1 + detect.sum_y2) / 20.0, + abs(detect.sum_x1 - detect.sum_x2) / 10.0 + + abs(detect.sum_y1 - detect.sum_y2) / 10.0) + print("ok") + continue + + # get detect result + kp_img, desc_img = sift.detectAndCompute(frame, None) + frame = get_frame(parent_conn) + for i, v in enumerate(res_queue): + # HACK: to update frame every time + detect_result = detect.obj_detect(frame, v, kp_img, desc_img, kp_list[i], desc_list[i], parent_conn) + if detect_result: + x, y = detect_result + # calculate real coord between cube and mycobot + real_x, real_y = detect.get_position(x, y) + detect.color = i + detect.pub_marker(real_x / 1000.0, real_y / 1000.0) + detect.decide_move(real_x, real_y, detect.color) + # if num == 5: + # detect.color = i + # detect.pub_marker(real_sx / 5.0 / 1000.0, + # real_sy / 5.0 / 1000.0) + # detect.decide_move(real_sx / 5.0, real_sy / 5.0, + # detect.color) + # num = real_sx = real_sy = 0 + # else: + # num += 1 + # real_sy += real_y + # real_sx += real_x + parent_conn.send(CLEAR_DRAW) + + # cv2.imshow("figure", frame) + time.sleep(0.05) + end_time = time.time() + # print("loop_time = ", end_time - start_time) + + # close the window + if cv2.waitKey(1) & 0xFF == ord('q'): + # cap.release() + cv2.destroyAllWindows() + sys.exit() + + child.join() + + +if __name__ == "__main__": + run() + # Object_detect().take_photo() + # Object_detect().cut_photo() diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/test.py b/mycobot_ai/ai_mypalletizer_260/scripts/test.py index d73de19..1d232e0 100755 --- a/mycobot_ai/ai_mypalletizer_260/scripts/test.py +++ b/mycobot_ai/ai_mypalletizer_260/scripts/test.py @@ -4,7 +4,7 @@ from pymycobot.genre import Angle from pymycobot import PI_PORT, PI_BAUD # 当使用树莓派版本的mycobot时,可以引用这两个变量进行MyCobot初始化 import time,os -mc = MyPalletizer(os.popen("ls /dev/ttyUSB*").readline()[:-1], 115200) +# mc = MyPalletizer(os.popen("ls /dev/ttyUSB*").readline()[:-1], 115200) # mc = MyPalletizer("/dev/ttyAMA0", 1000000) # mc.send_angles([-29.0, 5.88, -4.92, -76.28],25) # init the point coords:[155.3, -86.1, 218.4, -47.28] @@ -13,8 +13,8 @@ mc = MyPalletizer(os.popen("ls /dev/ttyUSB*").readline()[:-1], 115200) # mc.send_angles([-47.1, 10.19, -10.1, -76.37],25) # above the red bucket; coords:[127.3, -137.1, 219.2, -29.26] # time.sleep(1.5) -mc.send_angles([0,0,-15,0],25) -time.sleep(2) +# mc.send_angles([0,0,-15,0],25) +# time.sleep(2) # mc.send_coords([141.2, -142.0, 206.2, -26.8],25,1) # above the red bucket # time.sleep(2) @@ -38,4 +38,27 @@ time.sleep(2) # mc.set_servo_calibration(1) # mc.set_servo_calibration(2) # mc.set_servo_calibration(3) -# mc.set_servo_calibration(4) \ No newline at end of file +# mc.set_servo_calibration(4) + +import sys +import numpy as np +import cv2 + +print("Please enter blue:") +blue = input() +print("Please enter green:") +green = input() +print("Please enter red:") +red = input() + +color = np.uint8([[[blue, green, red]]]) +hsv_color = cv2.cvtColor(color, cv2.COLOR_BGR2HSV) + +hue = hsv_color[0][0][0] + +print("Lower bound is :") +print("[" + str(hue - 10) + ", 100, 100]\n") + +print("Upper bound is :"), +print("[" + str(hue + 10) + ", 255, 255]") + diff --git a/mypalletizer_260/mypalletizer_260/config/mypal_260.rviz b/mypalletizer_260/mypalletizer_260/config/mypal_260.rviz index 4e1a0a5..2c84dd7 100644 --- a/mypalletizer_260/mypalletizer_260/config/mypal_260.rviz +++ b/mypalletizer_260/mypalletizer_260/config/mypal_260.rviz @@ -8,8 +8,9 @@ Panels: - /Status1 - /RobotModel1 - /TF1 + - /Marker1 Splitter Ratio: 0.5 - Tree Height: 601 + Tree Height: 607 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties @@ -18,7 +19,7 @@ Panels: - /2D Nav Goal1 - /Publish Point1 Name: Tool Properties - Splitter Ratio: 0.5886790156364441 + Splitter Ratio: 0.588679016 - Class: rviz/Views Expanded: - /Current View1 @@ -29,8 +30,6 @@ Panels: Name: Time SyncMode: 0 SyncSource: "" -Preferences: - PromptSaveOnExit: true Toolbars: toolButtonStyle: 2 Visualization Manager: @@ -42,7 +41,7 @@ Visualization Manager: Color: 160; 160; 164 Enabled: true Line Style: - Line Width: 0.029999999329447746 + Line Width: 0.0299999993 Value: Lines Name: Grid Normal Cell Count: 0 @@ -69,6 +68,11 @@ Visualization Manager: Show Axes: false Show Trail: false Value: true + env: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true link1: Alpha: 1 Show Axes: false @@ -107,6 +111,8 @@ Visualization Manager: All Enabled: true base: Value: true + env: + Value: true link1: Value: true link2: @@ -117,13 +123,15 @@ Visualization Manager: Value: true link5: Value: true - Marker Scale: 0.30000001192092896 + Marker Scale: 0.300000012 Name: TF Show Arrows: true Show Axes: true Show Names: true Tree: base: + env: + {} link1: link2: link3: @@ -132,6 +140,14 @@ Visualization Manager: {} Update Interval: 0 Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /cube + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true Enabled: true Global Options: Background Color: 48; 48; 48 @@ -147,10 +163,7 @@ Visualization Manager: - Class: rviz/FocusCamera - Class: rviz/Measure - Class: rviz/SetInitialPose - Theta std deviation: 0.2617993950843811 Topic: /initialpose - X std deviation: 0.5 - Y std deviation: 0.5 - Class: rviz/SetGoal Topic: /move_base_simple/goal - Class: rviz/PublishPoint @@ -160,33 +173,33 @@ Visualization Manager: Views: Current: Class: rviz/Orbit - Distance: 1.2028908729553223 + Distance: 1.20289087 Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 + Stereo Eye Separation: 0.0599999987 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false Focal Point: X: 0 Y: 0 - Z: 0.10758385062217712 + Z: 0.107583851 Focal Shape Fixed Size: true - Focal Shape Size: 0.05000000074505806 + Focal Shape Size: 0.0500000007 Invert Z Axis: false Name: Current View - Near Clip Distance: 0.009999999776482582 - Pitch: 0.42039862275123596 + Near Clip Distance: 0.00999999978 + Pitch: 0.420398623 Target Frame: Value: Orbit (rviz) - Yaw: 1.1754094362258911 + Yaw: 1.17540944 Saved: ~ Window Geometry: Displays: collapsed: false - Height: 892 + Height: 888 Hide Left Dock: false Hide Right Dock: false - QMainWindow State: 000000ff00000000fd00000004000000000000016a000002e2fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000002e2000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c0000026100000001000001a4000002e2fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b000002e2000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000006200000003efc0100000002fb0000000800540069006d00650100000000000006200000024400fffffffb0000000800540069006d0065010000000000000450000000000000000000000306000002e200000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + QMainWindow State: 000000ff00000000fd00000004000000000000016a000002eefc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002ee000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c0000026100000001000001a4000002eefc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730100000028000002ee000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000006200000003efc0100000002fb0000000800540069006d00650100000000000006200000030000fffffffb0000000800540069006d0065010000000000000450000000000000000000000306000002ee00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: @@ -198,201 +211,3 @@ Window Geometry: Width: 1568 X: 144 Y: 41 - -# Panels: -# - Class: rviz/Displays -# Help Height: 78 -# Name: Displays -# Property Tree Widget: -# Expanded: -# - /Global Options1 -# - /Status1 -# - /RobotModel1 -# - /TF1 -# Splitter Ratio: 0.5 -# Tree Height: 775 -# - Class: rviz/Selection -# Name: Selection -# - Class: rviz/Tool Properties -# Expanded: -# - /2D Pose Estimate1 -# - /2D Nav Goal1 -# - /Publish Point1 -# Name: Tool Properties -# Splitter Ratio: 0.588679016 -# - Class: rviz/Views -# Expanded: -# - /Current View1 -# Name: Views -# Splitter Ratio: 0.5 -# - Class: rviz/Time -# Experimental: false -# Name: Time -# SyncMode: 0 -# SyncSource: "" -# Toolbars: -# toolButtonStyle: 2 -# Visualization Manager: -# Class: "" -# Displays: -# - Alpha: 0.5 -# Cell Size: 1 -# Class: rviz/Grid -# Color: 160; 160; 164 -# Enabled: true -# Line Style: -# Line Width: 0.0299999993 -# Value: Lines -# Name: Grid -# Normal Cell Count: 0 -# Offset: -# X: 0 -# Y: 0 -# Z: 0 -# Plane: XY -# Plane Cell Count: 10 -# Reference Frame: -# Value: true -# - Alpha: 1 -# Class: rviz/RobotModel -# Collision Enabled: false -# Enabled: true -# Links: -# All Links Enabled: true -# Expand link Details: false -# Expand Link Details: false -# Expand Tree: false -# Link Tree Style: Links in Alphabetic Order -# base: -# Alpha: 1 -# Show Axes: false -# Show Trail: false -# Value: true -# link1: -# Alpha: 1 -# Show Axes: false -# Show Trail: false -# Value: true -# link2: -# Alpha: 1 -# Show Axes: false -# Show Trail: false -# Value: true -# link3: -# Alpha: 1 -# Show Axes: false -# Show Trail: false -# Value: true -# link4: -# Alpha: 1 -# Show Axes: false -# Show Trail: false -# Value: true -# link5: -# Alpha: 1 -# Show Axes: false -# Show Trail: false -# Value: true - -# Name: RobotModel -# Robot Description: robot_description -# TF Prefix: "" -# Update Interval: 0 -# Value: true -# Visual Enabled: true -# - Class: rviz/TF -# Enabled: true -# Frame Timeout: 15 -# Frames: -# All Enabled: true -# base: -# Value: true -# link1: -# Value: true -# link2: -# Value: true -# link3: -# Value: true -# link4: -# Value: true -# link5: -# Value: true - -# Marker Scale: 0.300000012 -# Name: TF -# Show Arrows: true -# Show Axes: true -# Show Names: true -# Tree: -# base: -# link1: -# link2: -# link3: -# link4: -# link5: -# {} -# Update Interval: 0 -# Value: true -# Enabled: true -# Global Options: -# Background Color: 48; 48; 48 -# Default Light: true -# Fixed Frame: base -# Frame Rate: 30 -# Name: root -# Tools: -# - Class: rviz/Interact -# Hide Inactive Objects: true -# - Class: rviz/MoveCamera -# - Class: rviz/Select -# - Class: rviz/FocusCamera -# - Class: rviz/Measure -# - Class: rviz/SetInitialPose -# Topic: /initialpose -# - Class: rviz/SetGoal -# Topic: /move_base_simple/goal -# - Class: rviz/PublishPoint -# Single click: true -# Topic: /clicked_point -# Value: true -# Views: -# Current: -# Class: rviz/Orbit -# Distance: 1.20289087 -# Enable Stereo Rendering: -# Stereo Eye Separation: 0.0599999987 -# Stereo Focal Distance: 1 -# Swap Stereo Eyes: false -# Value: false -# Focal Point: -# X: 0 -# Y: 0 -# Z: 0.107583851 -# Focal Shape Fixed Size: true -# Focal Shape Size: 0.0500000007 -# Invert Z Axis: false -# Name: Current View -# Near Clip Distance: 0.00999999978 -# Pitch: 0.440398335 -# Target Frame: -# Value: Orbit (rviz) -# Yaw: 0.430389732 -# Saved: ~ -# Window Geometry: -# Displays: -# collapsed: false -# Height: 1056 -# Hide Left Dock: false -# Hide Right Dock: false -# QMainWindow State: 000000ff00000000fd00000004000000000000016a00000396fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000002800000396000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000022f00000396fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000002800000396000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073f0000003efc0100000002fb0000000800540069006d006501000000000000073f0000030000fffffffb0000000800540069006d006501000000000000045000000000000000000000039a0000039600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 -# Selection: -# collapsed: false -# Time: -# collapsed: false -# Tool Properties: -# collapsed: false -# Views: -# collapsed: false -# Width: 1855 -# X: 65 -# Y: 24 diff --git a/mypalletizer_260/mypalletizer_communication/launch/communication_topic.launch b/mypalletizer_260/mypalletizer_communication/launch/communication_topic.launch index 6cf9d22..3966f37 100644 --- a/mypalletizer_260/mypalletizer_communication/launch/communication_topic.launch +++ b/mypalletizer_260/mypalletizer_communication/launch/communication_topic.launch @@ -1,5 +1,5 @@ - + diff --git a/mypalletizer_260/mypalletizer_communication/scripts/mypal_topics.py b/mypalletizer_260/mypalletizer_communication/scripts/mypal_topics.py index 49deb6e..0655778 100755 --- a/mypalletizer_260/mypalletizer_communication/scripts/mypal_topics.py +++ b/mypalletizer_260/mypalletizer_communication/scripts/mypal_topics.py @@ -67,11 +67,17 @@ class MypalTopics(object): rospy.init_node("mypal_topics") rospy.loginfo("start ...") - port = rospy.get_param("~port", os.popen("ls /dev/ttyUSB*").readline()[:-1]) - print(port) - baud = rospy.get_param("~baud", 115200) - rospy.loginfo("%s,%s" % (port, baud)) - self.mc = MyPalletizer(port, baud) + port_m5 = rospy.get_param("~port", os.popen("ls /dev/ttyUSB*").readline()[:-1]) + # if not port: + port_wio = rospy.get_param("~port", os.popen("ls /dev/ttyACM*").readline()[:-1]) + if "dev" in port_m5: + baud = rospy.get_param("~baud", 115200) + rospy.loginfo("%s,%s" % (port_m5, baud)) + self.mc = MyPalletizer(port_m5, baud) + elif "dev" in port_wio: + baud = rospy.get_param("~baud", 115200) + rospy.loginfo("%s,%s" % (port_wio, baud)) + self.mc = MyPalletizer(port_wio, baud) self.lock = threading.Lock() def start(self): From 8a8032e93aa8816488ecf34fc2f332af7b796d9f Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Wed, 16 Nov 2022 18:16:56 +0800 Subject: [PATCH 02/12] update new aikit code --- mycobot_ai/ai_mecharm_270/res/blue/goal9.jpeg | Bin 0 -> 2944 bytes mycobot_ai/ai_mecharm_270/res/gray/goal9.jpeg | Bin 0 -> 3748 bytes .../ai_mecharm_270/res/green/goal1.jpeg | Bin 5717 -> 0 bytes .../ai_mecharm_270/res/green/goal11.jpeg | Bin 5682 -> 4545 bytes mycobot_ai/ai_mecharm_270/res/red/goal8.jpeg | Bin 0 -> 4044 bytes mycobot_ai/ai_mecharm_270/res/takephoto.jpeg | Bin 46764 -> 49421 bytes .../scripts/advance_detect_obj_color.py | 16 ++++++++-------- .../scripts/advance_detect_obj_img_folder.py | 17 ++++++++--------- 8 files changed, 16 insertions(+), 17 deletions(-) create mode 100644 mycobot_ai/ai_mecharm_270/res/blue/goal9.jpeg create mode 100644 mycobot_ai/ai_mecharm_270/res/gray/goal9.jpeg delete mode 100644 mycobot_ai/ai_mecharm_270/res/green/goal1.jpeg create mode 100644 mycobot_ai/ai_mecharm_270/res/red/goal8.jpeg diff --git a/mycobot_ai/ai_mecharm_270/res/blue/goal9.jpeg b/mycobot_ai/ai_mecharm_270/res/blue/goal9.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ef912575eff1ba0dfedc8ac622b586cd5e9b8c44 GIT binary patch literal 2944 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 literal 0 HcmV?d00001 diff --git a/mycobot_ai/ai_mecharm_270/res/gray/goal9.jpeg b/mycobot_ai/ai_mecharm_270/res/gray/goal9.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e92138f824609f06a82638dd07e615698f9e958d GIT binary patch literal 3748 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 BAgKTV diff --git a/mycobot_ai/ai_mecharm_270/res/green/goal11.jpeg b/mycobot_ai/ai_mecharm_270/res/green/goal11.jpeg index b1242b0d72552d6e8ba0dd4c70c81749c658d37f..e4315ee17f16b1f3e216f051afc2bd859c361153 100644 GIT binary patch delta 3967 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%0ASdXEV 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 a9h#FkK`<^Kb!3wz`M delta 46514 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 {=Z$qdjgvTSK{lDH^>Q}hP1cd( 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 b69W|9hd^{${tR@}1~uQm`hv+*|IPn@f<{A; diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py index ec46a57..ebd2336 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py @@ -17,8 +17,8 @@ __version__ = "1.0" class Object_detect(Movement): - def __init__(self, camera_x = 140, camera_y = 5): # m5 - # def __init__(self, camera_x = 140, camera_y = -5): # pi + def __init__(self, camera_x = 148, camera_y = 5): # m5 + # def __init__(self, camera_x = 148, camera_y = -5): # pi # inherit the parent class super(Object_detect, self).__init__() # get path of file @@ -35,10 +35,10 @@ class Object_detect(Movement): # 移动坐标 self.move_coords = [ - [92.3, -104.9, 211.4, -179.6, 28.91, 131.29], # above the red bucket - [165.0, -93.6, 201.4, -173.43, 46.23, 160.65], # above the green bucket - [88.1, 126.3, 193.4, 162.15, 2.23, 156.02], # above the blue bucket - [-5.4, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket + [109.1, -118.8, 164.9, -179.02, 11.07, 132.93], # above the red bucket + [178.4, -98.5, 172.7, -175.8, 41.25, 159.41], # above the green bucket + [97.9, 139.9, 170.7, 163.54, 2.03, 156.04], # above the blue bucket + [-1.8, 143.8, 172.4, 170.69, -4.62, 161.79], # above the gray bucket ] # which robot: USB* is m5; ACM* is wio; AMA* is raspi @@ -165,9 +165,9 @@ class Object_detect(Movement): self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 - # self.mc.send_coords([x, y, 90, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi + # self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi time.sleep(3) - self.pub_marker(x/1000.0, y/1000.0, 90/1000.0) + self.pub_marker(x/1000.0, y/1000.0, 103/1000.0) # open pump diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py index f2bc2c1..1eadbbf 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py @@ -16,7 +16,7 @@ __version__ = "1.0" # Adaptive seeed class Object_detect(Movement): - def __init__(self, camera_x = 145, camera_y = -5): + def __init__(self, camera_x = 148, camera_y = 5): # inherit the parent class super(Object_detect, self).__init__() # get path of file @@ -32,10 +32,10 @@ class Object_detect(Movement): # 移动坐标 self.move_coords = [ - [92.3, -104.9, 211.4, -179.6, 28.91, 131.29], # above the red bucket - [165.0, -93.6, 201.4, -173.43, 46.23, 160.65], # above the green bucket - [88.1, 126.3, 193.4, 162.15, 2.23, 156.02], # above the blue bucket - [-5.4, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket + [109.1, -118.8, 164.9, -179.02, 11.07, 132.93], # above the red bucket + [178.4, -98.5, 172.7, -175.8, 41.25, 159.41], # above the green bucket + [97.9, 139.9, 170.7, 163.54, 2.03, 156.04], # above the blue bucket + [-1.8, 143.8, 172.4, 170.69, -4.62, 161.79], # above the gray bucket ] # 判断连接设备:ttyUSB*为M5,ttyACM*为seeed @@ -147,18 +147,17 @@ class Object_detect(Movement): def move(self, x, y, color): # send Angle to move 270 self.mc.send_angles(self.move_angles[0], 30) - time.sleep(7) + time.sleep(4) print("x %s ,y %s" % (x,y)) # send coordinates to move 270 根据不同底板机械臂,调整吸泵高度 self.mc.send_coords([x, y, 140, 179.12, -0.18, 179.46], 30, 0) - time.sleep(7) - print("ntm") + time.sleep(3) self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 # self.mc.send_coords([x, y, 90, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi # self.mc.send_coords([x, y, 92, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 - time.sleep(6) + time.sleep(3) # open pump if "dev" in self.robot_m5 or "dev" in self.robot_wio: From a60a94aea05f92dad9ee042a2d49c77543e0e666 Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Thu, 17 Nov 2022 14:01:46 +0800 Subject: [PATCH 03/12] fix color --- .../scripts/advance_detect_obj_color.py | 12 +-- .../scripts/advance_detect_obj_color.py | 9 +- .../scripts/advance_detect_obj_color.py | 92 +++---------------- 3 files changed, 25 insertions(+), 88 deletions(-) diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py index ebd2336..ba75b97 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py @@ -77,7 +77,7 @@ class Object_detect(Movement): self.HSV = { "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], - "green": [np.array([35, 43, 46]), np.array([77, 255, 255])], + "green": [np.array([35, 43, 35]), np.array([90, 255, 255])], "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], } @@ -321,15 +321,15 @@ class Object_detect(Movement): def color_detect(self, img): # set the arrangement of color'HSV x = y = 0 + gs_img = cv2.GaussianBlur(img, (3, 3), 0) # 高斯模糊 + # transfrom the img to model of gray + hsv = cv2.cvtColor(gs_img, cv2.COLOR_BGR2HSV) + for mycolor, item in self.HSV.items(): # print("mycolor:",mycolor) redLower = np.array(item[0]) redUpper = np.array(item[1]) - # transfrom the img to model of gray - hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) - # print("hsv",hsv) - # wipe off all color expect color in range mask = cv2.inRange(hsv, item[0], item[1]) @@ -376,7 +376,7 @@ class Object_detect(Movement): self.color = 0 elif mycolor == "green": self.color = 1 - elif mycolor == "cyan": + elif mycolor == "cyan" or mycolor == "blue": self.color = 2 else: self.color = 3 diff --git a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py index 0809e89..da893b8 100644 --- a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py +++ b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py @@ -316,11 +316,13 @@ class Object_detect(Movement): def color_detect(self, img): # set the arrangement of color'HSV x = y = 0 + gs_img = cv2.GaussianBlur(img, (3, 3), 0) # 高斯模糊 + # transfrom the img to model of gray + hsv = cv2.cvtColor(gs_img, cv2.COLOR_BGR2HSV) + for mycolor, item in self.HSV.items(): redLower = np.array(item[0]) redUpper = np.array(item[1]) - # transfrom the img to model of gray - hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # wipe off all color expect color in range mask = cv2.inRange(hsv, item[0], item[1]) # a etching operation on a picture to remove edge roughness @@ -365,7 +367,7 @@ class Object_detect(Movement): elif mycolor == "green": self.color = 1 - elif mycolor == "cyan": + elif mycolor == "cyan" or mycolor == "blue": self.color = 2 else: @@ -400,7 +402,6 @@ if __name__ == "__main__": _, frame = cap.read() # deal img frame = detect.transform_frame(frame) - if _init_ > 0: _init_ -= 1 continue diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py index 6d3e902..4f79979 100644 --- a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py +++ b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py @@ -73,33 +73,15 @@ class Object_detect(Movement): # set cache of real coord self.cache_x = self.cache_y = 0 + # set color HSV self.HSV = { "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], - "green": [np.array([70, 100, 100]), np.array([90, 255, 255])], # [77, 255, 255] + "green": [np.array([35, 43, 35]), np.array([90, 255, 255])], # [77, 255, 255] "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], # np.array([78, 43, 46]), np.array([99, 255, 255]) } - - # set color HSV - # self.HSV = { - # # "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], - # "yellow": [np.array([22, 93, 70]), np.array([45, 255, 245])], - # "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], - # # "green": [np.array([35, 43, 46]), np.array([77, 255, 255])], - # "green": [np.array([35, 55, 30]), np.array([88, 255, 255])], - # "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], - # # "blue": [np.array([-10, 100, 100]), np.array([10, 255, 255])], - # "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], - # } - # self.HSV = { - # # "yellow": [np.array([11, 85, 70]), np.array([59, 255, 245])], - # "yellow": [np.array([22, 93, 0]), np.array([45, 255, 245])], - # "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], - # "green": [np.array([35, 43, 35]), np.array([90, 255, 255])], - # # "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], - # "cyan": [np.array([78, 43, 46]), np.array([99, 255, 255])], - # } + # use to calculate coord between cube and mypal260 self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 # The coordinates of the grab center point relative to the mypal260 @@ -328,14 +310,14 @@ class Object_detect(Movement): def color_detect(self, img): # set the arrangement of color'HSV x = y = 0 + gs_img = cv2.GaussianBlur(img, (3, 3), 0) # 高斯模糊 + # transfrom the img to model of gray + hsv = cv2.cvtColor(gs_img, cv2.COLOR_BGR2HSV) + for mycolor, item in self.HSV.items(): # print("mycolor:",mycolor) redLower = np.array(item[0]) redUpper = np.array(item[1]) - - # transfrom the img to model of gray - hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) - # print("hsv",hsv) # wipe off all color expect color in range mask = cv2.inRange(hsv, item[0], item[1]) @@ -380,64 +362,18 @@ class Object_detect(Movement): # calculate the real coordinates of mypal260 relative to the target if mycolor == "red": self.color = 0 - break - elif mycolor == "blue": - self.color = 2 - break + elif mycolor == "green": self.color = 1 - break - elif mycolor == "cyan": + + elif mycolor == "cyan" or mycolor == "blue": self.color = 2 - break - - elif mycolor == "yellow": - self.color = 3 - break - - # elif mycolor == "green": - # self.color = 1 - # if mycolor == "red": - # self.color = 0 - # break - # elif mycolor == "green": - # self.color = 1 - # print('green') - # break - # elif mycolor == "cyan": - # self.color = 2 - # break - # elif mycolor == "blue": - # self.color = 2 - # break - # elif mycolor == "yellow": - # self.color = 3 - # break - # if mycolor == "yellow": - - # self.color = 3 - # print(mycolor) - # break - - # elif mycolor == "red": - # self.color = 0 - # print(mycolor) - # break - - # elif mycolor == "cyan" or mycolor == "blue": - # self.color = 2 - # print(mycolor) - # break - - # # elif mycolor == "blue": - # # self.color =2 - # # break - # else: - # self.color = 1 - # print(mycolor) - # # break + else: + self.color = 3 + + if abs(x) + abs(y) > 0: return x, y else: From cf705e0dbb422476bc797071becc96c3d01c372f Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Thu, 17 Nov 2022 16:09:25 +0800 Subject: [PATCH 04/12] update --- mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py | 4 ++-- .../ai_mecharm_270/scripts/advance_detect_obj_img_folder.py | 4 ++-- .../ai_mypalletizer_260/scripts/advance_detect_obj_color.py | 2 +- .../scripts/advance_detect_obj_img_folder.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py index ba75b97..90c4967 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_color.py @@ -164,10 +164,10 @@ class Object_detect(Movement): self.pub_marker(x/1000.0, y/1000.0, 140/1000.0) - self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 + self.mc.send_coords([x, y, 96, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 # self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi time.sleep(3) - self.pub_marker(x/1000.0, y/1000.0, 103/1000.0) + self.pub_marker(x/1000.0, y/1000.0, 96/1000.0) # open pump diff --git a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py index 1eadbbf..43da98f 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py +++ b/mycobot_ai/ai_mecharm_270/scripts/advance_detect_obj_img_folder.py @@ -154,7 +154,7 @@ class Object_detect(Movement): self.mc.send_coords([x, y, 140, 179.12, -0.18, 179.46], 30, 0) time.sleep(3) - self.mc.send_coords([x, y, 103, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 + self.mc.send_coords([x, y, 96, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 # self.mc.send_coords([x, y, 90, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi # self.mc.send_coords([x, y, 92, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 time.sleep(3) @@ -176,7 +176,7 @@ class Object_detect(Movement): # print(tmp) self.mc.send_angles([tmp[0], 17.22, -32.51, tmp[3], 97, tmp[5]],30) - time.sleep(6) + time.sleep(3) self.mc.send_coords(self.move_coords[color], 30, 1) diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py index 4f79979..3c4293e 100644 --- a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py +++ b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_color.py @@ -162,7 +162,7 @@ class Object_detect(Movement): # send coordinates to move mypal260 self.mc.send_coords([x, y, 160, 0], 20, 0) time.sleep(1.5) - self.mc.send_coords([x, y, 101, 0], 20, 0) + self.mc.send_coords([x, y, 96, 0], 20, 0) time.sleep(1.5) # open pump diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py index 01a7153..6ded356 100644 --- a/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py +++ b/mycobot_ai/ai_mypalletizer_260/scripts/advance_detect_obj_img_folder.py @@ -152,7 +152,7 @@ class Object_detect(Movement): # send coordinates to move mypal260 根据不同底板机械臂,调整吸泵高度 self.mc.send_coords([x, y, 160, 0], 20, 0) time.sleep(1.5) - self.mc.send_coords([x, y, 101, 0], 20, 0) + self.mc.send_coords([x, y, 96, 0], 20, 0) time.sleep(1.5) # open pump From be8834ded1384f3f43bbe871344aa4052477a42b Mon Sep 17 00:00:00 2001 From: weijian Date: Fri, 2 Dec 2022 16:45:22 +0800 Subject: [PATCH 05/12] update --- mycobot_280/mycobot_280/scripts/1245.jpg | Bin 31972 -> 0 bytes mycobot_280/mycobot_280/scripts/3a4.bmp | Bin 1683414 -> 0 bytes .../mycobot_280/scripts/calibration_camera.py | 199 ------- mycobot_280/mycobot_280/scripts/mtx_dist.npz | Bin 476 -> 0 bytes mycobot_280/mycobot_280/scripts/test.py | 68 --- .../ai_mecharm_270/scripts/color_test.py | 164 ------ .../scripts/advance_detect_obj_color.py | 480 --------------- .../ai_mycobot_280/scripts/aikit_img.py | 555 ----------------- .../ai_mycobot_280/scripts/encode_test.py | 248 -------- .../ai_mypalletizer_260/scripts/aikit_img.py | 557 ------------------ 10 files changed, 2271 deletions(-) delete mode 100644 mycobot_280/mycobot_280/scripts/1245.jpg delete mode 100644 mycobot_280/mycobot_280/scripts/3a4.bmp delete mode 100644 mycobot_280/mycobot_280/scripts/calibration_camera.py delete mode 100644 mycobot_280/mycobot_280/scripts/mtx_dist.npz delete mode 100755 mycobot_280/mycobot_280/scripts/test.py delete mode 100644 mycobot_ai/ai_mecharm_270/scripts/color_test.py delete mode 100644 mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py delete mode 100644 mycobot_ai/ai_mycobot_280/scripts/aikit_img.py delete mode 100644 mycobot_ai/ai_mycobot_280/scripts/encode_test.py delete mode 100644 mycobot_ai/ai_mypalletizer_260/scripts/aikit_img.py diff --git a/mycobot_280/mycobot_280/scripts/1245.jpg b/mycobot_280/mycobot_280/scripts/1245.jpg deleted file mode 100644 index 62c992009d66fe4986c03c3b1f089e21af0229b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31972 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 zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N L0t5&U__e?XmL&t4 diff --git a/mycobot_280/mycobot_280/scripts/calibration_camera.py b/mycobot_280/mycobot_280/scripts/calibration_camera.py deleted file mode 100644 index 84843b4..0000000 --- a/mycobot_280/mycobot_280/scripts/calibration_camera.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: UTF-8 -*- -import os -import numpy as np -import cv2 as cv - -import cv2 -import matplotlib.pyplot as plt - -# 生成一张630*890的全黑图片 -# img = np.zeros((630,890,3),np.uint8) -# plt.imshow(img[:,:,::-1]) - -# while True: -# # plt.show() -# cv2.imshow('img', img) - -# key = cv2.waitKey(0) -# if key == ord('q'): -# break -# elif key == ord('s'): -# cv2.imwrite('/home/h/catkin_ws/src/mycobot_ros/mycobot_280/mycobot_280/scripts/123.png', img) -# print('saved') - -# cv2.destroyAllWindows() - -path = os.path.join(os.path.dirname(__file__), "3a4.bmp") -print(path) - -frame = cv2.imread(path) -row, col, nc = frame.shape - -width_of_roi = 90 -# 这里是对全黑图片做处理,将图片以黑白间隔的形式zh -for j in range(row): - data = frame[j] - for i in range(col): - f = int(i / width_of_roi) % 2 ^ int(j / width_of_roi) % 2 - if f: - frame[j][i][0] = 255 - frame[j][i][1] = 255 - frame[j][i][2] = 255 -cv2.imshow("", frame) -cv2.waitKey(0) & 0xFF == ord("q") -cv2.imwrite(os.path.join(os.path.dirname(__file__), "1245.jpg"), frame) - - -# import os -# import cv2 -# import threading - -# if_save = False -# # 设置摄像头编号(由于电脑型号不同,分配给USB摄像头的编号也可能不同,一般为0或1) -# cap_num = int(input("Input the camare number:")) -# # 设置所存储的图片名称,设置为1,即表示从1开始累加存储。如:1.jpg,2.jpg,3.jpg...... -# name = int(input("Input start name, use number:")) - -# cap = cv2.VideoCapture(cap_num) -# dir_path = os.path.dirname(__file__) - -# def save(): -# global if_save -# while True: -# input("Input any to save a image:") -# if_save = True - -# # 开启线程进行摄像头拍摄 -# t = threading.Thread(target=save) -# # 设置为异步运行 -# t.setDaemon(True) -# t.start() - -# while cv2.waitKey(1) != ord("q"): -# _, frame = cap.read() -# if if_save: -# # 设置名称为当前路径下,否则会因为运行环境的原因使得存储位置发生变化 -# img_name = os.path.join(dir_path,str(name)+".jpg") -# # 存储图片 -# cv2.imwrite(img_name, frame) -# print("Save {} successful.".format(img_name)) -# name += 1 -# if_save = False -# cv2.imshow("", frame) - - -# import os -# import glob -# import numpy as np -# import cv2 as cv -# from pprint import pprint - -# obj_points = [] # 3d点在现实世界的位置。 -# img_points = [] # 2d点在图片中的位置。 - -# gray = None - -# def calibration_camera(row, col, path=None, cap_num=None, saving=False): -# """校准摄像头 - -# 参数说明: -# row (int): 网格中的行数。 -# col (int): 网格中的列数。 -# path (string): 存放校准图片的位置。 -# cap_num (int): 表示摄像头的编号,一般0或1 -# saving (bool): 是否存放相机矩阵和失真系数(.npz). -# """ - -# # 终止准则/失效准则 -# criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001) -# # 准备物体点, 比如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) -# obj_p = np.zeros((row * col, 3), np.float32) -# obj_p[:, :2] = np.mgrid[0:row, 0:col].T.reshape(-1, 2) -# # 组用于存储来自所有图像的对象点和图像点。 - - -# def _find_grid(img): -# # 使用函数外的参数 -# global gray, obj_points, img_points -# # 将图片转换为灰色度图片 -# gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) -# # 寻找棋盘的角落 -# ret, corners = cv.findChessboardCorners(gray, (row, col), None) -# # 如果找到,则添加处理后的2d点和3d点 -# if ret == True: -# obj_points.append(obj_p) -# corners2 = cv.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) -# img_points.append(corners) -# # 在图片中绘制并展示所寻找到的角 -# cv.drawChessboardCorners(img, (row, col), corners2, ret) - -# # 要求必须选择使用图片校准或者摄像头实时捕获校准中的一种 -# if path and cap_num: -# raise Exception("The parameter `path` and `cap_num` only need one.") -# # 图片校准 -# if path: -# # 获取当前路径中的所有图片 -# images = glob.glob(os.path.join(path, "*.jpg")) -# pprint(images) -# # 对获取的每张图片进行处理 -# for f_name in images: -# # 读取图片 -# img = cv.imread(f_name) -# _find_grid(img) -# # 展示图片 -# cv.imshow("img", img) -# # 图片展示等待0.5s -# cv.waitKey(500) -# # 摄像头实时捕获校准 -# if cap_num: -# # 开启摄像头 -# cap = cv.VideoCapture(cap_num) -# while True: -# # 读取摄像头开启后的每帧图片 -# _, img = cap.read() -# _find_grid(img) -# cv.imshow("img", img) -# cv.waitKey(500) -# print(len(obj_points)) -# if len(obj_points) > 14: -# break -# # 销毁展示窗口 -# cv.destroyAllWindows() -# # 通过计算获取的3d点和2d点得出相机矩阵和失真系数 -# ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera( -# obj_points, img_points, gray.shape[::-1], None, None -# ) -# print("ret: {}".format(ret)) -# print("matrix:") -# pprint(mtx) -# print("distortion: {}".format(dist)) -# # 决定是否存储所计算出的参数 -# if saving: -# np.savez(os.path.join(os.path.dirname(__file__), "camera_mtx_dist.npz"), mtx=mtx, dist=dist) - -# mean_error = 0 -# for i in range(len(obj_points)): -# img_points_2, _ = cv.projectPoints(obj_points[i], rvecs[i], tvecs[i], mtx, dist) -# error = cv.norm(img_points[i], img_points_2, cv.NORM_L2) / len(img_points_2) -# mean_error += error -# print("total error: {}".format(mean_error / len(obj_points))) - -# return mtx, dist - -# if __name__ == "__main__": -# path = os.path.dirname(__file__) -# mtx, dist = calibration_camera(8, 6, path, saving=True) -# # 设置是否需要测试计算出的参数 -# if_test = input("If testing the result (default: no), [yes/no]:") -# if if_test not in ["y", "Y", "yes", "Yes"]: -# exit(0) - -# cap_num = int(input("Input camera number:")) -# cap = cv.VideoCapture(cap_num) -# while cv.waitKey(1) != ord("q"): -# _, img = cap.read() -# h, w = img.shape[:2] -# # 相机校准 -# dst = cv.undistort(img, mtx, dist) -# cv.imshow("", dst) \ No newline at end of file diff --git a/mycobot_280/mycobot_280/scripts/mtx_dist.npz b/mycobot_280/mycobot_280/scripts/mtx_dist.npz deleted file mode 100644 index 88f1cee94b75077c8812ba2091aa185d6dc84a4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 476 zcmWIWW@Zs#0D)6E?}OAD)ql?bvO$;~h;vIS^zsTSC;Nr^21GJ4xG_|#r=%7q7pYq* zsN1AjsOu=Gr{x!w6eZ@x=NF}8(>1*t&3hOv%hcmLl9DKZX=&)e^wv_QWm*>%6#=k7DwbJF*3 zZQOO?^1gNZ1H2iTM3`|0F2olM3=NGS7Br~QHKBV7p=mFW3G-rrH!B-Rh6xC>fpjz@ Ghz9^x<#y)) diff --git a/mycobot_280/mycobot_280/scripts/test.py b/mycobot_280/mycobot_280/scripts/test.py deleted file mode 100755 index a6d3a01..0000000 --- a/mycobot_280/mycobot_280/scripts/test.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/python -# -*- coding: UTF-8 -*- - -from pymycobot.mycobot import MyCobot -import time -import threading -import os - -print(os.path.join(os.path.dirname(__file__))) - -mc = MyCobot('/dev/ttyUSB0', 115200) -mc.set_tool_reference([-50,0,0,0,0,0]) -mc.set_end_type(1) - -init_angles = [0, 0.52, -85.69, 0.0, 89.82, 0.08] -start_angles = [18.64, 0.52, -85.69, 0.0, 89.82, 0.08] -end_angles = [-18.56, 0.52, -85.69, 0.0, 89.82, 0.08] - -ang = [] - -def wait_time(t): - global ang - for i in range(t*10+1): - time.sleep(0.1) - ang1 = mc.get_angles() - ang.append(ang1) - coord = mc.get_coords() - # print('ange-------->', ang) - print('coord-------->', coord) - - -def get_ang(): - i = 0 - - print('55555555555') - ang_list = None - while True: - for j in range(i,len(ang)): - i+=1 - # print('1111111111111') - # if ang_list != ang: - # ang_list = ang - - print('----------', ang[j]) - -t = threading.Thread(target=get_ang) -t.setDaemon(True) -t.start() - -def move(): - try: - mc.send_angles(init_angles, 5) - time.sleep(0.1) - - # for _ in range(50): - - # mc.send_angles(start_angles, 5) - # wait_time(6) - # mc.send_angles(end_angles, 5) - # wait_time(6) - except Exception as e: - print(e) - -while True: - t = wait_time(1) - print('dddd', t) - move() - diff --git a/mycobot_ai/ai_mecharm_270/scripts/color_test.py b/mycobot_ai/ai_mecharm_270/scripts/color_test.py deleted file mode 100644 index a21e333..0000000 --- a/mycobot_ai/ai_mecharm_270/scripts/color_test.py +++ /dev/null @@ -1,164 +0,0 @@ -# ecoding=utf-8 -import cv2 -import numpy as np -from imutils import contours -import math - -'''HSV中的颜色空间 -https://blog.csdn.net/wsp_1138886114/article/details/80660014 -''' -color_dist = {'red': {'Lower': np.array([0, 120, 120]), 'Upper': np.array([6, 255, 255])}, - # 'blue': {'Lower': np.array([100, 80, 46]), 'Upper': np.array([124, 255, 255])}, - # 'blue':{'Lower': np.array([100,43,46]),'Upper': np.array([124,255,255])}, - 'blue':{'Lower': np.array([100,43,46]),'Upper': np.array([124,255,255])}, - "cyan": {'Lower': np.array([78, 43, 46]),'Upper': np.array([99, 255, 255])}, - 'green': {'Lower': np.array([35, 43, 35]), 'Upper': np.array([90, 255, 255])}, - 'yellow': {"Lower": np.array([22, 93, 0]), "Upper": np.array([45, 255, 255])}, - # 'orange': {"Lower": np.array([0, 100, 45]), "Upper":np.array([255, 250, 255])}, - 'orange': {"Lower": np.array([11, 43, 46]), "Upper":np.array([25, 255, 255])}, - } - -cap = cv2.VideoCapture(0) -# cap = cv2.VideoCapture("src/test_1_2.mp4") -cap.set(3,420) -cap.set(4,360) - -cv2.namedWindow('camera', cv2.WINDOW_AUTOSIZE) -# 内核 -kernel = np.ones((5, 5), np.uint8) - -while cap.isOpened(): - ret, frame = cap.read() - if ret: - if frame is not None: - - gs_frame = cv2.GaussianBlur(frame, (5, 5), 0)# 高斯模糊 - hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV) # 转化成HSV图像 - erode_hsv = cv2.erode(hsv, None, iterations=2) # 腐蚀 作用是粗的变细 - for _color in color_dist: - _font_x_pos = 0 - _font_y_pos = 0 - ## 颜色阈值识别 - inRange_hsv = cv2.inRange(erode_hsv, color_dist[_color]['Lower'], color_dist[_color]['Upper']) - # 膨胀操作 - dilation = cv2.dilate(inRange_hsv, kernel, iterations=1) - # 闭操作 - closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel) - # 边缘检测 - edges = cv2.Canny(closing, 10, 20) - # 检测物体边框 - cnts, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) - - # 判断轮廓数量也就是判断是否寻找到轮廓,如果没有找到轮廓就不继续进行操作 - if len(cnts) > 0: - for cnt in cnts: - if cv2.contourArea(cnt) >1500: - peri = cv2.arcLength(cnt,True) - #print(peri) - # 用于获得轮廓的近似值,使用cv2.drawCountors进行画图操作 , - # 参数说明:cnt为输入的轮廓值, epsilon为阈值T,通常使用轮廓的周长作为阈值,True表示的是轮廓是闭合的 - ''' - cv2.approxPolyDP - @:param - cnt: - epsilon :算法参数 - True:表示是否闭合 - ''' - approx = cv2.approxPolyDP(cnt,0.02*peri,True) - # print(len(approx)) - # 提取拐点 - ''' - 返回列表元素,列表中的元素代表一个边沿信息。 - ''' - objCor = len(approx) - - if objCor ==3: - '''https://blog.51cto.com/hiszm/5201991''' - objectType = "Triangle" - mm = cv2.moments(cnt) - cx = int(mm['m10']/mm['m00']) - cy = int(mm['m01']/mm['m00']) - _font_x_pos = cx - _font_y_pos = cy - cv2.circle(frame,(cx,cy),3,(0,0,255),-1) - cv2.drawContours(frame, [cnt], 0, (0, 0, 255), 3) - print("三角形的坐标",cx,cy) - - - # 检测出是矩形 - elif objCor == 4: - # 可旋转矩形,即最小的外包矩形 - rect= cv2.minAreaRect(cnt) - ''' - @:param - 函数 cv2.minAreaRect() 返回一个Box2D结构 rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)。 - 分别对应于返回值:(rect[0][0], rect[0][1]), (rect[1][0], rect[1][1]), rect[2] - ''' - # 中心点坐标 - pos_x = int(rect[0][0]) - pos_y = int(rect[0][1]) - #print("position",pos_x,pos_y) - # 旋转角度 - theta = np.round(cv2.minAreaRect(cnt)[2],2) - box = cv2.boxPoints(rect) - box = np.int0(box) - print("物体的坐标为",(pos_x,pos_y),"旋转角度为",theta) - # 判断长方形还是正方形 - _font_x_pos = box[0][0] - _font_y_pos = box[0][1] - _W = math.sqrt(math.pow((box[0][0] - box[1][0]), 2) + math.pow((box[0][1] - box[1][1]), 2)) - _H = math.sqrt(math.pow((box[0][0] - box[3][0]), 2) + math.pow((box[0][1] - box[3][1]), 2)) - # 长宽比 - aspRatio = _W/float(_H) - if aspRatio >0.98 and aspRatio <1.03: - - objectType= "Square"#正方形 - else: - objectType="Rectangle"#长方形 - _pos = (pos_x,pos_y) - cv2.circle(frame,_pos,1,(0,0,255),2)#绘制中心点 - #cv2.putText(frame, 'teheta = ' + str(theta), (int(_font_x_pos),int(_font_y_pos+20)), cv2.FONT_HERSHEY_COMPLEX_SMALL,0.8, (0, 255, 0) ) - cv2.drawContours(frame,[box],0,(0,0,255),2) - # 圆形 - elif objCor>4: - objectType= "Circles" - ''' - void minEnclosingCircle(InputArray points, Point2f& center, float& radius) - @:param - points:输入信息,可以为包含点的容器(vector)或是Mat。 - center:包覆圆形的圆心。 - radius:包覆圆形的半径。 - ''' - (x,y),radius = cv2.minEnclosingCircle(cnt) - center = (int(x),int(y)) - radius = int(radius) - _font_x_pos = center[0] - _font_y_pos = center[1] - print("物体的圆心为:",(_font_x_pos, _font_y_pos),"半径为",radius) - cv2.circle(frame,center,1,(255,0,0),2)#绘制中心点 - cv2.circle(frame,center,radius,(255,0,0),2) - - else: - objectType="None" - # objectType 物体形状 - print("颜色类别:",_color) - cv2.putText(frame, str(_color + objectType), (int(_font_x_pos),int(_font_y_pos)), cv2.FONT_HERSHEY_COMPLEX_SMALL,1, (0, 255, 0) ) - - cv2.imshow('camera', frame) - # 存储识别结果视频 - # out.write(frame) - - cv2.waitKey(1) - if cv2.waitKey(10) & 0xFF == 27: - break - else: - print("无画面") - break - else: - print("无法读取摄像头!") - break - -cap.release() -# out.release() -cv2.waitKey(0) -cv2.destroyAllWindows() diff --git a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py deleted file mode 100644 index da893b8..0000000 --- a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py +++ /dev/null @@ -1,480 +0,0 @@ -# encoding:utf-8 -#!/usr/bin/env python2 - -import cv2 -import numpy as np -import time -import os,sys -import rospy -from visualization_msgs.msg import Marker -from pymycobot.mycobot import MyCobot -from moving_utils import Movement - -IS_CV_4 = cv2.__version__[0] == '4' -__version__ = "1.0" -# Adaptive seeed - - -class Object_detect(Movement): - - def __init__(self, camera_x = 155, camera_y = 10): - # inherit the parent class - super(Object_detect, self).__init__() - # get path of file - dir_path = os.path.dirname(__file__) - self.mc = None - - # 移动角度 - self.move_angles = [ - [-7.11, -6.94, -55.01, -24.16, 0, -15], # init the point - [18.8, -7.91, -54.49, -23.02, -0.79, -14.76], # point to grab - ] - - # 移动坐标 - self.move_coords = [ - [132.2, -136.9, 200.8, -178.24, -3.72, -107.17], # above the red bucket - [238.8, -124.1, 204.3, -169.69, -5.52, -96.52], # green - [115.8, 177.3, 210.6, 178.06, -0.92, -6.11], # blue - [-6.9, 173.2, 201.5, 179.93, 0.63, 33.83], # gray - ] - # which robot: USB* is m5; ACM* is wio; AMA* is raspi - self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] - self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] - self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] - self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] - self.raspi = False - if "dev" in self.robot_m5: - self.Pin = [2, 5] - elif "dev" in self.robot_wio: - # self.Pin = [20, 21] - self.Pin = [2, 5] - - for i in self.move_coords: - i[2] -= 20 - elif "dev" in self.robot_raspi or "dev" in self.robot_jes: - import RPi.GPIO as GPIO - GPIO.setwarnings(False) - self.GPIO = GPIO - GPIO.setmode(GPIO.BCM) - GPIO.setup(20, GPIO.OUT) - GPIO.setup(21, GPIO.OUT) - GPIO.output(20, 1) - GPIO.output(21, 1) - self.raspi = True - if self.raspi: - self.gpio_status(False) - - # choose place to set cube - self.color = 0 - # parameters to calculate camera clipping parameters - self.x1 = self.x2 = self.y1 = self.y2 = 0 - # set cache of real coord - self.cache_x = self.cache_y = 0 - # set color HSV - self.HSV = { - "yellow": [np.array([11, 115, 70]), np.array([40, 255, 245])], - "red": [np.array([0, 43, 46]), np.array([8, 255, 255])], - "green": [np.array([35, 43, 35]), np.array([90, 255, 255])], # [77, 255, 255] - "blue": [np.array([100, 43, 46]), np.array([124, 255, 255])], - "cyan": [np.array([89, 43, 46]), np.array([99, 255, 255])], # np.array([78, 43, 46]), np.array([99, 255, 255]) - } - # use to calculate coord between cube and mycobot - self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 - # The coordinates of the grab center point relative to the mycobot - self.camera_x, self.camera_y = camera_x, camera_y - # The coordinates of the cube relative to the mycobot - self.c_x, self.c_y = 0, 0 - # The ratio of pixels to actual values - self.ratio = 0 - # Get ArUco marker dict that can be detected. - self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) - # Get ArUco marker params. - self.aruco_params = cv2.aruco.DetectorParameters_create() - - # init a node and a publisher - rospy.init_node("marker", anonymous=True) - self.pub = rospy.Publisher('/cube', Marker, queue_size=1) - # init a Marker - self.marker = Marker() - self.marker.header.frame_id = "/joint1" - self.marker.ns = "cube" - self.marker.type = self.marker.CUBE - self.marker.action = self.marker.ADD - self.marker.scale.x = 0.04 - self.marker.scale.y = 0.04 - self.marker.scale.z = 0.04 - self.marker.color.a = 1.0 - self.marker.color.g = 1.0 - self.marker.color.r = 1.0 - - # marker position initial - self.marker.pose.position.x = 0 - self.marker.pose.position.y = 0 - self.marker.pose.position.z = 0.03 - self.marker.pose.orientation.x = 0 - self.marker.pose.orientation.y = 0 - self.marker.pose.orientation.z = 0 - self.marker.pose.orientation.w = 1.0 - - # publish marker - def pub_marker(self, x, y, z=0.03): - self.marker.header.stamp = rospy.Time.now() - self.marker.pose.position.x = x - self.marker.pose.position.y = y - self.marker.pose.position.z = z - self.marker.color.g = self.color - self.pub.publish(self.marker) - - def gpio_status(self, flag): - if flag: - # self.GPIO.output(20, 0) - self.GPIO.output(21, 0) - else: - # self.GPIO.output(20, 1) - self.GPIO.output(21, 1) - - # 开启吸泵 m5 - def pump_on(self): - # 让2号位工作 - # self.mc.set_basic_output(2, 0) - # 让5号位工作 - self.mc.set_basic_output(5, 0) - - # 停止吸泵 m5 - def pump_off(self): - # 让2号位停止工作 - # self.mc.set_basic_output(2, 1) - # 让5号位停止工作 - self.mc.set_basic_output(5, 1) - # Grasping motion - def move(self, x, y, color): - # send Angle to move mycobot - print (color) - self.mc.send_angles(self.move_angles[1], 25) - time.sleep(3) - - # send coordinates to move mycobot - self.mc.send_coords([x, y, 190.6, 179.87, -3.78, -62.75], 25, 1) # usb :rx,ry,rz -173.3, -5.48, -57.9 - time.sleep(3) - - # self.mc.send_coords([x, y, 150, 179.87, -3.78, -62.75], 25, 0) - # time.sleep(3) - - self.mc.send_coords([x, y, 103, 179.87, -3.78, -62.75], 25, 0) - time.sleep(3) - - # open pump - if "dev" in self.robot_m5 or "dev" in self.robot_wio: - self.pump_on() - elif "dev" in self.robot_raspi or "dev" in self.robot_jes: - self.gpio_status(True) - time.sleep(1.5) - - tmp = [] - while True: - if not tmp: - tmp = self.mc.get_angles() - else: - break - time.sleep(0.5) - - # print(tmp) - self.mc.send_angles([tmp[0], -0.71, -54.49, -23.02, -0.79, tmp[5]],25) # [18.8, -7.91, -54.49, -23.02, -0.79, -14.76] - time.sleep(2.5) - - self.pub_marker( - self.move_coords[2][0]/1000.0, self.move_coords[2][1]/1000.0, self.move_coords[2][2]/1000.0) - - self.mc.send_coords(self.move_coords[color], 25, 1) - self.pub_marker(self.move_coords[color][0]/1000.0, self.move_coords[color] - [1]/1000.0, self.move_coords[color][2]/1000.0) - time.sleep(3) - - # close pump - if "dev" in self.robot_m5 or "dev" in self.robot_wio: - self.pump_off() - elif "dev" in self.robot_raspi or "dev" in self.robot_jes: - self.gpio_status(False) - time.sleep(4) - - if color == 1: - self.pub_marker( - self.move_coords[color][0]/1000.0+0.04, self.move_coords[color][1]/1000.0-0.02) - elif color == 0: - self.pub_marker( - self.move_coords[color][0]/1000.0+0.03, self.move_coords[color][1]/1000.0) - # self.pub_angles(self.move_angles[0], 20) - self.mc.send_angles(self.move_angles[0], 25) - time.sleep(3) - - # decide whether grab cube - def decide_move(self, x, y, color): - print(x, y, self.cache_x, self.cache_y) - # detect the cube status move or run - if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm - self.cache_x, self.cache_y = x, y - return - else: - self.cache_x = self.cache_y = 0 - # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 - self.move(x, y, color) - - # init mycobot - def run(self): - if "dev" in self.robot_wio : - self.mc = MyCobot(self.robot_wio, 115200) - elif "dev" in self.robot_m5: - self.mc = MyCobot(self.robot_m5, 115200) - elif "dev" in self.robot_raspi: - self.mc = MyCobot(self.robot_raspi, 1000000) - if not self.raspi: - self.pub_pump(False, self.Pin) - self.mc.send_angles([-7.11, -6.94, -55.01, -24.16, 0, -15], 20) - time.sleep(3) - - # draw aruco - - def draw_marker(self, img, x, y): - # draw rectangle on img - cv2.rectangle( - img, - (x - 20, y - 20), - (x + 20, y + 20), - (0, 255, 0), - thickness=2, - lineType=cv2.FONT_HERSHEY_COMPLEX, - ) - # add text on rectangle - cv2.putText(img, "({},{})".format(x, y), (x, y), - cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (243, 0, 0), 2,) - - # get points of two aruco - def get_calculate_params(self, img): - # Convert the image to a gray image - gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - # Detect ArUco marker. - corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( - gray, self.aruco_dict, parameters=self.aruco_params - ) - - """ - Two Arucos must be present in the picture and in the same order. - There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. - Determine the center of the aruco by the four corners of the aruco. - """ - if len(corners) > 0: - if ids is not None: - if len(corners) <= 1 or ids[0] == 1: - return None - x1 = x2 = y1 = y2 = 0 - point_11, point_21, point_31, point_41 = corners[0][0] - x1, y1 = int((point_11[0] + point_21[0] + point_31[0] + point_41[0]) / 4.0), int( - (point_11[1] + point_21[1] + point_31[1] + point_41[1]) / 4.0) - point_1, point_2, point_3, point_4 = corners[1][0] - x2, y2 = int((point_1[0] + point_2[0] + point_3[0] + point_4[0]) / 4.0), int( - (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / 4.0) - return x1, x2, y1, y2 - return None - - # set camera clipping parameters - def set_cut_params(self, x1, y1, x2, y2): - self.x1 = int(x1) - self.y1 = int(y1) - self.x2 = int(x2) - self.y2 = int(y2) - print(self.x1, self.y1, self.x2, self.y2) - - # set parameters to calculate the coords between cube and mycobot - def set_params(self, c_x, c_y, ratio): - self.c_x = c_x - self.c_y = c_y - self.ratio = 220.0/ratio - - # calculate the coords between cube and mycobot - def get_position(self, x, y): - return ((y - self.c_y)*self.ratio + self.camera_x), ((x - self.c_x)*self.ratio + self.camera_y) - - """ - Calibrate the camera according to the calibration parameters. - Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. - If two ARuco values have been calculated, clip the video. - """ - - def transform_frame(self, frame): - # enlarge the image by 1.5 times - fx = 1.5 - fy = 1.5 - frame = cv2.resize(frame, (0, 0), fx=fx, fy=fy, - interpolation=cv2.INTER_CUBIC) - if self.x1 != self.x2: - # the cutting ratio here is adjusted according to the actual situation - frame = frame[int(self.y2*0.78):int(self.y1*1.1), - int(self.x1*0.86):int(self.x2*1.08)] - return frame - - # detect cube color - def color_detect(self, img): - # set the arrangement of color'HSV - x = y = 0 - gs_img = cv2.GaussianBlur(img, (3, 3), 0) # 高斯模糊 - # transfrom the img to model of gray - hsv = cv2.cvtColor(gs_img, cv2.COLOR_BGR2HSV) - - for mycolor, item in self.HSV.items(): - redLower = np.array(item[0]) - redUpper = np.array(item[1]) - # wipe off all color expect color in range - mask = cv2.inRange(hsv, item[0], item[1]) - # a etching operation on a picture to remove edge roughness - erosion = cv2.erode(mask, np.ones((1, 1), np.uint8), iterations=2) - # the image for expansion operation, its role is to deepen the color depth in the picture - dilation = cv2.dilate(erosion, np.ones( - (1, 1), np.uint8), iterations=2) - - - # adds pixels to the image - target = cv2.bitwise_and(img, img, mask=dilation) - # the filtered image is transformed into a binary image and placed in binary - ret, binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY) - # get the contour coordinates of the image, where contours is the coordinate value, here only the contour is detected - contours, hierarchy = cv2.findContours( - dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - - if len(contours) > 0: - # do something about misidentification - boxes = [ - box - for box in [cv2.boundingRect(c) for c in contours] - if min(img.shape[0], img.shape[1]) / 10 - < min(box[2], box[3]) - < min(img.shape[0], img.shape[1]) / 1 - ] - if boxes: - for box in boxes: - x, y, w, h = box - # find the largest object that fits the requirements - c = max(contours, key=cv2.contourArea) - # get the lower left and upper right points of the positioning object - x, y, w, h = cv2.boundingRect(c) - # locate the target by drawing rectangle - cv2.rectangle(img, (x, y), (x+w, y+h), (153, 153, 0), 2) - # calculate the rectangle center - x, y = (x*2+w)/2, (y*2+h)/2 - # calculate the real coordinates of mycobot relative to the target - if mycolor == "red": - self.color = 0 - - elif mycolor == "green": - self.color = 1 - - elif mycolor == "cyan" or mycolor == "blue": - self.color = 2 - - else: - self.color = 3 - - - if abs(x) + abs(y) > 0: - return x, y - else: - return None - - -if __name__ == "__main__": - # open the camera - cap_num = 0 - cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) - - if not cap.isOpened(): - cap.open() - # init a class of Object_detect - detect = Object_detect() - # init mycobot - detect.run() - - _init_ = 20 # - init_num = 0 - nparams = 0 - num = 0 - real_sx = real_sy = 0 - while cv2.waitKey(1) < 0: - # read camera - _, frame = cap.read() - # deal img - frame = detect.transform_frame(frame) - if _init_ > 0: - _init_ -= 1 - continue - # calculate the parameters of camera clipping - if init_num < 20: - if detect.get_calculate_params(frame) is None: - cv2.imshow("figure", frame) - continue - else: - x1, x2, y1, y2 = detect.get_calculate_params(frame) - detect.draw_marker(frame, x1, y1) - detect.draw_marker(frame, x2, y2) - detect.sum_x1 += x1 - detect.sum_x2 += x2 - detect.sum_y1 += y1 - detect.sum_y2 += y2 - init_num += 1 - continue - elif init_num == 20: - detect.set_cut_params( - (detect.sum_x1)/20.0, - (detect.sum_y1)/20.0, - (detect.sum_x2)/20.0, - (detect.sum_y2)/20.0, - ) - detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 - init_num += 1 - continue - - # calculate params of the coords between cube and mycobot - if nparams < 10: - if detect.get_calculate_params(frame) is None: - cv2.imshow("figure", frame) - continue - else: - x1, x2, y1, y2 = detect.get_calculate_params(frame) - detect.draw_marker(frame, x1, y1) - detect.draw_marker(frame, x2, y2) - detect.sum_x1 += x1 - detect.sum_x2 += x2 - detect.sum_y1 += y1 - detect.sum_y2 += y2 - nparams += 1 - continue - elif nparams == 10: - nparams += 1 - # calculate and set params of calculating real coord between cube and mycobot - detect.set_params( - (detect.sum_x1+detect.sum_x2)/20.0, - (detect.sum_y1+detect.sum_y2)/20.0, - abs(detect.sum_x1-detect.sum_x2)/10.0 + - abs(detect.sum_y1-detect.sum_y2)/10.0 - ) - print ("ok") - continue - - # get detect result - detect_result = detect.color_detect(frame) - if detect_result is None: - cv2.imshow("figure", frame) - continue - else: - x, y = detect_result - # calculate real coord between cube and mycobot - real_x, real_y = detect.get_position(x, y) - if num == 20: - detect.pub_marker(real_sx/20.0/1000.0, real_sy/20.0/1000.0) - detect.decide_move(real_sx/20.0, real_sy/20.0, detect.color) - num = real_sx = real_sy = 0 - - else: - num += 1 - real_sy += real_y - real_sx += real_x - - cv2.imshow("figure", frame) diff --git a/mycobot_ai/ai_mycobot_280/scripts/aikit_img.py b/mycobot_ai/ai_mycobot_280/scripts/aikit_img.py deleted file mode 100644 index f071a8a..0000000 --- a/mycobot_ai/ai_mycobot_280/scripts/aikit_img.py +++ /dev/null @@ -1,555 +0,0 @@ -# encoding=utf-8 -from multiprocessing import Process, Pipe -from cgi import parse -from difflib import restore -# import queue -from sys import path -from tokenize import Pointfloat -from turtle import color -# from typing_extensions import Self -import cv2 -import numpy as np -import time -import json -import os,sys - -from PIL import Image -from threading import Thread -from pymycobot.mypalletizer import MyPalletizer - -IS_CV_4 = cv2.__version__[0] == '4' -__version__ = "1.0" # Adaptive seeed - - -class Object_detect(): - - def __init__(self, camera_x = 160, camera_y = 10): - # inherit the parent class - super(Object_detect, self).__init__() - - # declare mypal260 - self.mc = None - # 移动角度 - self.move_angles = [ - [0, 0, 0, 0], # init the point - [-29.0, 5.88, -4.92, -76.28], # point to grab - [17.4, -10.1, -87.27, 5.8, -2.02, 15], # point to grab - ] - - # 移动坐标 - self.move_coords = [ - [132.6, -155.6, 211.8, -20.9], # above the red bucket - [232.5, -134.1, 197.7, -45.26], # above the green bucket - [111.6, 159, 221.5, -120], # above the blue bucket - [-15.9, 164.6, 217.5, -119.35], # above the gray bucket - ] - - # choose place to set cube - self.color = 0 - # parameters to calculate camera clipping parameters - self.x1 = self.x2 = self.y1 = self.y2 = 0 - # set cache of real coord - self.cache_x = self.cache_y = 0 - - # use to calculate coord between cube and mycobot - self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 - # The coordinates of the grab center point relative to the mycobot - self.camera_x, self.camera_y = camera_x, camera_y - # The coordinates of the cube relative to the mycobot - self.c_x, self.c_y = 0, 0 - # The ratio of pixels to actual values - self.ratio = 0 - # Get ArUco marker dict that can be detected. - self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) - # Get ArUco marker params. - self.aruco_params = cv2.aruco.DetectorParameters_create() - - # 开启吸泵 m5 - def pump_on(self): - # 让2号位工作 - # self.mc.set_basic_output(2, 0) - # 让5号位工作 - self.mc.set_basic_output(5, 0) - - # 停止吸泵 m5 - def pump_off(self): - # 让2号位停止工作 - # self.mc.set_basic_output(2, 1) - # 让5号位停止工作 - self.mc.set_basic_output(5, 1) - - # Grasping motion - def move(self, x, y, color): - # send Angle to move mypal260 - self.mc.send_angles(self.move_angles[0], 20) - time.sleep(3) - - # send coordinates to move mypal260 根据不同底板机械臂,调整吸泵高度 - self.mc.send_coords([x, y, 160, 0], 20, 0) - time.sleep(1.5) - self.mc.send_coords([x, y, 110, 0], 20, 0) - time.sleep(1.5) - - # open pump - self.pump_on() - time.sleep(1.5) - - self.mc.send_angle(2, 0, 20) - time.sleep(0.3) - self.mc.send_angle(3, -18, 20) - time.sleep(2) - - self.mc.send_coords(self.move_coords[color], 20, 1) - - time.sleep(3) - - # close pump - - self.pump_off() - time.sleep(6) - - self.mc.send_angles(self.move_angles[1], 20) - time.sleep(1.5) - self.mc.send_angles([-30, 0, 0, 0], 20) - time.sleep(1.5) - - # decide whether grab cube - def decide_move(self, x, y, color): - print(x, y, self.cache_x, self.cache_y) - # detect the cube status move or run - if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm - self.cache_x, self.cache_y = x, y - return - else: - self.cache_x = self.cache_y = 0 - # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 - print('start...') - self.move(x, y, color) - print('end....') - - # init mypal260 - def run(self): - - self.mc = MyPalletizer("COM9", 115200) - - self.mc.send_angles([-29.0, 5.88, -4.92, -76.28], 20) - time.sleep(3) - - # draw aruco - def draw_marker(self, img, x, y): - # draw rectangle on img - cv2.rectangle( - img, - (x - 20, y - 20), - (x + 20, y + 20), - (0, 255, 0), - thickness=2, - lineType=cv2.FONT_HERSHEY_COMPLEX, - ) - # add text on rectangle - cv2.putText( - img, - "({},{})".format(x, y), - (x, y), - cv2.FONT_HERSHEY_COMPLEX_SMALL, - 1, - (243, 0, 0), - 2, - ) - - # get points of two aruco - def get_calculate_params(self, img): - # Convert the image to a gray image - gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - # Detect ArUco marker. - corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( - gray, self.aruco_dict, parameters=self.aruco_params) - - """ - Two Arucos must be present in the picture and in the same order. - There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. - Determine the center of the aruco by the four corners of the aruco. - """ - if len(corners) > 0: - if ids is not None: - if len(corners) <= 1 or ids[0] == 1: - return None - x1 = x2 = y1 = y2 = 0 - point_11, point_21, point_31, point_41 = corners[0][0] - x1, y1 = int( - (point_11[0] + point_21[0] + point_31[0] + point_41[0]) / - 4.0), int( - (point_11[1] + point_21[1] + point_31[1] + point_41[1]) - / 4.0) - point_1, point_2, point_3, point_4 = corners[1][0] - x2, y2 = int( - (point_1[0] + point_2[0] + point_3[0] + point_4[0]) / - 4.0), int( - (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / - 4.0) - return x1, x2, y1, y2 - return None - - # set camera clipping parameters - def set_cut_params(self, x1, y1, x2, y2): - self.x1 = int(x1) - self.y1 = int(y1) - self.x2 = int(x2) - self.y2 = int(y2) - print(self.x1, self.y1, self.x2, self.y2) - - # set parameters to calculate the coords between cube and mycobot - def set_params(self, c_x, c_y, ratio): - self.c_x = c_x - self.c_y = c_y - self.ratio = 220.0 / ratio - - # calculate the coords between cube and mycobot - def get_position(self, x, y): - return ((y - self.c_y) * self.ratio + - self.camera_x), ((x - self.c_x) * self.ratio + self.camera_y) - - """ - Calibrate the camera according to the calibration parameters. - Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. - If two ARuco values have been calculated, clip the video. - """ - - def transform_frame(self, frame): - # enlarge the image by 1.5 times - fx = 1.5 - fy = 1.5 - frame = cv2.resize(frame, (0, 0), - fx=fx, - fy=fy, - interpolation=cv2.INTER_CUBIC) - if self.x1 != self.x2: - # the cutting ratio here is adjusted according to the actual situation - frame = frame[int(self.y2 * 0.2):int(self.y1 * 1.15), - int(self.x1 * 0.7):int(self.x2 * 1.15)] - return frame - - # according the class_id to get object name - def id_class_name(self, class_id): - for key, value in self.labels.items(): - if class_id == int(key): - return value - - # detect object - def obj_detect(self, img, goal, kp_img, desc_img, kp_list, desc_list, connection): - i = 0 - MIN_MATCH_COUNT = 5 - # sift = cv2.xfeatures2d.SIFT_create() - - # find the keypoints and descriptors with SIFT - # kp = [] - # des = [] - kp = kp_list - des = desc_list - - # for i in goal: - # kp0, des0 = sift.detectAndCompute(i, None) - # kp.append(kp0) - # des.append(des0) - - # kp1, des1 = sift.detectAndCompute(goal, None) - # kp2, des2 = sift.detectAndCompute(img, None) - kp2, des2 = kp_img, desc_img - - # FLANN parameters - FLANN_INDEX_KDTREE = 0 - index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) - search_params = dict(checks=50) # or pass empty dictionary - flann = cv2.FlannBasedMatcher(index_params, search_params) - - x, y = 0, 0 - try: - for i in range(len(des)): - matches = flann.knnMatch(des[i], des2, k=2) - # store all the good matches as per Lowe's ratio test. 根据Lowe比率测试存储所有良好匹配项。 - good = [] - for m, n in matches: - if m.distance < 0.7 * n.distance: - good.append(m) - - # When there are enough robust matching point pairs 当有足够的健壮匹配点对(至少个MIN_MATCH_COUNT)时 - if len(good) > MIN_MATCH_COUNT: - - # extract corresponding point pairs from matching 从匹配中提取出对应点对 - # query index of small objects, training index of scenarios 小对象的查询索引,场景的训练索引 - src_pts = np.float32([kp[i][m.queryIdx].pt - for m in good]).reshape(-1, 1, 2) - dst_pts = np.float32([kp2[m.trainIdx].pt - for m in good]).reshape(-1, 1, 2) - - # Using matching points to find homography matrix in cv2.ransac 利用匹配点找到CV2.RANSAC中的单应矩阵 - M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, - 5.0) - matchesMask = mask.ravel().tolist() - # Calculate the distortion of image, that is the corresponding position in frame 计算图1的畸变,也就是在图2中的对应的位置 - h, w, d = goal[i].shape - pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], - [w - 1, 0]]).reshape(-1, 1, 2) - dst = cv2.perspectiveTransform(pts, M) - coord = (dst[0][0] + dst[1][0] + dst[2][0] + - dst[3][0]) / 4.0 - connection.send((DRAW_COORDS, coord)) - # cv2.putText(img, "{}".format(coord), (50, 60), - # fontFace=None, fontScale=1, - # color=(0, 255, 0), lineType=1) - print(format(dst[0][0][0])) - x = (dst[0][0][0] + dst[1][0][0] + dst[2][0][0] + - dst[3][0][0]) / 4.0 - y = (dst[0][0][1] + dst[1][0][1] + dst[2][0][1] + - dst[3][0][1]) / 4.0 - - # bound box 绘制边框 - # img = cv2.polylines(img, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) - connection.send((DRAW_RECT, dst)) - # cv2.polylines(mixture, [np.int32(dst)], True, (0, 255, 0), 2, cv2.LINE_AA) - except Exception as e: - pass - - if x + y > 0: - return x, y - else: - return None - -# The path to save the image folder -def parse_folder(folder): - restore = [] - path1 = '/home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mypalletizer_260/' + folder - path2 = r'D:/BaiduSyncdisk/PythonProject/OpenCV' + folder - - # if os.path.exists(path1): - # path = path1 - # elif os.path.exists(path2): - path = path1 - - for i, j, k in os.walk(path): - for l in k: - restore.append(cv2.imread(folder + '/{}'.format(l))) - return restore - -def compute_keypoints_and_descriptors(sift, images_lists): - kp_list = [] - desc_list = [] - for images in images_lists: - kp_tmp = [] - desc_tmp = [] - for img in images: - kp, desc = sift.detectAndCompute(img, None) - kp_tmp.append(kp) - desc_tmp.append(desc) - kp_list.append(kp_tmp) - desc_list.append(desc_tmp) - - return kp_list, desc_list - -GET_FRAME = 1 -STOP_PROCESSING = 2 -DRAW_COORDS = 3 -DRAW_RECT = 4 -CLEAR_DRAW = 5 -CROP_FRAME = 6 - -def get_frame(connection): - connection.send(GET_FRAME) - frame = connection.recv() - return frame - -def process_transform_frame(frame, x1, y1, x2, y2): - # enlarge the image by 1.5 times - fx = 1.5 - fy = 1.5 - frame = cv2.resize(frame, (0, 0), - fx=fx, - fy=fy, - interpolation=cv2.INTER_CUBIC) -# if x1 != x2: - # the cutting ratio here is adjusted according to the actual situation -# frame = frame[int(y2 * 0.2):int(y1 * 1.15), -# int(x1 * 0.7):int(x2 * 1.15)] - return frame - -def process_display_frame(connection): - cap_num = 1 - coord = None - dst = None - x1 = 0 - y1 = 0 - x2 = 0 - y2 = 0 - cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) - if not cap.isOpened(): - cap.open(1) - while cv2.waitKey(1) < 0: - _, frame = cap.read() - frame = process_transform_frame(frame, x1, y1, x2, y2) - if connection.poll(): - request = connection.recv() - if request == GET_FRAME: - connection.send(frame) - elif request == CLEAR_DRAW: - coord = None - dst = None - elif type(request) is tuple: - if request[0] == DRAW_COORDS: - coord = request[1] - elif request[0] == DRAW_RECT: - dst = request[1] - elif request[0] == CROP_FRAME: - x1 = request[1] - y1 = request[2] - x2 = request[3] - y2 = request[4] - - if not coord is None: - cv2.putText(frame, "{}".format(coord), (50, 60), fontFace=None, - fontScale=1, color=(0, 255, 0), lineType=1) - if not dst is None: - frame = cv2.polylines(frame, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) - cv2.imshow("figure", frame) - time.sleep(0.04) - connection.send(STOP_PROCESSING) - -def run(): - parent_conn, child_conn = Pipe() - child = Process(target = process_display_frame, args=(child_conn,)) - child.start() - - res_queue = [[], [], [], []] - res_queue[0] = parse_folder('res/red') - res_queue[1] = parse_folder('res/green') - res_queue[2] = parse_folder('res/blue') - res_queue[3] = parse_folder('res/gray') - - sift = cv2.xfeatures2d.SIFT_create() - kp_list, desc_list = compute_keypoints_and_descriptors(sift, res_queue) - - # init a class of Object_detect - detect = Object_detect() - - # init mycobot - detect.run() - - # _init_ = 20 # - init_num = 0 - nparams = 0 - # num = 0 - # real_sx = real_sy = 0 - while True: - start_time = time.time() - if parent_conn.poll(): - data = parent_conn.recv() - if data == STOP_PROCESSING: - break - # read camera - frame = get_frame(parent_conn) - # deal img - #frame = detect.transform_frame(frame) - - # if _init_ > 0: - # _init_ -= 1 - # continue - # calculate the parameters of camera clipping - if init_num < 20: - if detect.get_calculate_params(frame) is None: - # cv2.imshow("figure", frame) - continue - else: - x1, x2, y1, y2 = detect.get_calculate_params(frame) - detect.draw_marker(frame, x1, y1) - detect.draw_marker(frame, x2, y2) - detect.sum_x1 += x1 - detect.sum_x2 += x2 - detect.sum_y1 += y1 - detect.sum_y2 += y2 - init_num += 1 - continue - elif init_num == 20: - detect.set_cut_params( - (detect.sum_x1) / 20.0, - (detect.sum_y1) / 20.0, - (detect.sum_x2) / 20.0, - (detect.sum_y2) / 20.0, - ) - parent_conn.send((CROP_FRAME, - (detect.sum_x1) / 20.0, - (detect.sum_y1) / 20.0, - (detect.sum_x2) / 20.0, - (detect.sum_y2) / 20.0)) - detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 - init_num += 1 - continue - - # calculate params of the coords between cube and mycobot - if nparams < 10: - if detect.get_calculate_params(frame) is None: - # cv2.imshow("figure", frame) - continue - else: - x1, x2, y1, y2 = detect.get_calculate_params(frame) - detect.draw_marker(frame, x1, y1) - detect.draw_marker(frame, x2, y2) - detect.sum_x1 += x1 - detect.sum_x2 += x2 - detect.sum_y1 += y1 - detect.sum_y2 += y2 - nparams += 1 - print ("ok") - continue - elif nparams == 10: - nparams += 1 - # calculate and set params of calculating real coord between cube and mycobot - detect.set_params((detect.sum_x1 + detect.sum_x2) / 20.0, - (detect.sum_y1 + detect.sum_y2) / 20.0, - abs(detect.sum_x1 - detect.sum_x2) / 10.0 + - abs(detect.sum_y1 - detect.sum_y2) / 10.0) - print("ok") - continue - - # get detect result - kp_img, desc_img = sift.detectAndCompute(frame, None) - frame = get_frame(parent_conn) - for i, v in enumerate(res_queue): - # HACK: to update frame every time - detect_result = detect.obj_detect(frame, v, kp_img, desc_img, kp_list[i], desc_list[i], parent_conn) - if detect_result: - x, y = detect_result - # calculate real coord between cube and mycobot - real_x, real_y = detect.get_position(x, y) - detect.color = i - detect.pub_marker(real_x / 1000.0, real_y / 1000.0) - detect.decide_move(real_x, real_y, detect.color) - # if num == 5: - # detect.color = i - # detect.pub_marker(real_sx / 5.0 / 1000.0, - # real_sy / 5.0 / 1000.0) - # detect.decide_move(real_sx / 5.0, real_sy / 5.0, - # detect.color) - # num = real_sx = real_sy = 0 - # else: - # num += 1 - # real_sy += real_y - # real_sx += real_x - parent_conn.send(CLEAR_DRAW) - - # cv2.imshow("figure", frame) - time.sleep(0.05) - end_time = time.time() - # print("loop_time = ", end_time - start_time) - - # close the window - if cv2.waitKey(1) & 0xFF == ord('q'): - # cap.release() - cv2.destroyAllWindows() - sys.exit() - - child.join() - - -if __name__ == "__main__": - run() - # Object_detect().take_photo() - # Object_detect().cut_photo() \ No newline at end of file diff --git a/mycobot_ai/ai_mycobot_280/scripts/encode_test.py b/mycobot_ai/ai_mycobot_280/scripts/encode_test.py deleted file mode 100644 index dfd5c47..0000000 --- a/mycobot_ai/ai_mycobot_280/scripts/encode_test.py +++ /dev/null @@ -1,248 +0,0 @@ -# encoding: UTF-8 -#!/usr/bin/env python2 -import cv2 as cv -import os -import numpy as np -import time -import rospy -from visualization_msgs.msg import Marker -from moving_utils import Movement - -# y轴偏移量 -pump_y = -55 -# x轴偏移量 -pump_x = 15 - - -class Detect_marker(Movement): - def __init__(self): - super(Detect_marker, self).__init__() - # set cache of real coord - self.cache_x = self.cache_y = 0 - - # which robot - self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] - self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] - self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] - self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] - self.raspi = False - if "dev" in self.robot_m5: - self.Pin = [2, 5] - elif "dev" in self.robot_wio: - self.Pin = [20, 21] - # for i in self.move_coords: - # i[2] -= 20 - elif "dev" in self.robot_raspi or "dev" in self.robot_jes: - import RPi.GPIO as GPIO - self.GPIO = GPIO - GPIO.setwarnings(False) - GPIO.setmode(GPIO.BCM) - GPIO.setup(20, GPIO.OUT) - GPIO.setup(21, GPIO.OUT) - self.raspi = True - if self.raspi: - self.gpio_status(False) - else: - self.pub_pump(False, self.Pin) - # Creating a Camera Object - cap_num = 0 - self.cap = cv.VideoCapture(cap_num, cv.CAP_V4L) - # Get ArUco marker dict that can be detected. - self.aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_6X6_250) - # Get ArUco marker params. - self.aruco_params = cv.aruco.DetectorParameters_create() - self.calibrationParams = cv.FileStorage( - "calibrationFileName.xml", cv.FILE_STORAGE_READ) - # Get distance coefficient. - self.dist_coeffs = self.calibrationParams.getNode("distCoeffs").mat() - - height = self.cap.get(4) - focal_length = width = self.cap.get(3) - center = [width / 2, height / 2] - # Calculate the camera matrix. - self.camera_matrix = np.array( - [ - [focal_length, 0, center[0]], - [0, focal_length, center[1]], - [0, 0, 1], - ], - dtype=np.float32, - ) - # init a node and a publisher - rospy.init_node("encode_marker", anonymous=True) - self.pub = rospy.Publisher('/cube', Marker, queue_size=1) - - self.marker = Marker() - self.marker.header.frame_id = "/joint1" - self.marker.ns = "cube" - self.marker.type = self.marker.CUBE - self.marker.action = self.marker.ADD - self.marker.scale.x = 0.04 - self.marker.scale.y = 0.04 - self.marker.scale.z = 0.04 - self.marker.color.a = 1 - self.marker.color.r = 0.3 - self.marker.color.g = 0.3 - self.marker.color.b = 0.3 - - # marker position initial - self.marker.pose.position.x = 0 - self.marker.pose.position.y = 0 - self.marker.pose.position.z = 0.03 - self.marker.pose.orientation.x = 0 - self.marker.pose.orientation.y = 0 - self.marker.pose.orientation.z = 0 - self.marker.pose.orientation.w = 1.0 - - # Grasping motion - def move(self, x, y): - if self.raspi: - coords = [ - [145.6, -64.9, 285.2, 179.88, 7.67, 179], - [130.1, -155.6, 243.9, 178.99, 5.38, -179.9] - ] - else: - coords = [ - [135.0, -65.5, 280.1, 178.99, 5.38, -179.9], - [136.1, -141.6, 243.9, 178.99, 5.38, -179.9] - ] - - # publish marker - self.marker.header.stamp = rospy.Time.now() - self.marker.pose.position.x = (coords[0][0]-x)/1000.0 - self.marker.pose.position.y = (coords[0][1]-y)/1000.0 - self.pub.publish(self.marker) - - # send coordinates to move mycobot - self.pub_coords(coords[0], 30, 1) - time.sleep(2) - self.pub_coords([coords[0][0]-x, coords[0][1]-y, - 240, 178.99, 5.38, -179.9], 25, 1) - time.sleep(2) - self.pub_coords([coords[0][0]-x, coords[0][1]-y, - 200, 178.99, 5.38, -179.9], 25, 1) - time.sleep(2) - if "dev" in self.robot_m5 or self.raspi: - self.pub_coords([coords[0][0]-x, coords[0][1]-y, - 90, 178.99, 5.38, -179.9], 25, 1) - elif "dev" in self.robot_wio: - self.pub_coords([coords[0][0]-x+20, coords[0][1] - - y-10, 70, 178.99, 5.38, -179.9], 25, 1) - time.sleep(2) - if self.raspi: - self.gpio_status(True) - else: - self.pub_pump(True, self.Pin) - time.sleep(1) - self.pub_coords(coords[0], 30, 1) - time.sleep(3) - self.pub_coords(coords[1], 30, 1) - time.sleep(2) - if self.raspi: - self.gpio_status(False) - else: - self.pub_pump(False, self.Pin) - # publish marker - time.sleep(1) - self.marker.header.stamp = rospy.Time.now() - self.marker.pose.position.x = coords[1][0]/1000.0 - self.marker.pose.position.y = coords[1][1]/1000.0 - self.pub.publish(self.marker) - - self.pub_coords(coords[0], 30, 1) - time.sleep(2) - - def gpio_status(self, flag): - if flag: - self.GPIO.output(20, 0) - self.GPIO.output(21, 0) - else: - self.GPIO.output(20, 1) - self.GPIO.output(21, 1) - - # decide whether grab cube - def decide_move(self, x, y): - - print(x, y) - # detect the cube status move or run - if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm - self.cache_x, self.cache_y = x, y - return - else: - self.cache_x = self.cache_y = 0 - if "dev" in self.robot_jes: - if x > -20: - y += 10 - if y > -25: - x -= 5 - x += 10 - - self.move(x, y) - - # init mycobot - def init_mycobot(self): - - for _ in range(5): - print(_) - self.pub_coords([145.6, -64.9, 285.2, 179.88, 7.67, 179], 20, 1) - time.sleep(0.5) - - def run(self): - global pump_y, pump_x - self.init_mycobot() - num = sum_x = sum_y = 0 - while cv.waitKey(1) < 0: - success, img = self.cap.read() - if not success: - print("It seems that the image cannot be acquired correctly.") - break - - # transfrom the img to model of gray - gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) - # Detect ArUco marker. - corners, ids, rejectImaPoint = cv.aruco.detectMarkers( - gray, self.aruco_dict, parameters=self.aruco_params - ) - font = cv.FONT_HERSHEY_SIMPLEX - if len(corners) > 0: - if ids is not None: - # get informations of aruco - ret = cv.aruco.estimatePoseSingleMarkers( - corners, 0.03, self.camera_matrix, self.dist_coeffs - ) - # rvec:rotation offset,tvec:translation deviator - (rvec, tvec) = (ret[0], ret[1]) - (rvec - tvec).any() - xyz = tvec[0, 0, :] - # calculate the coordinates of the aruco relative to the pump - xyz = [round(xyz[0]*1000+pump_y, 2), round(xyz[1] - * 1000+pump_x, 2), round(xyz[2]*1000, 2)] - cv.putText(img, "Id: " + str(ids[0][0]), (0, 40), font, 0.6, (0, 255, 0), 2, cv.LINE_AA) - for i in range(rvec.shape[0]): - # draw the aruco on img - cv.aruco.drawDetectedMarkers(img, corners) - cv.aruco.drawAxis( - img, - self.camera_matrix, - self.dist_coeffs, - rvec[i, :, :], - tvec[i, :, :], - 0.03, - ) - - if num < 40: - if self.raspi: - sum_x -= 30 - sum_x += xyz[1] - sum_y += xyz[0] - num += 1 - elif num == 40: - self.decide_move(sum_x/40.0, sum_y/40.0) - num = sum_x = sum_y = 0 - - cv.imshow("encode_image", img) - - -if __name__ == "__main__": - detect = Detect_marker() - detect.run() diff --git a/mycobot_ai/ai_mypalletizer_260/scripts/aikit_img.py b/mycobot_ai/ai_mypalletizer_260/scripts/aikit_img.py deleted file mode 100644 index 770ee11..0000000 --- a/mycobot_ai/ai_mypalletizer_260/scripts/aikit_img.py +++ /dev/null @@ -1,557 +0,0 @@ -# encoding=utf-8 -#!/usr/bin/env python2 -from multiprocessing import Process, Pipe -from cgi import parse -from difflib import restore -# import queue -from sys import path -from tokenize import Pointfloat -from turtle import color -# from typing_extensions import Self -import cv2 -import numpy as np -import time -import json -import os,sys - -from PIL import Image -from threading import Thread -from pymycobot.mypalletizer import MyPalletizer - -IS_CV_4 = cv2.__version__[0] == '4' -__version__ = "1.0" # Adaptive seeed - -__metaclass__ = type - -class Object_detect(): - - def __init__(self, camera_x = 160, camera_y = 10): - # inherit the parent class - super(Object_detect, self).__init__() - - # declare mypal260 - self.mc = None - # 移动角度 - self.move_angles = [ - [0, 0, 0, 0], # init the point - [-29.0, 5.88, -4.92, -76.28], # point to grab - [17.4, -10.1, -87.27, 5.8, -2.02, 15], # point to grab - ] - - # 移动坐标 - self.move_coords = [ - [132.6, -155.6, 211.8, -20.9], # above the red bucket - [232.5, -134.1, 197.7, -45.26], # above the green bucket - [111.6, 159, 221.5, -120], # above the blue bucket - [-15.9, 164.6, 217.5, -119.35], # above the gray bucket - ] - - # choose place to set cube - self.color = 0 - # parameters to calculate camera clipping parameters - self.x1 = self.x2 = self.y1 = self.y2 = 0 - # set cache of real coord - self.cache_x = self.cache_y = 0 - - # use to calculate coord between cube and mycobot - self.sum_x1 = self.sum_x2 = self.sum_y2 = self.sum_y1 = 0 - # The coordinates of the grab center point relative to the mycobot - self.camera_x, self.camera_y = camera_x, camera_y - # The coordinates of the cube relative to the mycobot - self.c_x, self.c_y = 0, 0 - # The ratio of pixels to actual values - self.ratio = 0 - # Get ArUco marker dict that can be detected. - self.aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) - # Get ArUco marker params. - self.aruco_params = cv2.aruco.DetectorParameters_create() - - # 开启吸泵 m5 - def pump_on(self): - # 让2号位工作 - # self.mc.set_basic_output(2, 0) - # 让5号位工作 - self.mc.set_basic_output(5, 0) - - # 停止吸泵 m5 - def pump_off(self): - # 让2号位停止工作 - # self.mc.set_basic_output(2, 1) - # 让5号位停止工作 - self.mc.set_basic_output(5, 1) - - # Grasping motion - def move(self, x, y, color): - # send Angle to move mypal260 - self.mc.send_angles(self.move_angles[0], 20) - time.sleep(3) - - # send coordinates to move mypal260 根据不同底板机械臂,调整吸泵高度 - self.mc.send_coords([x, y, 160, 0], 20, 0) - time.sleep(1.5) - self.mc.send_coords([x, y, 110, 0], 20, 0) - time.sleep(1.5) - - # open pump - self.pump_on() - time.sleep(1.5) - - self.mc.send_angle(2, 0, 20) - time.sleep(0.3) - self.mc.send_angle(3, -18, 20) - time.sleep(2) - - self.mc.send_coords(self.move_coords[color], 20, 1) - - time.sleep(3) - - # close pump - - self.pump_off() - time.sleep(6) - - self.mc.send_angles(self.move_angles[1], 20) - time.sleep(1.5) - self.mc.send_angles([-30, 0, 0, 0], 20) - time.sleep(1.5) - - # decide whether grab cube - def decide_move(self, x, y, color): - print(x, y, self.cache_x, self.cache_y) - # detect the cube status move or run - if (abs(x - self.cache_x) + abs(y - self.cache_y)) / 2 > 5: # mm - self.cache_x, self.cache_y = x, y - return - else: - self.cache_x = self.cache_y = 0 - # 调整吸泵吸取位置,y增大,向左移动;y减小,向右移动;x增大,前方移动;x减小,向后方移动 - print('start...') - self.move(x, y, color) - print('end....') - - # init mypal260 - def run(self): - - self.mc = MyPalletizer("/dev/ttyUSB0", 115200) - - self.mc.send_angles([-29.0, 5.88, -4.92, -76.28], 20) - time.sleep(3) - - # draw aruco - def draw_marker(self, img, x, y): - # draw rectangle on img - cv2.rectangle( - img, - (x - 20, y - 20), - (x + 20, y + 20), - (0, 255, 0), - thickness=2, - lineType=cv2.FONT_HERSHEY_COMPLEX, - ) - # add text on rectangle - cv2.putText( - img, - "({},{})".format(x, y), - (x, y), - cv2.FONT_HERSHEY_COMPLEX_SMALL, - 1, - (243, 0, 0), - 2, - ) - - # get points of two aruco - def get_calculate_params(self, img): - # Convert the image to a gray image - gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - # Detect ArUco marker. - corners, ids, rejectImaPoint = cv2.aruco.detectMarkers( - gray, self.aruco_dict, parameters=self.aruco_params) - - """ - Two Arucos must be present in the picture and in the same order. - There are two Arucos in the Corners, and each aruco contains the pixels of its four corners. - Determine the center of the aruco by the four corners of the aruco. - """ - if len(corners) > 0: - if ids is not None: - if len(corners) <= 1 or ids[0] == 1: - return None - x1 = x2 = y1 = y2 = 0 - point_11, point_21, point_31, point_41 = corners[0][0] - x1, y1 = int( - (point_11[0] + point_21[0] + point_31[0] + point_41[0]) / - 4.0), int( - (point_11[1] + point_21[1] + point_31[1] + point_41[1]) - / 4.0) - point_1, point_2, point_3, point_4 = corners[1][0] - x2, y2 = int( - (point_1[0] + point_2[0] + point_3[0] + point_4[0]) / - 4.0), int( - (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / - 4.0) - return x1, x2, y1, y2 - return None - - # set camera clipping parameters - def set_cut_params(self, x1, y1, x2, y2): - self.x1 = int(x1) - self.y1 = int(y1) - self.x2 = int(x2) - self.y2 = int(y2) - print(self.x1, self.y1, self.x2, self.y2) - - # set parameters to calculate the coords between cube and mycobot - def set_params(self, c_x, c_y, ratio): - self.c_x = c_x - self.c_y = c_y - self.ratio = 220.0 / ratio - - # calculate the coords between cube and mycobot - def get_position(self, x, y): - return ((y - self.c_y) * self.ratio + - self.camera_x), ((x - self.c_x) * self.ratio + self.camera_y) - - """ - Calibrate the camera according to the calibration parameters. - Enlarge the video pixel by 1.5 times, which means enlarge the video size by 1.5 times. - If two ARuco values have been calculated, clip the video. - """ - - def transform_frame(self, frame): - # enlarge the image by 1.5 times - fx = 1.5 - fy = 1.5 - frame = cv2.resize(frame, (0, 0), - fx=fx, - fy=fy, - interpolation=cv2.INTER_CUBIC) - if self.x1 != self.x2: - # the cutting ratio here is adjusted according to the actual situation - frame = frame[int(self.y2 * 0.2):int(self.y1 * 1.15), - int(self.x1 * 0.7):int(self.x2 * 1.15)] - return frame - - # according the class_id to get object name - def id_class_name(self, class_id): - for key, value in self.labels.items(): - if class_id == int(key): - return value - - # detect object - def obj_detect(self, img, goal, kp_img, desc_img, kp_list, desc_list, connection): - i = 0 - MIN_MATCH_COUNT = 5 - # sift = cv2.xfeatures2d.SIFT_create() - - # find the keypoints and descriptors with SIFT - # kp = [] - # des = [] - kp = kp_list - des = desc_list - - # for i in goal: - # kp0, des0 = sift.detectAndCompute(i, None) - # kp.append(kp0) - # des.append(des0) - - # kp1, des1 = sift.detectAndCompute(goal, None) - # kp2, des2 = sift.detectAndCompute(img, None) - kp2, des2 = kp_img, desc_img - - # FLANN parameters - FLANN_INDEX_KDTREE = 0 - index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) - search_params = dict(checks=50) # or pass empty dictionary - flann = cv2.FlannBasedMatcher(index_params, search_params) - - x, y = 0, 0 - try: - for i in range(len(des)): - matches = flann.knnMatch(des[i], des2, k=2) - # store all the good matches as per Lowe's ratio test. 根据Lowe比率测试存储所有良好匹配项。 - good = [] - for m, n in matches: - if m.distance < 0.7 * n.distance: - good.append(m) - - # When there are enough robust matching point pairs 当有足够的健壮匹配点对(至少个MIN_MATCH_COUNT)时 - if len(good) > MIN_MATCH_COUNT: - - # extract corresponding point pairs from matching 从匹配中提取出对应点对 - # query index of small objects, training index of scenarios 小对象的查询索引,场景的训练索引 - src_pts = np.float32([kp[i][m.queryIdx].pt - for m in good]).reshape(-1, 1, 2) - dst_pts = np.float32([kp2[m.trainIdx].pt - for m in good]).reshape(-1, 1, 2) - - # Using matching points to find homography matrix in cv2.ransac 利用匹配点找到CV2.RANSAC中的单应矩阵 - M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, - 5.0) - matchesMask = mask.ravel().tolist() - # Calculate the distortion of image, that is the corresponding position in frame 计算图1的畸变,也就是在图2中的对应的位置 - h, w, d = goal[i].shape - pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], - [w - 1, 0]]).reshape(-1, 1, 2) - dst = cv2.perspectiveTransform(pts, M) - coord = (dst[0][0] + dst[1][0] + dst[2][0] + - dst[3][0]) / 4.0 - connection.send((DRAW_COORDS, coord)) - # cv2.putText(img, "{}".format(coord), (50, 60), - # fontFace=None, fontScale=1, - # color=(0, 255, 0), lineType=1) - print(format(dst[0][0][0])) - x = (dst[0][0][0] + dst[1][0][0] + dst[2][0][0] + - dst[3][0][0]) / 4.0 - y = (dst[0][0][1] + dst[1][0][1] + dst[2][0][1] + - dst[3][0][1]) / 4.0 - - # bound box 绘制边框 - # img = cv2.polylines(img, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) - connection.send((DRAW_RECT, dst)) - # cv2.polylines(mixture, [np.int32(dst)], True, (0, 255, 0), 2, cv2.LINE_AA) - except Exception as e: - pass - - if x + y > 0: - return x, y - else: - return None - -# The path to save the image folder -def parse_folder(folder): - restore = [] - path1 = '/home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mypalletizer_260/' + folder - path2 = r'D:/BaiduSyncdisk/PythonProject/OpenCV' + folder - - # if os.path.exists(path1): - # path = path1 - # elif os.path.exists(path2): - path = path1 - - for i, j, k in os.walk(path): - for l in k: - restore.append(cv2.imread(folder + '/{}'.format(l))) - return restore - -def compute_keypoints_and_descriptors(sift, images_lists): - kp_list = [] - desc_list = [] - for images in images_lists: - kp_tmp = [] - desc_tmp = [] - for img in images: - kp, desc = sift.detectAndCompute(img, None) - kp_tmp.append(kp) - desc_tmp.append(desc) - kp_list.append(kp_tmp) - desc_list.append(desc_tmp) - - return kp_list, desc_list - -GET_FRAME = 1 -STOP_PROCESSING = 2 -DRAW_COORDS = 3 -DRAW_RECT = 4 -CLEAR_DRAW = 5 -CROP_FRAME = 6 - -def get_frame(connection): - connection.send(GET_FRAME) - frame = connection.recv() - return frame - -def process_transform_frame(frame, x1, y1, x2, y2): - # enlarge the image by 1.5 times - fx = 1.5 - fy = 1.5 - frame = cv2.resize(frame, (0, 0), - fx=fx, - fy=fy, - interpolation=cv2.INTER_CUBIC) -# if x1 != x2: - # the cutting ratio here is adjusted according to the actual situation -# frame = frame[int(y2 * 0.2):int(y1 * 1.15), -# int(x1 * 0.7):int(x2 * 1.15)] - return frame - -def process_display_frame(connection): - cap_num = 0 - coord = None - dst = None - x1 = 0 - y1 = 0 - x2 = 0 - y2 = 0 - cap = cv2.VideoCapture(cap_num, cv2.CAP_V4L) - if not cap.isOpened(): - cap.open() - while cv2.waitKey(1) < 0: - _, frame = cap.read() - frame = process_transform_frame(frame, x1, y1, x2, y2) - if connection.poll(): - request = connection.recv() - if request == GET_FRAME: - connection.send(frame) - elif request == CLEAR_DRAW: - coord = None - dst = None - elif type(request) is tuple: - if request[0] == DRAW_COORDS: - coord = request[1] - elif request[0] == DRAW_RECT: - dst = request[1] - elif request[0] == CROP_FRAME: - x1 = request[1] - y1 = request[2] - x2 = request[3] - y2 = request[4] - - if not coord is None: - cv2.putText(frame, "{}".format(coord), (50, 60), fontFace=None, - fontScale=1, color=(0, 255, 0), lineType=1) - if not dst is None: - frame = cv2.polylines(frame, [np.int32(dst)], True, 244, 3, cv2.LINE_AA) - cv2.imshow("figure", frame) - time.sleep(0.04) - connection.send(STOP_PROCESSING) - -def run(): - parent_conn, child_conn = Pipe() - child = Process(target = process_display_frame, args=(child_conn,)) - child.start() - - res_queue = [[], [], [], []] - res_queue[0] = parse_folder('res/red') - res_queue[1] = parse_folder('res/green') - res_queue[2] = parse_folder('res/blue') - res_queue[3] = parse_folder('res/gray') - - sift = cv2.xfeatures2d.SIFT_create() - kp_list, desc_list = compute_keypoints_and_descriptors(sift, res_queue) - - # init a class of Object_detect - detect = Object_detect() - - # init mycobot - detect.run() - - # _init_ = 20 # - init_num = 0 - nparams = 0 - # num = 0 - # real_sx = real_sy = 0 - while True: - start_time = time.time() - if parent_conn.poll(): - data = parent_conn.recv() - if data == STOP_PROCESSING: - break - # read camera - frame = get_frame(parent_conn) - # deal img - #frame = detect.transform_frame(frame) - - # if _init_ > 0: - # _init_ -= 1 - # continue - # calculate the parameters of camera clipping - if init_num < 20: - if detect.get_calculate_params(frame) is None: - # cv2.imshow("figure", frame) - continue - else: - x1, x2, y1, y2 = detect.get_calculate_params(frame) - detect.draw_marker(frame, x1, y1) - detect.draw_marker(frame, x2, y2) - detect.sum_x1 += x1 - detect.sum_x2 += x2 - detect.sum_y1 += y1 - detect.sum_y2 += y2 - init_num += 1 - continue - elif init_num == 20: - detect.set_cut_params( - (detect.sum_x1) / 20.0, - (detect.sum_y1) / 20.0, - (detect.sum_x2) / 20.0, - (detect.sum_y2) / 20.0, - ) - parent_conn.send((CROP_FRAME, - (detect.sum_x1) / 20.0, - (detect.sum_y1) / 20.0, - (detect.sum_x2) / 20.0, - (detect.sum_y2) / 20.0)) - detect.sum_x1 = detect.sum_x2 = detect.sum_y1 = detect.sum_y2 = 0 - init_num += 1 - continue - - # calculate params of the coords between cube and mycobot - if nparams < 10: - if detect.get_calculate_params(frame) is None: - # cv2.imshow("figure", frame) - continue - else: - x1, x2, y1, y2 = detect.get_calculate_params(frame) - detect.draw_marker(frame, x1, y1) - detect.draw_marker(frame, x2, y2) - detect.sum_x1 += x1 - detect.sum_x2 += x2 - detect.sum_y1 += y1 - detect.sum_y2 += y2 - nparams += 1 - print ("ok") - continue - elif nparams == 10: - nparams += 1 - # calculate and set params of calculating real coord between cube and mycobot - detect.set_params((detect.sum_x1 + detect.sum_x2) / 20.0, - (detect.sum_y1 + detect.sum_y2) / 20.0, - abs(detect.sum_x1 - detect.sum_x2) / 10.0 + - abs(detect.sum_y1 - detect.sum_y2) / 10.0) - print("ok") - continue - - # get detect result - kp_img, desc_img = sift.detectAndCompute(frame, None) - frame = get_frame(parent_conn) - for i, v in enumerate(res_queue): - # HACK: to update frame every time - detect_result = detect.obj_detect(frame, v, kp_img, desc_img, kp_list[i], desc_list[i], parent_conn) - if detect_result: - x, y = detect_result - # calculate real coord between cube and mycobot - real_x, real_y = detect.get_position(x, y) - detect.color = i - # detect.pub_marker(real_x / 1000.0, real_y / 1000.0) - detect.decide_move(real_x, real_y, detect.color) - # if num == 5: - # detect.color = i - # detect.pub_marker(real_sx / 5.0 / 1000.0, - # real_sy / 5.0 / 1000.0) - # detect.decide_move(real_sx / 5.0, real_sy / 5.0, - # detect.color) - # num = real_sx = real_sy = 0 - # else: - # num += 1 - # real_sy += real_y - # real_sx += real_x - parent_conn.send(CLEAR_DRAW) - - # cv2.imshow("figure", frame) - time.sleep(0.05) - end_time = time.time() - # print("loop_time = ", end_time - start_time) - - # close the window - if cv2.waitKey(1) & 0xFF == ord('q'): - # cap.release() - cv2.destroyAllWindows() - sys.exit() - - child.join() - - -if __name__ == "__main__": - run() - # Object_detect().take_photo() - # Object_detect().cut_photo() \ No newline at end of file From c682b6a9428969acdb6e97ecf1dba15d803ed6ae Mon Sep 17 00:00:00 2001 From: weijian Date: Wed, 7 Dec 2022 10:23:06 +0800 Subject: [PATCH 06/12] update mecharm_270 M5 point --- .../scripts/combine_detect_obj_color.py | 18 ++++++++----- .../combine_detect_obj_img_folder_opt.py | 26 +++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py index 3a8e940..1cf478a 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py +++ b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py @@ -40,8 +40,8 @@ class Object_detect(Movement): self.move_coords = [ [92.3, -104.9, 211.4, -179.6, 28.91, 131.29], # above the red bucket [165.0, -93.6, 201.4, -173.43, 46.23, 160.65], # above the green bucket - [88.1, 126.3, 193.4, 162.15, 2.23, 156.02], # above the blue bucket - [-5.4, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket + [84.3, 123.8, 205.0, 153.45, -3.67, 142.01], # above the blue bucket + [-15, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket ] # which robot: USB* is m5; ACM* is wio; AMA* is raspi @@ -54,7 +54,9 @@ class Object_detect(Movement): self.Pin = [2, 5] # self.Pin = [5] elif "dev" in self.robot_wio: - self.Pin = [20, 21] + # self.Pin = [20, 21] + self.Pin = [2, 5] + # self.Pin = [5] for i in self.move_coords: i[2] -= 20 elif "dev" in self.robot_raspi or "dev" in self.robot_jes: @@ -173,7 +175,7 @@ class Object_detect(Movement): # open pump - if "dev" in self.robot_m5: + if "dev" in self.robot_m5 or "dev" in self.robot_wio: self.pump_on() elif "dev" in self.robot_raspi or "dev" in self.robot_jes: self.gpio_status(True) @@ -188,7 +190,7 @@ class Object_detect(Movement): time.sleep(0.5) # print(tmp) - self.mc.send_angles([tmp[0], 17.22, -32.51, tmp[3], 97, tmp[5]],30) + self.mc.send_angles([tmp[0], 17.22, -45, tmp[3], 97, tmp[5]],30) time.sleep(3) @@ -200,7 +202,7 @@ class Object_detect(Movement): time.sleep(3) # close pump - if "dev" in self.robot_m5: + if "dev" in self.robot_m5 or "dev" in self.robot_wio: self.pump_off() elif "dev" in self.robot_raspi or "dev" in self.robot_jes: self.gpio_status(False) @@ -231,7 +233,9 @@ class Object_detect(Movement): # init 270 def run(self): if "dev" in self.robot_m5: - self.mc = MyCobot(self.robot_m5, 115200) + self.mc = MyCobot(self.robot_m5, 115200) + elif "dev" in self.robot_wio: + self.mc = MyCobot(self.robot_wio, 115200) elif "dev" in self.robot_raspi: self.mc = MyCobot(self.robot_raspi, 1000000) if not self.raspi: diff --git a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py index d0f7873..d9dc686 100755 --- a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py +++ b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py @@ -46,8 +46,8 @@ class Object_detect(Movement): self.move_coords = [ [92.3, -104.9, 211.4, -179.6, 28.91, 131.29], # above the red bucket [165.0, -93.6, 201.4, -173.43, 46.23, 160.65], # above the green bucket - [88.1, 126.3, 193.4, 162.15, 2.23, 156.02], # above the blue bucket - [-5.4, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket + [84.3, 123.8, 205.0, 153.45, -3.67, 142.01], # above the blue bucket + [-15, 120.6, 204.6, 162.66, -6.96, 159.93], # above the gray bucket ] # 判断连接设备:ttyUSB*为M5,ttyACM*为seeed @@ -59,7 +59,8 @@ class Object_detect(Movement): if "dev" in self.robot_m5: self.Pin = [2, 5] elif "dev" in self.robot_wio: - self.Pin = [20, 21] + # self.Pin = [20, 21] + self.Pin = [2, 5] for i in self.move_coords: i[2] -= 20 elif "dev" in self.robot_raspi or "dev" in self.robot_jes: @@ -158,21 +159,20 @@ class Object_detect(Movement): def move(self, x, y, color): # send Angle to move 270 self.mc.send_angles(self.move_angles[0], 30) - time.sleep(7) + time.sleep(4) print("x %s ,y %s" % (x,y)) # send coordinates to move 270 根据不同底板机械臂,调整吸泵高度 self.mc.send_coords([x, y, 140, 179.12, -0.18, 179.46], 30, 0) - time.sleep(7) - print("ntm") + time.sleep(3) self.mc.send_coords([x, y, 95, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 m5 # self.mc.send_coords([x, y, 90, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 pi # self.mc.send_coords([x, y, 92, 179.12, -0.18, 179.46], 30, 0) # -178.77, -2.69, 40.15 - time.sleep(6) + time.sleep(3) # open pump - if "dev" in self.robot_m5: + if "dev" in self.robot_m5 or "dev" in self.robot_wio: self.pump_on() elif "dev" in self.robot_raspi or "dev" in self.robot_jes: self.gpio_status(True) @@ -187,25 +187,25 @@ class Object_detect(Movement): time.sleep(0.5) # print(tmp) - self.mc.send_angles([tmp[0], 17.22, -32.51, tmp[3], 97, tmp[5]],30) - time.sleep(6) + self.mc.send_angles([tmp[0], 17.22, -45, tmp[3], 97, tmp[5]],30) + time.sleep(3) self.mc.send_coords(self.move_coords[color], 30, 1) self.pub_marker(self.move_coords[color][0] / 1000.0, self.move_coords[color][1] / 1000.0, self.move_coords[color][2] / 1000.0) - time.sleep(6) + time.sleep(3) # close pump - if "dev" in self.robot_m5: + if "dev" in self.robot_m5 or "dev" in self.robot_wio: self.pump_off() elif "dev" in self.robot_raspi or "dev" in self.robot_jes: self.gpio_status(False) time.sleep(6) self.mc.send_angles(self.move_angles[1], 30) - time.sleep(6) + time.sleep(2) # decide whether grab cube def decide_move(self, x, y, color): From d4b80b82fc1101486f536d2a76eeae71d062d67d Mon Sep 17 00:00:00 2001 From: weijian Date: Wed, 7 Dec 2022 11:10:08 +0800 Subject: [PATCH 07/12] update mecharm_270 M5 point --- .../ai_mecharm_270/scripts/combine_detect_obj_color.py | 6 ++---- .../scripts/combine_detect_obj_img_folder_opt.py | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py index 1cf478a..92d39af 100644 --- a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py +++ b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_color.py @@ -50,13 +50,11 @@ class Object_detect(Movement): self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] self.raspi = False - if "dev" in self.robot_m5: + if "dev" in self.robot_m5 or "dev" in self.robot_wio: self.Pin = [2, 5] # self.Pin = [5] elif "dev" in self.robot_wio: - # self.Pin = [20, 21] - self.Pin = [2, 5] - # self.Pin = [5] + self.Pin = [20, 21] for i in self.move_coords: i[2] -= 20 elif "dev" in self.robot_raspi or "dev" in self.robot_jes: diff --git a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py index d9dc686..5d891dd 100755 --- a/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py +++ b/mycobot_ai/ai_mecharm_270/scripts/combine_detect_obj_img_folder_opt.py @@ -56,11 +56,10 @@ class Object_detect(Movement): self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] - if "dev" in self.robot_m5: + if "dev" in self.robot_m5 or "dev" in self.robot_wio: self.Pin = [2, 5] elif "dev" in self.robot_wio: - # self.Pin = [20, 21] - self.Pin = [2, 5] + self.Pin = [20, 21] for i in self.move_coords: i[2] -= 20 elif "dev" in self.robot_raspi or "dev" in self.robot_jes: From d0ce79bc80dce4c1e05ac5bc71ddd2293fabc90e Mon Sep 17 00:00:00 2001 From: weijian Date: Wed, 7 Dec 2022 17:04:33 +0800 Subject: [PATCH 08/12] fix 280pi and mecharm_pi ubuntu20.04 ros1 from python3 --- mecharm/mecharm/scripts/simple_gui.py | 2 +- mecharm/mecharm/scripts/teleop_keyboard.py | 2 +- .../scripts/mecharm_services.py | 67 +++++++++++++++++-- mecharm/mecharm_pi/scripts/simple_gui.py | 7 +- mecharm/mecharm_pi/scripts/teleop_keyboard.py | 4 +- .../mycobot_280pi/scripts/simple_gui.py | 7 +- .../mycobot_280pi/scripts/teleop_keyboard.py | 2 +- .../scripts/mycobot_services.py | 61 +++++++++++++++-- 8 files changed, 129 insertions(+), 23 deletions(-) diff --git a/mecharm/mecharm/scripts/simple_gui.py b/mecharm/mecharm/scripts/simple_gui.py index 67784ec..387718d 100755 --- a/mecharm/mecharm/scripts/simple_gui.py +++ b/mecharm/mecharm/scripts/simple_gui.py @@ -33,7 +33,7 @@ class Window: # 计算 Tk 根窗口的 x 和 y 坐标 x = (self.ws / 2) - 190 y = (self.hs / 2) - 250 - self.win.geometry("430x400+{}+{}".format(x, y)) + self.win.geometry("430x400+{}+{}".format(int(x), int(y))) # layout,布局 self.set_layout() # input section,输入部分 diff --git a/mecharm/mecharm/scripts/teleop_keyboard.py b/mecharm/mecharm/scripts/teleop_keyboard.py index 3d2b971..b7d1033 100755 --- a/mecharm/mecharm/scripts/teleop_keyboard.py +++ b/mecharm/mecharm/scripts/teleop_keyboard.py @@ -84,7 +84,7 @@ def teleop_keyboard(): init_pose = [0, 0, 0, 0, 0, 0, speed] - home_pose = [0, 8, -127, 40, 0, 0, speed] + home_pose = [0, 30, 30, 0, 30, 0, speed] # rsp = set_angles(*init_pose) diff --git a/mecharm/mecharm_communication/scripts/mecharm_services.py b/mecharm/mecharm_communication/scripts/mecharm_services.py index 322127c..aa1e026 100755 --- a/mecharm/mecharm_communication/scripts/mecharm_services.py +++ b/mecharm/mecharm_communication/scripts/mecharm_services.py @@ -1,17 +1,55 @@ -#!/usr/bin/env python2 - # -*- coding: UTF-8 -*- +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- import time import rospy +import os +import fcntl from mycobot_communication.srv import * from pymycobot.mycobot import MyCobot mc = None +# Avoid serial port conflicts and need to be locked +def acquire(lock_file): + open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + fd = os.open(lock_file, open_mode) + + pid = os.getpid() + lock_file_fd = None + + timeout = 50.0 + start_time = current_time = time.time() + while current_time < start_time + timeout: + try: + # The LOCK_EX means that only one process can hold the lock + # The LOCK_NB means that the fcntl.flock() is not blocking + # and we are able to implement termination of while loop, + # when timeout is reached. + fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except (IOError, OSError): + pass + else: + lock_file_fd = fd + break + # print('pid waiting for lock:%d'% pid) + time.sleep(1.0) + current_time = time.time() + if lock_file_fd is None: + os.close(fd) + return lock_file_fd + + +def release(lock_file_fd): + # Do not remove the lockfile: + fcntl.flock(lock_file_fd, fcntl.LOCK_UN) + os.close(lock_file_fd) + return None + def create_handle(): global mc - rospy.init_node("mecharm_services") + rospy.init_node("mycobot_services") rospy.loginfo("start ...") port = rospy.get_param("~port") baud = rospy.get_param("~baud") @@ -43,7 +81,9 @@ def set_angles(req): sp = req.speed if mc: + lock = acquire("/tmp/mycobot_lock") mc.send_angles(angles, sp) + release(lock) return SetAnglesResponse(True) @@ -51,7 +91,9 @@ def set_angles(req): def get_angles(req): """get angles,获取角度""" if mc: + lock = acquire("/tmp/mycobot_lock") angles = mc.get_angles() + release(lock) return GetAnglesResponse(*angles) @@ -68,14 +110,18 @@ def set_coords(req): mod = req.model if mc: + lock = acquire("/tmp/mycobot_lock") mc.send_coords(coords, sp, mod) + release(lock) return SetCoordsResponse(True) def get_coords(req): if mc: + lock = acquire("/tmp/mycobot_lock") coords = mc.get_coords() + release(lock) return GetCoordsResponse(*coords) @@ -83,23 +129,26 @@ def switch_status(req): """Gripper switch status""" """夹爪开关状态""" if mc: + lock = acquire("/tmp/mycobot_lock") if req.Status: mc.set_gripper_state(0, 80) else: mc.set_gripper_state(1, 80) + release(lock) return GripperStatusResponse(True) def toggle_pump(req): if mc: + lock = acquire("/tmp/mycobot_lock") if req.Status: mc.set_basic_output(req.Pin1, 0) mc.set_basic_output(req.Pin2, 0) else: mc.set_basic_output(req.Pin1, 1) mc.set_basic_output(req.Pin2, 1) - + release(lock) return PumpStatusResponse(True) @@ -107,12 +156,12 @@ robot_msg = """ MyCobot Status -------------------------------- Joint Limit: - joint 1: -160 ~ +160 - joint 2: -90 ~ +90 + joint 1: -160 ~ +170 + joint 2: -85 ~ +90 joint 3: -180 ~ +45 joint 4: -160 ~ +160 joint 5: -100 ~ +100 - joint 6: -180 ~ +180 + joint 6: -∞ ~ +∞ Connect Status: %s @@ -131,11 +180,15 @@ def output_robot_message(): atom_version = "unknown" if mc: + lock = acquire("/tmp/mycobot_lock") cn = mc.is_controller_connected() + release(lock) if cn == 1: connect_status = True time.sleep(0.1) + lock = acquire("/tmp/mycobot_lock") si = mc.is_all_servo_enable() + release(lock) if si == 1: servo_infomation = "all connected" diff --git a/mecharm/mecharm_pi/scripts/simple_gui.py b/mecharm/mecharm_pi/scripts/simple_gui.py index 67784ec..c7e76cf 100644 --- a/mecharm/mecharm_pi/scripts/simple_gui.py +++ b/mecharm/mecharm_pi/scripts/simple_gui.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- -import Tkinter as tk +# import Tkinter as tk # python2 +import tkinter as tk from mycobot_communication.srv import GetCoords, SetCoords, GetAngles, SetAngles, GripperStatus import rospy import time @@ -33,7 +34,7 @@ class Window: # 计算 Tk 根窗口的 x 和 y 坐标 x = (self.ws / 2) - 190 y = (self.hs / 2) - 250 - self.win.geometry("430x400+{}+{}".format(x, y)) + self.win.geometry("430x400+{}+{}".format(int(x), int(y))) # layout,布局 self.set_layout() # input section,输入部分 diff --git a/mecharm/mecharm_pi/scripts/teleop_keyboard.py b/mecharm/mecharm_pi/scripts/teleop_keyboard.py index 3d2b971..6cfa0f3 100644 --- a/mecharm/mecharm_pi/scripts/teleop_keyboard.py +++ b/mecharm/mecharm_pi/scripts/teleop_keyboard.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding:utf-8 -*- from __future__ import print_function from mycobot_communication.srv import GetCoords, SetCoords, GetAngles, SetAngles, GripperStatus @@ -84,7 +84,7 @@ def teleop_keyboard(): init_pose = [0, 0, 0, 0, 0, 0, speed] - home_pose = [0, 8, -127, 40, 0, 0, speed] + home_pose = [0, 30, 30, 0, 30, 0, speed] # rsp = set_angles(*init_pose) diff --git a/mycobot_280/mycobot_280pi/scripts/simple_gui.py b/mycobot_280/mycobot_280pi/scripts/simple_gui.py index d2757cb..41f9258 100755 --- a/mycobot_280/mycobot_280pi/scripts/simple_gui.py +++ b/mycobot_280/mycobot_280pi/scripts/simple_gui.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- -import Tkinter as tk +# import Tkinter as tk +import tkinter as tk from mycobot_communication.srv import GetCoords, SetCoords, GetAngles, SetAngles, GripperStatus import rospy import time @@ -33,7 +34,7 @@ class Window: # 计算 Tk 根窗口的 x 和 y 坐标 x = (self.ws / 2) - 190 y = (self.hs / 2) - 250 - self.win.geometry("430x400+{}+{}".format(x, y)) + self.win.geometry("430x400+{}+{}".format(int(x), int(y))) # layout,布局 self.set_layout() # input section,输入部分 diff --git a/mycobot_280/mycobot_280pi/scripts/teleop_keyboard.py b/mycobot_280/mycobot_280pi/scripts/teleop_keyboard.py index e5ee716..110f8a4 100755 --- a/mycobot_280/mycobot_280pi/scripts/teleop_keyboard.py +++ b/mycobot_280/mycobot_280pi/scripts/teleop_keyboard.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # encoding=utf-8 from __future__ import print_function from mycobot_communication.srv import GetCoords, SetCoords, GetAngles, SetAngles, GripperStatus diff --git a/mycobot_communication/scripts/mycobot_services.py b/mycobot_communication/scripts/mycobot_services.py index 0f105a8..cbf1b75 100755 --- a/mycobot_communication/scripts/mycobot_services.py +++ b/mycobot_communication/scripts/mycobot_services.py @@ -1,13 +1,51 @@ #!/usr/bin/env python2 -# -*- coding: utf-8 -* +# -*- coding: utf-8 -*- import time import rospy +import os +import fcntl from mycobot_communication.srv import * from pymycobot.mycobot import MyCobot mc = None +# Avoid serial port conflicts and need to be locked +def acquire(lock_file): + open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + fd = os.open(lock_file, open_mode) + + pid = os.getpid() + lock_file_fd = None + + timeout = 50.0 + start_time = current_time = time.time() + while current_time < start_time + timeout: + try: + # The LOCK_EX means that only one process can hold the lock + # The LOCK_NB means that the fcntl.flock() is not blocking + # and we are able to implement termination of while loop, + # when timeout is reached. + fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except (IOError, OSError): + pass + else: + lock_file_fd = fd + break + # print('pid waiting for lock:%d'% pid) + time.sleep(1.0) + current_time = time.time() + if lock_file_fd is None: + os.close(fd) + return lock_file_fd + + +def release(lock_file_fd): + # Do not remove the lockfile: + fcntl.flock(lock_file_fd, fcntl.LOCK_UN) + os.close(lock_file_fd) + return None + def create_handle(): global mc @@ -41,9 +79,11 @@ def set_angles(req): req.joint_6, ] sp = req.speed - print('angles1:',angles) + if mc: + lock = acquire("/tmp/mycobot_lock") mc.send_angles(angles, sp) + release(lock) return SetAnglesResponse(True) @@ -51,8 +91,9 @@ def set_angles(req): def get_angles(req): """get angles,获取角度""" if mc: + lock = acquire("/tmp/mycobot_lock") angles = mc.get_angles() - print('angles2:',angles) + release(lock) return GetAnglesResponse(*angles) @@ -69,15 +110,18 @@ def set_coords(req): mod = req.model if mc: + lock = acquire("/tmp/mycobot_lock") mc.send_coords(coords, sp, mod) + release(lock) return SetCoordsResponse(True) def get_coords(req): if mc: + lock = acquire("/tmp/mycobot_lock") coords = mc.get_coords() - print('coords:',coords) + release(lock) return GetCoordsResponse(*coords) @@ -85,23 +129,26 @@ def switch_status(req): """Gripper switch status""" """夹爪开关状态""" if mc: + lock = acquire("/tmp/mycobot_lock") if req.Status: mc.set_gripper_state(0, 80) else: mc.set_gripper_state(1, 80) + release(lock) return GripperStatusResponse(True) def toggle_pump(req): if mc: + lock = acquire("/tmp/mycobot_lock") if req.Status: mc.set_basic_output(req.Pin1, 0) mc.set_basic_output(req.Pin2, 0) else: mc.set_basic_output(req.Pin1, 1) mc.set_basic_output(req.Pin2, 1) - + release(lock) return PumpStatusResponse(True) @@ -133,11 +180,15 @@ def output_robot_message(): atom_version = "unknown" if mc: + lock = acquire("/tmp/mycobot_lock") cn = mc.is_controller_connected() + release(lock) if cn == 1: connect_status = True time.sleep(0.1) + lock = acquire("/tmp/mycobot_lock") si = mc.is_all_servo_enable() + release(lock) if si == 1: servo_infomation = "all connected" From e11e0ac141fbd37b98011629875378f938e29424 Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Thu, 8 Dec 2022 11:21:56 +0800 Subject: [PATCH 09/12] update aikit280 m5 --- mycobot_280/mycobot_280/config/mycobot.rviz | 9 +++++++++ .../ai_mycobot_280/scripts/combine_detect_obj_color.py | 4 ++-- .../scripts/combine_detect_obj_img_folder_opt.py | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mycobot_280/mycobot_280/config/mycobot.rviz b/mycobot_280/mycobot_280/config/mycobot.rviz index 68ab389..6fe1018 100644 --- a/mycobot_280/mycobot_280/config/mycobot.rviz +++ b/mycobot_280/mycobot_280/config/mycobot.rviz @@ -8,6 +8,7 @@ Panels: - /Status1 - /RobotModel1 - /TF1 + - /Marker1 Splitter Ratio: 0.5 Tree Height: 607 - Class: rviz/Selection @@ -147,6 +148,14 @@ Visualization Manager: {} Update Interval: 0 Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /cube + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true Enabled: true Global Options: Background Color: 48; 48; 48 diff --git a/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_color.py b/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_color.py index f29c73f..389a29a 100755 --- a/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_color.py +++ b/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_color.py @@ -51,8 +51,8 @@ class Object_detect(Movement): # self.Pin = [20, 21] self.Pin = [2, 5] - for i in self.move_coords: - i[2] -= 20 + # for i in self.move_coords: + # i[2] -= 20 elif "dev" in self.robot_raspi or "dev" in self.robot_jes: import RPi.GPIO as GPIO GPIO.setwarnings(False) diff --git a/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py b/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py index ee5ca7d..de5ca4a 100644 --- a/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py +++ b/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py @@ -61,8 +61,8 @@ class Object_detect(Movement): self.Pin = [2, 5] elif "dev" in self.robot_wio: self.Pin = [2, 5] - for i in self.move_coords: - i[2] -= 20 + # for i in self.move_coords: + # i[2] -= 20 elif "dev" in self.robot_raspi or "dev" in self.robot_jes: import RPi.GPIO as GPIO GPIO.setwarnings(False) From db466ddafba0cd81a652e5a8d1be71b27709411a Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Thu, 8 Dec 2022 11:30:41 +0800 Subject: [PATCH 10/12] add aikit280 one touch start --- .../ai_mycobot_280/scripts/ai_windows.py | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 mycobot_ai/ai_mycobot_280/scripts/ai_windows.py diff --git a/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py b/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py new file mode 100644 index 0000000..09ad47f --- /dev/null +++ b/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +# encoding:utf-8 + +from tkinter import ttk +from tkinter import * +import os,sys +import time +import subprocess + +import threading +from multiprocessing import Process + + +class Application(object): + def __init__(self): + self.win = Tk() + # 窗口置顶 + self.win.wm_attributes('-topmost', 1) + self.ros = False + # 运行的文件 + self.run_py = "" + # 判断通信口并给权限 + try: + self.robot_m5 = os.popen("ls /dev/ttyUSB*").readline()[:-1] + self.robot_wio = os.popen("ls /dev/ttyACM*").readline()[:-1] + self.robot_raspi = os.popen("ls /dev/ttyAMA*").readline()[:-1] + self.robot_jes = os.popen("ls /dev/ttyTHS1").readline()[:-1] + if "dev" in self.robot_wio: + self.set_file(self.robot_wio) + elif "dev" in self.robot_m5: + self.set_file(self.robot_m5) + elif "dev" in self.robot_raspi: + self.change_file(self.robot_raspi) + elif "dev" in self.robot_jes: + self.change_file(self.robot_jes) + except Exception as e: + pass + + # 设置标题 + self.win.title("aikit启动工具") + self.win.geometry( + "600x400+100+100") # 290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置 + # 打开ros按钮 + self.btn = Button(self.win, text="open ROS", command=self.open_ros) + self.btn.grid(row=0) + + self.chanse_code = Label(self.win, text="选择程序:", width=10) + self.chanse_code.grid(row=1) + + self.myComboList = [u"颜色识别", u"物体识别", u"二维码识别"] + self.myCombox = ttk.Combobox(self.win, values=self.myComboList) + self.myCombox.grid(row=1, column=1) + + self.add_btn = Button(self.win, text="添加新的物体图像", command=self.add_img) + self.add_btn.grid(row=1, column=2) + + self.tips = "1、首先打开ros,大概需要等待5s\n2、选择所要运行的程序点击运行即可,开启大概需要10秒,可以通过查看终端查看开启情况。\n\n添加新的图像:\n1、点击按钮,等待开启摄像头\n2、选中图像框,按z键拍照\n3、使用鼠标框出需要识别的图像区域\n4、按Enter键提取图像\n5、根据终端提示,输入数字(1~4)保存到相对应图像的文件夹,按下Enter键即可保存至对应文件夹。" + + self.btn = Button(self.win, text="运行", command=self.start_run) + self.btn.grid(row=5) + + self.close = Button(self.win, text="close", command=self.close_py) + self.close.grid(row=5, column=1) + + self.t2 = None + self.log_data = Text(self.win, width=74, height=20) + self.log_data.grid(row=16, column=0, columnspan=10) + self.log_data.insert(END, self.tips) + + # self.open_ros() + self.win.protocol('WM_DELETE_WINDOW', self.close_rviz) + + def close_rviz(self): + os.system( + "ps -ef | grep -E mycobot.rviz | grep -v 'grep' | awk '{print $2}' | xargs kill -9") + sys.exit(0) + + def set_file(self,port): + self.command = ''.format( + port) + # 根据通信口修改ros启动文件 + os.system( + "sed -i '2c {}' ~/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/launch/vision_wio.launch" + .format(self.command)) + + def change_file(self, port): + command1 = ''.format(port) + command2 = ''.format(1000000) + # 根据通信口修改ros启动文件 + os.system( + "sed -i '2c {}' ~/catkin_ws/src/mycobot_ros/mycobot_ai/launch/vision.launch".format(command1)) + os.system( + "sed -i '3c {}' ~/catkin_ws/src/mycobot_ros/mycobot_ai/launch/vision.launch".format(command2)) + + def start_run(self): + try: + print(u"开始运行") + one = self.myCombox.get() + if one == u"颜色识别": + self.run_py = "combine_detect_obj_color.py" + t2 = threading.Thread(target=self.open_py1) + t2.setDaemon(True) + t2.start() + elif one == u"物体识别": + self.run_py = "combine_detect_obj_img_folder_opt.py" + t3 = threading.Thread(target=self.open_py) + t3.setDaemon(True) + t3.start() + elif one == u"二维码识别": + self.run_py = "detect_encode.py" + t3 = threading.Thread(target=self.open_py2) + t3.setDaemon(True) + t3.start() + except Exception as e: + self.tips = str(e) + self.log_data.insert(END, self.tips) + + def open_py(self): + os.system( + "cd /home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280 && python scripts/combine_detect_obj_img_folder_opt.py" + ) + + def open_py1(self): + os.system( + "python ~/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_color.py" + ) + + def open_py2(self): + os.system( + "python ~/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/scripts/detect_encode.py" + ) + + def add_img(self): + os.system( + "python ~/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/scripts/add_img.py" + ) + + def open_ros(self): + if self.ros: + print("ros is opened") + return + # t1 = threading.Thread(target=self.ross) + # t1.setDaemon(True) + # t1.start() + self.ross() + self.ros = True + + def ross(self): + # os.system( + # "roslaunch ~/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/launch/vision_wio.launch" + # ) + p = subprocess.Popen(["roslaunch", "/home/h/catkin_ws/src/mycobot_ros/mycobot_ai/ai_mycobot_280/launch/vision_wio.launch"],shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + def close_py(self): + t1 = threading.Thread(target=self.close_p) + t1.setDaemon(True) + t1.start() + + def close_p(self): + # 关闭ai程序 + os.system("ps -ef | grep -E " + self.run_py + + " | grep -v 'grep' | awk '{print $2}' | xargs kill -9") + + def get_current_time(self): + # 日志时间 + """Get current time with format.""" + current_time = time.strftime("%Y-%m-%d %H:%M:%S", + time.localtime(time.time())) + return current_time + + def write_log_to_Text(self, logmsg): + # 设置日志函数 + global LOG_NUM + current_time = self.get_current_time() + logmsg_in = str(current_time) + " " + str(logmsg) + "\n" # 换行 + + if LOG_NUM <= 18: + self.log_data_Text.insert(END, logmsg_in) + LOG_NUM += len(logmsg_in.split("\n")) + # print(LOG_NUM) + else: + self.log_data_Text.insert(END, logmsg_in) + self.log_data_Text.yview("end") + + def run(self): + self.win.mainloop() + + +if __name__ == "__main__": + mc = Application() + mc.run() From cdb76b5ce903b545a1e060c0febccbfbc0bb4f11 Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Thu, 8 Dec 2022 12:41:01 +0800 Subject: [PATCH 11/12] update ai_window.py font --- mycobot_ai/ai_mycobot_280/scripts/ai_windows.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py b/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py index 09ad47f..a0ebfe9 100644 --- a/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py +++ b/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py @@ -39,31 +39,31 @@ class Application(object): # 设置标题 self.win.title("aikit启动工具") self.win.geometry( - "600x400+100+100") # 290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置 + "800x600+100+100") # 290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置 # 打开ros按钮 - self.btn = Button(self.win, text="open ROS", command=self.open_ros) + self.btn = Button(self.win, text="open ROS", font=("Helvetica","13"), command=self.open_ros) self.btn.grid(row=0) - self.chanse_code = Label(self.win, text="选择程序:", width=10) + self.chanse_code = Label(self.win, text="选择程序:", font=("Helvetica","13"), width=10) self.chanse_code.grid(row=1) self.myComboList = [u"颜色识别", u"物体识别", u"二维码识别"] - self.myCombox = ttk.Combobox(self.win, values=self.myComboList) + self.myCombox = ttk.Combobox(self.win, font=("Helvetica","13"), values=self.myComboList) self.myCombox.grid(row=1, column=1) - self.add_btn = Button(self.win, text="添加新的物体图像", command=self.add_img) + self.add_btn = Button(self.win, text="添加新的物体图像", font=("Helvetica","13"), command=self.add_img) self.add_btn.grid(row=1, column=2) self.tips = "1、首先打开ros,大概需要等待5s\n2、选择所要运行的程序点击运行即可,开启大概需要10秒,可以通过查看终端查看开启情况。\n\n添加新的图像:\n1、点击按钮,等待开启摄像头\n2、选中图像框,按z键拍照\n3、使用鼠标框出需要识别的图像区域\n4、按Enter键提取图像\n5、根据终端提示,输入数字(1~4)保存到相对应图像的文件夹,按下Enter键即可保存至对应文件夹。" - self.btn = Button(self.win, text="运行", command=self.start_run) + self.btn = Button(self.win, text="运行", font=("Helvetica","13"), command=self.start_run) self.btn.grid(row=5) - self.close = Button(self.win, text="close", command=self.close_py) + self.close = Button(self.win, text="close", font=("Helvetica","13"), command=self.close_py) self.close.grid(row=5, column=1) self.t2 = None - self.log_data = Text(self.win, width=74, height=20) + self.log_data = Text(self.win, width=74, height=20, font=("Helvetica","13")) self.log_data.grid(row=16, column=0, columnspan=10) self.log_data.insert(END, self.tips) From 4688aab02be73f38b76d6d95fac550b32014213d Mon Sep 17 00:00:00 2001 From: wangWking <842749351@qq.com> Date: Mon, 12 Dec 2022 10:48:20 +0800 Subject: [PATCH 12/12] update chmod +x --- mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py | 0 .../ai_mycobot_280/scripts/advance_detect_obj_img_folder.py | 0 mycobot_ai/ai_mycobot_280/scripts/ai_windows.py | 0 .../ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py | 0 mycobot_ai/ai_mycobot_280/scripts/detect_obj_img_folder_opt.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py mode change 100644 => 100755 mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py mode change 100644 => 100755 mycobot_ai/ai_mycobot_280/scripts/ai_windows.py mode change 100644 => 100755 mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py mode change 100644 => 100755 mycobot_ai/ai_mycobot_280/scripts/detect_obj_img_folder_opt.py diff --git a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_color.py old mode 100644 new mode 100755 diff --git a/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py b/mycobot_ai/ai_mycobot_280/scripts/advance_detect_obj_img_folder.py old mode 100644 new mode 100755 diff --git a/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py b/mycobot_ai/ai_mycobot_280/scripts/ai_windows.py old mode 100644 new mode 100755 diff --git a/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py b/mycobot_ai/ai_mycobot_280/scripts/combine_detect_obj_img_folder_opt.py old mode 100644 new mode 100755 diff --git a/mycobot_ai/ai_mycobot_280/scripts/detect_obj_img_folder_opt.py b/mycobot_ai/ai_mycobot_280/scripts/detect_obj_img_folder_opt.py old mode 100644 new mode 100755