Giter Club home page Giter Club logo

fzi-forschungszentrum-informatik / ros2_ros_bt_py Goto Github PK

View Code? Open in Web Editor NEW
24.0 3.0 6.0 3.68 MB

This is a Behavior Tree library meant to be an alternative to SMACH, FlexBE and the like. It includes a ReactJS-based web GUI and all the building blocks you need to build moderately advanced mission control Behavior Trees without writing a single line of code!

License: BSD 3-Clause "New" or "Revised" License

Makefile 1.24% Python 97.53% CMake 1.07% HTML 0.15%
behavior-tree ros2

ros2_ros_bt_py's Introduction

Welcome to ros_bt_py!

ROS Industrial CI codecov Documentation

This is a Behavior Tree library meant to be an alternative to BehaviorTree.cpp, SMACH, FlexBE and the like.

It includes a ReactJS-based web GUI and all the building blocks you need to build moderately advanced mission control Behavior Trees without writing a single line of code!

Documentation

The main documentation effort is found in the docfolder. Simply execute the following commands in your shell to get browsable HTML documentation, including some tutorials:

$ cd ros_bt_py/doc
$ make html
$ cd build
$ python -m http.server & xdg-open http://localhost:8000/html

Installation

To actually start using ros_bt_py, you need to install its dependencies first:

$ cd colcon_workspace
$ rosdep install --from-paths src --ignore-src -r -y

Then you can just build the package with your prefered method i.e. colcon build

Note: Do not build the workspace using --symlink-install as this is currently not working with generate_parameter_library. You will get an error when running ModuleNotFoundError: No module named 'ros_bt_py.parameters'.

Running

The command

$ ros2 launch ros_bt_py ros_bt_py.launch.py enable_web_interface:=True

will start a BT server and the rosbridge and webserver needed for the GUI. Afterwards, you can open http://localhost:8085/index.html to use the editor.

Launch Options

Launch Argument Description Default Value
robot_namespace Namespace to launch all ros_bt_py nodes in! /
node_modules List of python packages that contain nodes to be loaded on startup. "['ros_bt_py.nodes','ros_bt_py.ros_nodes']"
enable_web_interface Start web GUI on startup. False
show_traceback_on_exception Show error traceback when an exception rises. True
diagnostics_frequency_hz Publishing frequency for diagnostics msgs. 1.0
load_default_tree Load the default tree on startup! False
load_default_tree_permissive Load the default tree in permissive mode on startup! False
default_tree_path Path to the default tree to load on startup!
default_tree_tick_frequency_hz Frequency with which to tick the default tree loaded on startup! 10.0
default_tree_control_command Command to execute per default after loading the default tree on startup! 2
web_server_port Port to use for the web interface. 8085
web_server_address IP address to use for the web interface. Default value uses all IP addresses of the host. 0.0.0.0

Stand-alone Web Interface

The web interface can be launched stand alone of the library, using the following command:

$ ros2 launch ros_bt_py_web_gui ros_bt_py_web_gui.launch.py web_server_port:=8085 web_server_address:=0.0.0.0

ros2_ros_bt_py's People

Contributors

fmauch avatar mdeitersen avatar nspielbau avatar oberacda avatar t-schnell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ros2_ros_bt_py's Issues

Custom Default Options

For Custom Nodes, most of the time, the option default values are the same in (nearly) all use-cases, so they should be modifiable during node definition.

Idea: Modify node generation decorator

Cleanup architecture

Refactor architecture to cleanup dependencies and so on...
Currently, things look like this:

image

Flake8 configs for humble/iron/rolling are incompatible.

ament_lint configs provided in ROS2 rolling are incompatible with the configs for humble / iron.
For now, we opted to ignore the result of the checks under rolling, but we should find a permanent solution.

