🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    Image recognition and object grabbing with robotic arms

    PROJECTS
    2
    3
    3.7k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ElephantRoboticsE
      ElephantRobotics
      last edited by

      When we encounter image processing, we generally use OpenCV. When we install a camera for our robot, how should we deal with the communication between the camera and the robot? When the image recognition is successful, how does the robot move? Let’s share our project next. :grinning:

      Project content: When the camera recognizes the image block, the robotic arm will go to grab the block and put it into the designated bucket.

      The next step involves ros, python, OpenCV, and other technologies.

      First, we set up our scene like this.
      0_1651110573651_52828d87-392a-4527-81f2-6eecc1bdc222-image.png
      The robot model has been built in the ros environment, and then we run the code.
      0_1651110541644_06d32f93-0a49-430e-ad24-b7d9c1b939c3-image.png
      When the target object appears
      0_1651110590074_61a266a2-1ee3-4696-8c13-70aaa95917a5-image.png
      We need to identify the content of the target image and draw a border for it, and then determine its position
      core code:

      def obj_detect(self, img, goal):
      i = 0
      MIN_MATCH_COUNT = 10
      sift = cv2.xfeatures2d.SIFT_create()

          # find the keypoints and descriptors with SIFT
          kp = []
          des = []
      
          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)
      
          # 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)
                      ccoord = (dst[0][0]+dst[1][0]+dst[2][0]+dst[3][0])/4.0
                      cv2.putText(img, "{}".format(ccoord), (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)
                      # 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
      

      After the recognition function is completed, it is necessary to calculate the distance between the target image and the real robot arm.
      core code:

      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
      

      def get_calculate_params()
      This method is to calculate the center position of the aruco code, which is the center position of the camera image.

      After the calculation, we need to move the robotic arm to grab the target object, and use the API from our own pymycobot library to control the movement of the robotic arm:
      core code:

      Grasping motion

      def move(self, x, y, color):
          # send Angle to move mycobot
          self.pub_angles(self.move_angles[0], 20)
          time.sleep(1.5)
          self.pub_angles(self.move_angles[1], 20)
          time.sleep(1.5)
          self.pub_angles(self.move_angles[2], 20)
          time.sleep(1.5)
          # send coordinates to move mycobot
          self.pub_coords([x, y, 165,  -178.9, -1.57, -66], 20, 1)
          time.sleep(1.5)
          # 根据不同底板机械臂,调整吸泵高度
          if "dev" in self.robot_m5 or "dev" in self.robot_raspi:
              # m5 and raspi
              self.pub_coords([x, y, 90,  -178.9, -1.57, -66], 25, 1)
          elif "dev" in self.robot_wio:
              h = 0
              if 165 < x < 180:
                  h = 10
              elif x > 180:
                  h = 20
              elif x < 135:
                  h = -20
              self.pub_coords([x, y, 31.9+h,  -178.9, -1, -66], 20, 1)
          elif "dev" in self.robot_jes:
              h = 0
              if x < 130:
                  h = 15
              self.pub_coords([x, y, 90-h,  -178.9, -1.57, -66], 25, 1)
          time.sleep(1.5)
          # open pump
          if self.raspi:
              self.gpio_status(True)
          else:
              self.pub_pump(True, self.Pin)
          time.sleep(0.5)
          self.pub_angles(self.move_angles[2], 20)
          time.sleep(3)
          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.pub_angles(self.move_angles[1], 20)
          time.sleep(1.5)
          self.pub_marker(
              self.move_coords[3][0]/1000.0, self.move_coords[3][1]/1000.0, self.move_coords[3][2]/1000.0)
      
          self.pub_angles(self.move_angles[0], 20)
          time.sleep(1.5)
          self.pub_marker(
              self.move_coords[4][0]/1000.0, self.move_coords[4][1]/1000.0, self.move_coords[4][2]/1000.0)
          print self.move_coords[color]
          self.pub_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(2)
          # close pump
          if self.raspi:
              self.gpio_status(False)
          else:
              self.pub_pump(False, self.Pin)
          time.sleep(1)
          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)
          time.sleep(3)
      

      move_angles()
      This method is the API of the mobile manipulator.
      In conclusion:
      The first step is to identify the target.
      The second step is to calculate the distance between the end of the real robot arm and the target.
      The third step moves the robotic arm to complete a series of movements and finally grab the target object and move it into a bucket.
      The complete code is on GitHub:
      https://github.com/elephantrobotics/mycobot_ros/tree/noetic/mycobot_ai

      Mainly run mycobot_ros/mycobot_ai/launch/vision.launch and
      mycobot_ros/mycobot_ai/scripts/detect_obj_img.py
      The main function of vision.launch is to build a 1:1 real scene.
      The main function of detect_obj_img.py is to realize image recognition and capture.
      Video demo:
      DEMO
      Our project is using mycobot280 M5stack

      1 Reply Last reply Reply Quote 1
      • ajb2k3A
        ajb2k3
        last edited by

        I see you are using a non m5stack camera.
        could you use the StickV or UnitV for some of the image recognition?

        UIFlow, so easy an adult can learn it!
        If I don't know it, be patient!
        I've ether not learned it or am too drunk to remember it!
        Author of the WIP UIFlow Handbook!
        M5Black, Go, Stick, Core2, and so much more it cant be fit in here!

        1 Reply Last reply Reply Quote 0
        • ElephantRoboticsE
          ElephantRobotics
          last edited by

          We use M5stack basic as our main controller, we can connect any camera. It only needs to adapt to the camera of StickV or UnitV to complete the recognition.

          1 Reply Last reply Reply Quote 0
          • First post
            Last post