Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support variables, references to members, late-initialization #103

Merged
merged 54 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
9620e3a
create test_scenario_execution
fred-labs Jun 27, 2024
4003090
execute()
fred-labs Jun 27, 2024
89e74eb
execute()
fred-labs Jun 27, 2024
1620818
scenario
fred-labs Jun 27, 2024
7f5c740
try
fred-labs Jun 27, 2024
4b69908
yes
fred-labs Jun 28, 2024
254751c
tests
fred-labs Jun 28, 2024
310ea1e
add
fred-labs Jun 28, 2024
b538a9c
fix os
fred-labs Jun 28, 2024
e610e8d
cleanup
fred-labs Jun 28, 2024
ed61a21
cleanup
fred-labs Jun 28, 2024
26c18ac
cleanup
fred-labs Jun 28, 2024
963122d
cleanup
fred-labs Jun 28, 2024
f3bc986
cleanup
fred-labs Jun 28, 2024
dda349c
cleanup
fred-labs Jun 28, 2024
195866a
cleanup
fred-labs Jun 28, 2024
1d4c28c
cleanup
fred-labs Jun 28, 2024
abda6d2
cleanup
fred-labs Jun 28, 2024
6200131
cleanup
fred-labs Jun 28, 2024
bdad8a5
blackboard
fred-labs Jul 1, 2024
9c99090
test
fred-labs Jul 1, 2024
1c27e5f
test
fred-labs Jul 1, 2024
dde172f
test
fred-labs Jul 1, 2024
6db5216
var
fred-labs Jul 1, 2024
bcbbe3f
test
fred-labs Jul 1, 2024
023062e
test
fred-labs Jul 1, 2024
9a60d9e
clneaup
fred-labs Jul 1, 2024
8a70539
clneaup
fred-labs Jul 1, 2024
9d47844
clneaup
fred-labs Jul 1, 2024
766d962
clneaup
fred-labs Jul 1, 2024
c148419
var
fred-labs Jul 1, 2024
be1aaaa
model
fred-labs Jul 1, 2024
e1e330f
addt
fred-labs Jul 1, 2024
fca3174
add
fred-labs Jul 1, 2024
07454de
add
fred-labs Jul 1, 2024
6fcab48
add
fred-labs Jul 1, 2024
9a6a2f4
add
fred-labs Jul 1, 2024
3cf6b3f
add
fred-labs Jul 1, 2024
4e4b692
set timeout
fred-labs Jul 2, 2024
877311b
Update test_assert_topic_latency.py
fred-labs Jul 2, 2024
18a89c4
Update libraries.rst
fred-labs Jul 2, 2024
6ae2346
Update test_build.yml
fred-labs Jul 2, 2024
00464a0
Update test_build.yml
fred-labs Jul 2, 2024
4d636a3
Update test_ros_launch.py
fred-labs Jul 2, 2024
32cd060
Update test_launch.py
fred-labs Jul 2, 2024
101b3bf
Update test_build.yml
fred-labs Jul 2, 2024
40234b7
Update test_assert_tf_moving.py
fred-labs Jul 2, 2024
bab7b85
Update test_build.yml
fred-labs Jul 3, 2024
1d7dc59
lib
fred-labs Jul 3, 2024
183385e
lib
fred-labs Jul 3, 2024
54dd7ce
fix external methods, add test
fred-labs Jul 3, 2024
31baef1
fixes
fred-labs Jul 3, 2024
5be8bd9
fixes
fred-labs Jul 3, 2024
18474ce
fixes
fred-labs Jul 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/linters/.pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ignore-paths=.*/osc2_parsing/.*

