示例#1
0
 def check_consistency(self):
     for (co,cso) in ((k,self._outcome_map[k]) for k in self._outcome_map):
         for state_label,outcome in ((k,cso[k]) for k in cso):
             if outcome not in self._states[state_label].get_registered_outcomes():
                 raise smach.InvalidTransitionError(
                         'Outcome map in SMACH Concurrence references a state outcome that does not exist. Requested state outcome: \'%s\', but state \'%s\' only has outcomes %s' %
                         (outcome, state_label, str(self._states[state_label].get_registered_outcomes())))
示例#2
0
 def execute(self, parent_ud=smach.UserData()):
     with self._condition:
         if self._root is None:
             raise smach.InvalidTransitionError("BehaviorTreeContainer has no root task")
     
         self._result = None
         self._current_exec_root = self._initial_task
         
         # Copy input keys
         self._copy_input_keys(parent_ud, self.userdata)
         
         result = self._current_exec_root.try_immediate(self.userdata)
     
         if result == Task.DEFERRED:
             self._current_exec_root.execute_deferred(self._root_termination_cb, self.userdata)
             while self._current_exec_root is not None:
                 # Releases condition mutex during wait
                 self._condition.wait(0.1)
             result = self._result
         else:
             self._current_exec_root = None
         
         # Copy output keys
         self._copy_output_keys(self.userdata, parent_ud)
         
         return self._outcome_from_result(result)
示例#3
0
    def check_consistency(self):
        """Check the entire state machine for consistency.
        This asserts that all transition targets are states that are in the
        state machine. If this fails, it raises an L{InvalidTransitionError}
        with relevant information.
        """
        # Construct a set of available states
        available_states = set(
            list(self._states.keys()) + list(self.get_registered_outcomes()))

        # Grab the registered outcomes for the state machine
        registered_sm_outcomes = self.get_registered_outcomes()

        # Hopefully this string stays empty
        errors = ""

        # Check initial_state_label
        if self._initial_state_label is None:
            errors = errors + "\n\tNo initial state set."
        elif self._initial_state_label not in self._states:
            errors = errors + "\n\tInitial state label: '" + str(
                self._initial_state_label) + "' is not in the state machine."

        # Generate state specifications
        state_specs = [(label, self._states[label], self._transitions[label])
                       for label in self._states]
        # Iterate over all states
        for label, state, transitions in state_specs:
            # Check that all potential outcomes are registered in this state
            transition_states = set(
                [s for s in transitions.values() if s is not None and s != ''])
            # Generate a list of missing states
            missing_states = transition_states.difference(available_states)

            # Check number of missing states
            if len(missing_states) > 0:
                errors = (errors + "\n\tState '" + str(label) +
                          "' references unknown states: " +
                          str(list(missing_states)))

            # Check terminal outcomes for this state
            terminal_outcomes = set([
                o for (o, s) in ((k, transitions[k]) for k in transitions)
                if s is None or s == ''
            ])
            # Terminal outcomes should be in the registered outcomes of this state machine
            missing_outcomes = terminal_outcomes.difference(
                registered_sm_outcomes)
            # Check number of missing outcomes
            if len(missing_outcomes) > 0:
                errors = (errors + "\n\tState '" + str(label) +
                          "' references unregistered outcomes: " +
                          str(list(missing_outcomes)))

        # Check errors
        if len(errors) > 0:
            raise smach.InvalidTransitionError(
                "State machine failed consistency check: " + errors +
                "\n\n\tAvailable states: " + str(list(available_states)))
    def _update_once(self):
        # Check if a preempt was requested before or while the last state was running
        if self.preempt_requested() or PreemptableState.preempt:
            return self._preempted_name

        #self._state_transitioning_lock.release()
        for state in self._ordered_states:
            if state.name in self._returned_outcomes.keys(
            ) and self._returned_outcomes[state.name] != self._loopback_name:
                continue
            if PriorityContainer.active_container is not None \
            and not PriorityContainer.active_container.startswith(state._get_path()) \
            and not state._get_path().startswith(PriorityContainer.active_container):
                if isinstance(state, EventState):
                    state._notify_skipped()
                elif state._get_deep_state() is not None:
                    state._get_deep_state()._notify_skipped()
                continue
            self._returned_outcomes[state.name] = self._execute_state(state)
        #self._state_transitioning_lock.acquire()

        # Determine outcome
        outcome = self._loopback_name
        for item in self._conditions:
            (oc, cond) = item
            if all(
                    self._returned_outcomes.has_key(sn)
                    and self._returned_outcomes[sn] == o for sn, o in cond):
                outcome = oc
                break

        # preempt (?)
        if outcome == self._loopback_name:
            return None

        if outcome in self.get_registered_outcomes():
            # Call termination callbacks
            self.call_termination_cbs([s.name for s in self._ordered_states],
                                      outcome)
            self.on_exit(
                self.userdata,
                states=filter(
                    lambda s: s.name not in self._returned_outcomes.keys() or
                    self._returned_outcomes[s.name] == self._loopback_name,
                    self._ordered_states))
            self._returned_outcomes = dict()
            # right now, going out of a cc may break sync
            # thus, as a quick fix, explicitly sync again
            self._parent._inner_sync_request = True
            self._current_state = None

            return outcome
        else:
            raise smach.InvalidTransitionError(
                "Outcome '%s' of state '%s' with transition target '%s' is neither a registered state nor a registered container outcome."
                % (outcome, self.name, outcome))
