Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 7532420

Browse files
fred-labsNikhil-Singhal-06
andauthored
Fix service_call with repeat() modifier (#154)
--------- Co-authored-by: Nikhil <nikhil.singhal@intel.com>
1 parent c0b6a77 commit 7532420

File tree

10 files changed

+99
-23
lines changed

10 files changed

+99
-23
lines changed

scenario_execution_ros/scenario_execution_ros/actions/assert_lifecycle_state.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def setup(self, **kwargs):
6767

6868
def execute(self, node_name: str, state_sequence: list, allow_initial_skip: bool, fail_on_unexpected: bool, keep_running: bool):
6969
if self.node_name != node_name or self.state_sequence != state_sequence:
70-
raise ValueError(f"Updating node name or state_sequence not supported.")
70+
raise ValueError("Runtime change of arguments 'name', 'state_sequence not supported.")
7171

7272
if all(isinstance(state, tuple) and len(state) == 2 for state in self.state_sequence):
7373
self.state_sequence = [state[0] for state in self.state_sequence]

scenario_execution_ros/scenario_execution_ros/actions/assert_tf_moving.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ def setup(self, **kwargs):
6565
tf_static_topic=(tf_prefix + "/tf_static"),
6666
)
6767

68+
def execute(self, frame_id: str, parent_frame_id: str, timeout: int, threshold_translation: float, threshold_rotation: float, wait_for_first_transform: bool, tf_topic_namespace: str, use_sim_time: bool):
69+
if self.tf_topic_namespace != tf_topic_namespace:
70+
raise ValueError("Runtime change of argument 'tf_topic_namespace' not supported.")
71+
self.frame_id = frame_id
72+
self.parent_frame_id = parent_frame_id
73+
self.timeout = timeout
74+
self.threshold_translation = threshold_translation
75+
self.threshold_rotation = threshold_rotation
76+
self.wait_for_first_transform = wait_for_first_transform
77+
self.use_sim_time = use_sim_time
78+
6879
def update(self) -> py_trees.common.Status:
6980
now = time.time()
7081
transform = self.get_transform(self.frame_id, self.parent_frame_id)

scenario_execution_ros/scenario_execution_ros/actions/assert_topic_latency.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ def setup(self, **kwargs):
5959
elif not success and not self.wait_for_first_message:
6060
raise ValueError("Topic type must be specified. Please provide a valid topic type.")
6161

62+
def execute(self, topic_name: str, topic_type: str, latency: float, comparison_operator: bool, rolling_average_count: int, wait_for_first_message: bool):
63+
if self.timer != 0:
64+
raise ValueError("Action does not yet support to get retriggered")
6265
self.timer = time.time()
6366

6467
def update(self) -> py_trees.common.Status:
@@ -122,13 +125,13 @@ def check_topic(self):
122125

123126
def call_subscriber(self):
124127
datatype_in_list = self.topic_type.split(".")
125-
self.topic_type = getattr(
128+
topic_type = getattr(
126129
importlib.import_module(".".join(datatype_in_list[:-1])),
127130
datatype_in_list[-1]
128131
)
129132

130133
self.subscription = self.node.create_subscription(
131-
msg_type=self.topic_type,
134+
msg_type=topic_type,
132135
topic=self.topic_name,
133136
callback=self._callback,
134137
qos_profile=get_qos_preset_profile(['sensor_data']))

scenario_execution_ros/scenario_execution_ros/actions/odometry_distance_traveled.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ def __init__(self, associated_actor, distance: float, namespace_override: str):
3838
self.node = None
3939
self.subscriber = None
4040
self.callback_group = None
41-
if namespace_override:
42-
self.namespace = namespace_override
41+
self.namespace_override = namespace_override
4342

4443
def setup(self, **kwargs):
4544
"""
@@ -52,8 +51,20 @@ def setup(self, **kwargs):
5251
self.name, self.__class__.__name__)
5352
raise KeyError(error_message) from e
5453
self.callback_group = rclpy.callback_groups.MutuallyExclusiveCallbackGroup()
54+
namespace = self.namespace
55+
if self.namespace_override:
56+
namespace = self.namespace_override
5557
self.subscriber = self.node.create_subscription(
56-
Odometry, self.namespace + '/odom', self._callback, 1000, callback_group=self.callback_group)
58+
Odometry, namespace + '/odom', self._callback, 1000, callback_group=self.callback_group)
59+
60+
def execute(self, associated_actor, distance: float, namespace_override: str):
61+
if self.namespace != associated_actor["namespace"] or self.namespace_override != namespace_override:
62+
raise ValueError("Runtime change of namespace not supported.")
63+
self.distance_expected = distance
64+
self.distance_traveled = 0.0
65+
self.previous_x = 0
66+
self.previous_y = 0
67+
self.first_run = True
5768

5869
def _callback(self, msg):
5970
'''
@@ -80,15 +91,6 @@ def calculate_distance(self, msg):
8091
self.previous_x = msg.pose.pose.position.x
8192
self.previous_y = msg.pose.pose.position.y
8293

83-
def initialise(self):
84-
'''
85-
Initialize before ticking.
86-
'''
87-
self.distance_traveled = 0.0
88-
self.previous_x = 0
89-
self.previous_y = 0
90-
self.first_run = True
91-
9294
def update(self) -> py_trees.common.Status:
9395
"""
9496
Check if the traveled distance is reached

scenario_execution_ros/scenario_execution_ros/actions/ros_log_check.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ def setup(self, **kwargs):
6464
)
6565
self.feedback_message = f"Waiting for log" # pylint: disable= attribute-defined-outside-init
6666

67+
def execute(self, values: list, module_name: str):
68+
self.module_name = module_name
69+
self.values = values
70+
self.found = None
71+
6772
def update(self) -> py_trees.common.Status:
6873
"""
6974
Wait for specified log entries

scenario_execution_ros/scenario_execution_ros/actions/ros_service_call.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ def __init__(self, service_name: str, service_type: str, data: str):
4444
self.node = None
4545
self.client = None
4646
self.future = None
47-
self.service_type = service_type
47+
self.service_type_str = service_type
48+
self.service_type = None
4849
self.service_name = service_name
50+
self.data_str = data
4951
try:
50-
trimmed_data = data.encode('utf-8').decode('unicode_escape')
52+
trimmed_data = self.data_str.encode('utf-8').decode('unicode_escape')
5153
self.data = literal_eval(trimmed_data)
5254
except Exception as e: # pylint: disable=broad-except
5355
raise ValueError(f"Error while parsing sevice call data:") from e
@@ -66,7 +68,7 @@ def setup(self, **kwargs):
6668
self.name, self.__class__.__name__)
6769
raise KeyError(error_message) from e
6870

69-
datatype_in_list = self.service_type.split(".")
71+
datatype_in_list = self.service_type_str.split(".")
7072
try:
7173
self.service_type = getattr(
7274
importlib.import_module(".".join(datatype_in_list[0:-1])),
@@ -77,6 +79,11 @@ def setup(self, **kwargs):
7779
self.client = self.node.create_client(
7880
self.service_type, self.service_name, callback_group=self.cb_group)
7981

82+
def execute(self, service_name: str, service_type: str, data: str):
83+
if self.service_name != service_name or self.service_type_str != service_type or self.data_str != data:
84+
raise ValueError("service_name, service_type and data arguments are not changeable during runtime.")
85+
self.current_state = ServiceCallActionState.IDLE
86+
8087
def update(self) -> py_trees.common.Status:
8188
"""
8289
Execute states

scenario_execution_ros/scenario_execution_ros/actions/ros_set_node_parameter.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class for setting a node parameter
2626
"""
2727

2828
def __init__(self, node_name: str, parameter_name: str, parameter_value: str):
29+
self.node_name = node_name
30+
self.parameter_name = parameter_name
31+
self.parameter_value = parameter_value
2932
service_name = node_name + '/set_parameters'
3033
if not service_name.startswith('/'):
3134
service_name = '/' + service_name
@@ -65,6 +68,10 @@ def __init__(self, node_name: str, parameter_name: str, parameter_value: str):
6568
service_type='rcl_interfaces.srv.SetParameters',
6669
data='{ "parameters": [{ "name": "' + parameter_name + '", "value": { "type": ' + str(parameter_type) + ', "' + parameter_assign_name + '": ' + parameter_value + '}}]}')
6770

71+
def execute(self, node_name: str, parameter_name: str, parameter_value: str): # pylint: disable=arguments-differ,arguments-renamed
72+
if self.node_name != node_name or self.parameter_name != parameter_name or self.parameter_value != parameter_value:
73+
raise ValueError("node_name, parameter_name and parameter_value are not changeable during runtime.")
74+
6875
@staticmethod
6976
def is_float(element: any) -> bool:
7077
"""

scenario_execution_ros/scenarios/test/test_ros_service_call.osc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,5 @@ import osc.ros
44
scenario test_ros_service_call:
55
timeout(30s)
66
do serial:
7-
service_call() with:
8-
keep(it.service_name == '/bla')
9-
keep(it.service_type == 'std_srvs.srv.SetBool')
10-
keep(it.data == '{\"data\": True}')
7+
service_call('/bla', 'std_srvs.srv.SetBool', '{\"data\": True}')
118
emit end

scenario_execution_ros/test/test_ros_log_check.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,25 @@ def test_success(self):
8181
self.execute(scenario_content)
8282
self.assertTrue(self.scenario_execution_ros.process_results())
8383

84+
def test_success_repeat(self):
85+
scenario_content = """
86+
import osc.ros
87+
import osc.helpers
88+
89+
scenario test_success:
90+
do parallel:
91+
serial:
92+
serial:
93+
repeat(2)
94+
log_check(values: ['ERROR'])
95+
emit end
96+
time_out: serial:
97+
wait elapsed(10s)
98+
emit fail
99+
"""
100+
self.execute(scenario_content)
101+
self.assertTrue(self.scenario_execution_ros.process_results())
102+
84103
def test_timeout(self):
85104
scenario_content = """
86105
import osc.helpers

scenario_execution_ros/test/test_ros_service_call.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
from scenario_execution_ros import ROSScenarioExecution
2222
from scenario_execution.model.osc2_parser import OpenScenario2Parser
2323
from scenario_execution.utils.logging import Logger
24+
from scenario_execution.model.model_to_py_tree import create_py_tree
2425
from ament_index_python.packages import get_package_share_directory
25-
26+
from antlr4.InputStream import InputStream
27+
import py_trees
2628
from std_srvs.srv import SetBool
2729

2830
os.environ["PYTHONUNBUFFERED"] = '1'
@@ -46,6 +48,14 @@ def setUp(self):
4648
self.srv = self.node.create_service(SetBool, "/bla", self.service_callback)
4749
self.parser = OpenScenario2Parser(Logger('test', False))
4850
self.scenario_execution_ros = ROSScenarioExecution()
51+
self.tree = py_trees.composites.Sequence(name="", memory=True)
52+
53+
def execute(self, scenario_content):
54+
parsed_tree = self.parser.parse_input_stream(InputStream(scenario_content))
55+
model = self.parser.create_internal_model(parsed_tree, self.tree, "test.osc", False)
56+
self.tree = create_py_tree(model, self.tree, self.parser.logger, False)
57+
self.scenario_execution_ros.tree = self.tree
58+
self.scenario_execution_ros.run()
4959

5060
def tearDown(self):
5161
self.node.destroy_node()
@@ -62,3 +72,18 @@ def test_success(self):
6272
self.scenario_execution_ros.run()
6373
self.assertTrue(self.scenario_execution_ros.process_results())
6474
self.assertTrue(self.request_received)
75+
76+
def test_success_repeat(self):
77+
scenario_content = """
78+
import osc.helpers
79+
import osc.ros
80+
81+
scenario test_ros_service_call:
82+
timeout(30s)
83+
do serial:
84+
repeat(2)
85+
service_call('/bla', 'std_srvs.srv.SetBool', '{\\\"data\\\": True}')
86+
emit end
87+
"""
88+
self.execute(scenario_content)
89+
self.assertTrue(self.scenario_execution_ros.process_results())

0 commit comments

Comments
 (0)