RobotService 인터페이스

이 부분에서 아래와 같이 RobotService와 관련된 인터페이스를 소개하고자 합니다.

RobotServer 서비스 시뮬레이션

RobotServer 시뮬레이션 서비스는 보통 풀 컨트롤(full control)인 경우 실제 RobotServer를 통해 로봇을 컨트롤하는 대신 RobotService를 만들어 RobotServer의 기능을 시뮬레이션하는 것입니다. RobotService가 Mech-Center에서 등록된 후 Mech-Viz가 리얼 로봇과 통신하는 것처람 RobotService와 상호적으로 통신할 것입니다.

RobotServer서비스 시뮬레이션의 주요 응용 시나리오가 아래와 같습니다.

  • Eye In Hand 경우에 Mech-Vision 계산에 사용되는 로봇 관절 각도를 획득합니다.

  • 리얼 로봇에서 포즈를 획득하여 RobotService에 보냅니다.

예시

Adapter 하위 클래스에서 호출하는 방식은 아래와 같습니다.

def _register_service(self):
       """
       register_service
       :return:
       """
       if self.robot_service:
           return

       self.robot_service = RobotService(self)
       other_info = {'robot_type': self.robot_service.service_name}
       self.server, _ = register_service(self.hub_caller, self.robot_service, other_info)

       self.robot_service.setJ([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])

RobotService의 클래스가 아래와 같습니다.

class RobotService(JsonService):
    service_type = "robot"
    service_name = "robot"
    jps = [0, 0, 0, 0, 0, 0]
    pose = [0, 0, 0, 1, 0, 0, 0]

    def getJ(self, *_):
        return {"joint_positions": self.jps}

    def setJ(self, jps):
        logging.info("setJ:{}".format(jps))
        self.jps = jps

    def getL(self, *_):
        return {"tcp_pose": self.pose}

    def getFL(self, *_):
        return {"flange_pose": self.pose}

    def setL(self, pose):
        logging.info("setL:{}".format(pose))
        self.pose = pose

    def moveXs(self, params, _):
        pass

    def stop(self, *_):
        pass

    def setTcp(self, *_):
        pass

    def setDigitalOut(self, params, _):
        pass

    def getDigitalIn(self, *_):
        pass

    def switchPauseContinue(self, *_):
        pass

getJ

getJ() 함수는 Mech-Viz와 Mech-Vision가 현재 관절 각도를 획득하는 데 사용됩니다. 구체적으로 아래와 같습니다. 보통 먼저 setJ() 함수를 통해 현재 관절 각도를 설정한 후 getJ()를 호출합니다.

예시

def getJ(self, *_):
     pose = {"joint_positions": self._jps}
     return pose
  1. Eye In Hand:로봇에서 보내 온 관절 각도를 setJ()에 입력합니다.

    def setJ(self, jps):
      assert len(jps) == 6
      for i in range(6):
          jps[i] = deg2rad(float(jps[i]))
      self._jps = jps
      logging.info("SetJ:{}".format(self._jps))
    

    그 중 jps는 로봇에서 보내 온 관절 각도 데이터이고 getJ()에게 호출되도록 self._jps에 수치를 할당합니다. getJ()가 라디안 포맷의 데이터를 획득하기 때문에 단위의 전환를 주의해야 합니다.

  2. Eye To Hand: 로봇의 현재 관절 각도에 따라 설정할 필요는 없지만 실제 로봇 상태를 시뮬레이션하려면 안전한 목표점을 시작점(보통 Home 포인트)으로 설정해야 합니다. 그렇지 않으면 임의의 숫자가 할당되며 오류가 발생하기 쉽습니다.

    def getJ(self, *_):
         return {"joint_positions": [1.246689,-0.525868,-0.789761,-1.330814, 0.922581, 4.364021]}
    

getFL

getFL() 함수는 로봇이 이미지를 캡처할 때의 플랜지 포즈를 제공하는 데 사용됩니다. Eye In Hand 모드에서 진행되는 캘리브레이션은 플랜지와 카메라의 상대적인 위치 관계를 설명하지만 결국 베이스 좌표계 아래의 데이터를 사용하기 때문에 이미지를 캡처했을 때의 플랜지 포즈를 제공해야 합니다.

def getFL(self, *_):
    return {"flange_pose": self.pose}

Eye In Hand 방식을 통해 포즈를 제공할 때 다음과 같은 사항을 주의해야 합니다.

  1. 로봇이 이미지를 캡처했을 때의 JPs를 반환하면 RobotService에서 직접 setJ()함수를 호출하여(단위: 라디안) 이 함수를 []에 반환하십시오.

  2. 로봇이 플랜지 포즈를 반환하면 다음과 같이 처리하십시오.

    • Mech-Vision 프로젝트 외부 파라미터 파일 extri_param.json 중 파라미터 "is_eye_in_hand"의 값은 true로 설정하십시오.

    • RobotService의 setFL()를 호출하십시오(단위: 미터, 포즈 유형: 사원수).

moveXs

Adapter를 통해 생성한 RobotService 서비스는 moveXs()를 사용하여 Mech-Viz가 계획한 경로 이동 목표점을 수신합니다. 구체적으로 아래와 같습니다.

함수 정의

def moveXs(self, params, _):
     with self.lock:
         for move in params["moves"]:
             self.targets.append(move)
     return {"finished": True}

그중에 params가 Mech-Viz 프로젝트의 모든 파라미터를 입력하고 params[《moves》]를 통해 모든 이동 포인트(비전 이동, 상대적인 이동 등 포함)의 포즈를 획득할 수 있습니다. 포즈는 기본적으로 관절 각도의 형식으로 반환되고 포즈를 self.targets에 입력한 후 나중에 파라미터를 조절하는 데 사용될 것입니다.

예시

일반적으로 이 기능은 [알림[ 태스크와 함께 사용되어야 합니다. Adapter가 알림에서 보내 온 메시지를 수신했을 때 self.targets를 함수에 입력하고 전환 및 압축한 후 로봇에 전송합니다. 예를 들면 아래와 같습니다.

def notify(self, request, _):
    msg = request["notify_message"]
    logging.info("{} notify message:{}".format(self.service_name, msg))
    if msg == "started":
        with self.lock:
            self.move_targets.clear()
    elif msg == "finished":
        with self.lock:
            targets = self.move_targets[:]
            self.move_targets.clear()
        self.send_moves(targets)

메시지 "started"를 수신했을 때 Mech-Viz 오류로 인해 중단되어 이동 전/후 두 개의 이동 포인트가 서로 겹치는 것을 방지하기 위해 목표점 리스트를 지워야 합니다. 메시지 "finished"를 수신했을 때 목표점 리스트를 pack_move 함수에 입력해 데이터를 정리하고 보내는 데 사용됩니다.

def pack_move(self, move_param):
     move_list = []
     for i, move in enumerate(move_param):
         target = move["target"]
         move_list.append(target)
     logging.info("move list num:{}".format(len(move_list)))
     logging.info("move list:{}".format(*move_list))
     motion_cmd = pack('>24f', *move_list)
     self.send(motion_cmd)

작업 현장의 실제 수요에 따라 Mech-Viz의 모든 이동 목표점을 전송해도 되고 index에 근거하여 몇 개를 선택해서 전송해도 됩니다. pack_move() 함수는 각 로봇 브랜드가 필요한 데이터 포맷에 따라 데이터를 정리합니다(일반적으로 통신 프로토콜에서 미리 설정됨).