[MESSAGES CONTROL]
max-line-length=140
disable=no-self-use,anomalous-backslash-in-string,too-many-arguments,too-few-public-methods,too-many-instance-attributes,redefined-variable-type,unused-argument,bad-continuation,too-many-lines,too-many-branches,locally-disabled,too-many-locals,too-many-statements,duplicate-code,too-many-nested-blocks,fixme,useless-object-inheritance,no-else-raise,no-else-break,unnecessary-pass,no-else-return,super-with-arguments,no-else-continue,bad-option-value,consider-using-dict-items,consider-using-f-string,line-too-long,wrong-import-order,missing-function-docstring,missing-class-docstring,f-string-without-interpolation,import-error,missing-module-docstring,consider-using-with,unspecified-encoding
disable=attribute-defined-outside-init,no-self-use,anomalous-backslash-in-string,too-many-arguments,too-few-public-methods,too-many-instance-attributes,redefined-variable-type,unused-argument,bad-continuation,too-many-lines,too-many-branches,locally-disabled,too-many-locals,too-many-statements,duplicate-code,too-many-nested-blocks,fixme,useless-object-inheritance,no-else-raise,no-else-break,unnecessary-pass,no-else-return,super-with-arguments,no-else-continue,bad-option-value,consider-using-dict-items,consider-using-f-string,line-too-long,wrong-import-order,missing-function-docstring,missing-class-docstring,f-string-without-interpolation,import-error,missing-module-docstring,consider-using-with,unspecified-encoding
ignored-modules=geometry_msgs,py_trees,launch
variable-rgx=[a-z0-9_]{1,40}$
function-rgx=[a-z0-9_]{1,40}$
21 changes: 15 additions & 6 deletions .github/workflows/test_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ jobs:
export ROS_DOMAIN_ID=2
colcon test --packages-select \
scenario_execution \
scenario_execution_gazebo \
scenario_execution_os \
scenario_coverage \
scenario_execution_test \
--event-handlers console_direct+ \
--return-code-on-test-failure \
--pytest-args \
Expand Down Expand Up @@ -93,6 +93,7 @@ jobs:
export ROS_DOMAIN_ID=2
colcon test --packages-select \
scenario_execution_ros \
scenario_execution_ros_test \
--event-handlers console_direct+ \
--return-code-on-test-failure \
--pytest-args \
Expand Down Expand Up @@ -340,6 +341,7 @@ jobs:
test-scenario-execution-gazebo:
needs: [build]
runs-on: intellabs-01
timeout-minutes: 30
container:
image: ghcr.io/intellabs/scenario-execution:humble
credentials:
Expand Down Expand Up @@ -367,8 +369,8 @@ jobs:
uses: actions/upload-artifact@ef09cdac3e2d3e60d8ccadda691f4f1cec5035cb
if: always()
with:
name: test-example-simulation-result
path: test_example_simulation/test.xml
name: test-scenario-execution-gazebo
path: test_scenario_execution_gazebo/test.xml
tests:
needs:
- test-scenario-execution
Expand All @@ -389,22 +391,29 @@ jobs:
uses: actions/download-artifact@7a1cd3216ca9260cd8022db641d960b1db4d1be4 #v4.0
with:
path: downloaded-artifacts
- name: Restore cache
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
key: ${{ runner.os }}-build-${{ github.run_number }}
path: .
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@f355d34d53ad4e7f506f699478db2dd71da9de5f #v2.15.1
uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e #v2.16.1
with:
check_name: Test Results
check_run: false
action_fail: true
comment_mode: always
files: |
downloaded-artifacts/test-scenario-execution/scenario_execution/TEST.xml
downloaded-artifacts/test-scenario-execution-ros/scenario_execution_ros/TEST.xml
downloaded-artifacts/test-scenario-execution/scenario_coverage/TEST.xml
downloaded-artifacts/test-scenario-execution/libs/scenario_execution_os/TEST.xml
downloaded-artifacts/test-scenario-execution/test/scenario_execution_test/TEST.xml
downloaded-artifacts/test-scenario-execution-ros/scenario_execution_ros/TEST.xml
downloaded-artifacts/test-scenario-execution-ros/test/scenario_execution_ros_test/TEST.xml
downloaded-artifacts/test-example-scenario-result/test.xml
downloaded-artifacts/test-example-library-result/test.xml
downloaded-artifacts/test-example-variation-result/test.xml
downloaded-artifacts/test-example-nav2-result/test.xml
downloaded-artifacts/test-example-simulation-result/test.xml
downloaded-artifacts/test-example-multirobot-result/test.xml
downloaded-artifacts/test-example-external-method-result/test.xml
downloaded-artifacts/test-scenario-execution-gazebo/test.xml
1 change: 1 addition & 0 deletions docs/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,4 @@ Implement an Action
- Make use of ``self.feedback_message``
- Make use of ``kwargs['logger']``, available in ``setup()``
- If you want to draw markers for RViz, use ``kwargs['marker_handler']``, available in ``setup()`` (with ROS backend)
- Use arguments from ``__init__()`` for longer running initializations in ``setup()`` and the arguments from ``execute()`` to set values just before executing the action.
10 changes: 4 additions & 6 deletions docs/libraries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -203,19 +203,17 @@ Check the latency of the specified topic (in system time). If the check with `co

``check_data()``
""""""""""""""""
Wait for a topic message, compare a message field against a specific value.

In the background, this action uses `check_data() <https://py-trees-ros.readthedocs.io/en/devel/modules.html#py_trees_ros.subscribers.CheckData>`__ from `py_trees_ros <https://github.com/splintered-reality/py_trees_ros>`__.
Compare received topic messages using the given ``comparison_operator``, against the specified value. Either the whole message gets compared or a member defined by ``member_name``.

