Example #1
0
 def deserialise_tree_recursively(msg):
     behaviour = conversions.msg_to_behaviour(msg)
     for serialised_child_id in msg.child_ids:
         child_id = conversions.msg_to_uuid4(serialised_child_id)
         child = deserialise_tree_recursively(
             serialised_behaviours[child_id])
         # invasive hack to revert the dummy child we added in msg_to_behaviour
         if isinstance(behaviour, py_trees.decorators.Decorator):
             behaviour.children = [child]
             behaviour.decorated = behaviour.children[0]
         else:
             behaviour.children.append(child)
         child.parent = behaviour
     # set the current child so tip() works properly everywhere
     if behaviour.children:
         if msg.current_child_id != unique_identifier_msgs.UUID():
             current_child_id = conversions.msg_to_uuid4(
                 msg.current_child_id)
             for index, child in enumerate(behaviour.children):
                 if child.id == current_child_id:
                     # somewhat ugly not having a consistent api here
                     if isinstance(behaviour,
                                   py_trees.composites.Selector):
                         behaviour.current_child = child
                     elif isinstance(behaviour,
                                     py_trees.composites.Sequence):
                         behaviour.current_index = index
                     # else Parallel, nothing to do since it infers
                     # the current child from children's status on the fly
                     break
     if msg.is_active:
         self.snapshot_visitor.visited[behaviour.id] = behaviour.status
     return behaviour
Example #2
0
def uuid4_to_msg(uuid4: uuid.UUID = uuid.uuid4()):
    """
    Convert a uuid4 python object to a ros unique identifier, UUID type.

    Args:
        uuid4 (:class:`uuid.UUID`), optional: unique identifier to convert, defaults to auto-generated uuid4

    Returns:
        :class:`unique_identifier_msgs.msg.UUID`: the ros message type
    """
    return unique_identifier_msgs.UUID(uuid=list(uuid4.bytes))
Example #3
0
def behaviour_to_msg(behaviour):
    """
    Convert a behaviour to a message.

    Args:
        behaviour (:class:`~py_trees.behaviour.Behaviour`): behaviour to convert

    Returns:
        :class:`~py_trees_msgs.msg.Behaviour`: a ros message representation of a behaviour
    """
    msg = py_trees_msgs.Behaviour()
    msg.name = behaviour.name
    msg.class_name = str(behaviour.__module__) + '.' + str(
        type(behaviour).__name__)
    msg.own_id = uuid4_to_msg(behaviour.id)
    msg.parent_id = uuid4_to_msg(
        behaviour.parent.id
    ) if behaviour.parent else unique_identifier_msgs.UUID()
    msg.child_ids = [
        uuid4_to_msg(child.id)
        for child in behaviour.iterate(direct_descendants=True)
        if not child.id == behaviour.id
    ]

    tip = behaviour.tip()
    # tip_id is empty if the behaviour is invalid or if it is a valid
    # leaf
    if tip is not None and tip != behaviour:
        msg.tip_id = uuid4_to_msg(tip.id)

    msg.type = behaviour_type_to_msg_constant(behaviour)
    msg.blackbox_level = blackbox_enum_to_msg_constant(
        behaviour.blackbox_level)
    msg.status = status_enum_to_msg_constant(behaviour.status)
    msg.message = behaviour.feedback_message

    return msg
