Lab 04 - Architektury behawioralne
Lab. 04 - Architektury behawioralne
1. Czym są architektury behawioralne?
Architektury behawioralne to takie podejście do sterowania robotami, gdzie robot wykonuje z góry zaprogramowane zachowania. Ich wygląd i priorytety są ustalane przez programistów.
Na zajęciach skupimy się na drzewach behawioralnych, którego przykład jest widoczny poniżej:
Będziemy korzystać z biblioteki py_trees
(link) i jej rozszerzenia py_trees_ros
(link).
Zachowania (Behaviours)
Są to najmniejsze elementy drzewa. Reprezentują najczęściej sprawdzanie warunków albo wykonywanie działań. Np. "Czy obiekt jest chwycony?" albo "Chwyć obiekt jedną ręką".
Każde zachowanie ma metodę, która jest wywoływana tuż po jego pierwszym uruchomieniu (initialise
), metodę, która jest wywoływana przy każdym uruchomieniu zachowania (update
), oraz metodę, która jest wywoływana po jego zakończeniu, powodzeniem lub nie (terminate
). Istnieje również metoda setup
wywoływana podczas przygotowywania drzewa.
Poza tym, każde zachowanie ma jeszcze swój status (SUCCESS
, FAILURE
, RUNNING
oraz INVALID
), a także feedback message, czyli wiadomość pomagającą śledzić co zachowanie aktualnie robi.
Kompozycje (Composites)
Kierują one sposobem przechodzenia po zachowaniach. W py_trees
mamy dostępne następujące kompozycje:
- Sequence - wykonuje zachowania po kolei, od pierwszego do ostatniego. Jeżeli którekolwiek z jego dzieci (ang. child) zakończy się stanem
FAILURE
, całość jest przerywana i kończy się stanemFAILURE
. Nastepne zachowanie nie jest wykonywane dopóki poprzednie nie zakończy się sukcesem. - Selector - wykonuje zachowania po kolei, od pierwszego do ostatniego. Różni się od Sequence tym, że powodzenie jednego z dzieci nie kończy się niepowodzeniem całości. Wystarczy, że jeden z dzieci zakończy się stanem
SUCCESS
, aby Selector zwrócił stanSUCCESS
. - Parallel - wykonuje zachowania równolegle. Istnieje możliwość dowolnego określenia, kiedy zwracany jest sukces:
- SuccessOnAll - wszystkie dzieci muszą zakończyć się stanem
SUCCESS
. - SuccessOnOne - co najmniej jedno dziecko kończy się stanem
SUCCESS
. - SuccessOnSelected - zdefiniowany podzbiór dzieci kończy się stanem
SUCCESS
.
- SuccessOnAll - wszystkie dzieci muszą zakończyć się stanem
Dekoratory (Decorators)
Inaczej kapelusze (ang. hats), zarządzają działaniem pojedynczych dzieci, modyfikując je w jakiś sposób. Pełna lista jest długa, ale jedne z istotniejszych to:
- EternalGuard - blokuje wykonywanie zachowania jeżeli warunek nie jest spełniony (zwraca wtedy
FAILURE
). - Inverter - odwraca zwracany przez zachowanie status.
SUCCESS
naFAILURE
i odwrotnie. - Retry powtarza wywołanie zachowania określoną liczbę razy, aż nie zostanie zwrócony status
SUCCESS
.
Tablice (Blackboards)
Jest to przestrzeń wymiany danych między zachowaniami. Ta koncepcja najbardziej kłóci się z koncepcjami ROSa (tam node'y komunikują się przez topici), ale z założenia drzewa behawioralne działają synchronicznie, a ROS asynchronicznie. Dlatego, w przypadku takiego sterowania, nie możemy wywoływać żadnych callbacków. W py_trees_ros
zostały utworzone klasy pozwalająca tworzyć subskrybenta topica, która synchronicznie, za każdym jej wywołaniem, udostępnia te dane na tablicy. Mają one różne sposoby działania, więcej w dokumentacji.
Po co to wszystko?
Uniwersalność
Drzewa behawioralne są szczególnie popularne podczas rozwijania gier. Możliwość stworzenia uniwersalnych zachowań, które dla różnych obiektów można łączyć w różne drzewa (często graficznie) pozwala na dużą uniwersalność stworzonego kodu. Wszelkie systemy z wieloma robotami też z tej zalety mogą korzystać.
Czytelność
Drzewa behawioralne są bardzo łatwe do interpretacji. Biblioteki mają natywnie wbudowane metody podglądu nie tylko architektury drzewa, ale również stanów i feedbacków podczas działania. Przez to również analiza i debugowanie staje się prostsze.
2. Cel zajęć
Celem tych zajęć będzie przygotowanie robota, który będzie realizował drzewo behawioralne zgodnie z założeniami:
- robot kręci się w kółko,
- robot sprawdza jaka jest odległość do przeszkody przed nim (±10°)
- jeżeli do przeszkody przed nim jest więcej niż 3 metry, jedzie do przodu.
Pożądane działanie zostało przedstawione na GIFie na górze instrukcji.
3. Przygotowanie środowiska
Wersja 1: Obraz (większy rozmiar)
Przed przystąpieniem do pracy należy przygotować środowisko: pobrać obraz dockera i utworzyć na jego podstawie kontener.
Obraz konieczny do wykonywania dzisiejszych zajęć opiera się o osrf/ros:humble-desktop-full
, ale zawiera paczki, które są niezbędne do prawidłowego wykonania zadań. Obraz można pobrać z tego linku, lub korzystając z polecenia:
wget --content-disposition --no-check-certificate https://chmura.put.poznan.pl/s/RMSf4EIKybsOhHL/download
Pobrany obraz należy wczytać, korzystając z polecenia, podając odpowiednią ścieżkę:
docker load < path/to/file.tar.gz
Następnie można przejść do tworzenia kontenera korzystając ze skryptów przygotowanych dla osób korzystających wyłącznie z CPU lub wyposażonych w GPU Nvidia. Można pobrać odpowiedni skrypt korzystając np. z wget
.
Domyślnie kontener nosi nazwę ARM_04. UWAGA! Skrypty po uruchomieniu usuwają kontener o takiej nazwie przed utworzeniem nowego.
Wersja 2: Dockerfile
Plik Dockerfile jest dostępny tutaj. Można go pobrać poleceniem:
wget https://raw.githubusercontent.com/kamilmlodzikowski/LabARM/main/Lab04-BehaviorTrees/Dockerfile
Skrypt budujący jest dostępny tutaj. Można go pobrać poleceniem:
wget https://raw.githubusercontent.com/kamilmlodzikowski/LabARM/main/Lab04-BehaviorTrees/arm_04_build.sh
Następnie można przejść do tworzenia kontenera korzystając ze skryptów przygotowanych dla osób korzystających wyłącznie z CPU lub wyposażonych w GPU Nvidia. Można pobrać odpowiedni skrypt korzystając np. z wget
.
Domyślnie kontener nosi nazwę ARM_04. UWAGA! Skrypty po uruchomieniu usuwają kontener o takiej nazwie przed utworzeniem nowego.
Korzystanie z kontenera
Po każdym ponownym uruchomieniu komputera (oraz w przypadku problemów z wyświetlaniem aplikacji okienkowych w dockerze), proszę pamiętać o wywoływaniu:
xhost +local:root
Nowy terminal można dołączyć do kontenera korzystając z polecenia:
docker exec -it ARM_04 bash
Konieczne będzie zbudowanie środowiska
cd /arm_ws
source /opt/ros/humble/setup.bash
colcon build --symlink-install
ROS_DOMAIN_ID
W przypadku pracy na komputerze w laboratorium może okazać się konieczne ustawienie ROS_DOMAIN_ID
. Domyślnie, ROS2 rozgłasza wszystko innym komputerom w sieci z tym samym ROS_DOMAIN_ID. Wartość tej zmiennej można ustawić korzystając z:
export ROS_DOMAIN_ID = <wybrana_wartość>
Proszę wybrać losową wartość.
Wygodne może być dodanie tego exportu do bashrc:
echo 'export ROS_DOMAIN_ID=<wybrana_wartość>' >> ~/.bashrc
4. Uruchomienie symulacji
W tej instrukcji będziemy ponownie wykorzystywać robota TurtleBot3, tym razem w świecie world1.sdf
z paczki turtlebot3_bt
. Można ją uruchomić poleceniem
cd /arm_ws
source install/setup.bash
ros2 launch turtlebot3_bt turtlebot3_world1.launch.py
Początkowo, symulacja uruchamia się ze ścianą oddzielającą robota od reszty pomieszczenia. W ten sposób zasięg skanera w żadnym punkcie nie przekracza 3 metrów.
Możliwe jest usunięcie przedzielającej ściany w gazebo
. Wystarczy zaznaczyć ją kliknięciem myszki i usunąć klawiszem delete
. Wtedy po prawej stronie pomieszczenia skany będą większe niż 3 metry.
5. Uruchomienie drzewa behawioralnego
Mając uruchomioną symulację (jeszcze z obecną ścianą przedzielającą), możliwe jest uruchomienie node'a drzewa behawioralnego:
cd /arm_ws
source /opt/ros/humble/setup.bash
colcon build --symlink-install
source install/setup.bash
ros2 run turtlebot3_bt run_bt.py
W tej sytuacji robot zacznie kręcić się w kółko i zbierać dane ze skanera, a w terminalu z uruchomionym nodem będzie widoczny aktualna struktura i stan drzewa.
Na ten moment, niezależnie od obecności ściany przedzielającej pomieszczenie, robot będzie robił to samo.
Możliwe jest podejrzenie zawartości Tablicy:
py-trees-blackboard-watcher
6. Zadanie do samodzielnej realizacji
W skrypcie run_bt.py
zaznaczono punkty TODO.
W skrypcie behaviours.py
należy utworzyć nowe zachowanie Drive
, które wysyła komendę jazdy prosto z prędkością przekazywaną przez argument vel
.
Nastepnie należy tak zmodyfikować skrypt run_bt.py
, aby realizował założenia z punktu 2. Cel zajęć.
Na eKursy proszę udostępnić:
- skrypt
run_bt.py
, z rozszerzeniem zmienionym na.txt
, - skrypt
behaviours.py
, z rozszerzeniem zmienionym na.txt
, - zrzut ekranu terminala node'a z uruchomionym drzewem.
7. Dodatkowe materiały
- Tutorial
py_trees_ros
wykorzystujący mock robota - Wytłumaczenie drzew behawioralnych w Unreal Engine - ciekawie pokazane działanie drzew, jednocześnie uruchamiane w grze
Autor: Kamil Młodzikowski