Skip to content

Latest commit

 

History

History
65 lines (48 loc) · 3.46 KB

clear_behavior.md

File metadata and controls

65 lines (48 loc) · 3.46 KB

Turtlesim Demo Clear Behavior

The "Clear" sub-behavior is implemented by a sequence of states as in the main editor view

State machine editor view

This discussion presumed you have already read through the "Home" discussion.

The "Clear" transition first invokes the "ClearLog" LogState to display the "Clear turtlesim window ..." text, then transitions to the "ClearWindow" state instance of the ClearTurtlesimState. After the ClearTurtlesimState returns, the system either transitions back to the "Operator" decision state, or into the "ClearFailed" LogState to notify the operator of problems.

The key difference between ClearTurtlesimState and the TeleportAbosoluteState discussed in "Home" is that ClearTurtlesimState uses a blocking service call.

    def on_enter(self, userdata):
        """
        Call when the state becomes active.

        This example does NOT use any userdata passed from upstream states.

        , i.e. a transition from another state to this one is taken.
        """
        self._start_time = self._node.get_clock().now()
        self._return = None  # reset the completion flag
        self._srv_result = None
        self._service_called = False
        try:
            if self._srv.is_available(self._srv_topic, wait_duration=0.0):
                Logger.localinfo(f"{self._name}: Service {self._srv_topic} is available ...")
                self._do_service_call()
            else:
                Logger.logwarn(f"{self._name}: Service {self._srv_topic} is not yet available ...")
        except Exception as exc:
            Logger.logerr(f"{self._name}: Service {self._srv_topic} exception {type(exc)} - {str(exc)}")

    def _do_service_call(self):
        """Make the service call using synchronous blocking call."""
        try:
            Logger.localinfo(f"{self._name}: Calling service {self._srv_topic} ...")
            self._service_called = True
            self._srv_result = self._srv.call(self._srv_topic, self._srv_request, wait_duration=0.0)
        except Exception as e:
            Logger.logerr(f"{self._name}: Service {self._srv_topic} exception {type(e)} - {str(e)}")
            self._srv_result = None

Use of blocking calls are discouraged with FlexBE and in most cases you should prefer the asynchronous model.

The typical state machine model assumes that on_enter, execute, and on_exit calls are relatively fast compared to the desired update rate of the system. This is especially important if the state can be embedded into a ConcurrencyContainer (discussed in Examples).

That said, blocking calls are possible as demonstrated here, and can be appropriate in some instances. Just beware that this impacts the timing of all other states as the state machine is executed in a single thread, even for concurrent containers.


This example has demonstrated using an blocking synchronous service call within FlexBE. For comparison with a non-blocking asynchronous service call, see the "Home" discussion.

Back to the overview