示例#5
0
 def check_state_spec(self, label, state, transitions):
     """Validate full state specification (label, state, and transitions).
     This checks to make sure the required variables are in the state spec,
     as well as verifies that all outcomes referenced in the transitions
     are registered as valid outcomes in the state object. If a state
     specification fails validation, a L{smach.InvalidStateError} is
     thrown.
     """
     # Make sure all transitions are from registered outcomes of this state
     registered_outcomes = state.get_registered_outcomes()
     for outcome in transitions:
         if outcome not in registered_outcomes:
             raise smach.InvalidTransitionError("Specified outcome '"+outcome+"' on state '"+label+"', which only has available registered outcomes: "+str(registered_outcomes))
示例#6
0
    def _update_once(self):
        """Method that updates the state machine once.
        This checks if the current state is ready to transition, if so, it
        requests the outcome of the current state, and then extracts the next state
        label from the current state's transition dictionary, and then transitions
        to the next state.
        """
        outcome = None
        transition_target = None
        last_state_label = self._current_label

        # Make sure the state exists
        if self._current_label not in self._states:
            raise smach.InvalidStateError(
                "State '%s' does not exist. Available states are: %s" %
                (self._current_label, list(self._states.keys())))

        # Check if a preempt was requested before or while the last state was running
        if self.preempt_requested():
            smach.loginfo(
                "Preempt requested on state machine before executing the next state."
            )
            # We were preempted
            if self._preempted_state is not None:
                # We were preempted while the last state was running
                if self._preempted_state.preempt_requested():
                    smach.loginfo(
                        "Last state '%s' did not service preempt. Preempting next state '%s' before executing..."
                        % (self._preempted_label, self._current_label))
                    # The flag was not reset, so we need to keep preempting
                    # (this will reset the current preempt)
                    self._preempt_current_state()
                else:
                    # The flag was reset, so the container can reset
                    self._preempt_requested = False
                    self._preempted_state = None
            else:
                # We were preempted after the last state was running
                # So we sho                 if(self._preempt_requested):uld preempt this state before we execute it
                self._preempt_current_state()

        # Execute the state
        self._tree_view_enable_state(self._current_label)
        try:
            self._state_transitioning_lock.release()
            outcome = self._current_state.execute(
                smach.Remapper(
                    self.userdata,
                    self._current_state.get_registered_input_keys(),
                    self._current_state.get_registered_output_keys(),
                    self._remappings[self._current_label]))
        except smach.InvalidUserCodeError as ex:
            smach.logerr("State '%s' failed to execute." % self._current_label)
            raise ex
        except:
            raise smach.InvalidUserCodeError(
                "Could not execute state '%s' of type '%s': " %
                (self._current_label, self._current_state) +
                traceback.format_exc())
        finally:
            self._state_transitioning_lock.acquire()

        self._tree_view_disable_state(self._current_label)
        # Check if outcome was a potential outcome for this type of state
        if outcome not in self._current_state.get_registered_outcomes():
            raise smach.InvalidTransitionError(
                "Attempted to return outcome '%s' preempt_requestedfrom state '%s' of"
                " type '%s' which only has registered outcomes: %s" %
                (outcome, self._current_label, self._current_state,
                 self._current_state.get_registered_outcomes()))

        # Check if this outcome is actually mapped to any target
        if outcome not in self._current_transitions:
            raise smach.InvalidTransitionError(
                "Outcome '%s' of state '%s' is not bound to any transition target. Bound transitions include: %s"
                % (str(outcome), str(
                    self._current_label), str(self._current_transitions)))

        # Set the transition target
        transition_target = self._current_transitions[outcome]

        # Check if the transition target is a state in this state machine, or an outcome of this state machine
        if transition_target in self._states:
            # Set the new state
            self._set_current_state(transition_target)

            # Spew some info
            smach.loginfo("State machine transitioning '%s':'%s'-->'%s'" %
                          (last_state_label, outcome, transition_target))

            # Call transition callbacks
            self.call_transition_cbs()
        else:
            # This is a terminal state

            if self._preempt_requested and self._preempted_state is not None:
                if not self._current_state.preempt_requested():
                    self.service_preempt()

            if transition_target not in self.get_registered_outcomes():
                # This is a container outcome that will fall through
                transition_target = outcome

            if transition_target in self.get_registered_outcomes():
                # The transition target is an outcome of the state machine
                self._set_current_state(None)

                # Spew some info
                smach.loginfo("State machine terminating '%s':'%s':'%s'" %
                              (last_state_label, outcome, transition_target))

                # Call termination callbacks
                self.call_termination_cbs([last_state_label],
                                          transition_target)

                return transition_target
            else:
                raise smach.InvalidTransitionError(
                    "Outcome '%s' of state '%s' with transition target '%s' is neither a registered state nor a registered container outcome."
                    % (outcome, self._current_label, transition_target))
        return None
