Пример #1
0
    def __init__(self, robot):
        # tf Listener
        self.listener = tf.TransformListener()

        # robot
        self.robot = robot
        self.robot_name = robot.getName()

        # trajectory
        self.trajectory_generator = FuzzyTrajectoryGenerator(self.robot)
        self.trajectory = []
        self.generate_trajectory_failure = False
        self.trajectory_correct = False

        # command
        self.current_command = None
        self.interpreter = CommandInterpreter(robot_name=self.robot_name,
                                              robot_object=self.robot)

        # frames
        self.ee_frame = None

        # target
        self.target = None
        self.target_q = None
        self.dist_target = -1

        # parameters
        self.node_frequency = Parameters.get(obj=self.robot_name,
                                             param="NODE_FREQUENCY")
        self.trajectory_points = Parameters.get(obj=self.robot_name,
                                                param="TRAJECTORY_POINTS")
        self.trajectory_time = Parameters.get(obj=self.robot_name,
                                              param="TRAJECTORY_TIME")
        self.joints_tollerance = self.robot.getParam("joints_tollerance")

        # timer
        self.init_generate_timer = 15 * self.node_frequency  # [sec]
        self.init_start_moving_timer = 10 * self.node_frequency  # [sec]

        # external callback
        self.feedback_ext_callback = None
        self.feedback = RobotMotionFeedback()
        self.result_ext_callback = None
        self.result = RobotMotionResult()

        # error
        self.err = self.result.NO_ERROR

        # noise velocity in steady state
        self.vel_noise_mean = 0.015

        # alarm
        self.in_allarm = False
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)
        self.alarm_proxy.registerResetCallback(self.alarm_reset_callback)
Пример #2
0
    def __init__(self, robot_name):
        self.robot_name = robot_name
        self.listener = tf.TransformListener()
        self.message_database = MessageStorage()

        # tool
        self.tools_list = Parameters.get(obj=self.robot_name, param="TOOLS")
        print self.tools_list
        self.new_tools = {}
        self.new_tools["dynamic"] = FrameVectorToKDL(
            self.tools_list["gripper"])

        # alarm
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)

        # target follower proxy
        self.target_follower = TargetFollowerProxy(self.robot_name)

        # robot outer message (no feedback/response)
        self.outer_message_proxy = SimpleMessageProxy()
        self.outer_message_proxy.register(self.command_callback)

        # robot outer command
        self.command_server = CommandProxyServer("{}_supervisor".format(
            self.robot_name))
        self.command_server.registerCallback(self.command_action_callback)
        self.command_server_last_message = None
        self.command_category = "unknown"

        # robot inner message
        self.inner_message_proxy = SimpleMessageProxy(
            "{}_inner_message".format(self.robot_name))

        # robot inner command
        self.robot_trajectory_client = RobotMotionClient(
            self.robot_name, ext_callback=self.robot_trajectory_callback)
        self.robot_control_client = CommandProxyClient(
            "{}_direct_commander".format(self.robot_name))
        self.robot_control_client.registerDoneCallback(
            self.control_done_callback)
Пример #3
0
    def __init__(self, uifile, node):
        super(CustomWindow, self).__init__(uifile=uifile)

        self.robot_name = robot_name

        ############# Variable Initialization #############
        self.available_tfs_map = {}
        self.available_shapes_map = {}
        self.available_ctrlpar_map = {}
        self.wire_z_offset = 0
        self.wire_x_offset = 0
        self.wire_angle = 0
        self.direct_control_active = False
        self.controller_input = {}
        self.controller_params = {}
        self.selected_tf = ""
        self.selected_tool = "gripper"
        self.selected_shape = ""
        self.selected_axis = [1, 0, 0]
        self.selected_controller = "none"
        self.command_sequence_index = 0
        self.seq_run_flg = False
        self.active_command = None

        ################
        self.listener = tf.TransformListener()

        self.node = node
        self.node.createSubscriber("/tf", tfMessage, self.tf_callback)

        self.robot_proxy_client = CommandProxyClient("{}_supervisor".format(
            self.robot_name))
        self.robot_proxy_client.registerDoneCallback(self.robot_done_callback)
        self.robot_message_proxy = SimpleMessageProxy()
        self.inner_message_proxy = SimpleMessageProxy(
            "{}_inner_message".format(self.robot_name))
        self.gripper_pub = self.node.createPublisher(
            "/schunk_pg70/joint_setpoint", JointState)
        # self.filter_pub = self.node.createPublisher(
        #     "/simple_message_stream/common", String)

        ################
        self.tf_manager = TfManagerStub()
        self.param_saver = SaveParams()
        self.shape_saver = SaveShape(self.robot_name)
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)
        self.alarm_proxy.registerResetCallback(self.alarm_reset_callback)
        self.message_database = MessageStorage()
        # self.command_proxy_client = CommandProxyClient(
        #     "{}_supervisor".format(self.robot_name))
        # self.command_proxy_client.registerDoneCallback(self.supervisor_done_callback)

        ############# Qt Objects ############
        self.alarm_set_button.setStyleSheet("background-color: green")
        self.direct_button.setStyleSheet("background-color: white")
        #---
        self.tool_box.currentIndexChanged.connect(self.tool_change)
        self.gripper_check_box.stateChanged.connect(self.gripper)
        self.joystick_check_box.stateChanged.connect(self.joystick)
        self.direct_button.clicked.connect(self.directMode)
        self.start_control_button.clicked.connect(self.startControl)
        self.clear_control_button.clicked.connect(self.clearControlList)
        self.select_control_button.clicked.connect(self.selectControl)
        self.update_controller_button.clicked.connect(
            self.setControlParameters)
        self.load_ctrlpar_button.clicked.connect(self.loadControlParameters)
        self.direct_reset_button.clicked.connect(self.directReset)
        self.update_button.clicked.connect(self.tfListUpdate)
        self.update_button_2.clicked.connect(self.shapeListUpdate)
        self.filter_button.clicked.connect(self.startFilter)
        self.clear_filter_button.clicked.connect(self.clearFilter)
        self.save_shape_button.clicked.connect(self.saveShape)
        self.save_controller_button.clicked.connect(self.saveController)
        self.update_button_3.clicked.connect(self.ctrlParamsListUpdate)
        self.delete_shape_button.clicked.connect(self.deleteShape)
        self.save_tf_button.clicked.connect(self.saveTf)
        self.alarm_reset_button.clicked.connect(self.reset_alarm)
        self.alarm_set_button.clicked.connect(self.set_alarm)
        self.tf_filter.textChanged.connect(self.tfListUpdate)
        self.shape_filter.textChanged.connect(self.shapeListUpdate)
        self.send_command.clicked.connect(self.sendCommand)
        self.forward_button.clicked.connect(self.commandSequence)
        self.forward_button.clicked.connect(self.nextCommand)
        self.set_index_button.clicked.connect(self.setCommandSequenceIndex)
        self.reset_index_button.clicked.connect(self.resetCommandSequenceIndex)

        self.tfListUpdate()
Пример #4
0
class CustomWindow(PyQtWindow):
    def __init__(self, uifile, node):
        super(CustomWindow, self).__init__(uifile=uifile)

        self.robot_name = robot_name

        ############# Variable Initialization #############
        self.available_tfs_map = {}
        self.available_shapes_map = {}
        self.available_ctrlpar_map = {}
        self.wire_z_offset = 0
        self.wire_x_offset = 0
        self.wire_angle = 0
        self.direct_control_active = False
        self.controller_input = {}
        self.controller_params = {}
        self.selected_tf = ""
        self.selected_tool = "gripper"
        self.selected_shape = ""
        self.selected_axis = [1, 0, 0]
        self.selected_controller = "none"
        self.command_sequence_index = 0
        self.seq_run_flg = False
        self.active_command = None

        ################
        self.listener = tf.TransformListener()

        self.node = node
        self.node.createSubscriber("/tf", tfMessage, self.tf_callback)

        self.robot_proxy_client = CommandProxyClient("{}_supervisor".format(
            self.robot_name))
        self.robot_proxy_client.registerDoneCallback(self.robot_done_callback)
        self.robot_message_proxy = SimpleMessageProxy()
        self.inner_message_proxy = SimpleMessageProxy(
            "{}_inner_message".format(self.robot_name))
        self.gripper_pub = self.node.createPublisher(
            "/schunk_pg70/joint_setpoint", JointState)
        # self.filter_pub = self.node.createPublisher(
        #     "/simple_message_stream/common", String)

        ################
        self.tf_manager = TfManagerStub()
        self.param_saver = SaveParams()
        self.shape_saver = SaveShape(self.robot_name)
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)
        self.alarm_proxy.registerResetCallback(self.alarm_reset_callback)
        self.message_database = MessageStorage()
        # self.command_proxy_client = CommandProxyClient(
        #     "{}_supervisor".format(self.robot_name))
        # self.command_proxy_client.registerDoneCallback(self.supervisor_done_callback)

        ############# Qt Objects ############
        self.alarm_set_button.setStyleSheet("background-color: green")
        self.direct_button.setStyleSheet("background-color: white")
        #---
        self.tool_box.currentIndexChanged.connect(self.tool_change)
        self.gripper_check_box.stateChanged.connect(self.gripper)
        self.joystick_check_box.stateChanged.connect(self.joystick)
        self.direct_button.clicked.connect(self.directMode)
        self.start_control_button.clicked.connect(self.startControl)
        self.clear_control_button.clicked.connect(self.clearControlList)
        self.select_control_button.clicked.connect(self.selectControl)
        self.update_controller_button.clicked.connect(
            self.setControlParameters)
        self.load_ctrlpar_button.clicked.connect(self.loadControlParameters)
        self.direct_reset_button.clicked.connect(self.directReset)
        self.update_button.clicked.connect(self.tfListUpdate)
        self.update_button_2.clicked.connect(self.shapeListUpdate)
        self.filter_button.clicked.connect(self.startFilter)
        self.clear_filter_button.clicked.connect(self.clearFilter)
        self.save_shape_button.clicked.connect(self.saveShape)
        self.save_controller_button.clicked.connect(self.saveController)
        self.update_button_3.clicked.connect(self.ctrlParamsListUpdate)
        self.delete_shape_button.clicked.connect(self.deleteShape)
        self.save_tf_button.clicked.connect(self.saveTf)
        self.alarm_reset_button.clicked.connect(self.reset_alarm)
        self.alarm_set_button.clicked.connect(self.set_alarm)
        self.tf_filter.textChanged.connect(self.tfListUpdate)
        self.shape_filter.textChanged.connect(self.shapeListUpdate)
        self.send_command.clicked.connect(self.sendCommand)
        self.forward_button.clicked.connect(self.commandSequence)
        self.forward_button.clicked.connect(self.nextCommand)
        self.set_index_button.clicked.connect(self.setCommandSequenceIndex)
        self.reset_index_button.clicked.connect(self.resetCommandSequenceIndex)

        self.tfListUpdate()

    def setCommandSequenceIndex(self):
        self.command_sequence_index = int(self.sequence_index_value.text())

    def resetCommandSequenceIndex(self):
        self.sequence_index_value.setText("0")
        self.command_sequence_index = -1
        self.nextCommand()

    def commandSequence(self, command_str):
        if command_str.startswith("FILTER"):
            self.selected_tf = command_str.split(" ")[1]
            self.clearFilter()
            self.startFilter()
        elif command_str.startswith("CLOSE_GRIPPER"):
            self.gripper_check_box.setChecked(True)
            self.gripper()
        elif command_str.startswith("OPEN_GRIPPER"):
            self.gripper_check_box.setChecked(False)
            self.gripper()
        else:
            self.current_command.setText(command_str)
            if self.link_to_send_check_box.isChecked():
                self.sendCommand()

    def sendCommand(self):
        print(self.current_command.text())
        cmd_str = str(self.current_command.text())
        command = str(self.command_type_box.currentText())
        if cmd_str.startswith("shape_"):
            simple_message = SimpleMessage(command=command,
                                           receiver="{}_supervisor".format(
                                               self.robot_name))
            shape_name = cmd_str.split(" ")[0]  # self.selected_shape
            simple_message.setData("shape_name", shape_name)
        else:
            simple_message = SimpleMessage(command=command,
                                           receiver="{}_supervisor".format(
                                               self.robot_name))
            tf_name = cmd_str.split(" ")[0]  # self.selected_tf
            tool_name = cmd_str.split(" ")[1]  # self.selected_tool
            simple_message.setData("tf_name", tf_name)
            simple_message.setData("tool_name", tool_name)
        print(simple_message.toString())
        self.active_command = self.robot_proxy_client.sendCommand(
            simple_message.toString())
        # self.robot_message_proxy.send(simple_message)
        self.direct_button.setStyleSheet("background-color: white")
        self.send_command.setStyleSheet("background-color: red")

    def robot_done_callback(self, command):
        sent_message = command.getSentMessage()
        if sent_message.getCommand().startswith("goto"):
            Logger.warning("trajectory DONE")
            try:
                source_done = command.response_data["trajectory_done"]
                if source_done:
                    print("trajectory OK   {}".format(
                        command.response_data["q_target_distance"]))
                    self.send_command.setStyleSheet("background-color: green")
                else:
                    print("trajectory FAIL   {}".format(
                        command.response_data["q_target_distance"]))
                    self.send_command.setStyleSheet("background-color: white")
            except Exception as e:
                print(e)
                self.send_command.setStyleSheet("background-color: red")

    def updateCommand(self, target_type):
        if target_type == "shape":
            command = "{}".format(self.selected_shape)
            self.current_command.setText(command)
        elif target_type == "tf":
            command = "{} {}".format(self.selected_tf, self.selected_tool)
            self.current_command.setText(command)
        else:
            return

    def updateList(self, commands):
        self.commands = commands
        self.command_sequence_index = 0
        model = QStandardItemModel(self.list)
        for c in commands:
            item = QStandardItem(str(c))
            model.appendRow(item)
        self.list.setModel(model)
        self.list.selectionModel().currentChanged.disconnect()
        self.list.selectionModel().currentChanged.connect(
            self.listSelectionChanged)
        self.setSelectedCommand(self.command_sequence_index)

    def setSelectedCommand(self, index):
        index = self.list.model().index(index, 0)
        self.list.setCurrentIndex(index)

    def nextCommand(self):
        self.command_sequence_index += 1
        self.command_sequence_index = self.command_sequence_index % len(
            self.commands)
        self.setSelectedCommand(self.command_sequence_index)

    def listSelectionChanged(self, v):
        print(v.data().toString())
        command = v.data().toString()
        self.current_command_text.setText(command)
        self.commandSequence(str(command))

    def directMode(self):
        simple_message = SimpleMessage(command="direct",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        self.direct_control_active = not self.direct_control_active
        if self.direct_control_active:
            self.direct_button.setStyleSheet("background-color: green")
        else:
            self.direct_button.setStyleSheet("background-color: white")
        simple_message.setData("active", self.direct_control_active)
        self.robot_message_proxy.send(simple_message)

    def directReset(self):
        simple_message = SimpleMessage(command="directreset",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        self.robot_message_proxy.send(simple_message)

    def set_alarm(self):
        self.alarm_set_button.setStyleSheet("background-color: red")
        self.enter_ready_to_reset = True
        self.alarm_proxy.setAlarm()

    def alarm_callback(self, alarm_info):
        if alarm_info != self.alarm_proxy.NONE_ALARM:
            self.alarm_set_button.setStyleSheet("background-color: red")
            self.enter_ready_to_reset = True
        elif alarm_info == self.alarm_proxy.NONE_ALARM and self.enter_ready_to_reset:
            self.alarm_set_button.setStyleSheet("background-color: orange")
            self.enter_ready_to_reset = False

    def alarm_reset_callback(self):
        self.alarm_set_button.setStyleSheet("background-color: green")

    def reset_alarm(self):
        self.alarm_set_button.setStyleSheet("background-color: green")
        self.enter_ready_to_reset = False
        cmd_str = "reset"
        simple_message = SimpleMessage(command=cmd_str,
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        self.robot_message_proxy.send(simple_message)

    def gripper(self):
        close_val = int(self.gripper_close_value.text())
        open_val = int(self.gripper_open_value.text())
        if self.gripper_check_box.isChecked() == True:
            self._setGripper(close_val)
        else:
            self._setGripper(open_val)

    def _setGripper(self, p, v=50, e=50):
        js = JointState()
        js.name = []
        js.position = [p]
        js.velocity = [v]
        js.effort = [e]
        self.gripper_pub.publish(js)

    def joystick(self):
        if self.joystick_check_box.isChecked() == True:
            cmd_str = "_joyon_"
        else:
            cmd_str = "_joyoff_"
        simple_message = SimpleMessage(command=cmd_str,
                                       receiver="{}_direct_commander".format(
                                           self.robot_name))
        self.inner_message_proxy.send(simple_message)
        print(cmd_str)

# ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
# ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇    TRAJECTORY TAB    ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
# ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def setSelectedTf(self, tf_name):
        self.selected_tf = str(tf_name)
        self.updateCommand("tf")

    def setSelectedShape(self, shape_name):
        self.selected_shape = shape_name
        self.updateCommand("shape")

    def tool_change(self, i):
        self.selected_tool = str(self.tool_box.currentText())
        simple_message = SimpleMessage(command="selecttool",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        simple_message.setData("tool_name", str(self.selected_tool))
        print(simple_message.toString())
        self.robot_message_proxy.send(simple_message)

        self.updateCommand("tf")

    def tf_change(self, v):
        itms = self.tf_list.selectedIndexes()
        for it in itms:
            self.setSelectedTf(it.data().toString())
            break

    def shape_change(self, v):
        itms = self.shape_list.selectedIndexes()
        for it in itms:
            self.setSelectedShape(it.data().toString())
            break

    def set_new_tool(self, transf):
        simple_message = SimpleMessage(command="settool",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        simple_message.setData("tool_name", str(self.selected_tool))
        simple_message.setData("new_tool_name", "dynamic")
        simple_message.setData("transformation", transf)
        print(simple_message.toString())
        self.robot_message_proxy.send(simple_message)

    def tf_callback(self, msg):
        self.available_tfs = []
        for tf in msg.transforms:
            if len(tf.child_frame_id) > 0:
                self.available_tfs_map[tf.child_frame_id] = tf

    def tfListUpdate(self):
        tf_list_model = QStandardItemModel(self.tf_list)
        tf_sorted = sorted(self.available_tfs_map.keys())
        filtered_str = str(self.tf_filter.text()).lower()
        for tf_name in tf_sorted:
            if filtered_str in tf_name.lower() or filtered_str == '':
                item = QStandardItem(tf_name)
                item.setEditable(False)
                tf_list_model.appendRow(item)
        self.tf_list.setModel(tf_list_model)
        self.tf_list.selectionModel().selectionChanged.connect(self.tf_change)
        self.tf_manager.update()

    def shapeListUpdate(self):
        shape_list_model = QStandardItemModel(self.shape_list)
        db_msg = self.message_database.searchByName("shape_",
                                                    JointState,
                                                    single=False)

        for i in range(0, len(db_msg)):
            name = db_msg[i][1]["name"]
            shape = db_msg[i][0].position
            self.available_shapes_map[name] = shape
        shape_sorted = sorted(self.available_shapes_map.keys())
        filtered_str = str(self.shape_filter.text()).lower()
        for shape_name in shape_sorted:
            if filtered_str in shape_name.lower() or filtered_str == '':
                item = QStandardItem(shape_name)
                item.setEditable(False)
                shape_list_model.appendRow(item)
        self.shape_list.setModel(shape_list_model)
        self.shape_list.selectionModel().selectionChanged.connect(
            self.shape_change)

    def startFilter(self):
        msg_str = String()
        tf_name = self.selected_tf
        msg = SimpleMessage(receiver="tf_filter_supervisor", command="start")
        msg.setData("slot_size", 200)
        msg.setData("tf_name", tf_name)
        self.robot_message_proxy.send(msg)

    def clearFilter(self):
        msg_str = String()
        tf_name = self.selected_tf
        msg = SimpleMessage(receiver="tf_filter_supervisor", command="clear")
        msg.setData("tf_name", tf_name)
        self.robot_message_proxy.send(msg)

    def saveShape(self):
        self.shape_saver.save("shape_" + str(self.obj_save_name_value.text()))

    def deleteShape(self):
        self.shape_saver.delete("shape_" +
                                str(self.obj_save_name_value.text()))
        print("delete " + str(self.obj_save_name_value.text()))

    def saveTf(self):
        current_tool_tf = node.retrieveTransform(
            self.robot_name + "/base_link", self.robot_name + "/tool", -1)
        if current_tool_tf:
            self.tf_manager.save(tf_name=self.robot_name + "/tool",
                                 tf_parent=self.robot_name + "/base_link",
                                 saving_name=str(
                                     self.obj_save_name_value.text()))
            time.sleep(0.5)
            self.tf_manager.update()
            time.sleep(0.5)
            self.tf_manager.startPublish()
            print("OK! Saved:{}".format(str(self.obj_save_name_value.text())))


# ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
# ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇    CONTROLLERS TAB    ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
# ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def ctrlParamsListUpdate(self):
        list_model = QStandardItemModel(self.ctrlpar_list)
        db_msg = self.message_database.searchByName("ctrl_",
                                                    String,
                                                    single=False)

        for i in range(0, len(db_msg)):
            name = db_msg[i][1]["name"]
            data = json.loads(db_msg[i][0].data)
            self.available_ctrlpar_map[name] = data
        ctrlpar_sorted = sorted(self.available_ctrlpar_map.keys())
        for ctrlpar_name in ctrlpar_sorted:
            item = QStandardItem(ctrlpar_name)
            item.setEditable(False)
            list_model.appendRow(item)
        self.ctrlpar_list.setModel(list_model)
        self.ctrlpar_list.selectionModel().selectionChanged.connect(
            self.ctrlpar_change)

    def ctrlpar_change(self):
        itms = self.ctrlpar_list.selectedIndexes()
        for it in itms:
            self.selected_ctrlpar.setText(it.data().toString())
            break

    def saveController(self):
        self.setControlParameters(action="save")
        print self.controller_params
        self.param_saver.save("ctrl_" + str(self.obj_save_name_value.text()),
                              self.controller_params)

    def clearControlList(self):
        simple_message = SimpleMessage(command="controllerdisable",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        simple_message.setData("id", ["_all_"])
        self.robot_message_proxy.send(simple_message)

    def startControl(self):
        controller_input = {}
        #➤ force
        if "force_spring" in self._getControllersList():
            controller_input["force_spring"] = {}
        if "force_dampedforward" in self._getControllersList():
            controller_input["force_dampedforward"] = {
                "axis": self.selected_axis
            }
        #➤ tactile
        if "tactile_spring" in self._getControllersList():
            controller_input["tactile_spring"] = {}
        if "tactile_dampedforward" in self._getControllersList():
            controller_input["tactile_dampedforward"] = {}
        if "wire_insertion" in self._getControllersList():
            hole_tf = None
            while not hole_tf:
                try:
                    hole_tf = node.retrieveTransform(
                        frame_id="tf_storage_hole",
                        parent_frame_id=self.robot_name + "/base_link",
                        time=-1)
                    hole_tf = transformations.KDLtoTf(hole_tf)
                except:
                    print("Waiting for 'tf_storage_hole'...")

            if hole_tf:
                controller_input["wire_insertion"] = {
                    "hole_tf": hole_tf,
                    "wire_angle": self.wire_angle
                }
            else:
                print("\n\n\n\nHOLE TF NOT FOUND\n\n\n\n")
        if len(self._getControllersList()) == 0:
            controller_input["none"] = {}

        simple_message = SimpleMessage(command="controllerstart",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        simple_message.setData("input_data", controller_input)
        self.robot_message_proxy.send(simple_message)
        print(simple_message.toString())

    def selectControl(self):
        simple_message = SimpleMessage(command="controllerselect",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))

        if len(self._getControllersList()) == 0:
            simple_message.setData("id", ["none"])
        else:
            simple_message.setData("id", self._getControllersList())
        self.robot_message_proxy.send(simple_message)
        print(simple_message.toString())

    def updateControlParam(self):
        simple_message = SimpleMessage(command="controllerparameters",
                                       receiver="{}_supervisor".format(
                                           self.robot_name))
        simple_message.setData("parameters", self.controller_params)
        self.robot_message_proxy.send(simple_message)
        print(simple_message.toString())

    def loadControlParameters(self):
        self.controller_params = self.available_ctrlpar_map[str(
            self.selected_ctrlpar.text())]
        print self.controller_params
        self.updateControlParam()

    def setControlParameters(self, action="load"):

        spring_force_params = {
            "translation_mag": float(self.translation_mag_value.text()),
            "rotation_mag": float(self.rotation_mag_value.text()),
            "thresholds": eval(str(self.force_thresholds_value.text()))
        }

        damp_force_params = {
            "velocity": float(self.velocity_value.text()),
            "damp_force_threshold": float(self.damp_threshold_value.text()),
            "damp_magnitude": float(self.damp_mag_value.text())
        }

        tactile_spring_params = {
            "threshold": [
                float(self.tactile_threshold_value_0.text()),
                float(self.tactile_threshold_value_1.text()),
                float(self.tactile_threshold_value_2.text())
            ],
            "linear_gain": [
                float(self.tactile_lin_gain_value_0.text()),
                float(self.tactile_lin_gain_value_1.text()),
                float(self.tactile_lin_gain_value_2.text())
            ],
            "angular_gain": [
                float(self.tactile_ang_gain_value_0.text()),
                float(self.tactile_ang_gain_value_1.text()),
                float(self.tactile_ang_gain_value_2.text())
            ],
            "angular_action":
            self.angular_action_check_box.isChecked(),
            "linear_action":
            self.linear_action_check_box.isChecked()
        }
        tactile_damp_params = {
            "step_size":
            float(self.step_size_value.text()),
            "direction_gain":
            float(self.direction_gain_value.text()),
            "regulation_angular_action":
            self.angular_reg_action_check_box.isChecked(),
            "regulation_linear_action":
            self.linear_reg_action_check_box.isChecked(),
            "linear_regulation_gain": [
                float(self.lin_reg_gain_value_0.text()),
                float(self.lin_reg_gain_value_1.text()),
                float(self.lin_reg_gain_value_2.text())
            ],
            "angular_regulation_gain": [
                float(self.ang_reg_gain_value_0.text()),
                float(self.ang_reg_gain_value_1.text()),
                float(self.ang_reg_gain_value_2.text())
            ],
            "regulation_threshold": [
                float(self.regulation_threshold_value_0.text()),
                float(self.regulation_threshold_value_1.text()),
                float(self.regulation_threshold_value_2.text())
            ],
            "global_gain":
            float(self.global_gain_value.text()),
            "direction_correction":
            self.correction_action_check_box.isChecked(),
            "direction_compensation":
            self.compensation_action_check_box.isChecked()
        }
        wire_insertion_params = {
            "step_size":
            float(self.in_step_size_value.text()),
            "force_p_gain":
            float(self.in_force_pgain_value.text()),
            "force_threshold":
            float(self.in_force_threshold_value.text()),
            "regulation_p_gain": [
                float(self.in_regulation_pgain_value_0.text()),
                float(self.in_regulation_pgain_value_1.text()),
                float(self.in_regulation_pgain_value_2.text())
            ],
            "regulation_i_gain": [
                float(self.in_regulation_igain_value_0.text()),
                float(self.in_regulation_igain_value_1.text()),
                float(self.in_regulation_igain_value_2.text())
            ],
            "regulation_i_size": [
                float(self.in_regulation_isize_value_0.text()),
                float(self.in_regulation_isize_value_1.text()),
                float(self.in_regulation_isize_value_2.text())
            ],
            "threshold": [
                float(self.in_regulation_threshold_value_0.text()),
                float(self.in_regulation_threshold_value_1.text()),
                float(self.in_regulation_threshold_value_2.text())
            ],
            "force_projection":
            self.force_projection_check_box.isChecked(),
            "position_ball_radious":
            float(self.position_ball_radious_value.text()),
            "position_ball_offset":
            float(self.position_ball_offset_value.text()),
            "position_scaling_gain":
            float(self.in_position_scaling_gain.text()),
            "position_scaling_limits": [
                float(self.in_position_scaling_limmin.text()),
                float(self.in_position_scaling_limmax.text())
            ]
        }

        self.controller_params = {}
        #➤ force
        if "force_spring" in self._getControllersList():
            self.controller_params["force_spring"] = spring_force_params
        if "force_dampedforward" in self._getControllersList():
            self.controller_params["force_dampedforward"] = damp_force_params
        #➤ tactile
        if "tactile_spring" in self._getControllersList():
            self.controller_params["tactile_spring"] = tactile_spring_params
        if "tactile_dampedforward" in self._getControllersList():
            self.controller_params[
                "tactile_dampedforward"] = tactile_damp_params
        if "wire_insertion" in self._getControllersList():
            self.controller_params["wire_insertion"] = wire_insertion_params

        print action
        if action == "save":
            pass
        else:
            self.updateControlParam()

    def _getControllersList(self):
        selected_controllers = []
        #➤ force
        if self.spring_force_ctrl_box.isChecked():
            selected_controllers.append("force_spring")
        return selected_controllers

    def getAxis(self, axis_name):
        sign = int("{}1".format(axis_name[0]))
        axis = axis_name[1]
        if axis == "x":
            return [sign, 0, 0]
        elif axis == "y":
            return [0, sign, 0]
        elif axis == "z":
            return [0, 0, sign]
        else:
            return [0, 0, 0]
Пример #5
0
class SFMachineRobotSupervisorDefinition(object):

    DIRECT_COMMANDER = 100
    TRAJECTORY_COMMANDER = 101

    def __init__(self, robot_name):
        self.robot_name = robot_name
        self.listener = tf.TransformListener()
        self.message_database = MessageStorage()

        # tool
        self.tools_list = Parameters.get(obj=self.robot_name, param="TOOLS")
        print self.tools_list
        self.new_tools = {}
        self.new_tools["dynamic"] = FrameVectorToKDL(
            self.tools_list["gripper"])

        # alarm
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)

        # target follower proxy
        self.target_follower = TargetFollowerProxy(self.robot_name)

        # robot outer message (no feedback/response)
        self.outer_message_proxy = SimpleMessageProxy()
        self.outer_message_proxy.register(self.command_callback)

        # robot outer command
        self.command_server = CommandProxyServer("{}_supervisor".format(
            self.robot_name))
        self.command_server.registerCallback(self.command_action_callback)
        self.command_server_last_message = None
        self.command_category = "unknown"

        # robot inner message
        self.inner_message_proxy = SimpleMessageProxy(
            "{}_inner_message".format(self.robot_name))

        # robot inner command
        self.robot_trajectory_client = RobotMotionClient(
            self.robot_name, ext_callback=self.robot_trajectory_callback)
        self.robot_control_client = CommandProxyClient(
            "{}_direct_commander".format(self.robot_name))
        self.robot_control_client.registerDoneCallback(
            self.control_done_callback)
        # self.robot_control_client.registerFeedbackCallback(
        #     self.control_feedback_callback)   # TODO

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ CALLBACKS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def alarm_callback(self, alarm_info):
        if alarm_info != self.alarm_proxy.NONE_ALARM:
            Logger.error(" !!!!!!!!  ALARM  !!!!!!!! ")
            self.alarm()

    def robot_trajectory_callback(self, cb_type, msg):
        if cb_type == self.robot_trajectory_client.FEEDBACK:
            self.trajectory_sm_feedback = msg
            # self._send_trajectory_feedback(msg) # TODO
        elif cb_type == self.robot_trajectory_client.RESULT:
            self._send_trajectory_command_result(msg)
            if self.state != "alarm":
                self.idle()

    def control_done_callback(self, command):
        # print command
        if command:
            success = (command.status == CommandMessage.COMMAND_STATUS_OK)
            command = command.getSentMessage().getCommand()
        else:
            command = "NONE"
            success = False
        self._send_command_result(success)
        print("controller: {} >>> SUCCESS={}".format(command, success))

        # if self.state != "alarm":
        #     self.idle()

    def command_action_callback(self, cmd):
        self.command_server_last_message = cmd
        cmd_msg = cmd.getSentMessage()
        self.command_callback(cmd_msg)

    def command_callback(self, msg):
        if msg.isValid():
            if msg.getReceiver() == "{}_supervisor".format(self.robot_name):
                print msg.toString()
                command = msg.getCommand()
                try:
                    #⬢⬢⬢⬢⬢➤ RESET
                    if command == "reset":
                        self.command_category = "setting"
                        Logger.warning(" !!!!!!!! ALARM RESET  !!!!!!!! ")
                        self.alarm_proxy.resetAlarm()
                        self.target_follower.resetAlarm()
                        self._reject_input_command(GlobalErrorList.ROBOT_ALARM)
                        self.idle()

                    elif self.state != "alarm":
                        #⬢⬢⬢⬢⬢➤ SET TOOL
                        if command == "settool":  # change multiple data structure in a single multi-entry dictionary
                            self.command_category = "setting"
                            tool_name = msg.getData("tool_name")
                            new_tool_name = msg.getData("new_tool_name")
                            transf = msg.getData("transformation")
                            tool = self._getToolFromName(tool_name)
                            transf = FrameVectorToKDL(transf)
                            self.new_tools[new_tool_name] = tool * transf
                            print("Tools: {}".format(self.new_tools))
                            self._send_command_result(True)
                            self.idle()

                        #⬢⬢⬢⬢⬢➤ SELECT TOOL
                        elif command == "selecttool":
                            self.command_category = "setting"
                            tool_name = msg.getData("tool_name")
                            tool = self._getToolFromName(tool_name)
                            self._setTool(tool)
                            self._send_command_result(True)
                            self.idle()

                        #⬢⬢⬢⬢⬢➤ SET TRAJECTORY
                        elif command == "settrajectory":
                            self.command_category = "setting"
                            points = msg.getData(
                                "points"
                            )  # if it returns none, this wasn't the set parameter
                            time = msg.getData("time")
                            if points is not None:
                                print Parameters.get(obj=self.robot_name,
                                                     param="TRAJECTORY_POINTS")
                                Parameters.change(obj=self.robot_name,
                                                  param="TRAJECTORY_POINTS",
                                                  value=int(points))
                                print Parameters.get(obj=self.robot_name,
                                                     param="TRAJECTORY_POINTS")
                            elif time is not None:
                                Parameters.change(obj=self.robot_name,
                                                  param="TRAJECTORY_TIME",
                                                  value=int(points))
                            self._send_command_result(True)
                            self.idle()

                        #⬢⬢⬢⬢⬢➤ MOVE TO TF
                        elif command == "movetotf":
                            self.command_category = "trajectory"
                            tf_name = msg.getData("tf_name")
                            tool_name = msg.getData("tool_name")
                            self._toTf(tf_name, tool_name, mode=command)
                            print("Tf: \033[1m\033[4m\033[94m{}\033[0m".format(
                                tf_name))
                            self.trajectory()

                        #⬢⬢⬢⬢⬢➤ JUMP TO TF
                        elif command == "jumptotf":
                            self.command_category = "trajectory"
                            tf_name = msg.getData("tf_name")
                            tool_name = msg.getData("tool_name")
                            self._toTf(tf_name, tool_name, mode=command)
                            print("Tf: \033[1m\033[4m\033[94m{}\033[0m".format(
                                tf_name))
                            self.trajectory()

                        #⬢⬢⬢⬢⬢➤ GO TO TF
                        elif command == "gototf":
                            self.command_category = "trajectory"
                            tf_name = msg.getData("tf_name")
                            tool_name = msg.getData("tool_name")
                            self._toTf(tf_name, tool_name, mode=command)
                            print("Tf: \033[1m\033[4m\033[94m{}\033[0m".format(
                                tf_name))
                            self.trajectory()

                        #⬢⬢⬢⬢⬢➤ GO TO JOINTS
                        elif command == "gotojoints":
                            self.command_category = "trajectory"
                            joints_str = msg.getData("joints_vector")
                            self._toJoints(joints_str)
                            print("Joints: \033[1m\033[4m\033[94m{}\033[0m".
                                  format(joints_str))
                            self.trajectory()

                        #⬢⬢⬢⬢⬢➤ GO TO SHAPE
                        elif command == "gotoshape":
                            self.command_category = "trajectory"
                            shape_name = msg.getData("shape_name", str)
                            self._toShape(shape_name)
                            print("Shape: \033[1m\033[4m\033[94m{}\033[0m".
                                  format(shape_name))
                            self.trajectory()

                        #⬢⬢⬢⬢⬢➤ RESET CONTROLLERS
                        elif command == "directreset":
                            self.command_category = "setting"
                            self._resetDirectCommander()

                        #⬢⬢⬢⬢⬢➤ ENABLE CONTROLLERS
                        elif command == "direct":
                            self.command_category = "setting"
                            active = msg.getData("active")
                            if active:
                                self._switchCommander(self.DIRECT_COMMANDER)
                                self.direct()
                            else:
                                self._switchCommander(
                                    self.TRAJECTORY_COMMANDER)
                                self.idle()

                        #⬢⬢⬢⬢⬢➤ START CONTROLLERS
                        elif command == "controllerstart":
                            self.command_category = "setting"
                            self._sendCommandActionToController(msg)
                            print("Inputs: {}".format(
                                msg.getData("input_data")))
                            self.controlling()

                        #⬢⬢⬢⬢⬢➤ UPDATE CONTROLLERS PARAMETERS
                        elif command == "controllerparameters":
                            self.command_category = "setting"
                            self._sendCommandActionToController(msg)
                            print("Params: {}".format(
                                msg.getData("parameters")))

                        #⬢⬢⬢⬢⬢➤ SELECT CONTROLLERS
                        elif command == "controllerselect":
                            self.command_category = "setting"
                            self._sendCommandActionToController(msg)
                            print("Controller selected: {}".format(
                                msg.getData("id")))

                        #⬢⬢⬢⬢⬢➤ DISABLE CONTROLLERS
                        elif command == "controllerdisable":
                            self.command_category = "setting"
                            self._sendCommandActionToController(msg)
                            print("Controllers removed: {}".format(
                                msg.getData("id")))
                        else:
                            self.command_category = "unknown"
                            Logger.error("INVALID input")
                            self._reject_input_command()
                except Exception as e:
                    Logger.error(e)
                    self._reject_input_command()

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ PRIVATE METHODS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def _getToolFromName(self, tool_name):
        tool_v = self.tools_list[tool_name]
        tool = FrameVectorToKDL(tool_v)
        return tool

    def _sendCommandActionToController(self, msg):
        msg.setReceiver("{}_direct_commander".format(self.robot_name))
        msg.setData("type", "force")
        self.robot_control_client.sendCommand(msg.toString())

    def _sendMessageToController(self, msg):
        msg.setReceiver("{}_direct_commander".format(self.robot_name))
        msg.setData("type", "force")
        self.inner_message_proxy.send(msg)

    def _resetDirectCommander(self):
        simple_message = SimpleMessage(command="_reset_",
                                       receiver="{}_direct_commander".format(
                                           self.robot_name))
        self._sendCommandActionToController(simple_message)

    def _setTool(self, tool):
        """ tool is a PyKDL frame"""
        self.target_follower.setTool(tool)

    def _toJoints(self, joint_str):
        self._switchCommander(self.TRAJECTORY_COMMANDER,
                              expect_done_response=False)
        q_str = joint_str
        txt_cmd = "joints {}".format(q_str)
        self.robot_trajectory_client.generateNewGoal(txt_cmd)

    def _toShape(self, shape_name):
        self._switchCommander(self.TRAJECTORY_COMMANDER,
                              expect_done_response=False)
        txt_cmd = self._getCommandFromShape(shape_name)
        self.robot_trajectory_client.generateNewGoal(txt_cmd)

    def _toTf(self, tf_name, tool_name, mode="goto"):
        self._switchCommander(self.TRAJECTORY_COMMANDER,
                              expect_done_response=False)
        if tool_name.startswith("dynamic"):
            tool = self.new_tools[tool_name]
        else:
            tool = self._getToolFromName(tool_name)
        self._setTool(tool)
        txt_cmd = "{} {}".format(mode, tf_name)
        self.robot_trajectory_client.generateNewGoal(txt_cmd)

    def _getCommandFromShape(self, shape_name):
        db_msg = self.message_database.searchByName(shape_name,
                                                    JointState,
                                                    single=False)
        q_str = str(db_msg[0][0].position).split("(")[1].split(")")[0].replace(
            " ", "")
        txt_cmd = "joints {}".format(q_str)
        return txt_cmd

    def _switchCommander(self, id, expect_done_response=True):
        if id == self.DIRECT_COMMANDER:
            simple_message = SimpleMessage(
                command="_on_",
                receiver="{}_direct_commander".format(self.robot_name))
            self.target_follower.setSource(TargetFollowerProxy.SOURCE_DIRECT)
        elif id == self.TRAJECTORY_COMMANDER:
            simple_message = SimpleMessage(
                command="_off_",
                receiver="{}_direct_commander".format(self.robot_name))
            self.target_follower.setSource(
                TargetFollowerProxy.SOURCE_TRAJECTORY)

        if expect_done_response:
            self._sendCommandActionToController(simple_message)
        else:
            self._sendMessageToController(simple_message)

    def _send_trajectory_command_result(self, msg):
        if self.command_server_last_message:
            if msg is None:
                error = GlobalErrorList.TRAJECTORY_ACTION_RESPONSE_NONETYPE
                Logger.error("Trajectory action response None-type")
                trajectory_done = False
                q_target_distance = -999
            else:
                error = msg.error
                q_target_distance = msg.q_target_distance
                trajectory_done = msg.success

            self.command_server_last_message.addResponseData("error", error)
            self.command_server_last_message.addResponseData(
                "q_target_distance", q_target_distance)
            self.command_server_last_message.addResponseData(
                "trajectory_done", trajectory_done)

            self._send_command_result(trajectory_done)

    def _reject_input_command(self, error_type=GlobalErrorList.UNKNOWN_ERROR):
        if self.command_server_last_message:
            self.command_server_last_message.addResponseData(
                "error", error_type)
            if self.command_category == "trajectory":
                self._send_trajectory_command_result(None)
            else:
                self._send_command_result(False)

    def _send_command_result(self, success):
        if self.command_server_last_message:
            if success:
                self.command_server.resolveCommand(
                    self.command_server_last_message)
            else:
                self.command_server.rejectCommand(
                    self.command_server_last_message)
            self.command_server_last_message = None

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ STATES ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ IDLE ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    # ➤ ➤ ➤ ➤ ➤ IDLE: enter
    def on_enter_idle(self):
        Logger.log("State:  IDLE")

    # ➤ ➤ ➤ ➤ ➤ IDLE: loop
    def on_loop_idle(self):
        pass

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ CONTROLLING ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    # ➤ ➤ ➤ ➤ ➤ CONTROLLING: enter
    def on_enter_controlling(self):
        Logger.log("State:  CONTROLLING")

    # ➤ ➤ ➤ ➤ ➤ CONTROLLING: loop
    def on_loop_controlling(self):
        pass

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ DIRECT ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    # ➤ ➤ ➤ ➤ ➤ DIRECT: enter
    def on_enter_direct(self):
        Logger.log("State:  DIRECT")

    # ➤ ➤ ➤ ➤ ➤ DIRECT: loop
    def on_loop_direct(self):
        if not rosnode.rosnode_ping("{}_direct_motion".format(
                self.robot_name)):
            self.alarm_proxy.setAlarm(AlarmProxy.NODE_DIED)
            self.alarm()
        pass

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ TRAJECTORY ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    # ➤ ➤ ➤ ➤ ➤ TRAJECTORY: enter
    def on_enter_trajectory(self):
        Logger.log("State:  TRAJECTORY")
        # self._switchCommander(self.TRAJECTORY_COMMANDER)

    # ➤ ➤ ➤ ➤ ➤ TRAJECTORY: loop
    def on_loop_trajectory(self):
        if not rosnode.rosnode_ping("{}_trajectory_motion".format(
                self.robot_name)):
            self.alarm_proxy.setAlarm(AlarmProxy.NODE_DIED)
            self.alarm()
        pass

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ ALARM ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    # ➤ ➤ ➤ ➤ ➤ ALARM: enter
    def on_enter_alarm(self):
        Logger.log("State:  ALARM")
        self._reject_input_command(GlobalErrorList.ROBOT_ALARM)

    # ➤ ➤ ➤ ➤ ➤ ALARM: loop
    def on_loop_alarm(self):
        self._reject_input_command(GlobalErrorList.ROBOT_ALARM)
Пример #6
0
    def __init__(self, robot_name, controllers_dict=None):
        self.robot_name = robot_name
        self.current_tf = None
        self.target_tf = None
        self.tf_target_name = "follow_target"
        self.active = False
        self.command_success_flg = False

        # target follower
        self.target_follower = TargetFollowerProxy(self.robot_name)

        # alarm
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)
        self.alarm_proxy.registerResetCallback(self.alarm_reset_callback)

        # command message
        self.message_proxy = SimpleMessageProxy("{}_inner_message".format(
            self.robot_name))
        self.message_proxy.register(self.command_callback)

        # command action
        self.command_server_last_message = None
        self.command_server = CommandProxyServer("{}_direct_commander".format(
            self.robot_name))
        self.command_server.registerCallback(self.command_action_callback)

        # tf
        self.br = tf.TransformBroadcaster()
        self.listener = tf.TransformListener()

        # Joystick Contorol
        joy_sub = rospy.Subscriber('/joy',
                                   Joy,
                                   self.joy_callback,
                                   queue_size=1)
        self.joystick = Joystick(translation_mag=0.0005, rotation_mag=0.0008)
        self.joystick.registerCallback(self.joystick_key_callback)
        self.joystick_flg = False  # Disable by default

        # Closed-Loop Control
        if controllers_dict is None or controllers_dict == {}:
            controllers_dict = {"none": NeutralController()}

        self.controllers_dict = controllers_dict
        self.active_controllers = {}
        self.active_controllers["none"] = NeutralController()
        Logger.warning("READY!!!")

        # Feedback
        self.feedback_data = {}

        # Force
        rospy.Subscriber('/atift',
                         Twist,
                         self.force_feedback_callback,
                         queue_size=1)

        # Tactile
        rospy.Subscriber('/tactile',
                         Float64MultiArray,
                         self.tactile_feedback_callback,
                         queue_size=1)
Пример #7
0
class DirectCommander(object):
    def __init__(self, robot_name, controllers_dict=None):
        self.robot_name = robot_name
        self.current_tf = None
        self.target_tf = None
        self.tf_target_name = "follow_target"
        self.active = False
        self.command_success_flg = False

        # target follower
        self.target_follower = TargetFollowerProxy(self.robot_name)

        # alarm
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)
        self.alarm_proxy.registerResetCallback(self.alarm_reset_callback)

        # command message
        self.message_proxy = SimpleMessageProxy("{}_inner_message".format(
            self.robot_name))
        self.message_proxy.register(self.command_callback)

        # command action
        self.command_server_last_message = None
        self.command_server = CommandProxyServer("{}_direct_commander".format(
            self.robot_name))
        self.command_server.registerCallback(self.command_action_callback)

        # tf
        self.br = tf.TransformBroadcaster()
        self.listener = tf.TransformListener()

        # Joystick Contorol
        joy_sub = rospy.Subscriber('/joy',
                                   Joy,
                                   self.joy_callback,
                                   queue_size=1)
        self.joystick = Joystick(translation_mag=0.0005, rotation_mag=0.0008)
        self.joystick.registerCallback(self.joystick_key_callback)
        self.joystick_flg = False  # Disable by default

        # Closed-Loop Control
        if controllers_dict is None or controllers_dict == {}:
            controllers_dict = {"none": NeutralController()}

        self.controllers_dict = controllers_dict
        self.active_controllers = {}
        self.active_controllers["none"] = NeutralController()
        Logger.warning("READY!!!")

        # Feedback
        self.feedback_data = {}

        # Force
        rospy.Subscriber('/atift',
                         Twist,
                         self.force_feedback_callback,
                         queue_size=1)

        # Tactile
        rospy.Subscriber('/tactile',
                         Float64MultiArray,
                         self.tactile_feedback_callback,
                         queue_size=1)

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ CALLBACKS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    # TODO problema: OGNI VOLTA CHE SI AGGIUNGE UN FEEDBACK OCCORRE CREARE UNA CALLBACK!!!!
    def force_feedback_callback(self, msg):
        msg = self._getForceOnTool(msg)
        self.feedback_data["atift"] = msg

    def tactile_feedback_callback(self, msg):
        self.feedback_data["tactile"] = msg

    def joy_callback(self, msg):
        self.joystick.update(msg)

    def joystick_key_callback(self, down, up):
        # if self.joystick.KEY_BACK in down:
        #     Logger.log(" ALARM: CLEAR ")
        #     self.target_tf = self.current_tf
        #     self.alarm_proxy.resetAlarm()
        #     self.target_follower.resetAlarm()
        if self.joystick.KEY_START in down:
            Logger.log(" USER ALARM: ON ")
            self.alarm_proxy.setAlarm()
            self.target_follower.setAlarm()
        if self.joystick.KEY_LOG in down:
            self.target_tf = self.current_tf

    def command_action_callback(self, cmd):
        self.command_server_last_message = cmd
        cmd_msg = cmd.getSentMessage()
        self.command_callback(cmd_msg)

        time.sleep(0.1)
        self._send_command_result(self.command_success_flg)

    def command_callback(self, msg):
        try:
            self.command_success_flg = True
            if msg.isValid():
                receiver = msg.getReceiver()
                if msg.getReceiver() == "{}_direct_commander".format(
                        self.robot_name):
                    command = msg.getCommand()

                    #⬢⬢⬢⬢⬢➤ ON
                    if command == "_on_":
                        Logger.log(
                            " ******** Direct Commander: ENABLE ******** ")
                        self._reset()
                        self._removeController()
                        self.active = True

                    #⬢⬢⬢⬢⬢➤ OFF
                    elif command == "_off_":
                        Logger.log(
                            " ******** Direct Commander: DISABLE ******** ")
                        self.current_tf = None
                        self._reset()
                        self._removeController()
                        self.active = False

                    #⬢⬢⬢⬢⬢➤ RESET
                    elif command == "_reset_":
                        Logger.log(" ******** RESET ******** ")
                        self._reset()

                    #⬢⬢⬢⬢⬢➤ JOYSTICK
                    elif command == "_joyon_":
                        Logger.log("  Joystick: ENABLE  ")
                        self.joystick_flg = True

                    elif command == "_joyoff_":
                        Logger.log("  Joystick: DISABLE  ")
                        self.joystick_flg = False

                    #⬢⬢⬢⬢⬢➤ SELECT CONTROLLER
                    elif command.startswith("controllerselect"):
                        ctrl_id_list = msg.getData("id")
                        Logger.log(
                            " Controller Selection: {}".format(ctrl_id_list))
                        for ctrl_id in ctrl_id_list:
                            if ctrl_id == "none":
                                Logger.log(" Neutral Controller ")
                                self._removeController()
                            else:
                                try:
                                    self._addController(ctrl_id)
                                except:
                                    self.command_success_flg = False
                                    Logger.error(
                                        "Wrong Controller ID: {}".format(
                                            ctrl_id))

                    #⬢⬢⬢⬢⬢➤ CONTROLLER PARAMETERS
                    elif command.startswith("controllerparameters"):
                        parameters = msg.getData("parameters")
                        Logger.log(
                            " Parameters Update: {} ".format(parameters))

                        for ctrl_id in parameters.keys():
                            if ctrl_id in self.active_controllers.keys():
                                self.active_controllers[ctrl_id].setParameters(
                                    parameters[ctrl_id])
                            else:
                                self.command_success_flg = False
                                Logger.error(
                                    "Wrong Controller ID: {}".format(ctrl_id))

                    #⬢⬢⬢⬢⬢➤ REMOVE CONTROLLER
                    elif command.startswith("controllerdisable"):
                        Logger.log(" Removing Controller ")
                        ctrl_id_list = msg.getData("id")
                        for ctrl_id in ctrl_id_list:
                            if ctrl_id == "_all_":
                                self._reset()
                                self._removeController()
                            elif ctrl_id in self.active_controllers.keys():
                                self._reset(ctrl_id)
                                self._removeController(ctrl_id)
                            else:
                                self.command_success_flg = False
                                Logger.error(
                                    "Wrong Controller ID: {}".format(ctrl_id))

                    # ⬢⬢⬢⬢⬢➤ START CONTROLLERS
                    elif command.startswith("controllerstart"):
                        Logger.log(" Controllers Start {}".format(
                            self.active_controllers.keys()))
                        input_data = msg.getData("input_data")
                        time.sleep(0.1)
                        for ctrl_id in input_data.keys():
                            if ctrl_id in self.active_controllers.keys():
                                self.active_controllers[ctrl_id].start(
                                    input_data[ctrl_id])
                            else:
                                self.command_success_flg = False
                                Logger.error(
                                    "Wrong Controller ID: {}".format(ctrl_id))
                    else:
                        self.command_success_flg = False
                        Logger.warning("INVALID COMMAND: {}".format(command))

            else:
                receiver = msg.getReceiver()
                if msg.getReceiver() == "{}_direct_commander".format(
                        self.robot_name):
                    self.command_success_flg = False
        except Exception as e:
            self.command_success_flg = False
            print(e)

        Logger.log(" \nActive Controllers: {}\n".format(
            self.active_controllers.keys()))

    def alarm_callback(self, alarm_info):
        if alarm_info != self.alarm_proxy.NONE_ALARM:
            Logger.error(" !!!!!!!!  ALARM  !!!!!!!! ")
            self.target_tf = self.current_tf
            self.active = False

    def alarm_reset_callback(self):
        Logger.warning(" ********  ALARM CLEAR  ******** ")
        self.target_tf = self.current_tf
        self._reset()

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ PRIVATE METHODS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def _send_command_result(self, success):
        if self.command_server_last_message:
            Logger.warning("Command result:{}".format(success))
            if success:
                self.command_server.resolveCommand(
                    self.command_server_last_message)
            else:
                self.command_server.rejectCommand(
                    self.command_server_last_message)
            self.command_server_last_message = None

    def _removeController(self, ctrl_id=None):
        if ctrl_id is None:
            self.active_controllers = {}
            self.active_controllers["none"] = NeutralController()
        else:
            if ctrl_id in self.active_controllers.keys():
                self.active_controllers.pop(ctrl_id)
                if self.active_controllers == {}:
                    self.active_controllers["none"] = NeutralController()
            else:
                Logger.error(
                    "Trying to remove a deactivate controller: {}".format(
                        ctrl_id))

    def _addController(self, ctrl_id=None):
        if ctrl_id:
            self.active_controllers[ctrl_id] = self.controllers_dict[ctrl_id]
            if "none" in self.active_controllers.keys():
                self._removeController("none")
        else:
            Logger.error(
                "Trying to activate an unlisted controller: {}".format(
                    ctrl_id))

    def _reset(self, ctrlid=None):
        self.target_tf = self.current_tf
        if ctrlid is None:
            for ctrl_id in self.active_controllers.keys():
                self.active_controllers[ctrl_id].reset()
        else:
            self.active_controllers[ctrlid].reset()

    def _getForceOnTool(self, twist_on_sensor):
        linear_force_on_sensor = PyKDL.Frame(TwistToKDLVector(twist_on_sensor))
        tr_link6_fs = PyKDL.Frame(
            PyKDL.Vector(WRIST_FT_SENSOR_POSITION[0],
                         WRIST_FT_SENSOR_POSITION[1],
                         WRIST_FT_SENSOR_POSITION[2]))
        tr_link6_fs.M = tr_link6_fs.M.RotX(-scipy.pi)
        tr_tool_link6 = transformations.retrieveTransform(
            self.listener,
            self.robot_name + "/tool",
            self.robot_name + "/link6",
            none_error=True,
            time=rospy.Time(0),
            print_error=True)
        # TODO aggiungere una tf eef (in comau coincide con link6 in shunk con finger1 (me media tra i 2))
        try:
            tr_tool_fs = tr_tool_link6 * tr_link6_fs
            linear_force_on_tool = tr_tool_fs * linear_force_on_sensor
            twist_on_tool = TwistFormKDLVector(linear_force_on_tool.p)
            return twist_on_tool
        except Exception as e:
            print(e)

    def _derivateLinearForce(self, twist):
        dT = Twist()
        dT.linear.x = self.force_calculator.derivate(twist.linear.x)
        dT.linear.y = self.force_calculator.derivate(twist.linear.y)
        dT.linear.z = self.force_calculator.derivate(twist.linear.z)
        np.savetxt(self.file_handler,
                   [[time.time(), dT.linear.x, dT.linear.y, dT.linear.z]],
                   fmt='%.18e %.18e %.18e %.18e',
                   delimiter=' ')
        return dT

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ PUBLIC METHODS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def stepForward(self):
        try:
            if self.active:
                self.current_tf = transformations.retrieveTransform(
                    self.listener,
                    self.robot_name +
                    "/base_link",  # TODO aggiungere base_link in shunck
                    self.robot_name + "/tool",
                    none_error=True,
                    time=rospy.Time(0),
                    print_error=True)

                if self.current_tf is not None:
                    if self.target_tf is None:
                        self.target_tf = self.current_tf

                    #➤ Joystick
                    if self.joystick_flg:
                        self.target_tf = self.joystick.transformT(
                            self.target_tf)

                    #➤ Control Action
                    else:
                        self.feedback_data["current_tf"] = self.current_tf
                        self.feedback_data["target_tf"] = self.target_tf
                        for ctrl_id in self.active_controllers.keys():
                            self.target_tf = self.active_controllers[
                                ctrl_id].output(self.feedback_data)

                    #######  Publish and Set Target  #######
                    transformations.broadcastTransform(self.br,
                                                       self.target_tf,
                                                       self.tf_target_name,
                                                       self.robot_name +
                                                       "/base_link",
                                                       time=rospy.Time.now())

                    dist = 1
                    # diff_tf = self.current_tf.Inverse() * self.target_tf
                    # transformations.broadcastTransform(self.br, diff_tf, "diff_tf",
                    #                                 self.robot_name + "/base_link", time = rospy.Time.now())

                    # dist_lin, distr_ang=transformations.frameDistance(diff_tf,
                    #                                                   PyKDL.Frame())
                    # distr_ang=np.linalg.norm(distr_ang)
                    # dist_lin=np.linalg.norm(
                    #     transformations.KDLVectorToNumpyArray(dist_lin))
                    # dist=distr_ang + dist_lin
                    # print dist
                    if dist > 0.0003 or self.joystick_flg:
                        self.target_follower.setTarget(
                            target=self.target_tf,
                            target_type=TargetFollowerProxy.TYPE_POSE,
                            target_source=TargetFollowerProxy.SOURCE_DIRECT)
                else:
                    Logger.error("tf not ready!!")

            else:
                pass
        except Exception as e:
            Logger.warning(e)
            pass
Пример #8
0
class SFMachineRobotDefinition(object):
    def __init__(self, robot):
        # tf Listener
        self.listener = tf.TransformListener()

        # robot
        self.robot = robot
        self.robot_name = robot.getName()

        # trajectory
        self.trajectory_generator = FuzzyTrajectoryGenerator(self.robot)
        self.trajectory = []
        self.generate_trajectory_failure = False
        self.trajectory_correct = False

        # command
        self.current_command = None
        self.interpreter = CommandInterpreter(robot_name=self.robot_name,
                                              robot_object=self.robot)

        # frames
        self.ee_frame = None

        # target
        self.target = None
        self.target_q = None
        self.dist_target = -1

        # parameters
        self.node_frequency = Parameters.get(obj=self.robot_name,
                                             param="NODE_FREQUENCY")
        self.trajectory_points = Parameters.get(obj=self.robot_name,
                                                param="TRAJECTORY_POINTS")
        self.trajectory_time = Parameters.get(obj=self.robot_name,
                                              param="TRAJECTORY_TIME")
        self.joints_tollerance = self.robot.getParam("joints_tollerance")

        # timer
        self.init_generate_timer = 15 * self.node_frequency  # [sec]
        self.init_start_moving_timer = 10 * self.node_frequency  # [sec]

        # external callback
        self.feedback_ext_callback = None
        self.feedback = RobotMotionFeedback()
        self.result_ext_callback = None
        self.result = RobotMotionResult()

        # error
        self.err = self.result.NO_ERROR

        # noise velocity in steady state
        self.vel_noise_mean = 0.015

        # alarm
        self.in_allarm = False
        self.alarm_proxy = AlarmProxy(self.robot_name)
        self.alarm_proxy.registerAlarmCallback(self.alarm_callback)
        self.alarm_proxy.registerResetCallback(self.alarm_reset_callback)

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ PUBLIC METHODS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def uploadCurrentCommand(self, command):
        if self.current_command != None:
            self.error("COMMAND_CONFLICT")
        else:
            self.current_command = command

    def isTrajectoryAdmissible(self):
        if self.trajectory_generator != None:
            if self.trajectory_generator.isTrajectoryAvailable():
                return self.trajectory_correct
        else:
            return False

    def applyTrajectory(self):
        if len(self.trajectory_generator.current_trajectory) > 0:
            self.trajectory_generator.applyTrajectory(rospy.Time.now())

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ PRIVATE METHODS ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    def _sendFeedback(self,
                      text="",
                      state="",
                      command="",
                      status=0,
                      progress=-1.0,
                      warning=0):
        if self.feedback_ext_callback:
            self.feedback.current_state = state
            self.feedback.text = text
            self.feedback.executing_command = command
            self.feedback.status = status
            self.feedback.progress = progress
            self.feedback.warning = warning
            self.feedback_ext_callback(self.feedback)
        else:
            Logger.error("External callback for FEEDBACK update NOT found!")

    def _sendResult(self, success=False, command="", error=0):
        if self.current_command != None:
            if self.result_ext_callback:
                q = self.robot.getController().getQ()
                pose = geometry_msgs.msg.Pose()
                eef_frame = self.robot.getEEFrame()
                pose.position.x = eef_frame.p.x()
                pose.position.y = eef_frame.p.y()
                pose.position.z = eef_frame.p.z()
                eef_quaternion = eef_frame.M.GetQuaternion()
                pose.orientation.x = eef_quaternion[0]
                pose.orientation.y = eef_quaternion[1]
                pose.orientation.z = eef_quaternion[2]
                pose.orientation.w = eef_quaternion[3]

                self.result.pose = pose
                self.result.q.data = list(q)
                self.result.success = success
                self.result.error = error
                self.result.executed_command = command
                self.result.q_target_distance = self.dist_target

                self.result_ext_callback(self.result)

                succ = "\033[91m" + "\033[92m" * success + "\033[1m\033[4m{}\033[0m".format(
                    success)
                print("{}: {}".format(self.current_command, succ))
            else:
                Logger.error("External callback for RESULT update NOT found!")
        self.current_command = None

    def _computeProgress(self):
        current_q = self.robot.getController().getQ()
        target_q = self.target_q
        initial_q = self.initial_q
        self.movement_progress = 100.0 * (1.0 - abs(
            (norm(subtract(current_q, target_q))) /
            (norm(subtract(initial_q, target_q)))))

    def _isOnTarget(self, tollerance=None):
        if tollerance == None:
            tollerance = self.joints_tollerance
        current_q = self.robot.getController().getQ()
        self.dist_target = norm(subtract(self.target_q, current_q))
        sys.stdout.write("Working --> Distance From Target: {} \r".format(
            self.dist_target))
        sys.stdout.flush()
        return self.dist_target < tollerance

    def _generateTrajectoryFromCommand(self):
        self.initial_q = self.robot.getController().getQ()
        self.trajectory_generator.clearTrajectory()
        self.generate_trajectory_failure = False
        steps = self.trajectory_time * self.node_frequency
        if self.target:
            self.trajectory_points = Parameters.get(obj=self.robot_name,
                                                    param="TRAJECTORY_POINTS")
            if self.trajectory_points is None:
                self.trajectory_points = self.node_frequency * self.trajectory_time
            try:
                if self.interpreter.trajectory_specs == "linear_joints":
                    self.trajectory = self.trajectory_generator.generateTrajectoryFromShapes(
                        self.initial_q, self.target, self.trajectory_points, 1)
                elif self.interpreter.trajectory_specs == "linear_frames_to_free_joints":
                    self.target = self.target * self.robot.getCurrentTool(
                    ).Inverse()
                    self.trajectory = self.trajectory_generator.generateTrajectoryFromFrames(
                        self.initial_q, self.robot.getEEFrame(), self.target,
                        self.node_frequency, self.trajectory_time)
                elif self.interpreter.trajectory_specs == "free_frames_to_linear_joints":
                    self.target = self.target * self.robot.getCurrentTool(
                    ).Inverse()
                    self.trajectory = self.trajectory_generator.generateTrajectoryFreeFromFrames(
                        self.initial_q,
                        self.robot.getEEFrame(),
                        self.target,
                        steps=steps,
                        agumented_middle_joints=True,
                        middle_frames=10,
                        number_of_tries=1,
                        perturbate_middle_frames=False)
                elif self.interpreter.trajectory_specs == "target_frame_to_target_joints":
                    self.target = self.target * self.robot.getCurrentTool(
                    ).Inverse()
                    self.trajectory = self.trajectory_generator.generateTrajectoryFreeFromFrames(
                        self.initial_q,
                        self.robot.getEEFrame(),
                        self.target,
                        steps=1,
                        agumented_middle_joints=False,
                        middle_frames=20,
                        number_of_tries=5,
                        perturbate_middle_frames=False)
                else:
                    self.trajectory = []
            except Exception as e:
                Logger.error(e)
                self.trajectory = []
        else:
            self.trajectory = []

        # Trajectory target update
        if len(self.trajectory) > 0:
            self.target_q = self.trajectory_generator.getTargetQ()
        else:
            self.generate_trajectory_failure = True
            self.target_q = self.initial_q

    def alarm_callback(self, alarm_info):
        if alarm_info != self.alarm_proxy.NONE_ALARM:
            self.error("ROBOT_ALARM")

    def alarm_reset_callback(self):
        if self.state == "error" and self.in_allarm:
            Logger.warning("\nAlarm Reset\n")
            self.in_allarm = False
            # self.idle()

    # ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ STATES ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ IDLE ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    # ➤ ➤ ➤ ➤ ➤ IDLE: enter
    def on_enter_idle(self):
        Logger.log("State:  IDLE")
        self._sendFeedback(state="idle")

    def on_loop_idle(self):
        pass

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ PREPARING ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ PREPARING: enter
    def on_enter_preparing(self):
        Logger.log("State:  PREPARING")
        self._sendFeedback(state="preparing")
        self.ee_frame = self.robot.getEEFrame()
        self.vel_noise_samples = []

    #➤ ➤ ➤ ➤ ➤ PREPARING: loop
    def on_loop_preparing(self):
        if self.vel_noise_samples >= 30:
            self.vel_noise_mean = mean(self.vel_noise_samples)
            self.idle()
        else:
            self.vel_noise_samples.append(self.robot.getController().getQ())

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ SENDCOMMAND ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ SENDCOMMAND: enter
    def on_enter_sendcommand(self):
        Logger.log("State:  SENDCOMMAND")
        self._sendFeedback(state="sendcommand")

    #➤ ➤ ➤ ➤ ➤ SENDCOMMAND: loop
    def on_loop_sendcommand(self):
        self._sendFeedback(status=self.feedback.WAITING_FOR_COMMAND)
        if self.current_command != None:
            self.checkcommand()

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ CHECKCOMMAND ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ CHECKCOMMAND: enter
    def on_enter_checkcommand(self):
        Logger.log("State:  CHECKCOMMAND")
        self._sendFeedback(state="checkcommand", command=self.current_command)
        self.target = self.interpreter.interpretCommand(self.current_command)

    #➤ ➤ ➤ ➤ ➤ CHECKCOMMAND: loop
    def on_loop_checkcommand(self):
        if self.interpreter.isCommandValid():
            self.generatetrajectory()
        else:
            self.error("NO_COMMAND")

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ GENERATETRAJECTORY ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ GENERATETRAJECTORY: enter
    def on_enter_generatetrajectory(self):
        Logger.log("State:  GENERATETRAJECTORY")
        self._sendFeedback(state="generatetrajectory",
                           command=self.current_command)

        self.generate_timer = self.init_generate_timer
        self.t_gen = -1
        self.trajectoryThread = threading.Thread(
            target=self._generateTrajectoryFromCommand)
        self.trajectoryThread.start()

    #➤ ➤ ➤ ➤ ➤ GENERATETRAJECTORY: loop
    def on_loop_generatetrajectory(self):
        self._sendFeedback(text=str(self.init_generate_timer),
                           state="generatetrajectory",
                           command=self.current_command,
                           status=self.feedback.WAITING_FOR_MOVING)

        t_new = self.generate_timer / self.node_frequency
        if self.t_gen != t_new:
            self.t_gen = t_new
            Logger.log("waiting start (time: {}s)".format(self.t_gen))
        if self.trajectory_generator.isTrajectoryAvailable():
            self.trajectoryThread.join()
            self.checktrajectory()
        elif self.generate_timer <= 0 or self.generate_trajectory_failure:
            self.trajectoryThread.join()
            self.error("NO_TRAJECTORY")

        self.generate_timer -= 1

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ CHECKTRAJECTORY ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ CHECKTRAJECTORY: enter
    def on_enter_checktrajectory(self):
        Logger.log("State:  CHECKTRAJECTORY")
        self._sendFeedback(state="checktrajectory")
        # print("{}".format(self.trajectory_generator.current_trajectory))

        if not self.trajectory_generator.computationSuccess():
            self.error("NO_TRAJECTORY")
        else:
            if self._isOnTarget():
                Logger.log("Already on Target")
                self._sendFeedback(state="checktrajectory",
                                   text="Already on Target")
                self.steady()
            else:
                self.trajectory_correct = True
                self.ready()

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ READY ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ READY: enter
    def on_enter_ready(self):
        Logger.log("State:  READY")
        self._sendFeedback(state="ready")

        self.start_moving_timer = self.init_start_moving_timer

        # if self.robot.getController().isMoving(epsilon=self.vel_noise_mean * 1.05): # TODO start-moving timer disabled!!!!!!!!!!!!!
        if len(self.trajectory_generator.current_trajectory) > 0:
            self.moving()

    #➤ ➤ ➤ ➤ ➤ READY: loop
    def on_loop_ready(self):
        self._sendFeedback(text=str(self.start_moving_timer),
                           state="ready",
                           status=self.feedback.WAITING_FOR_MOVING)

        # if self.robot.getController().isMoving(epsilon=self.vel_noise_mean * 1.05):
        if len(self.trajectory_generator.current_trajectory) > 0:
            self.moving()
        elif self.start_moving_timer <= 0:
            self.error("START_MOVING")

        self.start_moving_timer -= 1

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ MOVING ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ MOVING: enter
    def on_enter_moving(self):
        Logger.log("State:  MOVING")
        self._sendFeedback(state="moving", status=self.feedback.MOVING)
        delay = int(0.6 * float(self.trajectory_time * self.node_frequency))
        self.end_moving_timer = self.trajectory_time * self.node_frequency + delay
        self.movement_progress = 0
        # self.progressThread = threading.Thread(target=self._computeProgress)
        # self.progressThread.start()

    #➤ ➤ ➤ ➤ ➤ MOVING: loop
    def on_loop_moving(self):

        # Logger.log("waiting end (timer: {})".format(self.end_moving_timer))

        self._computeProgress()

        if self.end_moving_timer > 0:
            wrn = self.feedback.NO_WARNING
        else:
            wrn = self.feedback.WARNING_TRAJACTORY_TIME_OUT

        self._sendFeedback(text=str(self.end_moving_timer),
                           progress=self.movement_progress,
                           state="moving",
                           status=self.feedback.MOVING,
                           warning=wrn)

        if not self.robot.getController().isMoving(
                epsilon=self.vel_noise_mean * 1.05):
            if self._isOnTarget():
                print("On Target --> Distance: {}".format(self.dist_target))
                self.steady()
            elif self.end_moving_timer <= 0:
                print("Distance From Target: {}".format(self.dist_target))
                self.error("END_TRAJECTORY")
            else:
                self.end_moving_timer -= 1
        else:
            self.end_moving_timer -= 1

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ STEADY ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ STEADY: enter
    def on_enter_steady(self):
        self._sendFeedback(state="steady", status=self.feedback.STEADY)
        Logger.log("State:  STEADY")
        self._sendResult(success=True, command=self.current_command)
        self.trajectory_correct = False
        self.current_command = None
        self.idle()

    # #➤ ➤ ➤ ➤ ➤ STEADY: loop
    # def on_loop_steady(self):

    #
    #⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢ ERROR ⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢⬢
    #

    #➤ ➤ ➤ ➤ ➤ ERROR: enter
    def on_enter_error(self, error_type=""):
        Logger.log("State:  ERROR")
        self._sendFeedback(state="error")
        self.trajectory_generator.clearTrajectory()
        if error_type == "NO_COMMAND":
            self.err = self.result.ERROR_NO_COMMAND
            Logger.warning(
                "Command string NOT recognized. Waiting for a new command")
        elif error_type == "NO_TRAJECTORY":
            self.err = self.result.ERROR_NO_TRAJECTORY
            Logger.warning(
                "Trajectory NOT computed. Waiting for a new command")
        elif error_type == "START_MOVING":
            self.err = self.result.ERROR_START_MOVING
            Logger.warning(
                "Moving Time Out. Target NOT Reached.  Waiting for a new command"
            )
        elif error_type == "END_TRAJECTORY":
            self.err = self.result.ERROR_END_TRAJECTORY
            Logger.error(
                "Trajectory Time Out. Target NOT Reached. Waiting for a new command"
            )
        elif error_type == "ROBOT_ALARM":
            self.err = self.result.ERROR_ROBOT_ALARM
            self.in_allarm = True
            Logger.error(
                "\n\n\n ROBOT ALARM!!! \n Restore the machine and Reset the Alarm \n\n\n"
            )
        elif error_type == "COMMAND_CONFLICT":
            self.err = self.result.ERROR_COMMAND_CONFLICT
            Logger.error(
                "\n\n\n COMMAND CONFLICT!!! \n Waiting for a new command \n\n\n"
            )
        else:
            self.err = self.result.ERROR_UNKNOWN
            Logger.error("Unknown Error --- {}".format(error_type))

        # send result
        self._sendResult(success=False,
                         error=self.err,
                         command=self.current_command)

    #➤ ➤ ➤ ➤ ➤ ERROR: loop
    def on_loop_error(self):
        # send result multiple times (necessary? it seem that sometimes it's not received)
        # self._sendResult(success=False,
        #                  error=self.err,
        #                  command=self.current_command)

        if not self.in_allarm:
            self.idle()