build/ros_bt_py_web_gui/Testing/20231218-1357/Test.xml: 4 tests, 0 errors, 1 failure, 0 skipped
- flake8
  <<< failure message
    -- run_test.py: invoking following command in '/root/target_ws/src/ros_bt_py/ros_bt_py_web_gui':
     - /opt/ros/rolling/bin/ament_flake8 --xunit-file /root/target_ws/build/ros_bt_py_web_gui/test_results/ros_bt_py_web_gui/flake8.xunit.xml
    
    ./launch/ros_bt_py_web_gui.launch.py:38:1: I100 Import statements are in the wrong order. 'from launch_ros.actions import Node' should be before 'from launch_ros.substitutions import FindPackageShare'
    from launch_ros.actions import Node
    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:42:49: Q000 Double quotes found but single quotes preferred
        web_server_port_value = LaunchConfiguration("web_server_port")
                                                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:44:9: Q000 Double quotes found but single quotes preferred
            "web_server_port",
            ^
    
    ./launch/ros_bt_py_web_gui.launch.py:45:23: Q000 Double quotes found but single quotes preferred
            default_value="8085",
                          ^
    
    ./launch/ros_bt_py_web_gui.launch.py:46:21: Q000 Double quotes found but single quotes preferred
            description="Port to use for the web server, serving the ros_bt_py web gui.",
                        ^
    
    ./launch/ros_bt_py_web_gui.launch.py:49:52: Q000 Double quotes found but single quotes preferred
        web_server_address_value = LaunchConfiguration("web_server_address")
                                                       ^
    
    ./launch/ros_bt_py_web_gui.launch.py:51:9: Q000 Double quotes found but single quotes preferred
            "web_server_address",
            ^
    
    ./launch/ros_bt_py_web_gui.launch.py:52:23: Q000 Double quotes found but single quotes preferred
            default_value="0.0.0.0",
                          ^
    
    ./launch/ros_bt_py_web_gui.launch.py:53:21: Q000 Double quotes found but single quotes preferred
            description="Network address to use for the web server, serving the ros_bt_py web gui.",
                        ^
    
    ./launch/ros_bt_py_web_gui.launch.py:55:59: Q000 Double quotes found but single quotes preferred
        web_folder = os.path.join(get_package_share_directory("ros_bt_py_web_gui"), "html")
                                                              ^
    
    ./launch/ros_bt_py_web_gui.launch.py:55:81: Q000 Double quotes found but single quotes preferred
        web_folder = os.path.join(get_package_share_directory("ros_bt_py_web_gui"), "html")
                                                                                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:60:17: Q000 Double quotes found but single quotes preferred
                    "python3 ",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:61:17: Q000 Double quotes found but single quotes preferred
                    "-m http.server ",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:62:17: Q000 Double quotes found but single quotes preferred
                    "-b ",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:64:17: Q000 Double quotes found but single quotes preferred
                    " -d ",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:66:17: Q000 Double quotes found but single quotes preferred
                    " ",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:76:34: Q000 Double quotes found but single quotes preferred
                    FindPackageShare("rosbridge_server"),
                                     ^
    
    ./launch/ros_bt_py_web_gui.launch.py:77:17: Q000 Double quotes found but single quotes preferred
                    "/launch",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:78:17: Q000 Double quotes found but single quotes preferred
                    "/rosbridge_websocket_launch.xml",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:84:17: Q000 Double quotes found but single quotes preferred
            package="ros_bt_py_web_gui",
                    ^
    
    ./launch/ros_bt_py_web_gui.launch.py:85:19: Q000 Double quotes found but single quotes preferred
            namespace="ros_bt_py_web_gui",
                      ^
    
    ./launch/ros_bt_py_web_gui.launch.py:86:20: Q000 Double quotes found but single quotes preferred
            executable="show_editor_url.py",
                       ^
    
    ./launch/ros_bt_py_web_gui.launch.py:87:14: Q000 Double quotes found but single quotes preferred
            name="show_editor_url",
                 ^
    
    ./launch/ros_bt_py_web_gui.launch.py:89:14: Q000 Double quotes found but single quotes preferred
                {"hostname": web_server_address_value},
                 ^
    
    ./launch/ros_bt_py_web_gui.launch.py:90:14: Q000 Double quotes found but single quotes preferred
                {"port": web_server_port_value},
                 ^
    
    ./scripts/show_editor_url.py:31:1: I201 Missing newline between import groups. 'import rclpy' is identified as Third Party and 'from typing import List' is identified as Stdlib.
    import rclpy
    ^
    
    ./scripts/show_editor_url.py:34:1: I101 Imported names are in the wrong order. Should be AF_INET, ifaddresses, interfaces
    from netifaces import interfaces, ifaddresses, AF_INET
    ^
    
    ./scripts/show_editor_url.py:34:1: I100 Import statements are in the wrong order. 'from netifaces import interfaces, ifaddresses, AF_INET' should be before 'from rclpy.node import Node'
    from netifaces import interfaces, ifaddresses, AF_INET
    ^
    
    ./scripts/show_editor_url.py:42:37: Q000 Double quotes found but single quotes preferred
                    ip_list.append(link["addr"])
                                        ^
    
    ./scripts/show_editor_url.py:49:41: Q000 Double quotes found but single quotes preferred
        hostname_param = node.get_parameter("hostname")
                                            ^
    
    ./scripts/show_editor_url.py:50:37: Q000 Double quotes found but single quotes preferred
        port_param = node.get_parameter("port")
                                        ^
    
    ./scripts/show_editor_url.py:55:20: Q000 Double quotes found but single quotes preferred
        if hostname == "0.0.0.0":
                       ^
    
    ./scripts/show_editor_url.py:60:14: Q000 Double quotes found but single quotes preferred
        suffix = f":{port}/index.html"
                 ^
    
    ./scripts/show_editor_url.py:64:27: Q000 Double quotes found but single quotes preferred
            hostname_prefix = f"# http://{hostname}"
                              ^
    
    ./scripts/show_editor_url.py:65:55: Q000 Double quotes found but single quotes preferred
            hostname_len = len(hostname_prefix + suffix + " #")
                                                          ^
    
    ./scripts/show_editor_url.py:71:19: Q000 Double quotes found but single quotes preferred
        padding_str = "{:#>{w}}".format("", w=max_hostname_len)
                      ^
    
    ./scripts/show_editor_url.py:71:37: Q000 Double quotes found but single quotes preferred
        padding_str = "{:#>{w}}".format("", w=max_hostname_len)
                                        ^
    
    ./scripts/show_editor_url.py:74:32: Q000 Double quotes found but single quotes preferred
            hostname_padding_str = "{: >{w}}".format(
                                   ^
    
    ./scripts/show_editor_url.py:75:13: Q000 Double quotes found but single quotes preferred
                "", w=max_hostname_len - len(hostname_prefix) - len(suffix) - 2
                ^
    
    ./scripts/show_editor_url.py:77:59: Q000 Double quotes found but single quotes preferred
            node.get_logger().info(hostname_prefix + suffix + f"{hostname_padding_str} #")
                                                              ^
    
    ./scripts/show_editor_url.py:84:17: Q000 Double quotes found but single quotes preferred
        node = Node("url_printer")
                    ^
    
    ./scripts/show_editor_url.py:86:19: Q000 Double quotes found but single quotes preferred
            namespace="",
                      ^
    
    ./scripts/show_editor_url.py:88:14: Q000 Double quotes found but single quotes preferred
                ("hostname", rclpy.Parameter.Type.STRING),
                 ^
    
    ./scripts/show_editor_url.py:89:14: Q000 Double quotes found but single quotes preferred
                ("port", rclpy.Parameter.Type.INTEGER),
                 ^
    
    ./scripts/show_editor_url.py:96:16: Q000 Double quotes found but single quotes preferred
    if __name__ == "__main__":
                   ^
    
    2     I100 Import statements are in the wrong order. 'from launch_ros.actions import Node' should be before 'from launch_ros.substitutions import FindPackageShare'
    1     I101 Imported names are in the wrong order. Should be AF_INET, ifaddresses, interfaces
    1     I201 Missing newline between import groups. 'import rclpy' is identified as Third Party and 'from typing import List' is identified as Stdlib.
    41    Q000 Double quotes found but single quotes preferred
    
    2 files checked
    45 errors
    
    'I'-type errors: 4
    'Q'-type errors: 41
    
    Checked files:
    
    * ./launch/ros_bt_py_web_gui.launch.py
    * ./scripts/show_editor_url.py
    -- run_test.py: return code 1
    -- run_test.py: verify result file '/root/target_ws/build/ros_bt_py_web_gui/test_results/ros_bt_py_web_gui/flake8.xunit.xml'
  >>>
build/ros_bt_py_web_gui/test_results/ros_bt_py_web_gui/flake8.xunit.xml: 45 tests, 0 errors, 45 failures, 0 skipped
- ros_bt_py_web_gui.flake8 I100 (./launch/ros_bt_py_web_gui.launch.py:38:1)
  <<< failure message
    Import statements are in the wrong order. 'from launch_ros.actions import Node' should be before 'from launch_ros.substitutions import FindPackageShare':
    from launch_ros.actions import Node
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:42:49)
  <<< failure message
    Double quotes found but single quotes preferred:
        web_server_port_value = LaunchConfiguration("web_server_port")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:44:9)
  <<< failure message
    Double quotes found but single quotes preferred:
            "web_server_port",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:45:23)
  <<< failure message
    Double quotes found but single quotes preferred:
            default_value="8085",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:46:21)
  <<< failure message
    Double quotes found but single quotes preferred:
            description="Port to use for the web server, serving the ros_bt_py web gui.",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:49:52)
  <<< failure message
    Double quotes found but single quotes preferred:
        web_server_address_value = LaunchConfiguration("web_server_address")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:51:9)
  <<< failure message
    Double quotes found but single quotes preferred:
            "web_server_address",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:52:23)
  <<< failure message
    Double quotes found but single quotes preferred:
            default_value="0.0.0.0",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:53:21)
  <<< failure message
    Double quotes found but single quotes preferred:
            description="Network address to use for the web server, serving the ros_bt_py web gui.",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:55:59)
  <<< failure message
    Double quotes found but single quotes preferred:
        web_folder = os.path.join(get_package_share_directory("ros_bt_py_web_gui"), "html")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:55:81)
  <<< failure message
    Double quotes found but single quotes preferred:
        web_folder = os.path.join(get_package_share_directory("ros_bt_py_web_gui"), "html")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:60:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    "python3 ",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:61:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    "-m http.server ",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:62:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    "-b ",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:64:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    " -d ",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:66:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    " ",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:76:34)
  <<< failure message
    Double quotes found but single quotes preferred:
                    FindPackageShare("rosbridge_server"),
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:77:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    "/launch",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:78:17)
  <<< failure message
    Double quotes found but single quotes preferred:
                    "/rosbridge_websocket_launch.xml",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:84:17)
  <<< failure message
    Double quotes found but single quotes preferred:
            package="ros_bt_py_web_gui",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:85:19)
  <<< failure message
    Double quotes found but single quotes preferred:
            namespace="ros_bt_py_web_gui",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:86:20)
  <<< failure message
    Double quotes found but single quotes preferred:
            executable="show_editor_url.py",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:87:14)
  <<< failure message
    Double quotes found but single quotes preferred:
            name="show_editor_url",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:89:14)
  <<< failure message
    Double quotes found but single quotes preferred:
                {"hostname": web_server_address_value},
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./launch/ros_bt_py_web_gui.launch.py:90:14)
  <<< failure message
    Double quotes found but single quotes preferred:
                {"port": web_server_port_value},
  >>>
