-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Christian Henkel <[email protected]>
- Loading branch information
Showing
8 changed files
with
270 additions
and
14 deletions.
There are no files selected for viewing
171 changes: 171 additions & 0 deletions
171
bt_tools_common/testable_tutorials/testable_tutorials.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
# Copyright (c) 2024 - for information on the respective copyright owner | ||
# see the NOTICE file | ||
|
||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
|
||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
""" | ||
This takes tutorials written in markdown files and extracts the code blocks | ||
to be tested. The code blocks are then executed and the output is compared | ||
to the expected output. | ||
""" | ||
|
||
import os | ||
import re | ||
import sys | ||
import logging | ||
import subprocess | ||
import argparse | ||
import select | ||
from typing import Optional, List, Tuple | ||
|
||
BLOCK_DELIM = '```' | ||
|
||
class ROSTerminal: | ||
""" | ||
Class for interacting with a ROS terminal | ||
""" | ||
def __init__(self): | ||
self.process = subprocess.Popen( | ||
['bash'], | ||
stdin=subprocess.PIPE, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
text=True, | ||
bufsize=1) | ||
|
||
def execute(self, command: str) -> str: | ||
""" | ||
Executes a command in the terminal | ||
""" | ||
if not command.endswith('\n'): | ||
command += '\n' | ||
self.process.stdin.write(command) | ||
self.process.stdin.flush() | ||
self.process.stdin.flush() | ||
|
||
output = [] | ||
# Read the output | ||
while True: | ||
# Use select to wait for data to be available on stdout | ||
rlist, _, _ = select.select([self.process.stdout], [], [], 2.0) | ||
|
||
if self.process.stdout in rlist: | ||
line = self.process.stdout.readline().strip() | ||
print(line) | ||
if line: | ||
output.append(line) | ||
else: | ||
break | ||
else: | ||
break | ||
while True: | ||
# Use select to wait for data to be available on stdout | ||
rlist, _, _ = select.select([self.process.stdout], [], [], 2.0) | ||
|
||
if self.process.stdout in rlist: | ||
line = self.process.stdout.readline().strip() | ||
print(line) | ||
if line: | ||
output.append(line) | ||
else: | ||
break | ||
else: | ||
break | ||
|
||
error = [] | ||
# Read the error | ||
while True: | ||
# Use select to wait for data to be available on stderr | ||
rlist, _, _ = select.select([self.process.stderr], [], [], 2.0) | ||
|
||
if self.process.stderr in rlist: | ||
line = self.process.stderr.readline().strip() | ||
print(line) | ||
if line: | ||
error.append(line) | ||
else: | ||
break | ||
else: | ||
break | ||
|
||
if error: | ||
logging.error(f'Error: {error}') | ||
return output | ||
|
||
def close(self): | ||
""" | ||
Closes the terminal | ||
""" | ||
self.process.stdin.close() | ||
self.process.stdout.close() | ||
self.process.stderr.close() | ||
self.process.kill() | ||
|
||
def extract_code_blocks(file_path: str) -> List[Tuple[str, str]]: | ||
""" | ||
Extracts code blocks from a markdown file | ||
""" | ||
code_blocks: List[Tuple[str, str]] = [] # (language, code) | ||
with open(file_path, 'r') as file: | ||
code: Optional[str] = None | ||
language: Optional[str] = None | ||
in_code_block: bool = False | ||
for line in file: | ||
if line.startswith(BLOCK_DELIM): | ||
new_language = line.strip(BLOCK_DELIM).strip() | ||
if len(new_language) == 0: # end of code block | ||
code_blocks.append((language, code)) | ||
code = None | ||
language = None | ||
in_code_block = False | ||
else: | ||
language = new_language | ||
code = '' | ||
in_code_block = True | ||
elif in_code_block: | ||
if code is not None: | ||
code += line | ||
return code_blocks | ||
|
||
def run_code_blocks(code_blocks: List[Tuple[str, str]]): | ||
""" | ||
Runs the code blocks | ||
""" | ||
terminal = ROSTerminal() | ||
terminal.execute('source /opt/ros/humble/setup.bash') | ||
for language, code in code_blocks: | ||
if language == 'bash': | ||
for line in code.split('\n'): | ||
if len(line.strip()) == 0: | ||
continue | ||
logging.info(f'cmd: {line}') | ||
output = terminal.execute(line) | ||
logging.info(f'out: {output}') | ||
else: | ||
logging.warning(f'Unsupported language: {language}') | ||
terminal.close() | ||
|
||
def main(): | ||
""" | ||
Main function | ||
""" | ||
logging.basicConfig(level=logging.INFO) | ||
ap = argparse.ArgumentParser() | ||
ap.add_argument('file', help='Markdown file to extract code blocks from') | ||
args = ap.parse_args() | ||
code_blocks = extract_code_blocks(args.file) | ||
print(code_blocks) | ||
run_code_blocks(code_blocks) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# How to visualize a FBL file | ||
|
||
## Verify installation | ||
|
||
To verify that the installation was successful, run the following command: | ||
|
||
```bash | ||
ls | ||
``` | ||
|
||
```bash | ||
echo $ROS_DISTRO | ||
``` | ||
|
||
```bash | ||
ros2 topic list | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import argparse | ||
from btlib.bt_to_fsm import bt_to_fsm | ||
from btlib.bts import xml_to_networkx | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description='Converts a BT to an FSM') | ||
parser.add_argument('bt', type=str, help='The BT to convert') | ||
args = parser.parse_args() | ||
|
||
bt, _ = xml_to_networkx(args.bt) | ||
btf = bt_to_fsm.Bt2FSM(bt) | ||
fsm = btf.convert() | ||
btf.plot_fsm(fsm) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,5 +33,8 @@ | |
license='Apache-2.0', | ||
tests_require=[ | ||
'pytest', | ||
] | ||
], | ||
scripts=[ | ||
'scripts/bt_to_fsm', | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
## Transform a behavior tree into a finite state machine | ||
|
||
This tutorial will teach you how to use the algorithm in this package to transform a behavior tree into a functionally equivalent finite state machine. | ||
|
||
### Background | ||
|
||
This implements the algorithm described in [_Behavior Trees in Robotics and AI: An Introduction_ by Michele Colledanchise, Petter Ögren](https://arxiv.org/pdf/1709.00084). | ||
Of particular interest is the section __2.2.2 Creating a FSM that works like a BTs__ (page 29). | ||
|
||
For our implementation, please refer to [the Bt2FSM class](https://bt-tools.readthedocs.io/en/latest/apidocs/btlib/btlib.bt_to_fsm.bt_to_fsm.html#btlib.bt_to_fsm.bt_to_fsm.Bt2FSM). | ||
|
||
### Prerequisites | ||
|
||
You need to have this package installed in your workspace. | ||
If you don't have it, build it: | ||
|
||
```bash | ||
mkdir -p ~/catkin_ws/src | ||
cd ~/catkin_ws/src | ||
git clone https://github.com/boschresearch/bt_tools.git | ||
cd ~/catkin_ws | ||
catkin build --symlink-install --packages-select btlib | ||
source ~/catkin_ws/devel/setup.bash | ||
``` | ||
|
||
### Input file | ||
|
||
You can pass any behavior tree in the [behaviortree.cpp](https://behaviortree.dev) format to the algorithm. | ||
For example [simple_bt.xml](https://github.com/boschresearch/bt_tools/blob/main/btlib/test/_test_data/bt2fsm/simple_bt.xml): | ||
|
||
```xml | ||
<root BTCPP_format="4"> | ||
<BehaviorTree> | ||
<Sequence> | ||
<ServiceBtCondition name="TEST_CONDITION" /> | ||
<Fallback> | ||
<ActionBtAction name="TEST_ACTION_A" /> | ||
<ActionBtAction name="TEST_ACTION_B" /> | ||
</Fallback> | ||
</Sequence> | ||
</BehaviorTree> | ||
</root> | ||
``` | ||
|
||
### Call the algorithm | ||
|
||
Then pass it to the script: | ||
|
||
```bash | ||
bt_to_fsm.py ~/catkin_ws/src/bt_tools/btlib/test/_test_data/bt2fsm/simple_bt.xml | ||
``` | ||
|
||
### Output | ||
|
||
This will generate a file called `fsm.png` in your current directory. | ||
It will look something like this: | ||
|
||
![FSM](imgs/fsm.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,4 @@ | ||
Tutorials | ||
========= | ||
|
||
How to model check your robot | ||
----------------------------- | ||
|
||
1. Install the necessary packages: | ||
``` | ||
sudo apt install THAT | ||
``` | ||
|
||
2. Run the model checker: | ||
``` | ||
convince_toolchain -i model.scxml -o results.json | ||
``` | ||
.. mdinclude:: ../../btlib/tutorial.md |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.