Example #1
0
class AveragingSVR2(object):
    def __init__(self):
        self._action = SimpleActionServer('averaging',
                                          AveragingAction,
                                          auto_start=False)
        self._action.register_preempt_callback(self.preempt_cb)
        self._action.register_goal_callback(self.goal_cb)
        self.reset_numbers()
        rospy.Subscriber('number', Float32, self.execute_loop)
        self._action.start()

    def std_dev(self, lst):
        ave = sum(lst) / len(lst)
        return sum([x * x for x in lst]) / len(lst) - ave**2

    def goal_cb(self):
        self._goal = self._action.accept_new_goal()
        rospy.loginfo('goal callback %s' % (self._goal))

    def preempt_cb(self):
        rospy.loginfo('preempt callback')
        self.reset_numbers()
        self._action.set_preempted(text='message for preempt')

    def reset_numbers(self):
        self._samples = []

    def execute_loop(self, msg):
        if (not self._action.is_active()):
            return
        self._samples.append(msg.data)
        feedback = AveragingAction().action_feedback.feedback
        feedback.sample = len(self._samples)
        feedback.data = msg.data
        feedback.mean = sum(self._samples) / len(self._samples)
        feedback.std_dev = self.std_dev(self._samples)
        self._action.publish_feedback(feedback)
        ## sending result
        if (len(self._samples) >= self._goal.samples):
            result = AveragingAction().action_result.result
            result.mean = sum(self._samples) / len(self._samples)
            result.std_dev = self.std_dev(self._samples)
            rospy.loginfo('result: %s' % (result))
            self.reset_numbers()
            if (result.mean > 0.5):
                self._action.set_succeeded(result=result,
                                           text='message for succeeded')
            else:
                self._action.set_aborted(result=result,
                                         text='message for aborted')
Example #2
0
class AveragingSVR(object):
    def __init__(self):
        self._action = SimpleActionServer('averaging',
                                          AveragingAction,
                                          execute_cb=self.execute_cb,
                                          auto_start=False)
        self._action.register_preempt_callback(self.preempt_cb)
        self._action.start()

    def std_dev(self, lst):
        ave = sum(lst) / len(lst)
        return sum([x * x for x in lst]) / len(lst) - ave**2

    def preempt_cb(self):
        rospy.loginfo('preempt callback')
        self._action.set_preempted(text='message for preempt')

    def execute_cb(self, goal):
        rospy.loginfo('execute callback: %s' % (goal))
        feedback = AveragingAction().action_feedback.feedback
        result = AveragingAction().action_result.result
        ## execute loop
        rate = rospy.Rate(1 / (0.01 + 0.99 * random.random()))
        samples = []
        for i in range(goal.samples):
            sample = random.random()
            samples.append(sample)
            feedback.sample = i
            feedback.data = sample
            feedback.mean = sum(samples) / len(samples)
            feedback.std_dev = self.std_dev(samples)
            self._action.publish_feedback(feedback)
            rate.sleep()
        if (not self._action.is_active()):
            rospy.loginfo('not active')
            return
        ## sending result
        result.mean = sum(samples) / len(samples)
        result.std_dev = self.std_dev(samples)
        rospy.loginfo('result: %s' % (result))
        if (result.mean > 0.5):
            self._action.set_succeeded(result=result,
                                       text='message for succeeded')
        else:
            self._action.set_aborted(result=result, text='message for aborted')
Example #3
0
class AStarSearch(object):
    def __init__(self, name):
        rospy.loginfo("Starting {}".format(name))
        self._as = SimpleActionServer(name,
                                      TopoNavAction,
                                      self.execute_cb,
                                      auto_start=False)
        self._as.register_preempt_callback(self.preempt_cb)
        self.client = SimpleActionClient("/waypoint_nav_node",
                                         WayPointNavAction)
        rospy.loginfo("Waiting for nav server")
        self.client.wait_for_server()
        self.nodes = set()
        self.edges = defaultdict(list)
        self.distances = {}

        with open(rospy.get_param("~waypoint_yaml"), 'r') as f:
            self.waypointInfo = yaml.load(f)

        for waypoint, info in self.waypointInfo.items():
            self.add_node(waypoint)
            for edge in info["edges"]:
                self.add_edge(waypoint, edge, 1.0)
            self.waypointInfo[waypoint]["position"]["x"] *= 0.555
            self.waypointInfo[waypoint]["position"]["y"] *= 0.555

        self.sub = rospy.Subscriber("/orb_slam/pose", PoseStamped,
                                    self.pose_cb)
        self._as.start()
        rospy.loginfo("Started {}".format(name))

    def preempt_cb(self, *args):
        self.client.cancel_all_goals()

    def add_node(self, value):
        self.nodes.add(value)

    def add_edge(self, from_node, to_node, distance):
        self.edges[from_node].append(to_node)
        # self.edges[to_node].append(from_node)
        self.distances[(from_node, to_node)] = distance

    def pose_cb(self, msg):
        closest = (None, None)
        for k, v in self.waypointInfo.items():
            dist = self.get_dist(msg, v["position"])
            if closest[0] is None or dist < closest[0]:
                closest = (dist, k)
        self.closest = closest[1]

    def get_dist(self, pose1, position):
        return np.sqrt(
            np.power(pose1.pose.position.x - position["x"], 2) +
            np.power(pose1.pose.position.y - position["y"], 2))

    def execute_cb(self, goal):
        path = self.shortest_path(self.closest, goal.waypoint)[1]
        print path
        for p in path:
            if not self._as.is_preempt_requested():
                rospy.loginfo("Going to waypoint: {}".format(p))
                target = PoseStamped()
                target.header.stamp = rospy.Time.now()
                target.header.frame_id = "map"
                target.pose.position.x = self.waypointInfo[p]["position"]["x"]
                target.pose.position.y = self.waypointInfo[p]["position"]["y"]
                target.pose.orientation.x = self.waypointInfo[p][
                    "orientation"]["x"]
                target.pose.orientation.y = self.waypointInfo[p][
                    "orientation"]["y"]
                target.pose.orientation.z = self.waypointInfo[p][
                    "orientation"]["z"]
                target.pose.orientation.w = self.waypointInfo[p][
                    "orientation"]["w"]
                self.client.send_goal_and_wait(WayPointNavGoal(target))
        if not self._as.is_preempt_requested():
            self._as.set_succeeded(TopoNavResult())
        else:
            self._as.set_preempted()

    def dijkstra(self, initial):
        visited = {initial: 0}
        path = {}

        nodes = set(self.nodes)

        while nodes:
            min_node = None
            for node in nodes:
                if node in visited:
                    if min_node is None:
                        min_node = node
                    elif visited[node] < visited[min_node]:
                        min_node = node
            if min_node is None:
                break

            nodes.remove(min_node)
            current_weight = visited[min_node]

            for edge in self.edges[min_node]:
                weight = current_weight + self.distances[(min_node, edge)]
                if edge not in visited or weight < visited[edge]:
                    visited[edge] = weight
                    path[edge] = min_node

        return visited, path

    def shortest_path(self, origin, destination):
        visited, paths = self.dijkstra(origin)
        full_path = deque()
        _destination = paths[destination]

        while _destination != origin:
            full_path.appendleft(_destination)
            _destination = paths[_destination]

        full_path.appendleft(origin)
        full_path.append(destination)

        return visited[destination], list(full_path)