- ros_bt_py_web_gui.flake8 I201 (./scripts/show_editor_url.py:31:1)
  <<< failure message
    Missing newline between import groups. 'import rclpy' is identified as Third Party and 'from typing import List' is identified as Stdlib.:
    import rclpy
  >>>
- ros_bt_py_web_gui.flake8 I101 (./scripts/show_editor_url.py:34:1)
  <<< failure message
    Imported names are in the wrong order. Should be AF_INET, ifaddresses, interfaces:
    from netifaces import interfaces, ifaddresses, AF_INET
  >>>
- ros_bt_py_web_gui.flake8 I100 (./scripts/show_editor_url.py:34:1)
  <<< failure message
    Import statements are in the wrong order. 'from netifaces import interfaces, ifaddresses, AF_INET' should be before 'from rclpy.node import Node':
    from netifaces import interfaces, ifaddresses, AF_INET
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:42:37)
  <<< failure message
    Double quotes found but single quotes preferred:
                    ip_list.append(link["addr"])
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:49:41)
  <<< failure message
    Double quotes found but single quotes preferred:
        hostname_param = node.get_parameter("hostname")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:50:37)
  <<< failure message
    Double quotes found but single quotes preferred:
        port_param = node.get_parameter("port")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:55:20)
  <<< failure message
    Double quotes found but single quotes preferred:
        if hostname == "0.0.0.0":
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:60:14)
  <<< failure message
    Double quotes found but single quotes preferred:
        suffix = f":{port}/index.html"
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:64:27)
  <<< failure message
    Double quotes found but single quotes preferred:
            hostname_prefix = f"# http://{hostname}"
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:65:55)
  <<< failure message
    Double quotes found but single quotes preferred:
            hostname_len = len(hostname_prefix + suffix + " #")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:71:19)
  <<< failure message
    Double quotes found but single quotes preferred:
        padding_str = "{:#>{w}}".format("", w=max_hostname_len)
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:71:37)
  <<< failure message
    Double quotes found but single quotes preferred:
        padding_str = "{:#>{w}}".format("", w=max_hostname_len)
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:74:32)
  <<< failure message
    Double quotes found but single quotes preferred:
            hostname_padding_str = "{: >{w}}".format(
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:75:13)
  <<< failure message
    Double quotes found but single quotes preferred:
                "", w=max_hostname_len - len(hostname_prefix) - len(suffix) - 2
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:77:59)
  <<< failure message
    Double quotes found but single quotes preferred:
            node.get_logger().info(hostname_prefix + suffix + f"{hostname_padding_str} #")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:84:17)
  <<< failure message
    Double quotes found but single quotes preferred:
        node = Node("url_printer")
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:86:19)
  <<< failure message
    Double quotes found but single quotes preferred:
            namespace="",
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:88:14)
  <<< failure message
    Double quotes found but single quotes preferred:
                ("hostname", rclpy.Parameter.Type.STRING),
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:89:14)
  <<< failure message
    Double quotes found but single quotes preferred:
                ("port", rclpy.Parameter.Type.INTEGER),
  >>>
