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 niepowodzenie jednego z dzieci nie kończy się
niepowodzeniem całości. Wystarczy, że jedno 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.
SUCCESSnaFAILUREi 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
Przed przystąpieniem do pracy należy przygotować środowisko: Instrukcja
przygotowania środowiska do zajęć. Obraz bazuje na
osrf/ros:jazzy-desktop-full (ROS 2 Jazzy Jalisco) z
symulatorem Gazebo Harmonic.
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, 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
ROS_DOMAIN_ID
W przypadku pracy na wielu komputerach w tej samej sieci lokalnej
(eduroam też może tego wymagać), konieczne może być ustawienie
zmiennej środowiskowej ROS_DOMAIN_ID na różnych
wartościach. Należy wybrać dowolną liczbę całkowitą z zakresu 0-100.
Wartość tę należy ustawić w pliku ~/.bashrc:
export ROS_DOMAIN_ID=10 # przykładowa wartość
lub bezpośrednio w terminalu (wtedy będzie obowiązywać tylko w tym terminalu):
export ROS_DOMAIN_ID=10 # przykładowa wartość
Sugerowane jest użycie dwóch ostatnich cyfr numeru IP komputera jako
wartości ROS_DOMAIN_ID, aby uniknąć konfliktów z innymi
użytkownikami w sieci. Aby sprawdzić swój adres IP, można użyć
polecenia:
ip addr show
adres IP będzie widoczny przy interfejsie sieciowym, np.
wlan0 lub eth0.
Wygodne może być dodanie tego exportu do bashrc:
echo 'export ROS_DOMAIN_ID=<wybrana_wartość>' >> ~/.bashrc
Gazebo: GZ_IP i GZ_PARTITION
Gazebo komunikuje się niezależnie od ROS 2 (biblioteka
gz-transport), więc ROS_DOMAIN_ID nie rozdziela
symulacji. Domyślnie Gazebo łączy ze sobą symulacje uruchomione przez
tego samego użytkownika na komputerach o tej samej nazwie
(hostname), a kontener uruchomiony z
--network=host przejmuje nazwę komputera i działa jako
root. Jeżeli komputery w sieci mają takie same nazwy,
symulacje różnych osób mogą się wzajemnie zakłócać.
Dlatego w obrazie, w pliku ~/.bashrc, ustawiona jest
zmienna GZ_IP=127.0.0.1, dzięki której Gazebo komunikuje
się tylko w obrębie jednego komputera. W kontenerach utworzonych ze
starszej wersji obrazu (polecenie echo $GZ_IP nic nie
wypisuje) należy ją dopisać samodzielnie:
echo 'export GZ_IP=127.0.0.1' >> ~/.bashrc
Jeżeli na jednym komputerze działa kilka symulacji (np. w kilku
kontenerach), można je dodatkowo rozdzielić, ustawiając w każdym
kontenerze inną wartość zmiennej GZ_PARTITION (węzły Gazebo
widzą się nawzajem tylko w obrębie tej samej partycji):
echo 'export GZ_PARTITION=<wybrana_nazwa>' >> ~/.bashrc # np. arm_10
Wartość GZ_PARTITION musi być taka sama we wszystkich
terminalach, w których korzysta się z Gazebo (uruchomienie symulacji,
polecenia gz), dlatego lepiej ustawić ją w
~/.bashrc niż w pojedynczym terminalu. Zmiany w
~/.bashrc obowiązują w nowo otwartych terminalach, więc po
ich wprowadzeniu należy ponownie uruchomić symulację.
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
ros2 launch turtlebot3_bt turtlebot3_world1.launch.py
Aby zobaczyć wiązki skanera laserowego, w panelu
Visualize lidar (prawy dolny róg okna Gazebo) należy
kliknąć przycisk odświeżania (↻), wtedy zostanie wybrany topic
/scan.
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 kliknąć ją prawym przyciskiem myszy i wybrać
Remove. 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:
ros2 run turtlebot3_bt run_bt.py
W przypadku błędów z uruchomieniem może okazać się konieczne wywołanie poleceń:
apt install -y ros-jazzy-py-trees-ros
source install/setup.bash
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. TurtleBot3 w ROS 2 Jazzy
przyjmuje na topicu /cmd_vel wiadomości
geometry_msgs/msg/TwistStamped, tak jak w zachowaniu
Rotate.
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_roswykorzystujący mock robota - Wytłumaczenie drzew behawioralnych w Unreal Engine - ciekawie pokazane działanie drzew, jednocześnie uruchamiane w grze
Autor: Kamil Młodzikowski