Kod programu
Podczas zajęć udało nam się w całości zaimplementować jeden algorytm. Jego założeniem było sprawienie, aby robot przemieszczał się po pomieszczeniu a po zauważeniu przed sobą przeszkody zmieniał kierunek jazdy. Ponadto rozbudowaliśmy robota o sensor dotyku, dzięki czemu mogliśmy dodać warunek stopu programu: po wciśnięciu przycisku robot zatrzymywał się i zamykał połączenie. Pełny kod programu:
:- consult('plnxt.pl').
start :-
nxt_open,
trigger_create(_,check_touch,[nxt_stop,nxt_close]),
trigger_create(_,check_distance,[nxt_stop,rotate,nxt_go(300)],inf),
nxt_go(300).
check_distance :-
nxt_ultrasonic(Distance,force),
Distance < 20.
check_touch :-
nxt_touch(Value,force),
Value =:= 1.
rotate :-
Angle is 30 + random(150),
nxt_rotate(360,Angle).
Załączniki
Spostrzeżenia, wnioski, napotkane problemy
Podczas wykonywania ćwiczenia napotkaliśmy kilka problemów, z których większość spowodowana była brakiem doświadczenia w korzystaniu z plnxt. Na szczęście szybko udawało nam się wyłapywać i usuwać błędy tego typu.
Ważne jest, aby przy implementacji algorytmu uwzględnić warunki stopu, gdyż w przeciwnym wypadku możemy stać się świadkami sceny wziętej wprost z „Ucznia Czarnoksiężnika” Goethego, czyli w tym przypadku robota uparcie wykonującego zadane mu zadanie i nie reagującego na polecenie zatrzymania się. Gdy tak się zdarzy, wyjściem może być zrestartowanie xpce, otwarcie połączenia i dopiero wtedy wysłanie polecenia nxt_stop.
Podobnie niezbyt dobrym pomysłem okazało się rekurencyjne tworzenie nieskończonej ilości wątków i otwierania kolejnych połączeń. Tutaj pomógł już tylko sprzętowy restart robota.
nxt_close a sprawa warningów
Innym problemem, pojawiającym się chyba w każdej grupie, było występowanie ostrzeżeń:
Warning: [Thread ID] Thread running „trigger_start(Zdarzenie, Akcja, Licznik)” died on exception: source_sink 'nxt_close' does not exist.
pojawiających się w przypadku, gdy Akcja zawierała w sobie polecenie nxt_close
.
Przyczyny występowania tego błędu nie są nam znane, ale po przeanalizowaniu kodu plnxt i reference manual SWI Prologu doszliśmy do wniosku, że powodem zaistnienia tej sytuacji może być błąd w plnxt (lub ewentualnie wbudowany błąd Prologu).
Wywołanie trigger_create(_,check_touch,[nxt_stop,nxt_close])
powoduje w efekcie wywołanie reguły
trigger_cycle(ID,Event,Action,1) :-
Event,
fire(Action),
retract(threads_trigger(ID)).
Kiedy jedną z akcji jest zamknięcie połączenia, odpalany jest nxt_close
, który z kolei zabija wszystkie triggery (trigger_killall
).
W efekcie retract(threads_trigger(ID))
kończy się niepowodzeniem (nie ma już threads_triggera o zadanym ID), a więc cel wątku jest niespełniony.
Natomiast w SWI-Prolog 5.6.60 Reference Manual: Section 8.1
czytamy:
If a detached thread dies due to failure or exception of the initial goal the thread prints a message using print_message/2.
If such termination is considered normal the code must be wrapped using ignore/1 and/or catch/3 to ensure successful completion.
Update: Wygląda na to, że na chwilę obecną nie da się podlinkować sprawozdania pod osobistą stronę robota.