- ros_bt_py_web_gui.flake8 Q000 (./scripts/show_editor_url.py:96:16)
  <<< failure message
    Double quotes found but single quotes preferred:
    if __name__ == "__main__":
  >>>
Summary: 158 tests, 0 errors, 46 failures, 0 skipped

Ici results cannot be used in test result publisher because GitHub Variables Change.

Bug Report

Description

Currently, we run the ROS Industrial CI to build & test the code in the package.
The ici is supposed to put all build files in the folder ${{ github.workspace }}/.build.

The subsequent action to publish the test results fails because the two input paths are evaluated differently:

 - name: Publish Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: always()
        with:
          files: |
            ${{ env.basedir }}/.build/target_ws/build/ros_bt_py/pytest.xml
            ${{ env.basedir }}/.build/target_ws/build/**/*xunit.xml

      - name: Code Coverage Report
        uses: irongut/[email protected]
        with:
          filename: ${{ env.basedir }}/.build/target_ws/build/ros_bt_py/coverage.xml

Screenshot from 2023-12-19 09-26-14
image

This seems to be an issue in the GitHub action runners.

Automatically Shut Down the Tree when something is Faulty

Feature Request

Description

When there is an Error in performing the tick, like an unset input, it would be nice if the tree could immediately go into shutdown so one could start fixing the error without first shutting down the tree. The current behaviour is still helpful for debugging but is used less often, so maybe we could make this configurable?