示例#7
0
    def _update_once(self):
        # Check if a preempt was requested before or while the last state was running
        if self.preempt_requested() or PreemptableState.preempt:
            return self._preempted_name

        #self._state_transitioning_lock.release()
        sleep_dur = None
        for state in self._ordered_states:
            if state.name in list(self._returned_outcomes.keys(
            )) and self._returned_outcomes[state.name] != self._loopback_name:
                continue
            if (PriorityContainer.active_container is not None
                    and not all(a == s for a, s in zip(
                        PriorityContainer.active_container.split('/'),
                        state._get_path().split('/')))):
                if isinstance(state, EventState):
                    state._notify_skipped()
                elif state._get_deep_state() is not None:
                    state._get_deep_state()._notify_skipped()
                continue
            state_sleep_dur = state._rate.remaining().to_sec()
            if state_sleep_dur <= 0:
                sleep_dur = 0
                self._returned_outcomes[state.name] = self._execute_state(
                    state)
                # check again in case the sleep has already been handled by the child
                if state._rate.remaining().to_sec() < 0:
                    # this sleep returns immediately since sleep duration is negative,
                    # but is required here to reset the sleep time after executing
                    state._rate.sleep()
            else:
                if sleep_dur is None:
                    sleep_dur = state_sleep_dur
                else:
                    sleep_dur = min(sleep_dur, state_sleep_dur)
        if sleep_dur > 0:
            rospy.sleep(sleep_dur)
        #self._state_transitioning_lock.acquire()

        # Determine outcome
        outcome = self._loopback_name
        for item in self._conditions:
            (oc, cond) = item
            if all(sn in self._returned_outcomes
                   and self._returned_outcomes[sn] == o for sn, o in cond):
                outcome = oc
                break

        # preempt (?)
        if outcome == self._loopback_name:
            return None

        if outcome in self.get_registered_outcomes():
            # Call termination callbacks
            self.call_termination_cbs([s.name for s in self._ordered_states],
                                      outcome)
            self.on_exit(
                self.userdata,
                states=[
                    s for s in self._ordered_states
                    if s.name not in list(self._returned_outcomes.keys())
                    or self._returned_outcomes[s.name] == self._loopback_name
                ])
            self._returned_outcomes = dict()
            # right now, going out of a cc may break sync
            # thus, as a quick fix, explicitly sync again
            self._parent._inner_sync_request = True
            self._current_state = None

            return outcome
        else:
            raise smach.InvalidTransitionError(
                "Outcome '%s' of state '%s' with transition target '%s' is neither a registered state nor a registered container outcome."
                % (outcome, self.name, outcome))
示例#8
0
    def _update_once(self):
        #print 'update'
        # Check if a preempt was requested before or while the last state was running
        if self.preempt_requested() or PreemptableState.preempt:
            #if self._preempted_state is not None:
            #    if self._preempted_state.preempt_requested():
            #        self._preempt_current_state()
            #    else:
            #        self._preempt_requested = False
            #        self._preempted_state = None
            #else:
            #    self._preempt_current_state()
            return self._preempted_name

        #self._state_transitioning_lock.release()
        for state in self._ordered_states:
            if state.name in self._returned_outcomes.keys() and self._returned_outcomes[state.name] != self._loopback_name:
                continue
            if PriorityContainer.active_container is not None and not PriorityContainer.active_container.startswith(state._get_path()):
                if isinstance(state, EventState):
                    state._notify_skipped()
                elif state._get_deep_state() is not None:
                    state._get_deep_state()._notify_skipped()
                continue
            try:
                ud = smach.Remapper(
                            self.userdata,
                            state.get_registered_input_keys(),
                            state.get_registered_output_keys(),
                            self._remappings[state.name])
                self._returned_outcomes[state.name] = state.execute(ud)
                #print 'execute %s --> %s' % (state.name, self._returned_outcomes[state.name])
            except smach.InvalidUserCodeError as ex:
                smach.logerr("State '%s' failed to execute." % state.name)
                raise ex
            except:
                raise smach.InvalidUserCodeError("Could not execute state '%s' of type '%s': " %
                                                 (state.name, state)
                                                 + traceback.format_exc())
        #self._state_transitioning_lock.acquire()

        # Determine outcome
        outcome = self._loopback_name
        for item in self._conditions:
            (oc, cond) = item
            if all(self._returned_outcomes.has_key(sn) and self._returned_outcomes[sn] == o for sn,o in cond):
                outcome = oc
                break
        
        # preempt (?)
        if outcome == self._loopback_name:
            return None

        if outcome in self.get_registered_outcomes():
            # Call termination callbacks
            self.call_termination_cbs([s.name for s in self._ordered_states],outcome)
            self._returned_outcomes = dict()

            return outcome
        else:
            raise smach.InvalidTransitionError("Outcome '%s' of state '%s' with transition target '%s' is neither a registered state nor a registered container outcome." %
                    (outcome, self.name, outcome))