class MotionService(object):
    def __init__(self):
        rospy.init_node('motion_service')
        # Load config
        config_loader = RobotConfigLoader()
        try:
            robot_config_name = rospy.get_param(rospy.get_name() + '/robot_config')
        except KeyError:
            rospy.logwarn('Could not find robot config param in /' + rospy.get_name +'/robot_config. Using default config for '
                          'Thor Mang.')
            robot_config_name = 'thor'
        config_loader.load_xml_by_name(robot_config_name + '_config.xml')

        # Create publisher for first target
        if len(config_loader.targets) > 0:
            self._motion_publisher = MotionPublisher(
                config_loader.robot_config, config_loader.targets[0].joint_state_topic, config_loader.targets[0].publisher_prefix)
        else:
            rospy.logerr('Robot config needs to contain at least one valid target.')
        self._motion_data = MotionData(config_loader.robot_config)

        # Subscriber to start motions via topic
        self.motion_command_sub = rospy.Subscriber('motion_command', ExecuteMotionCommand, self.motion_command_request_cb)

        # Create action server
        self._action_server = SimpleActionServer(rospy.get_name() + '/motion_goal', ExecuteMotionAction, None, False)
        self._action_server.register_goal_callback(self._execute_motion_goal)
        self._action_server.register_preempt_callback(self._preempt_motion_goal)
        self._preempted = False

    def _execute_motion_goal(self):
        goal = self._action_server.accept_new_goal()
        # Check if motion exists
        if goal.motion_name not in self._motion_data:
            result = ExecuteMotionResult()
            result.error_code = [ExecuteMotionResult.MOTION_UNKNOWN]
            result.error_string = "The requested motion is unknown."
            self._action_server.set_aborted(result)
            return

        # check if a valid time_factor is set, otherwise default to 1.0
        if goal.time_factor <= 0.0:
            goal.time_factor = 1.0

        self._preempted = False

        self._motion_publisher.publish_motion(self._motion_data[goal.motion_name], goal.time_factor, self._trajectory_finished)
        print '[MotionService] New action goal received.'

    def _preempt_motion_goal(self):
        self._motion_publisher.stop_motion()
        print '[MotionService] Preempting goal.'
        self._preempted = True

    def _trajectory_finished(self, error_codes, error_groups):
        result = ExecuteMotionResult()
        result.error_code = error_codes
        error_string = ""
        for error_code, error_group in zip(error_codes, error_groups):
            error_string += error_group + ': ' + str(error_code) + '\n'
        result.error_string = error_string
        if self._preempted:
            self._action_server.set_preempted(result)
        else:
            self._action_server.set_succeeded(result)
        print '[MotionService] Trajectory finished with error code: \n', error_string

    def _execute_motion(self, request):
        response = ExecuteMotionResponse()

        # check if a motion with this name exists
        if request.motion_name not in self._motion_data:
            print '[MotionService] Unknown motion name: "%s"' % request.motion_name

            response.ok = False
            response.finish_time.data = rospy.Time.now()
            return response

        # check if a valid time_factor is set, otherwise default to 1.0
        if request.time_factor <= 0.0:
            request.time_factor = 1.0

        # find the duration of the requested motion
        motion_duration = 0.0
        for poses in self._motion_data[request.motion_name].values():
            if len(poses) > 0:
                endtime = poses[-1]['starttime'] + poses[-1]['duration']
                motion_duration = max(motion_duration, endtime)
        motion_duration *= request.time_factor

        # execute motion
        print '[MotionService] Executing motion: "%s" (time factor: %.3f, duration %.2fs)' % (request.motion_name, request.time_factor, motion_duration)
        self._motion_publisher.publish_motion(self._motion_data[request.motion_name], request.time_factor)

        # reply with ok and the finish_time of this motion
        response.ok = True
        response.finish_time.data = rospy.Time.now() + rospy.Duration.from_sec(motion_duration)
        return response

    def start_server(self):
        rospy.Service(rospy.get_name() + '/execute_motion', ExecuteMotion, self._execute_motion)
        self._action_server.start()
        print '[MotionService] Waiting for calls...'
        rospy.spin()

    def motion_command_request_cb(self, command):
        print "[MotionService] Initiate motion command via topic ..."
        request = ExecuteMotion()
        request.motion_name = command.motion_name
        request.time_factor = command.time_factor
        self._execute_motion(request)
        print "[MotionService] Motion command complete"
Example #5
0
class AudioFilePlayer(object):
    def __init__(self):
        rospy.loginfo("Initializing AudioFilePlayer...")
        self.current_playing_process = None
        self.afp_as = SimpleActionServer(rospy.get_name(),
                                         AudioFilePlayAction,
                                         self.as_cb,
                                         auto_start=False)
        self.afp_sub = rospy.Subscriber('~play',
                                        String,
                                        self.topic_cb,
                                        queue_size=1)
        # By default this node plays files using the aplay command
        # Feel free to use any other command or flags
        # by using the params provided
        self.command = rospy.get_param('~command', 'play')
        self.flags = rospy.get_param('~flags', '')
        self.wrap_file_path = rospy.get_param('~wrap_file_path', True)
        self.feedback_rate = rospy.get_param('~feedback_rate', 10)
        self.afp_as.start()
        # Needs to be done after start
        self.afp_as.register_preempt_callback(self.as_preempt_cb)

        rospy.loginfo(
            "Done, playing files from action server or topic interface.")

    def as_preempt_cb(self):
        if self.current_playing_process:
            self.current_playing_process.kill()
            # Put the AS as cancelled/preempted
            res = AudioFilePlayResult()
            res.success = False
            res.reason = "Got a cancel request."
            self.afp_as.set_preempted(res, text="Cancel requested.")

    def as_cb(self, goal):
        initial_time = time.time()
        self.play_audio_file(goal.filepath)
        r = rospy.Rate(self.feedback_rate)
        while not rospy.is_shutdown(
        ) and not self.current_playing_process.is_done():
            feedback = AudioFilePlayFeedback()
            curr_time = time.time()
            feedback.elapsed_played_time = rospy.Duration(curr_time -
                                                          initial_time)
            self.afp_as.publish_feedback(feedback)
            r.sleep()

        final_time = time.time()
        res = AudioFilePlayResult()
        if self.current_playing_process.is_succeeded():
            res.success = True
            res.total_time = rospy.Duration(final_time)
            self.afp_as.set_succeeded(res)
        else:
            if self.afp_as.is_preempt_requested():
                return
            res.success = False
            reason = "stderr: " + self.current_playing_process.get_stderr()
            reason += "\nstdout: " + self.current_playing_process.get_stdout()
            res.reason = reason
            self.afp_as.set_aborted(res)

    def topic_cb(self, data):
        if self.current_playing_process:
            if not self.current_playing_process.is_done():
                self.current_playing_process.kill()
        self.play_audio_file(data.data)

    def play_audio_file(self, audio_file_path):
        # Replace any ' or " characters with emptyness to avoid bad usage
        audio_file_path = audio_file_path.replace("'", "")
        audio_file_path = audio_file_path.replace('"', '')
        if self.wrap_file_path:
            full_command = self.command + " " + self.flags + " '" + audio_file_path + "'"
        else:
            full_command = self.command + " " + self.flags + " " + audio_file_path
        rospy.loginfo("Playing audio file: " + str(audio_file_path) +
                      " with command: " + str(full_command))
        self.current_playing_process = ShellCmd(full_command)
class MoveEndEffectorServer(object):
    def __init__(self):
        self._name = "/PANDORA_CONTROL/PANDORA_END_EFFECTOR_CONTROLLER"
        self.factory = ClientFactory()
        self.current_clients = list()
        self.current_goal = MoveEndEffectorGoal()

        self.server = Server(move_end_effector_controller_topic,
                             MoveEndEffectorAction, self.execute_cb, False)
        self.server.register_preempt_callback(self.preempt_cb)
        self.server.start()
        self.create_clients()
        self.wait_for_servers()

    def create_clients(self):
        """ Imports all clients and creates a list of them """

        for client in CLIENTS:
            self.current_clients.append(self.factory.make_client(client))

    def wait_for_servers(self):
        """ Waits for every client to connect with their server """

        for client in self.current_clients:
            client.wait_server()

    def execute_cb(self, goal):
        """ Callback triggered by the arrival of a goal """

        self.current_goal = goal
        self.fill_goals()
        self.send_goals()
        self.wait_for_result()
        rospy.logwarn("break from wait for result!")
        self.checkGoalState()

    def preempt_cb(self):
        """ Preempting all goals """

        for client in self.current_clients:
            client.preempt_if_active()

    def fill_goals(self):
        """ Filling goals into every client respectively """

        for client in self.current_clients:
            client.fill_goal(self.current_goal)

    def send_goals(self):
        """ Sending goals to every client respectively """

        for client in self.current_clients:
            client.send_goal()

    def wait_for_result(self):

        for client in self.current_clients:
            client.wait_result()

    def success(self):

        self.server.set_succeeded()

    def abort(self):

        self.server.set_aborted()

    def preempt(self):

        if self.server.is_active():
            self.server.set_preempted()
        else:
            rospy.logerr("[" + self._name +
                         "] Preempt requested when server goal is not active")

    def check_succeeded(self):
        """ Checks if the final state of the goal must be set succeeded """

        must_succeed = True

        for client in self.current_clients:
            must_succeed = must_succeed and client.has_succeeded()

        return must_succeed

    def check_aborted(self):
        """ Checks if the final state of the goal must be set aborted """

        must_abort = False

        for client in self.current_clients:
            must_abort = must_abort or client.has_aborted()

        return must_abort

    def check_preempted(self):
        """ Checks if the final state of the goal must be set preempted """

        must_preempt = False

        for client in self.current_clients:
            must_preempt = must_preempt or client.has_preempted()

        return must_preempt

    def check_recalled(self):
        """ Checks if the final state of the goal must be set preempted """

        must_recall = False

        for client in self.current_clients:
            must_recall = must_recall or client.has_been_recalled()

        return must_recall

    def checkGoalState(self):
        """ Checking final state of goal """

        if (self.check_succeeded()):
            rospy.logwarn("check_succeeded")
            self.success()
        elif (self.check_aborted()):
            rospy.logwarn("check_aborted")
            self.abort()
        elif (self.check_recalled()):
            rospy.logwarn("check_recalled")
            for client in self.current_clients:
                rospy.logerr("[" + self._name + "] Client " +
                             client.get_name() + " is in state " +
                             str(client.client.get_state()))
            rospy.logerr(
                "[" + self._name +
                "] One client at least is recalled, set server to aborted")
            self.abort()
        elif (self.check_preempted()):
            rospy.logwarn("check_preempted")
            self.preempt()
        else:
            rospy.logwarn("check_unexpected")
            for client in self.current_clients:
                rospy.logerr("[" + self._name + "] Client " +
                             client.get_name() + " is in state " +
                             str(client.client.get_state()))
            rospy.logerr("[" + self._name +
                         "] Unexpected State, set server to aborted")
            self.abort()