Implement capabilities

Currently, capabilities as dynamically dispatched subtrees are only present in the ROS1 version. We should also implement them in the ROS2 version.

💡 [REQUEST] - FileAndTopicLog

Implementation PR

No response

Reference Issues

No response

Summary

FileAndTopicLog was proven to be superb in giving live insight in the running BT without using the webgui and having a persistent logfile to retrace what's going on.
Implementing different log messages can be a pain tho, as it might require its own decision trees.
Idea:

  • Every Node can specify logmsgs to be logged on events (on_setup/on_tick/on_shutdown/...)
  • Logger as Decorator with options on which events of the child should be logged
  • FLA logging might be an option

Basic Example

Drawbacks

Unresolved questions

No response

Define documentation methods and locations

Currently, we have 2 separate documentation instances:

  • Gitlab Wiki
  • Sphinx Doc

We should make sure that there are solid definitions in place of what they contain and how to reduce confusion by not having stuff documented twice.

Documenation: How do I use this?

This package already contains documentation on how to build and start it and how to write own nodes, but it doesn't contain any instructions for newcomers.

  • How do I create a new tree?
  • Where do I start / What kind of options for a root node do I have?
  • How do I use the web GUI? Where do I add inputs, etc

I think a tutorial on building an example tree and explaining all the steps along the way would be very handy.

Add versioning

To make backward compatibility more obvious, we established a versioning system similar to semantic versioning (MAJOR.MINOR.PATCH).
Due to the obvious conflict that will arise between ROS 1 and 2, we are making a small shift to ROSVERSION.MAJOR.MINOR with a minor cap at 10 (x.x.10 would instead be x.x+1.0).
Version 1.0.0 will be the current main before capabilities are introduced.
Dev syncs will normally increase the MINOR, but larger features like capabilities will directly increase the MAJOR.
Version 2.0.0 will be the first stable ROS 2 release (this is TBD) and will follow the same pattern afterwards.