Example #4
0
    def callback_snapshot(self, msg):
        """
        Formats the string message coming in.

        Args
            msg (:class:`py_trees_ros_interfaces.msg.BehaviourTree`):serialised snapshot
        """
        ####################
        # Processing
        ####################
        self.snapshot_visitor.previously_visited = self.snapshot_visitor.visited
        self.snapshot_visitor.visited = {}
        serialised_behaviours = {}
        root_id = None
        for serialised_behaviour in msg.behaviours:
            if serialised_behaviour.parent_id == unique_identifier_msgs.UUID():
                root_id = conversions.msg_to_uuid4(serialised_behaviour.own_id)
            serialised_behaviours[conversions.msg_to_uuid4(
                serialised_behaviour.own_id)] = serialised_behaviour

        def deserialise_tree_recursively(msg):
            behaviour = conversions.msg_to_behaviour(msg)
            for serialised_child_id in msg.child_ids:
                child_id = conversions.msg_to_uuid4(serialised_child_id)
                child = deserialise_tree_recursively(
                    serialised_behaviours[child_id])
                # invasive hack to revert the dummy child we added in msg_to_behaviour
                if isinstance(behaviour, py_trees.decorators.Decorator):
                    behaviour.children = [child]
                    behaviour.decorated = behaviour.children[0]
                else:
                    behaviour.children.append(child)
                child.parent = behaviour
            # set the current child so tip() works properly everywhere
            if behaviour.children:
                if msg.current_child_id != unique_identifier_msgs.UUID():
                    current_child_id = conversions.msg_to_uuid4(
                        msg.current_child_id)
                    for index, child in enumerate(behaviour.children):
                        if child.id == current_child_id:
                            # somewhat ugly not having a consistent api here
                            if isinstance(behaviour,
                                          py_trees.composites.Selector):
                                behaviour.current_child = child
                            elif isinstance(behaviour,
                                            py_trees.composites.Sequence):
                                behaviour.current_index = index
                            # else Parallel, nothing to do since it infers
                            # the current child from children's status on the fly
                            break
            if msg.is_active:
                self.snapshot_visitor.visited[behaviour.id] = behaviour.status
            return behaviour

        # we didn't set the tip in any behaviour, but nothing depends
        # on that right now
        root = deserialise_tree_recursively(serialised_behaviours[root_id])

        ####################
        # Streaming
        ####################
        if self.mode == WatcherMode.SNAPSHOTS:
            if msg.changed:
                colour = console.green
            else:
                colour = console.bold
            ####################
            # Banner
            ####################
            title = "Tick {}".format(msg.statistics.count)
            print(colour + "\n" + 80 * "*" + console.reset)
            print(colour + "* " + console.bold + title.center(80) +
                  console.reset)
            print(colour + 80 * "*" + "\n" + console.reset)
            ####################
            # Tree Snapshot
            ####################
            print(
                py_trees.display.unicode_tree(
                    root=root,
                    visited=self.snapshot_visitor.visited,
                    previously_visited=self.snapshot_visitor.previously_visited
                ))
            print(colour + "-" * 80 + console.reset)
            ####################
            # Stream Variables
            ####################
            if self.parameters.blackboard_data:
                print("")
                print(colour + "Blackboard Data" + console.reset)
                indent = " " * 4
                if not msg.blackboard_on_visited_path:
                    print(console.cyan + indent + "-" + console.reset + " : " +
                          console.yellow + "-" + console.reset)
                else:
                    # could probably re-use the unicode_blackboard by passing a dict to it
                    # like we've done for the activity stream
                    max_length = 0
                    for variable in msg.blackboard_on_visited_path:
                        max_length = len(variable.key) if len(
                            variable.key) > max_length else max_length
                    for variable in msg.blackboard_on_visited_path:
                        print(console.cyan + indent +
                              '{0: <{1}}'.format(variable.key, max_length +
                                                 1) + console.reset + ": " +
                              console.yellow + '{0}'.format(variable.value) +
                              console.reset)
            ####################
            # Stream Activity
            ####################
            if self.parameters.blackboard_activity:
                print("")
                print(colour + "Blackboard Activity Stream" + console.reset)
                if msg.blackboard_activity:
                    print(
                        py_trees.display.unicode_blackboard_activity_stream(
                            msg.blackboard_activity,
                            indent=0,
                            show_title=False))
                else:
                    indent = " " * 4
                    print(console.cyan + indent + "-" + console.reset + " : " +
                          console.yellow + "-" + console.reset)
            ####################
            # Stream Statistics
            ####################
            if self.statistics:
                print("")
                print(colour + "Statistics" + console.reset)
                print(console.cyan + "    Timestamp: " + console.yellow +
                      "{}".format(
                          conversions.rclpy_time_to_float(
                              rclpy.time.Time.from_msg(msg.statistics.stamp))))
                print(console.cyan + "    Duration : " + console.yellow +
                      "{:.3f}/{:.3f}/{:.3f} (ms) [time/avg/stddev]".format(
                          msg.statistics.tick_duration *
                          1000, msg.statistics.tick_duration_average * 1000,
                          math.sqrt(msg.statistics.tick_duration_variance) *
                          1000))
                print(console.cyan + "    Interval : " + console.yellow +
                      "{:.3f}/{:.3f}/{:.3f} (s) [time/avg/stddev]".format(
                          msg.statistics.tick_interval,
                          msg.statistics.tick_interval_average,
                          math.sqrt(msg.statistics.tick_interval_variance)))
                print(console.reset)

        ####################
        # Dot Graph
        ####################
        elif self.mode == WatcherMode.DOT_GRAPH and not self.rendered:
            self.rendered = True
            directory_name = tempfile.mkdtemp()
            py_trees.display.render_dot_tree(
                root=root,
                target_directory=directory_name,
                with_blackboard_variables=self.parameters.blackboard_data)
            xdot_program = py_trees.utilities.which('xdot')

            if not xdot_program:
                print("")
                console.logerror(
                    "No xdot viewer found [hint: sudo apt install xdot]")
                print("")
                print(py_trees.display.dot_tree(root=root).to_string())
                self.done = True
                self.xdot_process = None
                return

            filename = py_trees.utilities.get_valid_filename(
                root.name) + '.dot'
            if xdot_program:
                try:
                    self.xdot_process = subprocess.Popen(
                        [xdot_program,
                         os.path.join(directory_name, filename)])
                except KeyboardInterrupt:
                    pass
            self.done = True