class ActionServerHandler(object):
    """
    Interface to action server which is more useful for behaviors.
    """
    def __init__(self, action_name, action_type):
        self.goal_queue = Queue(1)
        self.result_queue = Queue(1)
        self.lock = Blackboard().lock
        self.action_name = action_name
        self.cancel_next_goal = False
        self._as = SimpleActionServer(action_name, action_type, execute_cb=self.execute_cb, auto_start=False)
        self._as.register_preempt_callback(self.cancel_cb)
        self._as.start()

    def cancel_cb(self):
        self.cancel_next_goal = self._as.is_new_goal_available()

    def execute_cb(self, goal):
        """
        :type goal: MoveGoal
        """
        with self.lock.acquire_timeout(0) as got_lock:
            if got_lock and not self.cancel_next_goal:
                self.my_state = Status.RUNNING
                self.goal_queue.put(goal)
                self.result_queue.get()()
            else:
                self.my_state = Status.FAILURE
                r = self._as.action_server.ActionResultType()
                r.error = DetectShelfLayersResult.SERVER_BUSY
                print_with_prefix('rejected goal because server busy server busy', self.action_name)
                self._as.set_aborted(r)
                self.cancel_next_goal = False

    def get_goal(self):
        try:
            goal = self.goal_queue.get_nowait()
            return goal
        except Empty:
            return None

    def has_goal(self):
        return not self.goal_queue.empty()

    def send_preempted(self, result=None):
        def call_me_now():
            self._as.set_preempted(result)
        self.result_queue.put(call_me_now)

    def send_aborted(self, result=None):
        def call_me_now():
            self._as.set_aborted(result)
        self.result_queue.put(call_me_now)

    def send_result(self, result=None):
        """
        :type result: MoveResult
        """
        def call_me_now():
            self._as.set_succeeded(result)
        self.result_queue.put(call_me_now)

    def is_preempt_requested(self):
        return self._as.is_preempt_requested()
Example #8
0
class RobotPolicyExecutor():
    def __init__(self, port, file_dir, file_name):
        self.wait_for_result_dur = rospy.Duration(0.1)
        self.top_nav_policy_exec = SimpleActionClient(
            'topological_navigation/execute_policy_mode',
            ExecutePolicyModeAction)
        got_server = self.top_nav_policy_exec.wait_for_server(
            rospy.Duration(1))
        while not got_server:
            rospy.loginfo(
                "Waiting for topological navigation execute policy mode action server."
            )
            got_server = self.top_nav_policy_exec.wait_for_server(
                rospy.Duration(1))
            if rospy.is_shutdown():
                return
        self.policy_mode_pub = rospy.Publisher(
            "mdp_plan_exec/current_policy_mode", NavRoute, queue_size=1)

        self.current_waypoint_sub = rospy.Subscriber("current_node", String,
                                                     self.current_waypoint_cb)
        self.closest_waypoint_sub = rospy.Subscriber("closest_node", String,
                                                     self.closest_waypoint_cb)

        explicit_doors = rospy.get_param("mdp_plan_exec/explicit_doors", True)
        forget_doors = rospy.get_param("mdp_plan_exec/forget_doors", True)
        model_fatal_fails = rospy.get_param("mdp_plan_exec/model_fatal_fails",
                                            True)

        self.nav_before_action_exec = rospy.get_param(
            "mdp_plan_exec/nav_before_action_exec", True
        )  #If True the robot will always navigate to a waypoint before trying to execute an action; if False robot can execute actions anywhere, if they are added without waypoint constraints.

        self.mdp = TopMapMdp(explicit_doors=explicit_doors,
                             forget_doors=forget_doors,
                             model_fatal_fails=model_fatal_fails)
        self.policy_utils = PolicyExecutionUtils(port, file_dir, file_name,
                                                 self.mdp)
        self.action_executor = ActionExecutor()

        self.cancelled = False
        self.mdp_as = SimpleActionServer('mdp_plan_exec/execute_policy',
                                         ExecutePolicyAction,
                                         execute_cb=self.execute_policy_cb,
                                         auto_start=False)
        self.mdp_as.register_preempt_callback(self.preempt_policy_execution_cb)
        self.mdp_as.start()

    def current_waypoint_cb(self, msg):
        self.current_waypoint = msg.data

    def closest_waypoint_cb(self, msg):
        self.closest_waypoint = msg.data

    def execute_nav_policy(self, nav_policy_msg):
        self.policy_mode_pub.publish(nav_policy_msg)
        self.regenerated_nav_policy = False
        self.top_nav_policy_exec.send_goal(
            ExecutePolicyModeGoal(route=nav_policy_msg),
            feedback_cb=self.top_nav_feedback_cb)
        top_nav_running = True
        while top_nav_running and not self.cancelled:
            top_nav_running = not self.top_nav_policy_exec.wait_for_result(
                self.wait_for_result_dur)
            if not top_nav_running:
                if self.regenerated_nav_policy:
                    nav_policy_msg = self.policy_utils.generate_current_nav_policy(
                    )
                    print(nav_policy_msg)
                    self.top_nav_policy_exec.send_goal(
                        ExecutePolicyModeGoal(route=nav_policy_msg),
                        feedback_cb=self.top_nav_feedback_cb)
                    top_nav_running = True
                    self.regenerated_nav_policy = False
                else:
                    status = self.top_nav_policy_exec.get_state()
        if self.cancelled:
            status = GoalStatus.PREEMPTED
        return status

    def top_nav_feedback_cb(self, feedback):
        executed_action = self.policy_mdp.get_current_action()
        next_flat_state = None
        if feedback.status == GoalStatus.SUCCEEDED:
            next_flat_state = self.policy_utils.get_next_nav_policy_state(
                feedback.current_wp, self.policy_mdp)
            if next_flat_state is None:
                rospy.logwarn(
                    "Error getting MDP next state: There is no transition modelling the state evolution. Looking for state in full state list..."
                )
                next_flat_state = self.policy_utils.get_next_state_from_wp_update(
                    self.policy_mdp, feedback.current_wp)
                self.top_nav_policy_exec.cancel_all_goals()
                if next_flat_state is not None:
                    self.regenerated_nav_policy = True
        publish = next_flat_state != self.policy_mdp.current_flat_state
        self.policy_mdp.set_current_state(next_flat_state)
        if publish:
            next_action = self.policy_mdp.get_current_action()
            self.publish_feedback(executed_action, feedback.status,
                                  next_action)

    def execute_policy_cb(self, goal):
        self.cancelled = False
        self.policy_mdp = self.policy_utils.generate_policy_mdp(
            goal.spec, self.closest_waypoint, rospy.Time.now())

        if self.policy_mdp is None:
            rospy.logerr("Failure to build policy for specification: " +
                         goal.spec.ltl_task)
            self.mdp_as.set_aborted()
            return

        self.publish_feedback(None, None, self.policy_mdp.get_current_action())
        if self.nav_before_action_exec:
            starting_exec = True  #used to make sure the robot executes calls topological navigation at least once before executing non-nav actions. This is too ensure the robot navigates to the exact pose of a waypoint before executing an action there
        else:
            starting_exec = False
        while (self.policy_mdp.has_action_defined()
               and not self.cancelled) or starting_exec:
            next_action = self.policy_mdp.get_current_action()
            if next_action in self.mdp.nav_actions or starting_exec:
                starting_exec = False
                current_nav_policy = self.policy_utils.generate_current_nav_policy(
                    self.policy_mdp)
                status = self.execute_nav_policy(current_nav_policy)
                rospy.loginfo(
                    "Topological navigation execute policy action server exited with status: "
                    + GoalStatus.to_string(status))
                if status != GoalStatus.SUCCEEDED:
                    self.policy_mdp.set_current_state(None)
                    break
            else:
                print("EXECUTE ACTION")
                (status, state_update) = self.action_executor.execute_action(
                    self.mdp.action_descriptions[next_action])
                executed_action = next_action
                print(executed_action)
                if not self.cancelled:
                    next_flat_state = self.policy_utils.get_next_state_from_action_outcome(
                        state_update, self.policy_mdp)
                    self.policy_mdp.set_current_state(next_flat_state)
                    if next_flat_state is None:
                        rospy.logerr(
                            "Error finding next state after action execution. Aborting..."
                        )
                        break
                    next_action = self.policy_mdp.get_current_action()
                    self.publish_feedback(executed_action, status, next_action)
        if self.cancelled:
            self.cancelled = False
            rospy.loginfo("Policy execution preempted.")
            self.mdp_as.set_preempted()
        elif self.policy_mdp.current_flat_state is None:
            rospy.loginfo("Policy execution failed.")
            self.mdp_as.set_aborted()
        else:
            rospy.loginfo("Policy execution successful.")
            self.mdp_as.set_succeeded()

    def publish_feedback(self, executed_action, status, next_action):
        (probability, prog_reward,
         expected_time) = self.policy_mdp.get_guarantees_at_current_state()
        self.mdp_as.publish_feedback(
            ExecutePolicyFeedback(probability=probability,
                                  expected_time=expected_time,
                                  prog_reward=prog_reward,
                                  current_waypoint=self.current_waypoint,
                                  executed_action=executed_action,
                                  execution_status=status,
                                  next_action=next_action))

    def preempt_policy_execution_cb(self):
        self.top_nav_policy_exec.cancel_all_goals()
        self.action_executor.cancel_all_goals()
        self.cancelled = True

    def main(self):
        # Wait for control-c
        rospy.spin()
        if rospy.is_shutdown():
            self.policy_utils.shutdown_prism(True)