Add Best Practice Documentation to README/Wiki/Tutorials

To make BTs easier to get into we should add more best practice and HowTos to the Wiki, this includes but is not limited to common design patterns, how a "good" tree structure looks like and how to start with building more complicated trees

New Action/Service Creation

In the BT Workshop, an idea was introduced to modify actions and services in a way that all goal/result fields are available as inputs/outputs and you can decide while building the BT which of those you want to set and which to set as an option. This requires a major overhaul of how nodes are actually generated but might be a good feature to reduce GetAttr/SetAttr patterns without custom node usage

Static Check for unset inputs

Currently, only unconnected inputs are detected when checking the tree before ticking starts. We want to expand this to also check for unset inputs.

🐛 [BUG] - WebGUI launch failed

Description

[show_editor_url.py-4] /usr/bin/env: ‘python’: No such file or directory

Fix: sudo apt install python-is-python3

Reproduction URL

https://github.com/fzi-forschungszentrum-informatik

Reproduction steps

1. Launch Webgui

Screenshots

No response

Logs

→ ros2 launch ros_bt_py_web_gui ros_bt_py_web_gui.launch.py web_server_port:=8085 web_server_address:=0.0.0.0
[INFO] [launch]: All log files can be found below /home/keller/.ros/log/2024-02-22-10-06-36-956152-sinkbrettle-26949
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [html 8085-1]: process started with pid [26950]
[INFO] [rosbridge_websocket-2]: process started with pid [26952]
[INFO] [rosapi_node-3]: process started with pid [26955]
[INFO] [show_editor_url.py-4]: process started with pid [26957]
[show_editor_url.py-4] /usr/bin/env: ‘python’: No such file or directory
[ERROR] [show_editor_url.py-4]: process has died [pid 26957, exit code 127, cmd ‘/home/keller/checkout/cordenka/colcon_ws/install/ros_bt_py_web_gui/lib/ros_bt_py_web_gui/show_editor_url.py --ros-args -r __node:=show_editor_url -r __ns:=/ros_bt_py_web_gui --params-file /tmp/launch_params_za5taa4p --params-file /tmp/launch_params_zujn57a5’].
[rosbridge_websocket-2] [INFO] [1708592798.318226208] [rosbridge_websocket]: Rosbridge WebSocket server started on port 9090
^C[WARNING] [launch]: user interrupted with ctrl-c (SIGINT)
[rosbridge_websocket-2] registered capabilities (classes):
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.call_service.CallService’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.advertise.Advertise’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.publish.Publish’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.subscribe.Subscribe’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.defragmentation.Defragment’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.advertise_service.AdvertiseService’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.service_response.ServiceResponse’>
[rosbridge_websocket-2] - <class ‘rosbridge_library.capabilities.unadvertise_service.UnadvertiseService’>
[rosbridge_websocket-2] Exiting due to SIGINT
[ERROR] [html 8085-1]: process has died [pid 26950, exit code -2, cmd ‘python3 -m http.server -b 0.0.0.0 -d /home/keller/checkout/cordenka/colcon_ws/install/ros_bt_py_web_gui/share/ros_bt_py_web_gui/html 8085’].
[INFO] [rosapi_node-3]: process has finished cleanly [pid 26955]
[INFO] [rosbridge_websocket-2]: process has finished cleanly [pid 26952]

ROS2 Version

Humble

OS

Ubuntu 22.04

Design Patterns

Provide Documentation and common Handling of:

  • if elif else
  • for loops
  • while loops
  • do while
  • try except

Other situations:

  • process user input (e.g. by topics to enable functionality like "stop everything and do xyz next"; should be parallel to the normal BT execution)
  • detect and return a failure to the parent node, but execute some cleanup procedures beforehand
  • a short guideline on when to use a ros action and when to implement it as a BT subtree
  • what to do when the target ticking rate is not achieved
  • BT interaction using services

comprehensible compact git versioning should be ensured

renaming nodes, modifying constants, etc. lead to many changes in the corresponding yaml files (eg. renaming "ProcessSubtree" to "ProcessSubtree1")
git diffs and commits cannot be quickly checked with such a behavior. it seems a more deterministic file saving process is required. An important point is to ensure comparability for reading existing trees and allowing them to migrate to any new strategy.