Example #5
0
    def callback_snapshot(self, msg):
        """
        Formats the string message coming in.

        Args
            msg (:class:`py_trees_ros_interfaces.msg.BehaviourTree`):serialised snapshot
        """
        ####################
        # Processing
        ####################
        self.snapshot_visitor.previously_visited = self.snapshot_visitor.visited
        self.snapshot_visitor.visited = {}
        serialised_behaviours = {}
        root_id = None
        for serialised_behaviour in msg.behaviours:
            if serialised_behaviour.parent_id == unique_identifier_msgs.UUID():
                root_id = conversions.msg_to_uuid4(serialised_behaviour.own_id)
            serialised_behaviours[conversions.msg_to_uuid4(
                serialised_behaviour.own_id)] = serialised_behaviour

        def deserialise_tree_recursively(msg):
            behaviour = conversions.msg_to_behaviour(msg)
            for serialised_child_id in msg.child_ids:
                child_id = conversions.msg_to_uuid4(serialised_child_id)
                child = deserialise_tree_recursively(
                    serialised_behaviours[child_id])
                child.parent = behaviour
                behaviour.children.append(child)
            if msg.is_active:
                self.snapshot_visitor.visited[behaviour.id] = behaviour.status
            return behaviour

        # we didn't set the tip in any behaviour, but nothing depends
        # on that right now
        root = deserialise_tree_recursively(serialised_behaviours[root_id])

        ####################
        # Streaming
        ####################
        if self.viewing_mode == WatcherMode.ASCII_SNAPSHOT:
            console.banner("Tick {}".format(msg.statistics.count))
            print(
                py_trees.display.ascii_tree(
                    root=root,
                    visited=self.snapshot_visitor.visited,
                    previously_visited=self.snapshot_visitor.previously_visited
                ))
            print(console.green + "-" * 80 + "\n" + console.reset)
            print("Timestamp: {}".format(
                conversions.rclpy_time_to_float(
                    rclpy.time.Time.from_msg(msg.statistics.stamp))))
            print("Duration : {:.3f}/{:.3f}/{:.3f} (ms) [time/avg/stddev]".
                  format(
                      msg.statistics.tick_duration * 1000,
                      msg.statistics.tick_duration_average * 1000,
                      math.sqrt(msg.statistics.tick_duration_variance) * 1000))
            print(
                "Interval : {:.3f}/{:.3f}/{:.3f} (s) [time/avg/stddev]".format(
                    msg.statistics.tick_interval,
                    msg.statistics.tick_interval_average,
                    math.sqrt(msg.statistics.tick_interval_variance)))

        ####################
        # Printing
        ####################
        elif self.viewing_mode == WatcherMode.ASCII_TREE:
            print("")
            print(
                py_trees.display.ascii_tree(
                    root=root,
                    show_status=True,
                    visited=self.snapshot_visitor.visited,
                    previously_visited=self.snapshot_visitor.previously_visited
                ))
            self.done = True
        ####################
        # Dot Graph
        ####################
        elif self.viewing_mode == WatcherMode.DOT_TREE and not self.rendered:
            self.rendered = True
            directory_name = tempfile.mkdtemp()
            py_trees.display.render_dot_tree(root=root,
                                             target_directory=directory_name)
            xdot_program = py_trees.utilities.which('xdot')

            if not xdot_program:
                console.logerror(
                    "No xdot viewer found, skipping display [hint: sudo apt install xdot]"
                )
                print(py_trees.display.dot_graph(root=root).to_string())
                self.done = True
                self.xdot_process = 1
                return

            filename = py_trees.utilities.get_valid_filename(
                root.name) + '.dot'
            if xdot_program:
                try:
                    self.xdot_process = subprocess.Popen(
                        [xdot_program,
                         os.path.join(directory_name, filename)])
                except KeyboardInterrupt:
                    pass
            self.done = True
