Example #1
0
class Dobot(metaclass=ABCMeta):

    ROTATE_EEF = Orientation.from_rotation_vector(y=math.pi)
    UNROTATE_EEF = ROTATE_EEF.inversed()

    def __init__(self,
                 pose: Pose,
                 port: str = "/dev/dobot",
                 simulator: bool = False) -> None:

        self.pose = pose
        self.simulator = simulator
        self._move_lock = NonBlockingLock()

        if not self.simulator:

            try:
                self._dobot = DobotApi(port)
            except DobotApiException as e:
                raise DobotApiException(
                    "Could not connect to the robot.") from e

        else:
            self._joint_values: List[Joint] = [
            ]  # has to be set to some initial value in derived classes
            self._hand_teaching = False

    def alarms_to_exception(self) -> None:

        try:
            alarms = self._dobot.get_alarms()
        except DobotApiException as e:
            raise DobotApiException("Failed to get alarms.") from e

        if alarms:
            raise DobotApiException(
                f"Alarm(s): {','.join([alarm.name for alarm in alarms])}.")

    def cleanup(self) -> None:

        if not self.simulator:
            self._dobot.close()

    @property
    def hand_teaching_mode(self) -> bool:

        if self.simulator:
            return self._hand_teaching

        return self._dobot.get_hht_trig_output()

    @hand_teaching_mode.setter
    def hand_teaching_mode(self, value: bool) -> None:

        if self.simulator:
            self._hand_teaching = value
            return

        self._dobot.set_hht_trig_output(value)

    def _inverse_kinematics(self, pose: Pose) -> List[Joint]:
        raise Arcor2NotImplemented()

    def inverse_kinematics(self, pose: Pose) -> List[Joint]:
        raise Arcor2NotImplemented()

    def forward_kinematics(self, joints: List[Joint]) -> Pose:
        raise Arcor2NotImplemented()

    def _handle_pose_out(self, pose: Pose) -> None:
        """This is called (only for a real robot) from `get_end_effector_pose`
        so derived classes can do custom changes to the pose.

        :param pose:
        :return:
        """

        pass

    def _handle_pose_in(self, pose: Pose) -> None:
        """This is called (only for a real robot) from `move` so derived
        classes can do custom changes to the pose.

        :param pose:
        :return:
        """

        pass

    def _check_orientation(self, pose: Pose) -> None:

        unrotated = self.UNROTATE_EEF * pose.orientation

        eps = 1e-6

        if abs(unrotated.x) > eps or abs(unrotated.y) > eps:
            raise DobotApiException("Impossible orientation.")

    def get_end_effector_pose(self) -> Pose:

        if self.simulator:
            return self.forward_kinematics(self.robot_joints())

        try:
            pos = self._dobot.get_pose()  # in mm
        except DobotApiException as e:
            raise DobotException("Failed to get pose.") from e

        p = Pose()
        p.position.x = pos.position.x / 1000.0
        p.position.y = pos.position.y / 1000.0
        p.position.z = pos.position.z / 1000.0
        p.orientation = self.ROTATE_EEF * Orientation.from_rotation_vector(
            z=math.radians(pos.position.r))

        self._handle_pose_out(p)
        return tr.make_pose_abs(self.pose, p)

    def home(self) -> None:
        """Run the homing procedure."""

        with self._move_lock:

            if self.simulator:
                time.sleep(2.0)
                return

            try:
                self._dobot.clear_alarms()
                self._dobot.wait_for_cmd(self._dobot.home())
            except DobotApiException as e:
                raise DobotException("Homing failed.") from e

        self.alarms_to_exception()

    def move(self,
             pose: Pose,
             move_type: MoveType,
             velocity: float = 50.0,
             acceleration: float = 50.0) -> None:
        """Moves the robot's end-effector to a specific pose.

        :param pose: Target pose.
        :move_type: Move type.
        :param velocity: Speed of move (percent).
        :param acceleration: Acceleration of move (percent).
        :return:
        """

        if not (0.0 <= velocity <= 100.0):
            raise DobotException("Invalid velocity.")

        if not (0.0 <= acceleration <= 100.0):
            raise DobotException("Invalid acceleration.")

        with self._move_lock:

            rp = tr.make_pose_rel(self.pose, pose)

            # prevent Dobot from moving when given an unreachable goal
            try:
                jv = self._inverse_kinematics(rp)
            except Arcor2NotImplemented:  # TODO remove this once M1 has IK
                pass

            if self.simulator:
                self._joint_values = jv
                time.sleep((100.0 - velocity) * 0.05)
                return

            self._handle_pose_in(rp)

            try:
                self._dobot.clear_alarms()
                unrotated = self.UNROTATE_EEF * rp.orientation
                rotation = math.degrees(
                    quaternion.as_rotation_vector(
                        unrotated.as_quaternion())[2])
                self._dobot.speed(velocity, acceleration)

                self._dobot.wait_for_cmd(
                    self._dobot.move_to(
                        rp.position.x * 1000.0,
                        rp.position.y * 1000.0,
                        rp.position.z * 1000.0,
                        rotation,
                        MOVE_TYPE_MAPPING[move_type],
                    ))
            except DobotApiException as e:
                raise DobotException("Move failed.") from e

        self.alarms_to_exception()

    @abstractmethod
    def suck(self) -> None:
        pass

    @abstractmethod
    def release(self) -> None:
        pass

    @abstractmethod
    def robot_joints(self) -> List[Joint]:
        pass
Example #2
0
def test_make_pose_abs_2() -> None:

    parent = Pose(Position(-1, 2, -3), Orientation(0, 0.707, -0.707, 0))
    child = Pose()
    assert make_pose_abs(parent, child) == parent
Example #3
0
def test_make_pose_rel_and_abs_again_2() -> None:

    parent = Pose(Position(-1, 1, -1), Orientation(0, -0.707, 0.707, 0))
    child_to_be = Pose(Position(10, -10, 3))
    child = make_pose_rel(parent, child_to_be)
    assert make_pose_abs(parent, child) == child_to_be
Example #4
0
def test_make_pose_rel() -> None:

    parent = Pose(Position(1, 2, 3), Orientation(0, 0, 1, 0))
    child_to_be = copy.deepcopy(parent)
    assert make_pose_rel(parent, child_to_be) == Pose()
Example #5
0
def test_make_pose_abs() -> None:

    parent = Pose(Position(1, 2, 3), Orientation(0, 0, 1, 0))
    child = Pose()
    assert make_pose_abs(parent, child) == parent
Example #6
0
def test_valid_orientation() -> None:

    o1 = Orientation(0, 0, 0, 1)
    o2 = Orientation()
    o2.set_from_quaternion(o1.as_quaternion())
    assert o1 == o2
Example #7
0
def test_pose_inv() -> None:

    p = Pose(Position(1, 1, 1), Orientation(0.707, 0, 0, 0.707))
    pi = p.inversed()
    assert pi == Pose(Position(-1, -1, 1), Orientation(-0.707, 0, 0, 0.707))
    assert p == pi.inversed()
Example #8
0
def test_make_orientation_rel():

    parent = Orientation(0.707, 0, 0.707, 0)
    child = Orientation(0.707, 0, 0.707, 0)
    assert make_orientation_rel(parent, child) == Orientation(0, 0, 0, 1)
Example #9
0
def test_make_orientation_abs_3():

    parent = Orientation(0, 1, 0, 0)
    child = Orientation(0, 0, 0, 1)
    assert make_orientation_abs(parent, child) == parent
Example #10
0
def test_project_ap_rpcs(start_processes: None, ars: ARServer) -> None:

    upload_def(Box, BoxModel(Box.__name__, 1, 2, 3))

    event(ars, events.c.ShowMainScreen)

    assert ars.call_rpc(
        rpc.s.NewScene.Request(get_id(), rpc.s.NewScene.Request.Args("Test scene")), rpc.s.NewScene.Response
    ).result

    assert len(event(ars, events.o.ChangedObjectTypes).data) == 1

    scene_data = event(ars, events.s.OpenScene).data
    assert scene_data
    scene = scene_data.scene

    event(ars, events.s.SceneState)

    assert ars.call_rpc(
        rpc.s.AddObjectToScene.Request(get_id(), rpc.s.AddObjectToScene.Request.Args("box", Box.__name__, Pose())),
        rpc.s.AddObjectToScene.Response,
    ).result

    obj = event(ars, events.s.SceneObjectChanged).data
    assert obj

    # ------------------------------------------------------------------------------------------------------------------

    assert ars.call_rpc(
        rpc.p.NewProject.Request(get_id(), rpc.p.NewProject.Request.Args(scene.id, "Project name")),
        rpc.p.NewProject.Response,
    ).result

    event(ars, events.s.SceneSaved)
    event(ars, events.p.OpenProject)
    event(ars, events.s.SceneState)

    assert ars.call_rpc(
        rpc.p.AddActionPoint.Request(get_id(), rpc.p.AddActionPoint.Request.Args("parent_ap", Position())),
        rpc.p.AddActionPoint.Response,
    ).result

    parent_ap_evt = event(ars, events.p.ActionPointChanged)

    assert ars.call_rpc(
        rpc.p.AddActionPoint.Request(
            get_id(), rpc.p.AddActionPoint.Request.Args("child_ap", Position(-1), parent_ap_evt.data.id)
        ),
        rpc.p.AddActionPoint.Response,
    ).result

    child_ap_evt = event(ars, events.p.ActionPointChanged)
    assert child_ap_evt.data.parent == parent_ap_evt.data.id

    lock_object(ars, child_ap_evt.data.id)

    assert ars.call_rpc(
        rpc.p.AddActionPointOrientation.Request(
            get_id(), rpc.p.AddActionPointOrientation.Request.Args(child_ap_evt.data.id, Orientation())
        ),
        rpc.p.AddActionPointOrientation.Response,
    ).result

    ori = event(ars, events.p.OrientationChanged)

    assert ars.call_rpc(
        rpc.p.AddAction.Request(
            get_id(),
            rpc.p.AddAction.Request.Args(
                child_ap_evt.data.id,
                "act_name",
                f"{obj.id}/{Box.update_pose.__name__}",
                [ActionParameter("new_pose", PosePlugin.type_name(), json.dumps(ori.data.id))],
                [Flow()],
            ),
        ),
        rpc.p.AddAction.Response,
    ).result

    event(ars, events.p.ActionChanged)

    unlock_object(ars, child_ap_evt.data.id)

    ars.event_mapping[ActionChanged.__name__] = ActionChanged

    assert ars.call_rpc(
        rpc.p.CopyActionPoint.Request(get_id(), rpc.p.CopyActionPoint.Request.Args(parent_ap_evt.data.id)),
        rpc.p.CopyActionPoint.Response,
    ).result

    new_parent_ap = event(ars, events.p.ActionPointChanged)
    assert not new_parent_ap.data.parent

    new_child_ap = event(ars, events.p.ActionPointChanged)
    assert new_child_ap.data.parent == new_parent_ap.data.id

    new_ori = event(ars, events.p.OrientationChanged)
    assert new_ori.parent_id == new_child_ap.data.id

    # with events.p.ActionChanged it would return only BareAction (without parameters)
    new_action = event(ars, ActionChanged)
    ars.event_mapping[ActionChanged.__name__] = events.p.ActionChanged
    assert new_action.parent_id == new_child_ap.data.id

    # Pose parameter (orientation id) should be updated now
    assert len(new_action.data.parameters) == 1
    assert json.loads(new_action.data.parameters[0].value) == new_ori.data.id