- ``topic_name: string``: Name of the topic to connect to
- ``topic_type: string``: Class of the message type (e.g. ``std_msgs.msg.String``)
- ``qos_profile: qos_preset_profiles``: QoS Preset Profile for the subscriber (default: ``qos_preset_profiles!system_default``)
- ``variable_name: string``: Name of the variable to check
- ``expected_value: string``: Expected value of the variable
- ``member_name: string``: Name of the type member to check. If empty, the whole type is checked (default: ``""``)
- ``expected_value: string``: Expected value
- ``comparison_operator: comparison_operator``: The comparison operator to apply (default: ``comparison_operator!eq``)
- ``fail_if_no_data: bool``: return failure if there is no data yet (default: ``false``)
- ``fail_if_bad_comparison: bool``: return failure if comparison failed (default: ``true``)
- ``clearing_policy: clearing_policy``: When to clear the data (default: ``clearing_policy!on_initialise``)
- ``wait_for_first_message: bool``: start checking with the first received message after action execution. If false, the check is executed on the last received message. (default: ``true``)

``differential_drive_robot.init_nav2()``
""""""""""""""""""""""""""""""""""""""""
Expand Down
23 changes: 12 additions & 11 deletions docs/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,28 @@ Then, we can write the implementation of action plugin in Python.

.. code-block::

import py_trees
from scenario_execution.actions.base_action import BaseAction

# define the py_trees behavior
class CustomAction(py_trees.behaviour.Behaviour):
class CustomAction(BaseAction):

# Override the __init__ function to accept parsed arguments.
def __init__(self, name, data: str):
super().__init__(name)
def __init__(self, data: str):
super().__init__()

def execute(self, data: str):
self.data = data

# Override the update function to define how the behavior is ticking.
def update(self):
print(f"Custom Action Triggered. Data: {self.data}")
return py_trees.common.Status.SUCCESS


In the example, we created a custom action plugin to print a message on the
screen. The first step is to create a ``py_trees`` behavior for the action
plugin. First, override the ``__init__()`` function to accept the parsed
parameter from the action plugin. Beside the fixed parameter ``name`` all parameters defined within the OpenSCENARIO 2 file
are handed over to `__init__`.
screen. The first step is to create an action implementation, based on the class ``BaseAction``.
There are two methods that can be overloaded in order to receive the action arguments as defined in the osc file.
The first is the ``__init__()`` function which gets the argument values as they get initialized during parsing the scenario file.
The second is the ``execute()`` function which gets the argument values as they are currently defined at the time the action gets executed.
This allows to initialize the action and then set the latest values just before the action gets triggered.

The action plugin ``custom_action`` only defines one parameter ``data``, so the behavior only has to accept ``data`` as an
argument. Then, override the ``update()`` function to define how the
behavior works. In this case, the behavior prints the message on the screen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@

""" Example for creating an action plugin for scenario execution """
import py_trees
from scenario_execution.actions.base_action import BaseAction


class CustomAction(py_trees.behaviour.Behaviour):
# pylint: disable=missing-class-docstring
# Override the __init__ function to accept parsed arguments.
def __init__(self, name, data: str):
super().__init__(name)
class CustomAction(BaseAction):

def __init__(self, data: str): # get action arguments, at the time of initialization
super().__init__()

def execute(self, data: str): # get action arguments, at the time of execution (may got updated during scenario execution)
self.data = data

# Override the update function to define how the behavior is ticking.
def update(self):
# pylint: disable=missing-function-docstring
print(f"Custom Action Triggered. Data: {self.data}")
return py_trees.common.Status.SUCCESS
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@

import os
import py_trees
from scenario_execution.actions.base_action import BaseAction


class CheckFileExists(py_trees.behaviour.Behaviour):
class CheckFileExists(BaseAction):
"""
Check existance of a file
Check existence of a file
"""

def __init__(self, name, file_name):
super().__init__(name)
def __init__(self, file_name):
super().__init__()
self.file_name = file_name

def update(self) -> py_trees.common.Status:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@

import os
import py_trees
from scenario_execution.actions.base_action import BaseAction


class CheckFileNotExists(py_trees.behaviour.Behaviour):
class CheckFileNotExists(BaseAction):
"""
Check that a file does not exist
"""

def __init__(self, name, file_name):
super().__init__(name)
def __init__(self, file_name):
super().__init__()
self.file_name = file_name

def update(self) -> py_trees.common.Status:
Expand Down
32 changes: 14 additions & 18 deletions libs/scenario_execution_os/test/test_check_file_exists.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#
# SPDX-License-Identifier: Apache-2.0

import py_trees
import unittest
import tempfile
from scenario_execution import ScenarioExecution
Expand All @@ -24,18 +25,25 @@
from antlr4.InputStream import InputStream


class TestCheckData(unittest.TestCase):
class TestCheckFileExists(unittest.TestCase):
# pylint: disable=missing-function-docstring,missing-class-docstring

def setUp(self) -> None:
self.parser = OpenScenario2Parser(Logger('test', False))
self.scenario_execution = ScenarioExecution(debug=False, log_model=False, live_tree=False,
scenario_file="test.osc", output_dir=None)
self.tree = py_trees.composites.Sequence()
self.tmp_file = tempfile.NamedTemporaryFile()
print(self.tmp_file.name)

def parse(self, scenario_content):
parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
model = self.parser.create_internal_model(parsed_tree, self.tree, "test.osc", False)
create_py_tree(model, self.tree, self.parser.logger, False)
self.scenario_execution.tree = self.tree
self.scenario_execution.run()

def test_success(self):
scenario_content = """
self.parse("""
import osc.os

scenario test:
Expand All @@ -46,17 +54,11 @@ def test_success(self):
time_out: serial:
wait elapsed(1s)
emit fail
"""

parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
model = self.parser.create_internal_model(parsed_tree, "test.osc", False)
scenarios = create_py_tree(model, self.parser.logger, False)
self.scenario_execution.scenarios = scenarios
self.scenario_execution.run()
""")
self.assertTrue(self.scenario_execution.process_results())

def test_fail(self):
scenario_content = """
self.parse("""
import osc.os

scenario test:
Expand All @@ -67,11 +69,5 @@ def test_fail(self):
time_out: serial:
wait elapsed(1s)
emit fail
"""

parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
model = self.parser.create_internal_model(parsed_tree, "test.osc", False)
scenarios = create_py_tree(model, self.parser.logger, False)
self.scenario_execution.scenarios = scenarios
self.scenario_execution.run()
""")
self.assertFalse(self.scenario_execution.process_results())
32 changes: 14 additions & 18 deletions libs/scenario_execution_os/test/test_check_file_not_exists.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import unittest
import tempfile
import py_trees
from scenario_execution import ScenarioExecution
from scenario_execution.model.osc2_parser import OpenScenario2Parser
from scenario_execution.model.model_to_py_tree import create_py_tree
Expand All @@ -24,18 +25,25 @@
from antlr4.InputStream import InputStream


class TestCheckData(unittest.TestCase):
class TestCheckFileNotExists(unittest.TestCase):
# pylint: disable=missing-function-docstring,missing-class-docstring

def setUp(self) -> None:
self.parser = OpenScenario2Parser(Logger('test', False))
self.scenario_execution = ScenarioExecution(debug=False, log_model=False, live_tree=False,
scenario_file="test.osc", output_dir=None)
self.tree = py_trees.composites.Sequence()
self.tmp_file = tempfile.NamedTemporaryFile()
print(self.tmp_file.name)

def parse(self, scenario_content):
parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
model = self.parser.create_internal_model(parsed_tree, self.tree, "test.osc", False)
create_py_tree(model, self.tree, self.parser.logger, log_tree=False)
self.scenario_execution.tree = self.tree
self.scenario_execution.run()

def test_success(self):
scenario_content = """
self.parse("""
import osc.os

scenario test:
Expand All @@ -46,17 +54,11 @@ def test_success(self):
time_out: serial:
wait elapsed(1s)
emit fail
"""

parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
model = self.parser.create_internal_model(parsed_tree, "test.osc", False)
scenarios = create_py_tree(model, self.parser.logger, False)
self.scenario_execution.scenarios = scenarios
self.scenario_execution.run()
""")
self.assertTrue(self.scenario_execution.process_results())

def test_fail(self):
scenario_content = """
self.parse("""
import osc.os

scenario test:
Expand All @@ -67,11 +69,5 @@ def test_fail(self):
time_out: serial:
wait elapsed(1s)
emit fail
"""

parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
model = self.parser.create_internal_model(parsed_tree, "test.osc", False)
scenarios = create_py_tree(model, self.parser.logger, False)
self.scenario_execution.scenarios = scenarios
self.scenario_execution.run()
""")
self.assertFalse(self.scenario_execution.process_results())
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ def combine_test_xml(self):
print(f"### XML file has no 'testsuite' element. {test_file}")

if not parsed_successfully:
total_errors += 1
missing_test_elem = ET.Element('testcase')
missing_test_elem.set("classname", "tests.scenario")
missing_test_elem.set("name", "no_test_result")
Expand Down
5 changes: 3 additions & 2 deletions scenario_coverage/scenario_coverage/scenario_variation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from copy import deepcopy

import yaml

import py_trees
from scenario_execution.model.osc2_parser import OpenScenario2Parser
from scenario_execution.model.model_resolver import resolve_internal_model
from scenario_execution.model.types import RelationExpression, ListExpression, FieldAccessExpression, Expression, print_tree, serialize, to_string
Expand Down Expand Up @@ -130,7 +130,8 @@ def save_resulting_scenarios(self, models):
if self.debug:
print_tree(model[0], self.logger)
try:
resolve_internal_model(model[0], self.logger, False)
tree = py_trees.composites.Sequence()
resolve_internal_model(model[0], tree, self.logger, False)
except ValueError as e:
raise ValueError(f"Resulting model is not resolvable: {e}") from e

Expand Down
Loading
Loading