class ActionPerformer(Node, ABC):
    def __init__(self, name: str):
        super().__init__(name, "action")
        self.name = name

        # Service for action point computation
        self._action_point_server = Service(get_action_point_service(name),
                                            ComputeActionPoint,
                                            self._compute_action_point)

        # Action server for this action
        self._action_server = SimpleActionServer(get_action_server(name),
                                                 PerformAction,
                                                 auto_start=False)

        self._action_server.register_goal_callback(self._on_goal)
        self._action_server.register_preempt_callback(self._on_preempt)
        self._action_server.start()

    # Function managing the action
    def returns(self, state=ActionStatus.DONE):
        '''
			Function to call when the action is interrupted
			with a given state
		'''
        # Create result message
        result = PerformResult()
        result.state = state

        # Send back to client
        self._action_server.set_succeeded(result)

    # Hidden handlers
    def _compute_action_point(
            self,
            request: ComputeActionPointRequest) -> ComputeActionPointResponse:
        # Extract data from request and call performer's function
        result: ActionPoint = self.compute_action_point(
            Argumentable().from_list(request.args), request.robot_pos)

        response = ComputeActionPointResponse()
        response.action_point = result

        return response

    def _on_goal(self):
        if self._action_server.is_new_goal_available():
            goal: PerformGoal = self._action_server.accept_new_goal()

            # run action with given args
            self.start(Argumentable().from_list(goal.arguments))

    def _on_preempt(self):
        self.cancel()
        self._action_server.set_preempted()

    # Function to be defined by inherited actions
    @abstractmethod
    def compute_action_point(self, args: Argumentable,
                             robot_pos: Pose2D) -> ActionPoint:
        pass

    @abstractmethod
    def start(self, args: Argumentable):
        pass

    def cancel(self):
        pass
