Spis treści

Opis

Piotr Hołownia, holownia@student.agh.edu.pl

Build an API prototype in Prolog for NXT-based robots

Architecture:

Issues:

Ideas:

Spotkania

08.03.04

080311

080318

080401

080408

080415

080422

080520 -> 080527

0806??

Projekt

08.03.04

:pl:miw:miw08_mindstormsapi:akcje.pl :pl:miw:miw08_mindstormsapi:ruch.pl

nxt_motor(Motor,Speed, Direction) :-
  var(Speed), % odczyt pr
  get_speed(Speed)
nxt_motor(Motor,Speed, Direction) :-
  var(Dir), % odczyt dir
nxt_motor(Motor,Speed, Direction) :-
  nonvar(S),
  set_speed(S),
nxt_motor(Motor,Speed, Direction) :-
  Speed < 0,
nxt_motor(Motor,reverse, Direction) :-
  nxt_motor(Motor,Speed, _),
  Speedn is - Speed,
  nxt_motor(Motor,Speedn).
 
nxt_motor(Motor,Speed, Time) :-
  create_timer(T1), %potrzebuje miec timery
  set_speed(M,S),
  wakeup(T1,Time,nxt_motor(,0,_)).
nxt_motor(M,S,_),S \= 0.
nxt_motor(Motor,Speed, Direction) :-
  var(Speed), % odczyt pr
  nxt_get_speed(Speed).
 
nxt_get_speed(Speed) :-
  icmnd_get_speed(Speed).
 
nxt_get_speed(Speed) :-
  ptcp_get_speed(Speed).

08.03.11

08.03.18

08.04.01

08.04.08

08.04.15

08.04.22

W stosunku do projektu z 08.04.15 zmieniły się następujące pliki:

iCommand how-to for Windows users

nxtcomm=COM6

nxtcomm.type=bluesock

I'm not sure if that's all. ;) Try it. If there's something missing, don't hesitate to fix this how-to.

08.05.27

Sprawozdanie

08.03.04

Podejście inżynierskie zawiesiłem. Spróbowałem tworzyć API wyższego poziomu przy założeniu, że mam dostępne pewne predykaty API niższego poziomu (ustawianie prędkości obrotowej serwomechanizmu, obracanie o zadany kąt). Jest to trudne do realizacji bez gotowych rozwiązań API niższego poziomu. Istotne jest, aby stworzyć mechanizmy działania, które w leJOS są dostępne w klasie Behavior i umożliwiają podejmowanie akcji po zajściu jakiegoś zdarzenia. Myślę, że należy skupić się na podejściu inżynierskim.

08.03.11

W pliku ruch2.pl zamieszczone są predykaty realizujące złożoną pracę silników: ruch pojazdu do przodu, do tyłu, skręcanie, obracanie. W pliku silnik.pl znajduje się predykat nxtMotor, pozwalający w wybrany sposób poruszać silnikiem. W pliku akcje2.pl są predykaty, które powinny obracać silnik z zadaną prędkością, o zadany kąt, odczytywać prędkość obrotową silnika, a także umożliwiać tworzenie timerów i triggerów. Wprowadzenie triggerów pozwala dodać dla każdego z ruchów pojazdu warunek: „do napotkania przeszkody” i wiele innych możliwości. Np. jedź do napotkania przeszkody, skręcaj do napotkania przeszkody, rozpocznij jazdę na komendę dźwiękową. W tym momencie predykaty z pliku akcja2.pl wypisują jedynie swój zamierzony cel, aby móc testować działanie. Wobec tego od realizujących warstwy niższe oczekuję wykonania w tym miejscu działających mechanizmów. Czyli:

08.03.18

Utworzyłem moduły:

Aby nie wprowadzać zbyt dużej ilości kodu przed stwierdzeniem słuszności zastosowania triggerów, tylko predykat 'go' z modułu 'nxt_movement' pozwala na ruch do napotkania przeszkody. W każdym razie niezbędny jest jakiś sposób implementacji callbacków.

W module nxt_actions znajdują się predykaty, które powinny być pomostem pomiędzy moim projektem a projektami realizujących niższe warstwy.

08.04.01

Dodane komentarze oraz trigger i timer z wykorzystaniem wątków w SWIProlog.

08.04.08

Zdecydowałem się jednak na wprowadzenie przedrostka nxt dla predykatów. Mimo iż moduł ma swoją przestrzeń nazw, hipotetycznie mogłaby zaistnieć sytuacja, w której ktoś korzystałby jednocześnie z mojego modułu i czyjegoś, który dostarczałby przynajmniej jeden predykat o tej samej nazwie, co w moim module.

iCommand nie umożliwia obsługi wyświetlacza i wydawania dźwięków!

W iCommand metoda Motor.A.rotate(long count,boolean returnNow) obraca silnik o zadany kąt i zwraca sterowanie, jeśli returnNow==true. Nie zwraca go jednak wystarczająco szybko (wywoływana przez jpl), aby uruchomienie dwóch silników bezpośrednio po sobie odbyło się bez opóźnienia. Stąd błędy w poruszaniu się robota przy użyciu tej metody. Np. predykat nxt_go(200,1000) sprawia, że robot nieznacznie skręca przed wykonaniem ruchu prostoliniowego i na koniec także. Praca silników jest lekko przesunięta w czasie. Przy większych prędkościach obrotowych (np. 700 stopni na sekundę) ta różnica staje się niedopuszczalnie duża. Przy mniejszych (np. 150 stopni na sekundę) wydaje się nie przeszkadzać. Dla wyeliminowania tego błędu należałoby zastosować wielowątkowość w Javie.

