diff --git a/docs/custom.css b/docs/custom.css index 97c6fd4d..facce85d 100644 --- a/docs/custom.css +++ b/docs/custom.css @@ -1,3 +1,3 @@ .tight-table td { white-space: normal !important -} \ No newline at end of file +} diff --git a/docs/dictionary.txt b/docs/dictionary.txt index 105b5501..ec11f1be 100644 --- a/docs/dictionary.txt +++ b/docs/dictionary.txt @@ -26,4 +26,8 @@ odometry tf amcl RViz -junit \ No newline at end of file +junit +runtime +dot +png +svg \ No newline at end of file diff --git a/docs/how_to_run.rst b/docs/how_to_run.rst index 1ed2d792..ef7faf52 100644 --- a/docs/how_to_run.rst +++ b/docs/how_to_run.rst @@ -2,6 +2,33 @@ How to run ========== +.. _runtime_parameters: + +Runtime Parameters +------------------ + +.. list-table:: + :header-rows: 1 + :class: tight-table + + * - Parameter + - Description + * - ``-h`` ``--help`` + - show help message + * - ``-d`` ``--debug`` + - (For debugging) print internal debugging output + * - ``--dot`` + - Write dot files of resulting py-tree (``.[dot|png|svg]``). Writes files into current directory if no ``output-dir`` is given. + * - ``-l`` ``--log-model`` + - (For debugging) Produce tree output of parsed scenario + * - ``-n`` ``--dry-run`` + - Parse and resolve scenario, but do not execute + * - ``-o OUTPUT_DIR`` ``--output-dir OUTPUT_DIR`` + - Directory for output (e.g. test results) + * - ``-t`` ``--live-tree`` + - (For debugging) Show current state of py tree + + Run locally with ROS2 --------------------- @@ -24,12 +51,13 @@ To run an osc-file with ROS2: ros2 run scenario_execution_ros scenario_execution_ros $(PATH_TO_SCENARIO_FILE) -Use the ``-t`` flag to see the printed tree and use the ``-d`` flag to see debug -information of py_trees and the parser: +To log the current state of the behavior tree during execution, add the ``-t`` flag as an argument and run it again: .. code-block:: bash - ros2 run scenario_execution_ros scenario_execution_ros $(PATH_TO_SCENARIO_FILE) -t -d + ros2 run scenario_execution_ros scenario_execution_ros $(PATH_TO_SCENARIO_FILE) -t + +Additional parameters are describe in section :ref:`runtime_parameters`. Run as standalone Python package without ROS2 --------------------------------------------- @@ -40,13 +68,13 @@ After installing :repo_link:`scenario_execution` using pip (see :ref:`install_wi scenario_execution $(PATH_TO_SCENARIO_FILE) - -Use the ``-t`` flag to see the printed tree and use the ``-d`` flag to see debug -information of py_trees and the parser: +To log the current state of the behavior tree during execution, add the ``-t`` flag as an argument and run it again: .. code-block:: bash - scenario_execution $(PATH_TO_SCENARIO_FILE) -t -d + scenario_execution $(PATH_TO_SCENARIO_FILE) -t + +Additional parameters are describe in section :ref:`runtime_parameters`. diff --git a/scenario_execution/scenario_execution/scenario_execution_base.py b/scenario_execution/scenario_execution/scenario_execution_base.py index d4d878e1..eef5a496 100644 --- a/scenario_execution/scenario_execution/scenario_execution_base.py +++ b/scenario_execution/scenario_execution/scenario_execution_base.py @@ -68,6 +68,7 @@ def __init__(self, scenario_file: str, output_dir: str, dry_run=False, + render_dot=False, setup_timeout=py_trees.common.Duration.INFINITE, tick_tock_period: float = 0.1) -> None: @@ -85,6 +86,7 @@ def signal_handler(sig, frame): self.scenario_file = scenario_file self.output_dir = output_dir self.dry_run = dry_run + self.render_dot = render_dot if self.output_dir and not self.dry_run: if not os.path.isdir(self.output_dir): try: @@ -213,7 +215,9 @@ def parse(self): # pylint: disable=too-many-return-statements failure_output=str(e), processing_time=datetime.now() - start)) return False - + if self.render_dot: + self.logger.info(f"Writing py-trees dot files to {self.tree.name.lower()}.[dot|svg|png] ...") + py_trees.display.render_dot_tree(self.tree, target_directory=self.output_dir) return True def run(self): @@ -335,6 +339,7 @@ def parse_args(args): help='For debugging: Show current state of py tree') parser.add_argument('-o', '--output-dir', type=str, help='Directory for output (e.g. test results)') parser.add_argument('-n', '--dry-run', action='store_true', help='Parse and resolve scenario, but do not execute') + parser.add_argument('--dot', action='store_true', help='Render dot trees of resulting py-tree') parser.add_argument('scenario', type=str, help='scenario file to execute', nargs='?') args, _ = parser.parse_known_args(args) return args @@ -351,7 +356,8 @@ def main(): live_tree=args.live_tree, scenario_file=args.scenario, output_dir=args.output_dir, - dry_run=args.dry_run) + dry_run=args.dry_run, + render_dot=args.dot) except ValueError as e: print(f"Error while initializing: {e}") sys.exit(1) diff --git a/scenario_execution_ros/scenario_execution_ros/scenario_execution_ros.py b/scenario_execution_ros/scenario_execution_ros/scenario_execution_ros.py index 87b1d013..13381762 100644 --- a/scenario_execution_ros/scenario_execution_ros/scenario_execution_ros.py +++ b/scenario_execution_ros/scenario_execution_ros/scenario_execution_ros.py @@ -42,6 +42,7 @@ def __init__(self) -> None: scenario = args.scenario output_dir = args.output_dir self.dry_run = args.dry_run + self.render_dot = args.dot # override commandline by ros parameters self.node.declare_parameter('debug', False) @@ -50,6 +51,7 @@ def __init__(self) -> None: self.node.declare_parameter('output_dir', "") self.node.declare_parameter('scenario', "") self.node.declare_parameter('dry_run', False) + self.node.declare_parameter('dot', False) if self.node.get_parameter('debug').value: debug = self.node.get_parameter('debug').value @@ -63,7 +65,9 @@ def __init__(self) -> None: output_dir = self.node.get_parameter('output_dir').value if self.node.get_parameter('dry_run').value: self.dry_run = self.node.get_parameter('dry_run').value - super().__init__(debug=debug, log_model=log_model, live_tree=live_tree, scenario_file=scenario, output_dir=output_dir) + if self.node.get_parameter('dot').value: + self.render_dot = self.node.get_parameter('dot').value + super().__init__(debug=debug, log_model=log_model, live_tree=live_tree, scenario_file=scenario, output_dir=output_dir, dry_run=self.dry_run, render_dot=self.render_dot) def _get_logger(self, debug): """