Example #6
0
    def callback_snapshot(self, msg):
        """
        Formats the string message coming in.

        Args
            msg (:class:`py_trees_ros_interfaces.msg.BehaviourTree`):serialised snapshot
        """
        ####################
        # Processing
        ####################
        self.snapshot_visitor.previously_visited = self.snapshot_visitor.visited
        self.snapshot_visitor.visited = {}
        serialised_behaviours = {}
        root_id = None
        for serialised_behaviour in msg.behaviours:
            if serialised_behaviour.parent_id == unique_identifier_msgs.UUID():
                root_id = conversions.msg_to_uuid4(serialised_behaviour.own_id)
            serialised_behaviours[conversions.msg_to_uuid4(
                serialised_behaviour.own_id)] = serialised_behaviour

        def deserialise_tree_recursively(msg):
            behaviour = conversions.msg_to_behaviour(msg)
            for serialised_child_id in msg.child_ids:
                child_id = conversions.msg_to_uuid4(serialised_child_id)
                child = deserialise_tree_recursively(
                    serialised_behaviours[child_id])
                # invasive hack to revert the dummy child we added in msg_to_behaviour
                if isinstance(behaviour, py_trees.decorators.Decorator):
                    behaviour.children = [child]
                    behaviour.decorated = behaviour.children[0]
                else:
                    behaviour.children.append(child)
                child.parent = behaviour
            # set the current child so tip() works properly everywhere
            if behaviour.children:
                if msg.current_child_id != unique_identifier_msgs.UUID():
                    current_child_id = conversions.msg_to_uuid4(
                        msg.current_child_id)
                    for index, child in enumerate(behaviour.children):
                        if child.id == current_child_id:
                            # somewhat ugly not having a consistent api here
                            if isinstance(behaviour,
                                          py_trees.composites.Selector):
                                behaviour.current_child = child
                            elif isinstance(behaviour,
                                            py_trees.composites.Chooser):
                                behaviour.current_child = child
                            elif isinstance(behaviour,
                                            py_trees.composites.Sequence):
                                behaviour.current_index = index
                            # else Parallel, nothing to do since it infers
                            # the current child from children's status on the fly
                            break
            if msg.is_active:
                self.snapshot_visitor.visited[behaviour.id] = behaviour.status
            return behaviour

        # we didn't set the tip in any behaviour, but nothing depends
        # on that right now
        root = deserialise_tree_recursively(serialised_behaviours[root_id])

        ####################
        # Streaming
        ####################
        if self.viewing_mode == WatcherMode.STREAM:
            console.banner("Tick {}".format(msg.statistics.count))
            print(
                py_trees.display.unicode_tree(
                    root=root,
                    visited=self.snapshot_visitor.visited,
                    previously_visited=self.snapshot_visitor.previously_visited
                ))
            print(console.green + "-" * 80 + "\n" + console.reset)
            print("Timestamp: {}".format(
                conversions.rclpy_time_to_float(
                    rclpy.time.Time.from_msg(msg.statistics.stamp))))
            print("Duration : {:.3f}/{:.3f}/{:.3f} (ms) [time/avg/stddev]".
                  format(
                      msg.statistics.tick_duration * 1000,
                      msg.statistics.tick_duration_average * 1000,
                      math.sqrt(msg.statistics.tick_duration_variance) * 1000))
            print(
                "Interval : {:.3f}/{:.3f}/{:.3f} (s) [time/avg/stddev]".format(
                    msg.statistics.tick_interval,
                    msg.statistics.tick_interval_average,
                    math.sqrt(msg.statistics.tick_interval_variance)))

        ####################
        # Printing
        ####################
        elif self.viewing_mode == WatcherMode.SNAPSHOT:
            print("")
            print(
                py_trees.display.unicode_tree(
                    root=root,
                    show_status=True,
                    visited=self.snapshot_visitor.visited,
                    previously_visited=self.snapshot_visitor.previously_visited
                ))
            self.done = True
        ####################
        # Dot Graph
        ####################
        elif self.viewing_mode == WatcherMode.DOT_GRAPH and not self.rendered:
            self.rendered = True
            directory_name = tempfile.mkdtemp()
            py_trees.display.render_dot_tree(root=root,
                                             target_directory=directory_name)
            xdot_program = py_trees.utilities.which('xdot')

            if not xdot_program:
                print("")
                console.logerror(
                    "No xdot viewer found [hint: sudo apt install xdot]")
                print("")
                print(py_trees.display.dot_tree(root=root).to_string())
                self.done = True
                self.xdot_process = None
                return

            filename = py_trees.utilities.get_valid_filename(
                root.name) + '.dot'
            if xdot_program:
                try:
                    self.xdot_process = subprocess.Popen(
                        [xdot_program,
                         os.path.join(directory_name, filename)])
                except KeyboardInterrupt:
                    pass
            self.done = True