RQT GUI for Diagnostics

For only running existing trees and observing their execution the Web GUI is often unsuited and too slow.
Also the console output can be hard to track sometimes.
One solution could be a RQT GUI that shows the current status of the tree on a certain ip and the tick frequency topic (And maybe more!)

Add automatic GUI deployment

Once the web GUI has an additional repo we want to automatically deploy it using a GitHub workflow.

  • Automated CI deployment via MR into the main BT repo

Change control_execution service interface into an action based one

Feature Request

Description

This will allow the reporting of feedback on which nodes are getting setup/ticked at the moment and will allow a user to abort setup/execution that takes too long.
The service interface should still be available after the conversion, using the new actions "under the hood," allowing the new behaviour to be tested with the current assumptions

GetAttr can't access int16[] field as list

Bug report

Bug Description

Let's say we have a service response that has a single int16[] field in its definition.

int16[] numbers

When trying to access the whole field as a list, it fails:

TypeError: Expected data to be of type list, got tuple instead

Field can be accessed as a builtin.tuple, but in most other cases it can be accessed as a list

Minimal Example

Mockingly the left setup (getting the list from a constant) succeeds, the right one (getting the list from the service response) fails
image

Urgency

Not very urgent, easily worked around

{} creates empty set instead of dict

When creating a new node in the web editor that has options the folliwng error appears:

[tree_node-1] Traceback (most recent call last):
[tree_node-1]   File "/home/doberacker/repos/ros_ws/ros2_ros_bt_py/colcon_ws/install/ros_bt_py/lib/ros_bt_py/tree_node", line 33, in <module>
[tree_node-1]     sys.exit(load_entry_point('ros-bt-py==0.1.0', 'console_scripts', 'tree_node')())
[tree_node-1]   File "/home/doberacker/repos/ros_ws/ros2_ros_bt_py/colcon_ws/install/ros_bt_py/lib/python3.10/site-packages/ros_bt_py/tree_node.py", line 424, in main
[tree_node-1]     executor.spin()
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 279, in spin
[tree_node-1]     self.spin_once()
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 764, in spin_once
[tree_node-1]     self._spin_once_impl(timeout_sec)
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 761, in _spin_once_impl
[tree_node-1]     future.result()
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/task.py", line 94, in result
[tree_node-1]     raise self.exception()
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/task.py", line 239, in __call__
[tree_node-1]     self._handler.send(None)
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 418, in handler
[tree_node-1]     await call_coroutine(entity, arg)
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 372, in _execute_service
[tree_node-1]     response = await await_or_execute(srv.callback, request, srv.srv_type.Response())
[tree_node-1]   File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 107, in await_or_execute
[tree_node-1]     return callback(*args)
[tree_node-1]   File "/home/doberacker/repos/ros_ws/ros2_ros_bt_py/colcon_ws/install/ros_bt_py/lib/python3.10/site-packages/ros_bt_py/tree_manager.py", line 105, in service_handler
[tree_node-1]     return func(self, request, response, **kwds)
[tree_node-1]   File "/home/doberacker/repos/ros_ws/ros2_ros_bt_py/colcon_ws/install/ros_bt_py/lib/python3.10/site-packages/ros_bt_py/tree_manager.py", line 1655, in set_options
[tree_node-1]     for key, value in deserialized_options.items():
[tree_node-1] AttributeError: 'set' object has no attribute 'items'
[tree_node-1] The following exception was never retrieved: cannot use Destroyable because destruction was requested

Variable Number of Parameters

Feature Request

Description

A variable number of Options, Inputs or Outputs could be a huge benefit for some nodes.
For example, a single Constant node instead of 20 different ones or a variable number of inputs for an addition.
This request might be more challenging to realize than I would like... let's see what's required for something like that.

Subtrees/Trees should actually be selectable like a node

The current way of using a subtree is rather complex. It would be cool if the trees or subtrees could be the same as every other Node in the selection list.
Of course, it would be good to separate them optically, just as with the flow nodes.

Tree breaks if message definition changes

When a tree has an explicit message definition inside of it (constant, etc.), the tree will break if the message is updated to have more fields. The changed message definition is already caught by bt_py, so why not offer some sort of migration?

Allow all nodes/modules of a package to be loaded

