diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0d8e783..a5b5211d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -55,9 +55,17 @@ jobs: if: ${{ matrix.os == 'ubuntu-22.04' }} # lint packages # TODO: add linting + # Prepare ROS WS for the tests + - name: Install ROS support pkgs + run: | + source /opt/ros/${{ matrix.ros-distro }}/setup.bash + mkdir ros_interfaces_ws + cd ros_interfaces_ws + ln -s ../ros_support_interfaces src + colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release # run the tests - name: Run tests run: | export PATH=$PATH:${{ steps.get_smc_storm.outputs.SMC_STORM_PATH }} - source /opt/ros/${{ matrix.ros-distro }}/setup.bash + source ros_interfaces_ws/install/setup.bash pytest-3 -vs test/ diff --git a/docs/source/howto.rst b/docs/source/howto.rst index e6604023..ba2175c0 100644 --- a/docs/source/howto.rst +++ b/docs/source/howto.rst @@ -341,15 +341,80 @@ Or we can use `start_value` to define the initial value of a variable. BT ports can also be linked to variables in the `BT Blackboard` by wrapping the variable name in curly braces in the BT XML file. However, this feature is not yet supported. -.. _additional_params_howto: +.. _main_xml_howto: -Additional Parameters for the Main XML file -------------------------------------------- +The System Description (High Level XML file) +--------------------------------------------- +This file references all the components defining the system, including the Behavior Tree, its plugins and the additional nodes that might be running on the side. +Additionally, it contains additional configuration for the model, e.g. the maximum time the clock can reach or the tick rate of a Behavior Tree. -.. _max_time_tag: +An exemplary system description is the following: + +.. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + +.. _mc_parameters: + +Available Parameters +~~~~~~~~~~~~~~~~~~~~~ + +AS2FM provides a number of parameters to control the generation of the formal model. They are all contained in the tag ``. Max Time -~~~~~~~~ +____________ -TODO +The maximum time the global clock is allowed to reach. + +The tag is called `max_time`. The `value` argument is the max time, and the argument `unit` specifies the time unit of the provided value. Supported units are `s`, `ms`, `us`, `ns`. + +For example `` would allow the model to run for 100 seconds. + +Max Array Size +_________________ + +The maximum size assigned to a dynamic array. + +The tag is called `max_array_size`. The `value` argument defines the max size the dynamic array can reach, and is 100 by default. + +For example `` would allow dynamic arrays to contain up tp 100 entries. + +BT Tick Rate +_________________ + +The tick rate of the Behavior Tree (in Hz). + +The tag is called `bt_tick_rate`. The `value` argument defines the tick rate in Hz, and is 1.0 by default. + +For example `` would tick the behavior tree with a frequency of _10Hz_. + +BT Tick If Not Running +_________________________ + +Whether we shall keep ticking a Behavior Tree after it returns something different from `RUNNING` (i.e. `SUCCESS` or `FAILURE`). + +The tag is called `bt_tick_if_not_running`. The `value` argument enables or disables the ticking of non-running Behavior Trees, and is set to `false` by default. After the tree is stopped, the model execution will stop as well. + +For example `` would stop ticking the tree after it returned either _SUCCESS_ or _FAILURE_. diff --git a/docs/source/tutorials.rst b/docs/source/tutorials.rst index 891b0d20..25036ef0 100644 --- a/docs/source/tutorials.rst +++ b/docs/source/tutorials.rst @@ -49,7 +49,7 @@ The **Behavior Tree** continuously checks the alarm topic and, once it is trigge The JANI property `battery_charged` given in `battery_properties.jani `_ defines the property of interest to be model-checked. In this case, it calculates the minimal probability that the battery level will eventually be 100%, after an initial depletion time, i.e., all we verify here is that the battery is charged at some point. -In the `main.xml file `_ introduced earlier, the maximum run time of the system is specified with ``max_time`` and shared across the components. To make sure that the model-checked property makes sense, the allowed runtime needs to be high enough to have enough time to deplete the battery, i.e., in this example the maximal time needs to be at least 100s because the battery is depleted by 1% per second. Further information about this concept can be found in the :ref:`related section ` of the :ref:`How-To page `. +In the `main.xml file `_ introduced earlier, the maximum run time of the system is specified with ``max_time`` and shared across the components. To make sure that the model-checked property makes sense, the allowed runtime needs to be high enough to have enough time to deplete the battery, i.e., in this example the maximal time needs to be at least 100s because the battery is depleted by 1% per second. Further information about this and other configuration parameters can be found in the :ref:`Available Parameters section ` of the :ref:`How-To page `. In addition, in this main file, all the components of the example are put together, and the property to use is indicated. diff --git a/support_pkgs/delib_ws_24_interfaces/CMakeLists.txt b/ros_support_interfaces/delib_ws_24_interfaces/CMakeLists.txt similarity index 100% rename from support_pkgs/delib_ws_24_interfaces/CMakeLists.txt rename to ros_support_interfaces/delib_ws_24_interfaces/CMakeLists.txt diff --git a/support_pkgs/delib_ws_24_interfaces/action/Navigate.action b/ros_support_interfaces/delib_ws_24_interfaces/action/Navigate.action similarity index 100% rename from support_pkgs/delib_ws_24_interfaces/action/Navigate.action rename to ros_support_interfaces/delib_ws_24_interfaces/action/Navigate.action diff --git a/support_pkgs/delib_ws_24_interfaces/action/Pick.action b/ros_support_interfaces/delib_ws_24_interfaces/action/Pick.action similarity index 100% rename from support_pkgs/delib_ws_24_interfaces/action/Pick.action rename to ros_support_interfaces/delib_ws_24_interfaces/action/Pick.action diff --git a/support_pkgs/delib_ws_24_interfaces/action/Place.action b/ros_support_interfaces/delib_ws_24_interfaces/action/Place.action similarity index 100% rename from support_pkgs/delib_ws_24_interfaces/action/Place.action rename to ros_support_interfaces/delib_ws_24_interfaces/action/Place.action diff --git a/support_pkgs/delib_ws_24_interfaces/package.xml b/ros_support_interfaces/delib_ws_24_interfaces/package.xml similarity index 100% rename from support_pkgs/delib_ws_24_interfaces/package.xml rename to ros_support_interfaces/delib_ws_24_interfaces/package.xml diff --git a/ros_support_interfaces/uc2_interfaces/CMakeLists.txt b/ros_support_interfaces/uc2_interfaces/CMakeLists.txt new file mode 100644 index 00000000..691987bb --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.5) +project(uc2_interfaces) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +find_package(std_msgs REQUIRED) + +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + "msg/BlockStatus.msg" + "srv/GetBlockStatus.srv" + "action/MoveBlock.action" + "action/MoveBlockImplem.action" + "action/RecoverBlock.action" + "action/RecoverBlockImplem.action" + "action/InspectBlock.action" + "action/InspectBlockImplem.action" + DEPENDENCIES std_msgs + ) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/ros_support_interfaces/uc2_interfaces/README.md b/ros_support_interfaces/uc2_interfaces/README.md new file mode 100644 index 00000000..4fc58c40 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/README.md @@ -0,0 +1,7 @@ +# Current status +This repository stores message, service, action definitions for all the moonshot runs prepared until 31/07/2023, namely `RUN 2` and `RUN 3`. + +In the current version, interface definitions from all runs are mixed together. Some of them, though, have become obsolete; others need to undergo a complete re-examination and/or refactoring. + +# Future versions +Next versions of the repository will re-organize the interface definitions to be compatible with the developments from `RUN 3` on. diff --git a/ros_support_interfaces/uc2_interfaces/action/InspectBlock.action b/ros_support_interfaces/uc2_interfaces/action/InspectBlock.action new file mode 100644 index 00000000..804d68c1 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/action/InspectBlock.action @@ -0,0 +1,7 @@ +# action pattern +# attributes of goal +int32 block_id +--- +# attributes of result +--- +# attributes of feedback diff --git a/ros_support_interfaces/uc2_interfaces/action/InspectBlockImplem.action b/ros_support_interfaces/uc2_interfaces/action/InspectBlockImplem.action new file mode 100644 index 00000000..804d68c1 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/action/InspectBlockImplem.action @@ -0,0 +1,7 @@ +# action pattern +# attributes of goal +int32 block_id +--- +# attributes of result +--- +# attributes of feedback diff --git a/ros_support_interfaces/uc2_interfaces/action/MoveBlock.action b/ros_support_interfaces/uc2_interfaces/action/MoveBlock.action new file mode 100644 index 00000000..804d68c1 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/action/MoveBlock.action @@ -0,0 +1,7 @@ +# action pattern +# attributes of goal +int32 block_id +--- +# attributes of result +--- +# attributes of feedback diff --git a/ros_support_interfaces/uc2_interfaces/action/MoveBlockImplem.action b/ros_support_interfaces/uc2_interfaces/action/MoveBlockImplem.action new file mode 100644 index 00000000..804d68c1 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/action/MoveBlockImplem.action @@ -0,0 +1,7 @@ +# action pattern +# attributes of goal +int32 block_id +--- +# attributes of result +--- +# attributes of feedback diff --git a/ros_support_interfaces/uc2_interfaces/action/RecoverBlock.action b/ros_support_interfaces/uc2_interfaces/action/RecoverBlock.action new file mode 100644 index 00000000..804d68c1 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/action/RecoverBlock.action @@ -0,0 +1,7 @@ +# action pattern +# attributes of goal +int32 block_id +--- +# attributes of result +--- +# attributes of feedback diff --git a/ros_support_interfaces/uc2_interfaces/action/RecoverBlockImplem.action b/ros_support_interfaces/uc2_interfaces/action/RecoverBlockImplem.action new file mode 100644 index 00000000..804d68c1 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/action/RecoverBlockImplem.action @@ -0,0 +1,7 @@ +# action pattern +# attributes of goal +int32 block_id +--- +# attributes of result +--- +# attributes of feedback diff --git a/ros_support_interfaces/uc2_interfaces/msg/BlockStatus.msg b/ros_support_interfaces/uc2_interfaces/msg/BlockStatus.msg new file mode 100644 index 00000000..f1468e6f --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/msg/BlockStatus.msg @@ -0,0 +1 @@ +int32 block_down diff --git a/ros_support_interfaces/uc2_interfaces/package.xml b/ros_support_interfaces/uc2_interfaces/package.xml new file mode 100644 index 00000000..eca82e26 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/package.xml @@ -0,0 +1,22 @@ + + + + uc2_interfaces + 0.0.0 + TODO: Package description + root + TODO: License declaration + + ament_cmake + std_msgs + ament_lint_auto + ament_lint_common + + rosidl_default_generators + rosidl_default_runtime + rosidl_interface_packages + + + ament_cmake + + diff --git a/ros_support_interfaces/uc2_interfaces/srv/GetBlockStatus.srv b/ros_support_interfaces/uc2_interfaces/srv/GetBlockStatus.srv new file mode 100644 index 00000000..e76ae128 --- /dev/null +++ b/ros_support_interfaces/uc2_interfaces/srv/GetBlockStatus.srv @@ -0,0 +1,2 @@ +--- +int32 block_down diff --git a/src/as2fm/jani_generator/scxml_helpers/top_level_interpreter.py b/src/as2fm/jani_generator/scxml_helpers/top_level_interpreter.py index 790dd63a..9c4f1ee2 100644 --- a/src/as2fm/jani_generator/scxml_helpers/top_level_interpreter.py +++ b/src/as2fm/jani_generator/scxml_helpers/top_level_interpreter.py @@ -42,13 +42,23 @@ @dataclass() class FullModel: + # The maximum time the model is allowed to run, in nanoseconds max_time: Optional[int] = None + # Max size of "dynamic" arrays defined in the SCXML models max_array_size: int = field(default=100) + # Tick rate for the loaded BT in Hz bt_tick_rate: float = field(default=1.0) + # Whether to keep ticking the BT after it returns SUCCESS / FAILURE + bt_tick_when_not_running: bool = field(default=False) + # Path to the behavior tree loaded in the model bt: Optional[str] = None + # Paths to the SCXML models of the BT nodes used in the model plugins: List[str] = field(default_factory=list) + # Paths to the SCXML models of the non-BT nodes in the model skills: List[str] = field(default_factory=list) + # Similar to the skills, currently unused components: List[str] = field(default_factory=list) + # Path to the properties definition, currently in JANI properties: List[str] = field(default_factory=list) @@ -67,15 +77,7 @@ def _parse_time_element(time_element: ET.Element) -> int: def parse_main_xml(xml_path: str) -> FullModel: """ - Interpret the top-level XML file as a dictionary. - - The returned dictionary contains the following keys: - - max_time: The maximum time in nanoseconds. - - bt: The path to the Behavior Tree definition. - - plugins: A list of paths to the Behavior Tree plugins. - - skills: A list of paths to SCXML files encoding an FSM. - - components: Similar to skills, but representing abstract models of existing skills - - properties: A list of paths to Jani properties. + Interpret the top-level XML file and return it as a FullModel object. """ # Used to generate absolute paths of scxml models folder_of_xml = os.path.dirname(xml_path) @@ -98,6 +100,8 @@ def parse_main_xml(xml_path: str) -> FullModel: model.max_array_size = int(mc_parameter.attrib["value"]) elif remove_namespace(mc_parameter.tag) == "bt_tick_rate": model.bt_tick_rate = float(mc_parameter.attrib["value"]) + elif remove_namespace(mc_parameter.tag) == "bt_tick_if_not_running": + model.bt_tick_when_not_running = bool(mc_parameter.attrib["value"]) else: raise ValueError( error(mc_parameter, f"Invalid mc_parameter tag: {mc_parameter.tag}") @@ -160,7 +164,11 @@ def generate_plain_scxml_models_and_timers( ros_scxmls.append(ScxmlRoot.from_scxml_file(fname)) # Convert behavior tree and plugins to ROS-SCXML if model.bt is not None: - ros_scxmls.extend(bt_converter(model.bt, model.plugins, model.bt_tick_rate)) + ros_scxmls.extend( + bt_converter( + model.bt, model.plugins, model.bt_tick_rate, model.bt_tick_when_not_running + ) + ) # Convert the loaded entries to plain SCXML plain_scxml_models = [] all_timers: List[RosTimer] = [] diff --git a/src/as2fm/scxml_converter/bt_converter.py b/src/as2fm/scxml_converter/bt_converter.py index 286aa2de..38645fec 100644 --- a/src/as2fm/scxml_converter/bt_converter.py +++ b/src/as2fm/scxml_converter/bt_converter.py @@ -29,6 +29,7 @@ BtTickChild, RosRateCallback, RosTimeRate, + ScxmlExecutionBody, ScxmlRoot, ScxmlState, ) @@ -60,10 +61,18 @@ def load_available_bt_plugins(bt_plugins_scxml_paths: List[str]) -> Dict[str, Sc def bt_converter( - bt_xml_path: str, bt_plugins_scxml_paths: List[str], bt_tick_rate: float + bt_xml_path: str, + bt_plugins_scxml_paths: List[str], + bt_tick_rate: float, + tick_if_not_running: bool, ) -> List[ScxmlRoot]: """ Generate all Scxml files resulting from a Behavior Tree (BT) in XML format. + + :param bt_xml_path: Path to the xml file implementing the Behavior Tree. + :param bt_plugins_scxml_paths: Paths to the scxml files implementing the BT nodes (plugins). + :param bt_tick_rate: The rate at which the root of the input BT is ticked. + :param tick_if_not_running: If true, keep ticking the BT root after it stops returning RUNNING. """ available_bt_plugins = load_available_bt_plugins(bt_plugins_scxml_paths) xml_tree: ET.ElementBase = ET.parse(bt_xml_path, ET.XMLParser(remove_comments=True)).getroot() @@ -78,36 +87,55 @@ def bt_converter( ), f"Error: Expected one BehaviorTree child, found {len(bt_children)}." root_child_tick_idx = 1000 bt_name = os.path.basename(bt_xml_path).replace(".xml", "") - bt_scxml_root = generate_bt_root_scxml(bt_name, root_child_tick_idx, bt_tick_rate) + bt_scxml_root = generate_bt_root_scxml( + bt_name, root_child_tick_idx, bt_tick_rate, tick_if_not_running + ) generated_scxmls = [bt_scxml_root] + generate_bt_children_scxmls( bt_children[0], root_child_tick_idx, available_bt_plugins ) return generated_scxmls -def generate_bt_root_scxml(scxml_name: str, tick_id: int, tick_rate: float) -> ScxmlRoot: +def generate_bt_root_scxml( + scxml_name: str, tick_id: int, tick_rate: float, tick_if_not_running: bool +) -> ScxmlRoot: """ Generate the root SCXML for a Behavior Tree. + + :param scxml_name: name of the scxml object to be generated. + :param tick_id: A tick ID for the BT Root node. + :param tick_rate: The rate at which the root is ticked. + :param tick_if_not_running: If true, tick the BT root after it stops returning RUNNING. """ bt_scxml_root = ScxmlRoot(BT_ROOT_PREFIX + scxml_name) ros_rate_decl = RosTimeRate(f"{scxml_name}_tick", tick_rate) bt_scxml_root.add_ros_declaration(ros_rate_decl) idle_state = ScxmlState( - "idle", body=[RosRateCallback(ros_rate_decl, "wait_tick_res", None, [BtTickChild(0)])] + "idle", + body=[ + RosRateCallback(ros_rate_decl, "wait_tick_res", None, [BtTickChild(0)]), + BtChildStatus(0, "error"), + ], + ) + tick_res_body: ScxmlExecutionBody = ( + # In case we keep ticking after BT root finishes running + [BtChildStatus(0, "idle")] + if tick_if_not_running + # In case we stop the BT after the BT root result is not RUNNING + else [ + BtChildStatus(0, "idle", "_bt.status == RUNNING"), + # This is the case in which BT-status != RUNNING + BtChildStatus(0, "done"), + ] ) wait_res_state = ScxmlState( "wait_tick_res", - body=[ - # If we allow timer ticks here, the automata will generate timer callbacks and make the - # BT automaton transition to error state (since our concept of time is not real). - # RosRateCallback(ros_rate_decl, "error"), - BtChildStatus(0, "idle") - ], + body=tick_res_body, ) - error_state = ScxmlState("error") bt_scxml_root.add_state(idle_state, initial=True) bt_scxml_root.add_state(wait_res_state) - bt_scxml_root.add_state(error_state) + bt_scxml_root.add_state(ScxmlState("done")) + bt_scxml_root.add_state(ScxmlState("error")) # The BT root's ID is set to -1 (unused anyway) bt_scxml_root.set_bt_plugin_id(-1) bt_scxml_root.append_bt_child_id(tick_id) diff --git a/test/jani_generator/_test_data/.gitignore b/test/jani_generator/_test_data/.gitignore index 2192b1f8..1df0e5bc 100644 --- a/test/jani_generator/_test_data/.gitignore +++ b/test/jani_generator/_test_data/.gitignore @@ -1,6 +1,7 @@ */generated_bt_scxml */generated_plain_scxml -*/main*.jani -*/*.csv +*/**/main*.jani +*/**/*.csv +*/**/*.ods */output.jani */out diff --git a/test/jani_generator/_test_data/bt_test_models/main_test_fallback.xml b/test/jani_generator/_test_data/bt_test_models/main_test_fallback.xml index ae79a272..d65a71fd 100644 --- a/test/jani_generator/_test_data/bt_test_models/main_test_fallback.xml +++ b/test/jani_generator/_test_data/bt_test_models/main_test_fallback.xml @@ -2,6 +2,7 @@ + diff --git a/test/jani_generator/_test_data/bt_test_models/main_test_reactive_fallback.xml b/test/jani_generator/_test_data/bt_test_models/main_test_reactive_fallback.xml index 1a9b113f..0798e0ce 100644 --- a/test/jani_generator/_test_data/bt_test_models/main_test_reactive_fallback.xml +++ b/test/jani_generator/_test_data/bt_test_models/main_test_reactive_fallback.xml @@ -2,6 +2,7 @@ + diff --git a/test/jani_generator/_test_data/bt_test_models/main_test_reactive_sequence.xml b/test/jani_generator/_test_data/bt_test_models/main_test_reactive_sequence.xml index e826b445..2683fc79 100644 --- a/test/jani_generator/_test_data/bt_test_models/main_test_reactive_sequence.xml +++ b/test/jani_generator/_test_data/bt_test_models/main_test_reactive_sequence.xml @@ -2,6 +2,7 @@ + diff --git a/test/jani_generator/_test_data/bt_test_models/main_test_sequence.xml b/test/jani_generator/_test_data/bt_test_models/main_test_sequence.xml index c3d30f97..a8024e28 100644 --- a/test/jani_generator/_test_data/bt_test_models/main_test_sequence.xml +++ b/test/jani_generator/_test_data/bt_test_models/main_test_sequence.xml @@ -2,6 +2,7 @@ + diff --git a/test/jani_generator/_test_data/ros_example_w_bt/main.xml b/test/jani_generator/_test_data/ros_example_w_bt/main.xml index cf6888f0..c51fc0ba 100644 --- a/test/jani_generator/_test_data/ros_example_w_bt/main.xml +++ b/test/jani_generator/_test_data/ros_example_w_bt/main.xml @@ -1,6 +1,8 @@ + + diff --git a/test/jani_generator/_test_data/ros_example_w_bt_deprecated/main.xml b/test/jani_generator/_test_data/ros_example_w_bt_deprecated/main.xml index cf6888f0..0feda93c 100644 --- a/test/jani_generator/_test_data/ros_example_w_bt_deprecated/main.xml +++ b/test/jani_generator/_test_data/ros_example_w_bt_deprecated/main.xml @@ -1,6 +1,7 @@ + diff --git a/test/jani_generator/_test_data/uc1_docking/main.xml b/test/jani_generator/_test_data/uc1_docking/main.xml index 8f5c65d1..0540a327 100644 --- a/test/jani_generator/_test_data/uc1_docking/main.xml +++ b/test/jani_generator/_test_data/uc1_docking/main.xml @@ -2,6 +2,7 @@ + diff --git a/test/jani_generator/_test_data/uc1_docking/main_with_problem.xml b/test/jani_generator/_test_data/uc1_docking/main_with_problem.xml index 346538d8..3fa69a13 100644 --- a/test/jani_generator/_test_data/uc1_docking/main_with_problem.xml +++ b/test/jani_generator/_test_data/uc1_docking/main_with_problem.xml @@ -2,6 +2,7 @@ + diff --git a/test/jani_generator/_test_data/uc2_assembly/Components/Clock.scxml b/test/jani_generator/_test_data/uc2_assembly/Components/Clock.scxml new file mode 100644 index 00000000..84b04830 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Components/Clock.scxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Main/Policy0.xml b/test/jani_generator/_test_data/uc2_assembly/Main/Policy0.xml new file mode 100644 index 00000000..0bb8b047 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Main/Policy0.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Main/Policy0_bug.xml b/test/jani_generator/_test_data/uc2_assembly/Main/Policy0_bug.xml new file mode 100644 index 00000000..8f33d108 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Main/Policy0_bug.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Main/main.xml b/test/jani_generator/_test_data/uc2_assembly/Main/main.xml new file mode 100644 index 00000000..3e9b403d --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Main/main.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Main/main_bug.xml b/test/jani_generator/_test_data/uc2_assembly/Main/main_bug.xml new file mode 100644 index 00000000..d14d17d9 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Main/main_bug.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Main/properties.jani b/test/jani_generator/_test_data/uc2_assembly/Main/properties.jani new file mode 100644 index 00000000..d1e4a592 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Main/properties.jani @@ -0,0 +1,43 @@ +{ + "properties": [ + { + "name": "can_execute_recovery_branch", + "expression": { + "op": "filter", + "fun": "values", + "values": { + "op": "Pmin", + "exp": { + "comment": "((abort_time > 0) ⇒ (clock < abort_time + 5000)) U (recover_block_running > 0)", + "op": "U", + "left": { + "op": "⇒", + "left": { + "op": ">", + "left": "topic_uc2__info__properties__move_block_abort_time_msg.ros_fields__data", + "right": 0 + }, + "right": { + "op": "<", + "left": "topic_uc2__info__clock_msg.ros_fields__data", + "right": { + "op": "+", + "left": "topic_uc2__info__properties__move_block_abort_time_msg.ros_fields__data", + "right": 5000 + } + } + }, + "right": { + "op": ">", + "left": "topic_uc2__info__properties__recover_block_running_msg.ros_fields__data", + "right": 0 + } + } + }, + "states": { + "op": "initial" + } + } + } + ] +} diff --git a/test/jani_generator/_test_data/uc2_assembly/Plugins/IsBlockFell.scxml b/test/jani_generator/_test_data/uc2_assembly/Plugins/IsBlockFell.scxml new file mode 100644 index 00000000..1cdbc9a9 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Plugins/IsBlockFell.scxml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Plugins/MoveBlock.scxml b/test/jani_generator/_test_data/uc2_assembly/Plugins/MoveBlock.scxml new file mode 100644 index 00000000..86a638db --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Plugins/MoveBlock.scxml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Plugins/RecoverBlock.scxml b/test/jani_generator/_test_data/uc2_assembly/Plugins/RecoverBlock.scxml new file mode 100644 index 00000000..79529d17 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Plugins/RecoverBlock.scxml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Skills/MoveBlockSkill.scxml b/test/jani_generator/_test_data/uc2_assembly/Skills/MoveBlockSkill.scxml new file mode 100644 index 00000000..ea3efef1 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Skills/MoveBlockSkill.scxml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/_test_data/uc2_assembly/Skills/RecoverBlockSkill.scxml b/test/jani_generator/_test_data/uc2_assembly/Skills/RecoverBlockSkill.scxml new file mode 100644 index 00000000..ca06bc61 --- /dev/null +++ b/test/jani_generator/_test_data/uc2_assembly/Skills/RecoverBlockSkill.scxml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jani_generator/test_systemtest_scxml_to_jani.py b/test/jani_generator/test_systemtest_scxml_to_jani.py index 6deede05..dfbb684e 100644 --- a/test/jani_generator/test_systemtest_scxml_to_jani.py +++ b/test/jani_generator/test_systemtest_scxml_to_jani.py @@ -402,13 +402,13 @@ def test_robot_navigation_with_bt_demo(self): ) def test_uc1_docking(self): - """Test the robot demo.""" + """Test the UC1 docking BT.""" self._test_with_main( "uc1_docking", store_generated_scxmls=True, property_name="tree_success", success=True ) def test_uc1_docking_bugged(self): - """Test the robot demo.""" + """Test the UC1 docking BT (with a bug).""" self._test_with_main( "uc1_docking", model_xml="main_with_problem.xml", @@ -416,6 +416,25 @@ def test_uc1_docking_bugged(self): success=False, ) + @pytest.mark.skip(reason="Result is 0.98, need to find the 2 percent failures.") + def test_uc2_assembly(self): + """Test the UC2 BT example.""" + self._test_with_main( + os.path.join("uc2_assembly", "Main"), + model_xml="main.xml", + property_name="can_execute_recovery_branch", + success=True, + ) + + def test_uc2_assembly_with_bug(self): + """Test the UC2 BT example, with bugged BT policy.""" + self._test_with_main( + os.path.join("uc2_assembly", "Main"), + model_xml="main_bug.xml", + property_name="can_execute_recovery_branch", + success=False, + ) + def test_command_line_output_with_line_numbers(self): """Test the command line output with line numbers for the main.xml file.""" tmp_test_dir = os.path.join("/tmp", "test_as2fm") diff --git a/test/scxml_converter/_test_data/battery_drainer_w_bt/gt_bt_scxml/bt_root_fsm_bt.scxml b/test/scxml_converter/_test_data/battery_drainer_w_bt/gt_bt_scxml/bt_root_fsm_bt.scxml index c1b9c6da..e630a08a 100644 --- a/test/scxml_converter/_test_data/battery_drainer_w_bt/gt_bt_scxml/bt_root_fsm_bt.scxml +++ b/test/scxml_converter/_test_data/battery_drainer_w_bt/gt_bt_scxml/bt_root_fsm_bt.scxml @@ -4,9 +4,11 @@ + + diff --git a/test/scxml_converter/_test_data/bt_ports_only/gt_bt_scxml/bt_root_fsm_bt.scxml b/test/scxml_converter/_test_data/bt_ports_only/gt_bt_scxml/bt_root_fsm_bt.scxml index c1b9c6da..e630a08a 100644 --- a/test/scxml_converter/_test_data/bt_ports_only/gt_bt_scxml/bt_root_fsm_bt.scxml +++ b/test/scxml_converter/_test_data/bt_ports_only/gt_bt_scxml/bt_root_fsm_bt.scxml @@ -4,9 +4,11 @@ + + diff --git a/test/scxml_converter/test_systemtest_xml.py b/test/scxml_converter/test_systemtest_xml.py index f290ea6f..8e26aa95 100644 --- a/test/scxml_converter/test_systemtest_xml.py +++ b/test/scxml_converter/test_systemtest_xml.py @@ -45,13 +45,13 @@ def bt_to_scxml_test( :param test_folder: The name of the folder with the files to evaluate. :param bt_file: The name to the BT xml file. - :param bt_plugins: The names of the BT plugins scxml files. + :param bt_plugins: The names of the BT plugins SCXML files. :param store_generated: If True, the generated SCXML files are stored in the output folder. """ test_data_path = os.path.join(os.path.dirname(__file__), "_test_data", test_folder) bt_file = os.path.join(test_data_path, bt_file) plugin_files = [os.path.join(test_data_path, f) for f in bt_plugins] - scxml_objs = bt_converter(bt_file, plugin_files, 1.0) + scxml_objs = bt_converter(bt_file, plugin_files, 1.0, True) if store_generated: clear_output_folder(test_folder) for scxml_obj in scxml_objs: