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

SCXML implementation of BT Control Nodes #58

Merged
merged 46 commits into from
Oct 25, 2024
Merged
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
b5ea3be
Initial verasion of BT control nodes scxml
MarcoLm993 Oct 8, 2024
5cb16d3
Second iteration of scxml_control_nodes
MarcoLm993 Oct 8, 2024
1e353c3
Rename BT Ports scxml declarations
MarcoLm993 Oct 9, 2024
7fd7fc6
One more iteration over the BT Control node SCXML
MarcoLm993 Oct 9, 2024
8bd28ed
STart implementing new scxml bt tags
MarcoLm993 Oct 9, 2024
02b7454
First skeleton on new BT tags
MarcoLm993 Oct 9, 2024
019d6c3
Prepare for testing new bt functionality
MarcoLm993 Oct 9, 2024
045f5f7
Prepare example using new format
MarcoLm993 Oct 9, 2024
1f8f6ff
Start implementing new BT SCXML generator
MarcoLm993 Oct 9, 2024
f86b904
Integrate bt_children ids in the scxml root
MarcoLm993 Oct 9, 2024
f7e8f90
Fix package not found in ipython
MarcoLm993 Oct 9, 2024
f11c651
Move controllers scxml to another folder
MarcoLm993 Oct 9, 2024
dab8efe
Check type of BtTickChild id
MarcoLm993 Oct 9, 2024
64e1ed4
Continue new import of bt plugins
MarcoLm993 Oct 14, 2024
44651f8
Install and import plugins in resources
MarcoLm993 Oct 14, 2024
a9bf8de
Continue integration
MarcoLm993 Oct 14, 2024
bc16c96
Implement missing conversions
MarcoLm993 Oct 14, 2024
5d2f706
First scxml without errors
MarcoLm993 Oct 14, 2024
f93c9e3
Substitution of xml escape sequence and re-order ecmascript entities…
MarcoLm993 Oct 14, 2024
54ea01e
First jani result
MarcoLm993 Oct 14, 2024
e00f599
Various fixes
MarcoLm993 Oct 15, 2024
dc64bac
Fix bug and improve variables naming
MarcoLm993 Oct 15, 2024
dd6f908
Yet another bug
MarcoLm993 Oct 15, 2024
84a3e57
First working version
MarcoLm993 Oct 15, 2024
c018af3
Support for old implementation
MarcoLm993 Oct 15, 2024
6e2692a
Rename battery_depleted_bt_tests
MarcoLm993 Oct 15, 2024
3a9704e
Remove btlib-based BT conversion
MarcoLm993 Oct 15, 2024
9797151
Add input ports support
MarcoLm993 Oct 15, 2024
bc24073
Fixing various tests
MarcoLm993 Oct 15, 2024
0a69d0e
Finish tests fixes
MarcoLm993 Oct 15, 2024
02307be
Adjust BT implementations
MarcoLm993 Oct 15, 2024
8c91364
Fix ReactiveFallback control node
MarcoLm993 Oct 15, 2024
8164302
Documentation
MarcoLm993 Oct 15, 2024
29e7a56
Remove deprecated use of importlib's path
MarcoLm993 Oct 15, 2024
5301d90
Remove unused btlib
MarcoLm993 Oct 15, 2024
bb267d7
Remove old dependencies
MarcoLm993 Oct 15, 2024
46478bd
Fix font path in toml file
MarcoLm993 Oct 15, 2024
aeafe3d
Test for reactive sequence
MarcoLm993 Oct 16, 2024
5cb1a43
Add test for reactive fallbacks
MarcoLm993 Oct 16, 2024
ad544f4
Implement BT sequence model and update test plugin for counting ticks
MarcoLm993 Oct 17, 2024
0a61598
Test for sequence controller
MarcoLm993 Oct 17, 2024
6eb2c4c
Implement Fallback control
MarcoLm993 Oct 17, 2024
c5cb74e
Add test for fallback bt controller
MarcoLm993 Oct 17, 2024
18712ea
Small TODO
MarcoLm993 Oct 18, 2024
2a3c64c
Prevent extra self-loops in the BT root jani automaton
MarcoLm993 Oct 18, 2024
e5d3666
Always return a List of transitions when instantiating BT events
MarcoLm993 Oct 25, 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
Prev Previous commit
Next Next commit
Various fixes
Signed-off-by: Marco Lampacrescia <marco.lampacrescia@de.bosch.com>
MarcoLm993 committed Oct 15, 2024
commit e00f5994974024bab462973c45b767c8d25570c7
10 changes: 0 additions & 10 deletions src/as2fm/as2fm_common/common.py
Original file line number Diff line number Diff line change
@@ -59,16 +59,6 @@ def remove_namespace(tag: str) -> str:
return tag_wo_ns


def substitute_xml_escaping(text: str) -> str:
"""
Substitute the XML escaping characters in the text.

:param text: The text to substitute the characters in.
:return: The text with the characters substituted.
"""
return text.replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&")


def is_comment(element: _Element) -> bool:
"""
Check if an element is a comment.
3 changes: 1 addition & 2 deletions src/as2fm/as2fm_common/ecmascript_interpretation.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@

import js2py

from as2fm.as2fm_common.common import ValidTypes, substitute_xml_escaping
from as2fm.as2fm_common.common import ValidTypes

BasicJsTypes = Union[int, float, bool]

@@ -36,7 +36,6 @@ def interpret_ecma_script_expr(
:param expr: The ECMA script expression
:return: The interpreted object
"""
expr = substitute_xml_escaping(expr)
if variables is None:
variables = {}
context = js2py.EvalJs(variables)
2 changes: 0 additions & 2 deletions src/as2fm/jani_generator/scxml_helpers/scxml_expression.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,6 @@

import esprima

from as2fm.as2fm_common.common import substitute_xml_escaping
from as2fm.jani_generator.jani_entries.jani_convince_expression_expansion import (
CALLABLE_OPERATORS_MAP,
OPERATORS_TO_JANI_MAP,
@@ -54,7 +53,6 @@ def parse_ecmascript_to_jani_expression(
:param array_info: The type and max size of the array, if required.
:return: The jani expression.
"""
ecmascript = substitute_xml_escaping(ecmascript)
try:
ast = esprima.parseScript(ecmascript)
except esprima.error_handler.Error as e:
17 changes: 12 additions & 5 deletions src/as2fm/scxml_converter/scxml_entries/scxml_bt_ticks.py
Original file line number Diff line number Diff line change
@@ -35,7 +35,11 @@
generate_bt_response_event,
generate_bt_tick_event,
)
from as2fm.scxml_converter.scxml_entries.utils import is_non_empty_string
from as2fm.scxml_converter.scxml_entries.utils import (
CallbackType,
get_plain_expression,
is_non_empty_string,
)
from as2fm.scxml_converter.scxml_entries.xml_utils import assert_xml_tag_ok, get_xml_argument


@@ -176,6 +180,9 @@ def __init__(
def instantiate_bt_events(
self, instance_id: int, children_ids: List[int]
) -> List[ScxmlTransition]:
plain_cond_expr = None
if self._condition is not None:
plain_cond_expr = get_plain_expression(self._condition, CallbackType.BT_RESPONSE)
if isinstance(self._child_id, int):
# Handling specific child ID, return a single transition
assert self._child_id < len(children_ids), (
@@ -186,18 +193,18 @@ def instantiate_bt_events(
return [
ScxmlTransition(
self._target,
[generate_bt_tick_event(target_child_id)],
self._condition,
[generate_bt_response_event(target_child_id)],
plain_cond_expr,
self._body,
).instantiate_bt_events(instance_id, children_ids)
]
else:
# Handling a generic child ID, return a transition for each child
condition_prefix = "" if self._condition is None else f"({self._condition}) &amp;&amp; "
condition_prefix = "" if plain_cond_expr is None else f"({plain_cond_expr}) && "
return [
ScxmlTransition(
self._target,
[generate_bt_tick_event(child_id)],
[generate_bt_response_event(child_id)],
condition_prefix + f"({self._child_id} == {child_id})",
self._body,
).instantiate_bt_events(instance_id, children_ids)
22 changes: 13 additions & 9 deletions src/as2fm/scxml_converter/scxml_entries/utils.py
Original file line number Diff line number Diff line change
@@ -71,6 +71,7 @@ class CallbackType(Enum):
ROS_ACTION_GOAL = auto() # Action callback
ROS_ACTION_RESULT = auto() # Action callback
ROS_ACTION_FEEDBACK = auto() # Action callback
BT_RESPONSE = auto() # BT response callback

@staticmethod
def get_expected_prefixes(cb_type: "CallbackType") -> List[str]:
@@ -90,6 +91,8 @@ def get_expected_prefixes(cb_type: "CallbackType") -> List[str]:
return ["_action.goal_id", "_wrapped_result.code", "_wrapped_result.result."]
elif cb_type == CallbackType.ROS_ACTION_FEEDBACK:
return ["_action.goal_id", "_feedback."]
elif cb_type == CallbackType.BT_RESPONSE:
return ["_bt.status"]

@staticmethod
def get_plain_callback(cb_type: "CallbackType") -> "CallbackType":
@@ -147,27 +150,28 @@ def _contains_prefixes(msg_expr: str, prefixes: List[str]) -> bool:
return False


def get_plain_expression(msg_expr: str, cb_type: CallbackType) -> str:
def get_plain_expression(in_expr: str, cb_type: CallbackType) -> str:
"""
Convert a ROS interface expressions (using ROS-specific PREFIXES) to plain SCXML.

:param msg_expr: The expression to convert.
:param in_expr: The expression to convert.
:param cb_type: The type of callback the expression is used in.
"""
expected_prefixes = CallbackType.get_expected_prefixes(cb_type)
# pre-check over the expression
if PLAIN_SCXML_EVENT_PREFIX not in expected_prefixes:
assert not _contains_prefixes(msg_expr, [PLAIN_SCXML_EVENT_PREFIX]), (
"Error: SCXML ROS conversion: "
f"unexpected {PLAIN_SCXML_EVENT_PREFIX} prefix in expr. {msg_expr}"
assert not _contains_prefixes(in_expr, [PLAIN_SCXML_EVENT_PREFIX]), (
"Error: SCXML-ROS expression conversion: "
f"unexpected {PLAIN_SCXML_EVENT_PREFIX} prefix in expr. {in_expr}"
)
forbidden_prefixes = ROS_EVENT_PREFIXES.copy()
if len(expected_prefixes) == 0:
forbidden_prefixes.append(PLAIN_SCXML_EVENT_PREFIX)
new_expr = _replace_ros_interface_expression(msg_expr, expected_prefixes)
assert not _contains_prefixes(
new_expr, forbidden_prefixes
), f"Error: SCXML ROS conversion: unexpected ROS interface prefixes in expr.: {msg_expr}"
new_expr = _replace_ros_interface_expression(in_expr, expected_prefixes)
assert not _contains_prefixes(new_expr, forbidden_prefixes), (
"Error: SCXML-ROS expression conversion: "
f"unexpected ROS interface prefixes in expr.: {in_expr}"
)
return new_expr