Feature Request

Description

Right now, we only support loading specific modules; we should also allow the loading of all nodes/modules of a package.
Additionally, loading only a specific node of a module should probably be supported as well.

Testing Strategy

A lot of our current testing just tries to execute examples, but some of them rely on weird timings or other easily breaking parameters and should be reworked.

For that we need to discuss:

  • What are the goals of our testing
  • How to write good tests

Subtrees without IOs change the Tree state

So, adding a Subtree without IOs is weird.
When just adding it to a sequence as the SINGLE node. Everything is fine. Upon updating the Node, the inputs are added, and everything is as expected.

But, instead of first adding two constants to the Sequence while it is SHUTDOWN, giving them values, etc., then adding the Subtree, the tree will change in the overall state IDLE while leaving the subtree UNINITAILIZED. This leads to a bug because the subtree can not be initialized, but the tree can not be shut down as there are uninitialized nodes.

Steps to Reproduce:

  • Create a subtree with inputs (I used the multiply example from the tutorial)
  • Create a new tree
  • add a sequence
  • add two constants, update their type and value
    -- The nodes are added as UNITIALIZED (Grey)
    subtree_1
  • Add a subtree
    -- Disable "use_io_nodes" and point it to the created subtree
  • Press update node
  • The two constant values will now be in IDLE while the whole tree is in Shutdown (editable) and the subtree is in uninitialized

subtree_2

  • Connecting the inputs works. But starting does not:
    BehaviorTreeException: Calling setup() is only allowed in states UNINITIALIZED and SHUTDOWN, but node Constant is in state IDLE
  • Shutdown is also disabled:
    Constant_2 (Constant), state: IDLENot all children are shut down after calling shutdown(). List of not-shutdown children and states:

Subtree (Subtree), state: UNINITIALIZED

Constant input might be a good idea

Feature Request

Description

In some cases, a constant input is required. Of course, we can use an extra node, but setting some input to a constant might be useful.
Example: The service node with an empty service.
Allowing users to set inputs to constants might reduce boilerplate nodes and node duplication (Service vs ServiceOption).
It might be useful to allow an input to be set via static value or external data connection.
However, I would prefer a switch for each input on the node to determine which input source should be used.

Substitute Subtrees with Capabilities

To avoid Capabilities being forgotten and left in an unusable state the long-term goal is to make capabilities a drop-in replacement for subtrees in the future.

For that:

  • Usability should be similar to subtrees (little to no overhead)
  • Capabilities should be observable in GUI (Either through the "Publish Subtrees" already in place or better through expanding them in the Editor)

Related to #20

Data Wiring duplication check seems to not delete Date when moving/deleting Nodes

Bug Report

Description

When constructing a tree, adding the wiring works, then removing a node, adding it again and re-adding the wiring fails with the error:

"Failed to wire data null to null: {
    "error_message": "Failed to execute wiring "source: \n node_name: "TopicSubscriber"\n data_kind: "outputs"\n data_key: "message"\ntarget: \n node_name: "MessageToFields"\n data_kind: "inputs"\n data_key: "in"": Duplicate subscription!",
     "success": false
}"

It seems that the check for duplicate subscriptions is not reset.
This Error persists even when Removing and Adding the Nodes in question again.

Removing the source node also resolved the issue.
The faulty connection persisted into a tree yaml on disk.

06_topic_subscriber.yaml.txt

💡 [REQUEST] - TF Lookup fixes

Implementation PR

No response

Reference Issues

No response

Summary

We did a fix on this in the ROS 1 version and should port it to the ROS 2 Version

Basic Example

fixed errors for tf lookup and returns error message if lookup fails

Drawbacks

None

Unresolved questions

No response

Improve Node Naming Scheme

The current naming scheme for nodes is not always consistent. Changing the naming convention will probably not be backwards compatible, so we should consider how we would want to introduce this.
Known Issues with the current scheme:

  • Repeat and Repeat Always are not consistent
  • Option and Input Suffixes are not consistent

Create Node Libraries

To have an easy way to access all nodes that are already built and ready to use in projects we want to create a Library.
This should start with the Nodes natively shipped with ros_bt_py but should be extendable with other node packages.

Node Idea: Enum Switch

Node request

Node Description

Similar to the NameSwitch Node, an EnumSwitch with the input being an int would be nice because strings are not that common in switch-case type scenarios

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.