Dodatkowym poważnym problemem jest brak możliwości odczytu kierunku obracania się silnika przy użyciu iCommand. To także należy rozwiązać.

Poza powyższymi dwoma problemami moduł nxt_movement działa prawidłowo (testowałem na „żywym” robocie). Muszę jeszcze poprawić komentarze, bo nie wszystko jest jasno określone.

Ponadto W iCommand jest dostępna klasa icommand.navigation.Pilot. Umożliwia pewne ruchy robota na średnim poziomie (alternatywa dla modułu nxt_movement). Próbowałem używać jej w Prologu, ale nie zdążyłem przetestować. Efekt w module nxt_java_movement.

Z mniej ciekawych rzeczy:

Metody iCommand Motor.A.stop() i Motor.A.flt() działają nieprawidłowo. Funkcja „stop” używa hamulca, a „flt” odcina zasilanie i sprawia, że silnik zatrzymuje się w wyniku oporów ruchu. Do zatrzymania silnika rozsądnie byłoby użyć funkcji „stop”. Robot na równi pochyłej nie będzie się staczał pod swoim cięzarem. Oczywiście powinno się także umożliwić korzystanie z zatrzymania płynnego innym predykatem, ale idea predykatu nxt_motor(Motor,0) jest taka, ze silnik sie nie obraca. W każdej sytuacji! Po użyciu funkcji „stop” funkcja „isMoving” zwraca „true”, chociaż silnik jest nieruchomy. Poważy błąd ze strony iCommand. Spróbowałem jednocześnie używać funkjci „stop” i „flt” po sobie. Takie zestawienie sprawia, że hamulec wciąz działa, a po zastosowaniu funkcji „flt” funkcja „isMoving” działa poprawnie. Znowu błąd ze strony iCommand. Po użyciu funkcji „flt” ponowne uruchomienie silnika jest niemożliwe. Wreszcie prawidłowe zatrzymanie silnika powinno składać się z zastosowania funkjci „stop” i ustawienia prędkości silnika na zero (setSpeed(0)). Wtedy co prawda funkcja „isMoving” zwraca „true”, ale funkcja „getSpeed” zwraca zero i w ten sposób można rozpoznać, że silnik się nie obraca.

Predykat obracający silnik o zadany kąt z zadaną prędkością także musi na koniec ustawić prędkość zerową, aby zapewnić poprawny odczyt prędkości. Należy się zastanowić nad rozsądniejszym rozwiązaniem. Jako tymczasowe jest dobre, ale w przyszłości może powodować błędy. Np. przy wielowątkowym sterowaniu robotem.

Nazwy modułów, predykatów są robocze. W każdej chwili do zmiany. Proponowana przeze mnie konstrukcja: nxt_components (może warto nazwać nxt_icommand, bo teraz wykorzystuje icommand) jest warstwą niższą. Używa jej warstwa wyższa (nxt_movement i ewentualnie nxt_java_movement, bo nie wiem, co z tym „dobrodziejstwem” zrobić). Do tego dochodzi moduł threads, implementujący prymitywny trigger i timer za pomocą wątków SWIProlog. Pan Ziółkowski powinien zaproponować swoją wersję nxt_components.

08.04.15

Wróciłem do trójwarstowej konstrukcji. nxt_movement korzysta z nxt_sensomoto, do którego przy użyciu predykatu use_module/1 można podłączyć warstwę komunikacyjną z NXT (np.nxt_actions_icommand). Dla potrzb testowania bez użycia klocków należy podłączyć nxt_actions_dummy. Ten moduł także może posłużyć jako wzór do konstruowania alternatywnego dla nxt_actions_icommand modułu komunikacyjnego.

08.04.22

Aby uzupełnić funkcjonalność dodałem predykaty realizujące w icommand:

O wilku mowa! Nie przetestowałem wprowadzonych predykatów z powodu rozładowanych baterii. Zrobię to w najbliższym czasie.

Pan Ziółkowski realizuje taką funkcjonalność, więc może znów bazując na nxt_actions_dummy wprowadzić swoje rozwiązania.

Wyglądałoby na to, że mam pokrytą funkcjonalność protokołu Lego, Ziółka i icommand(w stopniu wykluczającym zagłębianie się w niepotrzebne szczegóły).

08.05.27

Przygotowałem laboratorium: lab5. Laboratorium składa się z obserwowania testowego programu oraz implementacji wybranego algorytmu.

Proponowana nazwa API to PlNXT. Podobnie do PlDoc, PlUnit. Krótko i konkretnie.

Chyba powinienem jeszcze dokładniejszą dokumentację przygotować. Niektóre rzeczy mogą być niejasne dla kogoś, kto ma pierwszy raz styczność z PlNXT.

PlDoc generuje dokumentację w latex, ale nie mogłem tego rozgryźć. Nie działało to prawidłowo. Dokumentacja w html jest generowana przez serwer dokumentacji w Prolog. Ta droga tworzenia dokumentacji działa bez zarzutu. Może przydałoby się taki uruchomić, aby dokumentacja była automatycznie generowana po wprowadzanych zmianach i dostępna na wiki? Tymczasowo wygenerowane pliki html i css po małej przeróbce umieściłem tutaj:

Materiały