Example #10
0
class DummyInterface(object):
    READY = -1

    KILL_DETECT_SHELF_LAYER = 0
    KILL_DETECT_FACINGS = 1
    KILL_COUNT_PRODUCTS = 2

    BUSY_DETECT_SHELF_LAYER = 3
    BUSY_DETECT_FACINGS = 4
    BUSY_COUNT_PRODUCTS = 5

    FINISH = 6
    ABORT = 7

    def __init__(self):
        self.query_shelf_systems_srv = rospy.Service(
            '~query_shelf_systems', QueryShelfSystems,
            self.query_shelf_systems_cb)
        self.query_shelf_layers_srv = rospy.Service('~query_shelf_layers',
                                                    QueryShelfLayers,
                                                    self.query_shelf_layers_cb)
        self.query_facings_srv = rospy.Service('~query_facings', QueryFacings,
                                               self.query_facings_cb)
        self.query_shelf_layer_detection_path_srv = rospy.Service(
            '~query_detect_shelf_layers_path', QueryDetectShelfLayersPath,
            self.query_detect_shelf_layers_path_cb)
        self.query_facing_detection_path_srv = rospy.Service(
            '~query_detect_facings_path', QueryDetectFacingsPath,
            self.query_detect_facings_path_cb)
        self.query_product_counting_path_srv = rospy.Service(
            '~query_count_products_posture', QueryCountProductsPosture,
            self.query_count_products_posture_cb)
        self.finish_perception_srv = rospy.Service('~finish_perception',
                                                   FinishPerception,
                                                   self.finish_perception_cb)
        self.query_reset_beliefstate_srv = rospy.Service(
            '~reset_beliefstate', Trigger, lambda x: TriggerResponse())

        self.detect_shelf_layer_as = SimpleActionServer(
            '~detect_shelf_layers',
            DetectShelfLayersAction,
            execute_cb=self.detect_shelf_layers_cb,
            auto_start=False)
        self.detect_shelf_layer_as.register_preempt_callback(self.cancel_cb)
        self.detect_facings_as = SimpleActionServer(
            '~detect_facings',
            DetectFacingsAction,
            execute_cb=self.detect_facings_cb,
            auto_start=False)
        self.detect_facings_as.register_preempt_callback(self.cancel_cb)
        self.count_products_as = SimpleActionServer(
            '~count_products',
            CountProductsAction,
            execute_cb=self.count_products_cb,
            auto_start=False)
        self.count_products_as.register_preempt_callback(self.cancel_cb)

        self.state_lock = Queue(1)

        self.detect_shelf_layer_as.start()
        self.detect_facings_as.start()
        self.count_products_as.start()
        self.set_ready(prefix='init')
        self.set_names()

    def set_names(self):
        self.shelf_ids = ['shelf_535dc8']
        self.layer_ids = ['layer_faa57d']
        self.facing_ids = ['facing_92c6c2', 'facing_77bce2', 'facing_c4a62e']
        self.shelf_to_layer = {'shelf_535dc8': ['layer_faa57d']}
        self.layer_to_facing = {
            'layer_faa57d':
            ['facing_92c6c2', 'facing_77bce2', 'facing_c4a62e']
        }
        self.product_counts = {}

        # for shelf_id in self.shelf_ids:
        #     self.shelf_to_layer[shelf_id] = ['layer_{}'.format(rnd_hash()) for x in range(NUM_LAYER)]
        #     self.layer_ids.extend(self.shelf_to_layer[shelf_id])
        # for layer_id in self.layer_ids:
        #     self.layer_to_facing[layer_id] = ['facing_{}'.format(rnd_hash()) for x in range(NUM_FACINGS)]
        #     self.facing_ids.extend(self.layer_to_facing[layer_id])
        for facing_id in self.facing_ids:
            self.product_counts[facing_id] = randint(0, 5)

    def query_shelf_systems_cb(self, data):
        """
        :type data: QueryShelfSystemsRequest
        :rtype: QueryShelfSystemsResponse
        """
        prefix = 'query_shelf_systems'
        self.print_with_prefix('called', prefix)
        r = QueryShelfSystemsResponse()
        r.ids = self.shelf_ids
        return r

    def query_shelf_layers_cb(self, data):
        """
        :type data: QueryShelfLayersRequest
        :rtype: QueryShelfLayersResponse
        """
        prefix = 'query_shelf_layers'
        self.print_with_prefix('called', prefix)
        r = QueryShelfLayersResponse()
        if data.id in self.shelf_ids:
            r.error = QueryShelfLayersResponse.SUCCESS
            r.ids = self.shelf_to_layer[data.id]
        else:
            self.print_with_prefix('invalid id', prefix)
            r.error = QueryShelfLayersResponse.INVALID_ID
        return r

    def query_facings_cb(self, data):
        """
        :type data: QueryFacingsRequest
        :rtype: QueryFacingsResponse
        """
        prefix = 'query_facings'
        self.print_with_prefix('called', prefix)
        r = QueryFacingsResponse()
        if data.id in self.layer_ids:
            r.error = QueryFacingsResponse.SUCCESS
            r.ids = self.layer_to_facing[data.id]
        else:
            self.print_with_prefix('invalid id', prefix)
            r.error = QueryFacingsResponse.INVALID_ID
        return r

    def query_detect_shelf_layers_path_cb(self, data):
        """
        :type data: QueryDetectShelfLayersPathRequest
        :rtype: QueryDetectShelfLayersPathResponse
        """
        self.print_with_prefix('called', 'query_detect_shelf_layers_path')
        r = QueryDetectShelfLayersPathResponse()

        if data.id in self.shelf_ids:
            r.error = QueryDetectShelfLayersPathResponse.SUCCESS
            base_pose = PoseStamped()
            base_pose.header.frame_id = '/map'
            base_pose.pose.position = Point(
                rospy.get_param('shelf_detection_path/position/x'),
                rospy.get_param('shelf_detection_path/position/y'),
                rospy.get_param('shelf_detection_path/position/z'))
            base_pose.pose.orientation = Quaternion(
                rospy.get_param('shelf_detection_path/orientation/x'),
                rospy.get_param('shelf_detection_path/orientation/y'),
                rospy.get_param('shelf_detection_path/orientation/z'),
                rospy.get_param('shelf_detection_path/orientation/w'))

            for k in range(5):
                posture = FullBodyPosture()
                posture.base_pos = base_pose
                posture.joints.append(
                    JointPosition(
                        'Torso_lin1',
                        rospy.get_param('shelf_detection_path/Torso_lin1')))
                posture.joints.append(
                    JointPosition(
                        'Torso_lin2',
                        rospy.get_param('shelf_detection_path/Torso_lin2/gain')
                        * k))
                posture.joints.append(
                    JointPosition(
                        'Torso_rot_1',
                        rospy.get_param('shelf_detection_path/Torso_rot_1')))
                r.path.postures.append(posture)
        else:
            r.error = QueryDetectShelfLayersPathResponse.INVALID_ID
        return r

    def query_detect_facings_path_cb(self, data):
        """
        :type data: QueryDetectFacingsPathRequest
        :rtype: QueryDetectFacingsPathResponse
        """
        self.print_with_prefix('called', 'query_detect_facings_path')
        r = QueryDetectFacingsPathResponse()
        if data.id in self.layer_ids:
            r.error = QueryDetectFacingsPathResponse.SUCCESS
            # Start
            posture = FullBodyPosture()
            posture.base_pos.header.frame_id = '/map'
            posture.base_pos.pose.position = Point(
                rospy.get_param('detect_facing_path/start/position/x'),
                rospy.get_param('detect_facing_path/start/position/y'),
                rospy.get_param('detect_facing_path/start/position/z'))
            posture.base_pos.pose.orientation = Quaternion(
                rospy.get_param('detect_facing_path/start/orientation/x'),
                rospy.get_param('detect_facing_path/start/orientation/y'),
                rospy.get_param('detect_facing_path/start/orientation/z'),
                rospy.get_param('detect_facing_path/start/orientation/w'))
            posture.joints.append(
                JointPosition(
                    'Torso_lin1',
                    rospy.get_param('detect_facing_path/start/Torso_lin1')))
            posture.joints.append(
                JointPosition(
                    'Torso_lin2',
                    rospy.get_param('detect_facing_path/start/Torso_lin2')))
            posture.joints.append(
                JointPosition(
                    'Torso_rot_1',
                    rospy.get_param('detect_facing_path/start/Torso_rot_1')))
            r.path.postures.append(posture)

            # End
            posture = FullBodyPosture()
            posture.base_pos.header.frame_id = '/map'
            posture.base_pos.pose.position = Point(
                rospy.get_param('detect_facing_path/end/position/x'),
                rospy.get_param('detect_facing_path/end/position/y'),
                rospy.get_param('detect_facing_path/end/position/z'))
            posture.base_pos.pose.orientation = Quaternion(
                rospy.get_param('detect_facing_path/end/orientation/x'),
                rospy.get_param('detect_facing_path/end/orientation/y'),
                rospy.get_param('detect_facing_path/end/orientation/z'),
                rospy.get_param('detect_facing_path/end/orientation/w'))
            posture.joints.append(
                JointPosition(
                    'Torso_lin1',
                    rospy.get_param('detect_facing_path/end/Torso_lin1')))
            posture.joints.append(
                JointPosition(
                    'Torso_lin2',
                    rospy.get_param('detect_facing_path/end/Torso_lin2')))
            posture.joints.append(
                JointPosition(
                    'Torso_rot_1',
                    rospy.get_param('detect_facing_path/end/Torso_rot_1')))
            r.path.postures.append(posture)

        else:
            r.error = QueryDetectFacingsPathResponse.INVALID_ID
        return r

    def query_count_products_posture_cb(self, data):
        """
        :type data: QueryCountProductsPostureRequest
        :rtype: QueryCountProductsPostureResponse
        """
        self.print_with_prefix('called', 'query_count_products_posture')
        r = QueryCountProductsPostureResponse()
        if data.id in self.facing_ids:
            r.error = QueryCountProductsPostureResponse.SUCCESS
            if data.id == 'facing_92c6c2':
                r.posture = FullBodyPosture()
                r.posture.base_pos.header.frame_id = '/map'
                r.posture.base_pos.pose.position = Point(
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/position/x'),
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/position/y'),
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/position/z'))
                r.posture.base_pos.pose.orientation = Quaternion(
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/orientation/x'),
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/orientation/y'),
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/orientation/z'),
                    rospy.get_param(
                        'count_products_posture/facing_92c6c2/orientation/w'))
                r.posture.joints.append(
                    JointPosition(
                        'Torso_lin1',
                        rospy.get_param(
                            'count_products_posture/facing_92c6c2/Torso_lin1'))
                )
                r.posture.joints.append(
                    JointPosition(
                        'Torso_lin2',
                        rospy.get_param(
                            'count_products_posture/facing_92c6c2/Torso_lin2'))
                )
                r.posture.joints.append(
                    JointPosition(
                        'Torso_rot_1',
                        rospy.get_param(
                            'count_products_posture/facing_92c6c2/Torso_rot_1')
                    ))

            elif data.id == 'facing_77bce2':
                r.posture = FullBodyPosture()
                r.posture.base_pos.header.frame_id = '/map'
                r.posture.base_pos.pose.position = Point(
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/position/x'),
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/position/y'),
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/position/z'))
                r.posture.base_pos.pose.orientation = Quaternion(
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/orientation/x'),
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/orientation/y'),
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/orientation/z'),
                    rospy.get_param(
                        'count_products_posture/facing_77bce2/orientation/w'))
                r.posture.joints.append(
                    JointPosition(
                        'Torso_lin1',
                        rospy.get_param(
                            'count_products_posture/facing_77bce2/Torso_lin1'))
                )
                r.posture.joints.append(
                    JointPosition(
                        'Torso_lin2',
                        rospy.get_param(
                            'count_products_posture/facing_77bce2/Torso_lin2'))
                )
                r.posture.joints.append(
                    JointPosition(
                        'Torso_rot_1',
                        rospy.get_param(
                            'count_products_posture/facing_77bce2/Torso_rot_1')
                    ))

            elif data.id == 'facing_c4a62e':
                r.posture = FullBodyPosture()
                r.posture.base_pos.header.frame_id = '/map'
                r.posture.base_pos.pose.position = Point(
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/position/x'),
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/position/y'),
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/position/z'))
                r.posture.base_pos.pose.orientation = Quaternion(
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/orientation/x'),
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/orientation/y'),
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/orientation/z'),
                    rospy.get_param(
                        'count_products_posture/facing_c4a62e/orientation/w'))
                r.posture.joints.append(
                    JointPosition(
                        'Torso_lin1',
                        rospy.get_param(
                            'count_products_posture/facing_c4a62e/Torso_lin1'))
                )
                r.posture.joints.append(
                    JointPosition(
                        'Torso_lin2',
                        rospy.get_param(
                            'count_products_posture/facing_c4a62e/Torso_lin2'))
                )
                r.posture.joints.append(
                    JointPosition(
                        'Torso_rot_1',
                        rospy.get_param(
                            'count_products_posture/facing_c4a62e/Torso_rot_1')
                    ))

        else:
            r.error = QueryCountProductsPostureResponse.INVALID_ID
        return r

    def finish_perception_cb(self, data):
        """
        :type data: FinishPerceptionRequest
        :rtype: FinishPerceptionResponse
        """
        prefix = 'finish_perception'
        self.print_with_prefix('service called', prefix)
        state = self.get_state(prefix)
        if self.is_ready(state) or self.is_abort(state) or self.is_finish(
                state):
            self.put_state(state, prefix)
            self.warn_with_prefix('server idle', prefix)
            return FinishPerceptionResponse(
                error=FinishPerceptionResponse.NO_RUNNING_JOB,
                error_msg='no running job')
        elif self.is_busy(state):
            self.set_finish(prefix)
            self.print_with_prefix(
                'finishing {}'.format(self.state_code_to_name(state)), prefix)
            return FinishPerceptionResponse(
                error=FinishPerceptionResponse.SUCCESS)
        else:
            self.put_state(state, prefix)
            self.print_with_prefix(
                'called in unexpected state {}'.format(state), prefix)

    def detect_shelf_layers_cb(self, data):
        """
        :type data: DetectShelfLayersGoal
        """
        result_type = DetectShelfLayersResult
        action_server = self.detect_shelf_layer_as
        prefix = 'detect_shelf_layers'

        self.print_with_prefix('called', prefix)
        r = result_type()
        state = self.wait_for([
            self.READY, self.KILL_DETECT_SHELF_LAYER, self.KILL_DETECT_FACINGS,
            self.KILL_COUNT_PRODUCTS, self.BUSY_DETECT_SHELF_LAYER,
            self.BUSY_COUNT_PRODUCTS, self.BUSY_DETECT_FACINGS
        ], prefix)
        if state in [
                self.KILL_DETECT_FACINGS, self.READY, self.KILL_COUNT_PRODUCTS
        ]:
            if data.id in self.shelf_ids:
                self.print_with_prefix('started', prefix)
                self.put_state(self.BUSY_DETECT_SHELF_LAYER, prefix)
                state = self.wait_for([self.ABORT, self.FINISH], prefix)
                if self.is_abort(state):
                    r.error = 3
                    if action_server.new_goal:
                        self.set_ready(self.KILL_DETECT_SHELF_LAYER, prefix)
                        self.warn_with_prefix(
                            'aborted because new action of same type requested',
                            prefix)
                    else:
                        self.set_ready(prefix=prefix)
                        self.print_with_prefix('aborted', prefix)
                    action_server.set_aborted(r)
                elif self.is_finish(state):
                    r.error = result_type.SUCCESS
                    r.ids = self.shelf_to_layer[data.id]
                    self.set_ready(prefix=prefix)
                    action_server.set_succeeded(r)
                    self.print_with_prefix('finished successful', prefix)
            else:
                r.error = result_type.INVALID_ID
                r.error_msg = 'invalid shelf id: {}'.format(data.id)
                self.set_ready(prefix=prefix)
                self.print_with_prefix('invalid id {}'.format(data.id), prefix)
                action_server.set_aborted(r)
        elif self.is_busy(state):
            self.set_abort(prefix)
            self.print_with_prefix('aborted because server busy', prefix)
            r.error = result_type.SERVER_BUSY
            r.error_msg = 'aborted because server busy: {}'.format(
                self.state_code_to_name(state))
            action_server.set_aborted(r)
        elif state == self.KILL_DETECT_SHELF_LAYER:
            r.error = result_type.SERVER_BUSY
            r.error_msg = 'aborted because server busy: {}'.format(
                self.state_code_to_name(state))
            self.set_ready(prefix=prefix)
            self.print_with_prefix('aborted because server busy', prefix)
            action_server.set_aborted(r)

    def detect_facings_cb(self, data):
        """
        :type data: DetectFacingsGoal
        """
        result_type = DetectFacingsResult
        action_server = self.detect_facings_as
        prefix = 'detect_facings'

        self.print_with_prefix('called', prefix)
        r = result_type()
        state = self.wait_for([
            self.READY, self.KILL_DETECT_SHELF_LAYER, self.KILL_DETECT_FACINGS,
            self.KILL_COUNT_PRODUCTS, self.BUSY_DETECT_SHELF_LAYER,
            self.BUSY_COUNT_PRODUCTS, self.BUSY_DETECT_FACINGS
        ], prefix)
        if state in [
                self.KILL_DETECT_SHELF_LAYER, self.READY,
                self.KILL_COUNT_PRODUCTS
        ]:
            if data.id in self.layer_ids:
                self.print_with_prefix('started', prefix)
                self.put_state(self.BUSY_DETECT_FACINGS, prefix)
                state = self.wait_for([self.ABORT, self.FINISH], prefix)
                if self.is_abort(state):
                    r.error = 3
                    if action_server.new_goal:
                        self.set_ready(self.KILL_DETECT_FACINGS, prefix)
                        self.warn_with_prefix(
                            'aborted because new action of same type requested',
                            prefix)
                    else:
                        self.set_ready(prefix=prefix)
                        self.print_with_prefix('aborted', prefix)
                    action_server.set_aborted(r)
                elif self.is_finish(state):
                    r.error = result_type.SUCCESS
                    r.ids = self.layer_to_facing[data.id]
                    self.set_ready(prefix=prefix)
                    action_server.set_succeeded(r)
                    self.print_with_prefix('finished successful', prefix)
            else:
                r.error = result_type.INVALID_ID
                r.error_msg = 'invalid layer id: {}'.format(data.id)
                self.set_ready(prefix=prefix)
                self.print_with_prefix('invalid id {}'.format(data.id), prefix)
                action_server.set_aborted(r)
        elif self.is_busy(state):
            self.set_abort(prefix)
            self.print_with_prefix('aborted because server busy', prefix)
            r.error = result_type.SERVER_BUSY
            r.error_msg = 'aborted because server busy: {}'.format(
                self.state_code_to_name(state))
            action_server.set_aborted(r)
        elif state == self.KILL_DETECT_FACINGS:
            r.error = result_type.SERVER_BUSY
            r.error_msg = 'aborted because server busy: {}'.format(
                self.state_code_to_name(state))
            self.set_ready(prefix=prefix)
            self.print_with_prefix('aborted because server busy', prefix)
            action_server.set_aborted(r)

    def count_products_cb(self, data):
        """
        :type data: CountProductsGoal
        """
        result_type = CountProductsResult
        action_server = self.count_products_as
        prefix = 'count_products'

        self.print_with_prefix('called', prefix)
        r = result_type()
        state = self.wait_for([
            self.READY, self.KILL_DETECT_SHELF_LAYER, self.KILL_DETECT_FACINGS,
            self.KILL_COUNT_PRODUCTS, self.BUSY_DETECT_SHELF_LAYER,
            self.BUSY_COUNT_PRODUCTS, self.BUSY_DETECT_FACINGS
        ], prefix)
        if state in [
                self.KILL_DETECT_SHELF_LAYER, self.READY,
                self.KILL_DETECT_FACINGS
        ]:
            if data.id in self.facing_ids:
                self.print_with_prefix('started', prefix)
                # self.put_state(self.BUSY_COUNT_PRODUCTS, prefix)
                self.set_finish(prefix)
                state = self.wait_for([self.ABORT, self.FINISH], prefix)
                if self.is_abort(state):
                    r.error = 3
                    if action_server.new_goal:
                        self.set_ready(self.KILL_COUNT_PRODUCTS, prefix)
                        self.warn_with_prefix(
                            'aborted because new action of same type requested',
                            prefix)
                    else:
                        self.set_ready(prefix=prefix)
                        self.print_with_prefix('aborted', prefix)
                    action_server.set_aborted(r)
                elif self.is_finish(state):
                    r.error = result_type.SUCCESS
                    r.count = self.product_counts[data.id]
                    self.set_ready(prefix=prefix)
                    action_server.set_succeeded(r)
                    self.print_with_prefix('finished successful', prefix)
            else:
                r.error = result_type.INVALID_ID
                r.error_msg = 'invalid facing id: {}'.format(data.id)
                self.set_ready(prefix=prefix)
                self.print_with_prefix('invalid id {}'.format(data.id), prefix)
                action_server.set_aborted(r)
        elif self.is_busy(state):
            self.set_abort(prefix)
            self.print_with_prefix('aborted because server busy', prefix)
            r.error = result_type.SERVER_BUSY
            r.error_msg = 'aborted because server busy: {}'.format(
                self.state_code_to_name(state))
            action_server.set_aborted(r)
        elif state == self.KILL_COUNT_PRODUCTS:
            r.error = result_type.SERVER_BUSY
            r.error_msg = 'aborted because server busy: {}'.format(
                self.state_code_to_name(state))
            self.set_ready(prefix=prefix)
            self.print_with_prefix('aborted because server busy', prefix)
            action_server.set_aborted(r)

    def cancel_cb(self):
        prefix = 'cancel_callback'
        self.print_with_prefix('called', prefix)
        state = self.get_state(prefix)
        if self.is_server_idle(state):
            self.put_state(state, prefix)
            self.print_with_prefix('server idle', prefix)
        elif self.is_busy(state):
            self.set_abort(prefix)
            # self.state_lock.task_done()
            self.print_with_prefix(
                'aborting {}'.format(self.state_code_to_name(state)), prefix)
        else:
            self.put_state(state, prefix)
            self.warn_with_prefix('called in unexpected state', prefix)

    def get_state(self, prefix):
        state = self.state_lock.get(timeout=ONE_YEAR)
        # self.print_with_prefix('removed state token {}'.format(state), prefix)
        # if task_done:
        #     self.state_lock.task_done()
        return state

    def put_state(self, state, prefix=''):
        self.state_lock.put(state)
        # self.print_with_prefix('added state {}'.format(state), prefix)

    def is_ready(self, state):
        return state in {
            self.KILL_DETECT_SHELF_LAYER, self.KILL_DETECT_FACINGS,
            self.KILL_COUNT_PRODUCTS, self.READY
        }

    def is_busy(self, state):
        return state in {
            self.BUSY_DETECT_SHELF_LAYER, self.BUSY_DETECT_FACINGS,
            self.BUSY_COUNT_PRODUCTS
        }

    def is_abort(self, state):
        return state == self.ABORT

    def is_finish(self, state):
        return state == self.FINISH

    def is_server_idle(self, state):
        return self.is_ready(state) or self.is_finish(state) or self.is_abort(
            state)

    def set_finish(self, prefix):
        self.put_state(self.FINISH, prefix)

    def set_ready(self, state=None, prefix=''):
        if state is None:
            self.put_state(self.READY, prefix)
        else:
            if state in [
                    self.KILL_DETECT_SHELF_LAYER, self.KILL_COUNT_PRODUCTS,
                    self.KILL_DETECT_FACINGS
            ]:
                self.put_state(state, prefix)

    def set_kill_next(self, state, prefix):
        self.put_state(state, prefix)

    def set_busy(self, state, prefix):
        self.put_state(state, prefix)

    def set_abort(self, prefix):
        self.put_state(self.ABORT, prefix)

    def wait_for(self, events, prefix):
        state = None
        while not rospy.is_shutdown():
            state = self.check_state(events, prefix)
            if state is not None:
                break
            else:
                rospy.sleep(.5)
        # try:
        #     self.state_lock.task_done()
        # except:
        #     pass
        return state

    def check_state(self, events, prefix):
        state = self.get_state(prefix)
        if state in events:
            return state
        else:
            self.put_state(state, prefix)
            # self.state_lock.task_done()
            return None

    def state_code_to_name(self, code):
        if code in {
                self.READY, self.KILL_DETECT_SHELF_LAYER,
                self.KILL_DETECT_FACINGS, self.KILL_COUNT_PRODUCTS
        }:
            return 'ready'
        if code == self.BUSY_DETECT_SHELF_LAYER:
            return 'detecting shelf layers'
        if code == self.BUSY_DETECT_FACINGS:
            return 'detecting shelf facings'
        if code == self.BUSY_COUNT_PRODUCTS:
            return 'counting products'
        if code == self.ABORT:
            return 'ABORT'
        if code == self.FINISH:
            return 'FINISH'
        return 'UNKNOWN STATE'

    def print_with_prefix(self, msg, prefix):
        rospy.loginfo('[{}] {}'.format(prefix, msg))

    def warn_with_prefix(self, msg, prefix):
        rospy.logwarn('[{}] {}'.format(prefix, msg))
Example #11
0
class MotionService(object):
    def __init__(self):
        rospy.init_node('motion_service')
        # Load config
        config_loader = RobotConfigLoader()
        try:
            robot_config_name = rospy.get_param(rospy.get_name() +
                                                '/robot_config')
        except KeyError:
            rospy.logwarn('Could not find robot config param in /' +
                          rospy.get_name +
                          '/robot_config. Using default config for '
                          'Thor Mang.')
            robot_config_name = 'thor'
        config_loader.load_xml_by_name(robot_config_name + '_config.xml')

        # Create publisher for first target
        if len(config_loader.targets) > 0:
            self._motion_publisher = MotionPublisher(
                config_loader.robot_config,
                config_loader.targets[0].joint_state_topic,
                config_loader.targets[0].publisher_prefix)
        else:
            rospy.logerr(
                'Robot config needs to contain at least one valid target.')
        self._motion_data = MotionData(config_loader.robot_config)

        # Subscriber to start motions via topic
        self.motion_command_sub = rospy.Subscriber(
            'motion_command', ExecuteMotionCommand,
            self.motion_command_request_cb)

        # Create action server
        self._action_server = SimpleActionServer(
            rospy.get_name() + '/motion_goal', ExecuteMotionAction, None,
            False)
        self._action_server.register_goal_callback(self._execute_motion_goal)
        self._action_server.register_preempt_callback(
            self._preempt_motion_goal)
        self._preempted = False

    def _execute_motion_goal(self):
        goal = self._action_server.accept_new_goal()
        # Check if motion exists
        if goal.motion_name not in self._motion_data:
            result = ExecuteMotionResult()
            result.error_code = [ExecuteMotionResult.MOTION_UNKNOWN]
            result.error_string = "The requested motion is unknown."
            self._action_server.set_aborted(result)
            return

        # check if a valid time_factor is set, otherwise default to 1.0
        if goal.time_factor <= 0.0:
            goal.time_factor = 1.0

        self._preempted = False

        self._motion_publisher.publish_motion(
            self._motion_data[goal.motion_name], goal.time_factor,
            self._trajectory_finished)
        print '[MotionService] New action goal received.'

    def _preempt_motion_goal(self):
        self._motion_publisher.stop_motion()
        print '[MotionService] Preempting goal.'
        self._preempted = True

    def _trajectory_finished(self, error_codes, error_groups):
        result = ExecuteMotionResult()
        result.error_code = error_codes
        error_string = ""
        for error_code, error_group in zip(error_codes, error_groups):
            error_string += error_group + ': ' + str(error_code) + '\n'
        result.error_string = error_string
        if self._preempted:
            self._action_server.set_preempted(result)
        else:
            self._action_server.set_succeeded(result)
        print '[MotionService] Trajectory finished with error code: \n', error_string

    def _execute_motion(self, request):
        response = ExecuteMotionResponse()

        # check if a motion with this name exists
        if request.motion_name not in self._motion_data:
            print '[MotionService] Unknown motion name: "%s"' % request.motion_name

            response.ok = False
            response.finish_time.data = rospy.Time.now()
            return response

        # check if a valid time_factor is set, otherwise default to 1.0
        if request.time_factor <= 0.0:
            request.time_factor = 1.0

        # find the duration of the requested motion
        motion_duration = 0.0
        for poses in self._motion_data[request.motion_name].values():
            if len(poses) > 0:
                endtime = poses[-1]['starttime'] + poses[-1]['duration']
                motion_duration = max(motion_duration, endtime)
        motion_duration *= request.time_factor

        # execute motion
        print '[MotionService] Executing motion: "%s" (time factor: %.3f, duration %.2fs)' % (
            request.motion_name, request.time_factor, motion_duration)
        self._motion_publisher.publish_motion(
            self._motion_data[request.motion_name], request.time_factor)

        # reply with ok and the finish_time of this motion
        response.ok = True
        response.finish_time.data = rospy.Time.now() + rospy.Duration.from_sec(
            motion_duration)
        return response

    def start_server(self):
        rospy.Service(rospy.get_name() + '/execute_motion', ExecuteMotion,
                      self._execute_motion)
        self._action_server.start()
        print '[MotionService] Waiting for calls...'
        rospy.spin()

    def motion_command_request_cb(self, command):
        print "[MotionService] Initiate motion command via topic ..."
        request = ExecuteMotion()
        request.motion_name = command.motion_name
        request.time_factor = command.time_factor
        self._execute_motion(request)
        print "[MotionService] Motion command complete"
Example #12
0
class AudioFilePlayer(object):
    def __init__(self,
                 volume_set_command='amixer -c 0 sset Master playback',
                 volume_get_command='amixer -c 0 sget Master playback'):
        self.current_playing_process = None
        self.volume_set_command = volume_set_command
        self.volume_get_command = volume_get_command
        self.curr_vol = 0

        rospy.loginfo("Initializing AudioFilePlayer...")
        rospy.loginfo("VolumeManager using base set command: '" +
                      self.volume_set_command + "'")
        rospy.loginfo("VolumeManager using base get command: '" +
                      self.volume_get_command + "'")
        # By default this node plays files using the aplay command
        # Feel free to use any other command or flags
        # by using the params provided
        self.command = rospy.get_param('~/command', 'play')
        self.flags = rospy.get_param('~/flags', '')
        self.feedback_rate = rospy.get_param('~/feedback_rate', 10)

        self.afp_as = SimpleActionServer(rospy.get_name(),
                                         AudioFilePlayAction,
                                         self.as_cb,
                                         auto_start=False)
        self.afp_sub = rospy.Subscriber('~play',
                                        String,
                                        self.topic_cb,
                                        queue_size=1)
        self.afp_as.start()
        # Needs to be done after start
        self.afp_as.register_preempt_callback(self.as_preempt_cb)

        self.volume_sub = rospy.Subscriber('~set_volume',
                                           Int8,
                                           self.volume_cb,
                                           queue_size=1)
        # Get volume to start publishing
        self.curr_vol = self.get_current_volume()
        self.volume_listener = VolumeListener(self)
        self.volume_pub = rospy.Publisher(
            '~get_volume',
            Int8,
            subscriber_listener=self.volume_listener,
            latch=True,
            queue_size=1)
        self.volume_timer = None
        rospy.loginfo(
            "Done, playing files from action server or topic interface.")

    def as_preempt_cb(self):
        if self.current_playing_process:
            self.current_playing_process.kill()
            # Put the AS as cancelled/preempted
            res = AudioFilePlayResult()
            res.success = False
            res.reason = "Got a cancel request."
            self.afp_as.set_preempted(res, text="Cancel requested.")

    def as_cb(self, goal):
        initial_time = time.time()
        self.play_audio_file(goal.filepath)
        r = rospy.Rate(self.feedback_rate)
        while not rospy.is_shutdown(
        ) and not self.current_playing_process.is_done():
            feedback = AudioFilePlayFeedback()
            curr_time = time.time()
            feedback.elapsed_played_time = rospy.Duration(curr_time -
                                                          initial_time)
            self.afp_as.publish_feedback(feedback)
            r.sleep()

        final_time = time.time()
        res = AudioFilePlayResult()
        if self.current_playing_process.is_succeeded():
            res.success = True
            res.total_time = rospy.Duration(final_time)
            self.afp_as.set_succeeded(res)
        else:
            if self.afp_as.is_preempt_requested():
                return
            res.success = False
            reason = "stderr: " + self.current_playing_process.get_stderr()
            reason += "\nstdout: " + self.current_playing_process.get_stdout()
            res.reason = reason
            self.afp_as.set_aborted(res)

    def topic_cb(self, data):
        if self.current_playing_process:
            if not self.current_playing_process.is_done():
                self.current_playing_process.kill()
        self.play_audio_file(data.data)

    def play_audio_file(self, audio_file_path):
        # Replace any ' or " characters with emptyness to avoid bad usage
        audio_file_path = audio_file_path.replace("'", "")
        audio_file_path = audio_file_path.replace('"', '')
        full_command = self.command + " " + self.flags + " '" + audio_file_path + "'"
        rospy.loginfo("Playing audio file: " + str(audio_file_path) +
                      " with command: " + str(full_command))
        self.current_playing_process = ShellCmd(full_command)

    def curr_vol_cb(self, event):
        self.curr_vol = self.get_current_volume()
        self.volume_pub.publish(Int8(self.curr_vol))

    def get_current_volume(self):
        cmd = ShellCmd(self.volume_get_command)
        while not cmd.is_done() and not rospy.is_shutdown():
            rospy.sleep(0.1)
        output = cmd.get_stdout()
        rospy.logdebug("self.volume_get_command output: " + str(output))
        # Output looks like:
        # Simple mixer control 'Master',0
        # Capabilities: pvolume pvolume-joined pswitch pswitch-joined
        # Playback channels: Mono
        # Limits: Playback 0 - 87
        # Mono: Playback 44 [51%] [-32.25dB] [on]

        pct_idx = output.index('%')
        # At most 3 characters of 100%
        pct_text = output[pct_idx - 3:pct_idx]
        # Remove [ if it was less than 3 chars
        pct_text = pct_text.replace('[', '')
        # Remove spaces if it was less than 2 char
        pct_text = pct_text.strip()
        curr_vol = int(pct_text)
        return curr_vol

    def volume_cb(self, data):
        if data.data > 100:
            to_pct = 100
        elif data.data < 0:
            to_pct = 0
        else:
            to_pct = data.data
        rospy.loginfo("Changing volume to: " + str(to_pct) + "%")
        cmd_line = self.volume_set_command + " " + str(to_pct) + "%"
        rospy.loginfo("Executing command: " + cmd_line)
        cmd = ShellCmd(cmd_line)
        while not cmd.is_done() and not rospy.is_shutdown():
            rospy.sleep(0.1)
        output = cmd.get_stdout()
        rospy.logdebug("Set command output: " + str(output))

    def enable_volume_service(self):
        if not self.volume_timer:
            rospy.loginfo("Enable audio volume subscription service.")
            self.volume_timer = rospy.Timer(rospy.Duration(1.0),
                                            self.curr_vol_cb)

    def disable_volume_servce(self):
        if self.volume_timer:
            rospy.loginfo("Disable audio volume subscription service.")
            self.volume_timer.shutdown()
            self.volume_timer = None
Example #13
0
class Server(object):
    def __init__(self, name):
        rospy.loginfo("Starting '{test}'.".format(test=name))
        self._as = SimpleActionServer(name, WayPointNavAction, auto_start=False)
        self._as.register_goal_callback(self.execute_cb)
        self._as.register_preempt_callback(self.preempt_cb)
        self.listener = tf.TransformListener()
        self.pub = rospy.Publisher("/cmd_vel", Twist, queue_size=10)
        self.sub = None
        self._as.start()
        rospy.loginfo("Started '{test}'.".format(test=name))

    def execute_cb(self):
        self.goal = self._as.accept_new_goal()
        print self.goal
        self.sub = rospy.Subscriber("/orb_slam/pose", PoseStamped, self.pose_cb)

    def preempt_cb(self, *args):
        self.sub.unregister()
        self.sub = None
        t = Twist()
        self.pub.publish(t)
        self._as.set_preempted(WayPointNavResult())

    def pose_cb(self, msg):
        dist = self.get_dist(self.goal.goal, msg)
        t = Twist()
        new_goal = self._transform(self.goal.goal, "camera_pose")
        print new_goal
        print "Dist", dist
        theta = self.get_theta(new_goal.pose)
        print "Theta", theta
        if dist < 0.02:
            self._as.set_succeeded(WayPointNavResult())
            self.sub.unregister()
            self.sub = None
            t.linear.x = 0.0
            t.angular.z = 0.0
        else:
            t.linear.x = 0.03
            t.angular.z = theta * .6
        
        self.pub.publish(t)

    def get_dist(self, pose1, pose2):
        return np.sqrt(np.power(pose1.pose.position.x-pose2.pose.position.x, 2)+np.power(pose1.pose.position.y-pose2.pose.position.y, 2))

    def _transform(self, msg, target_frame):
        if msg.header.frame_id != target_frame:
            try:
                t = self.listener.getLatestCommonTime(target_frame, msg.header.frame_id)
                msg.header.stamp = t
                return self.listener.transformPose(target_frame, msg)
            except (tf.Exception, tf.LookupException, tf.ConnectivityException) as ex:
                rospy.logwarn(ex)
                return None
        else:
            return msg

    def get_theta(self, pose):
        return np.arctan2(pose.position.y, pose.position.x)