Naszym celem jest skonfigurowanie środowiska deweloperskiego w Windows XP w taki sposób aby umożliwić sterowanie klockami LEGO z poziomu Prologu. Sterowanie będzie odbywało się poprzez Bluetooth, w czasie rzeczywistym. „Program” Prologu będzie wykonywany na maszynie PC, zaś odczyty z czujników oraz rozkazy dla silników będą wysyłane w czasie rzeczywistym via bluetooth.
Struktura warstw komunikacyjnych wygląda następująco:
Prolog | ← Wraz z zestawem napisanych przez nas predykatów |
---|---|
JPL | |
iCommand | |
Sterowniki bluetooth | ← bluetooth stack + imprementacja dostarczona wraz z iCommand |
Klocki LEGO NXT |
Do testów podczas instalacji przydatny jest Eclipse
W moim przypadku JPL był dostarczony wraz z pakietem instalacyjnym SWI-Prolog. Wystarczyło jedynie pobrać z internetu odpowiedni pakiet instalacyjny, uruchomić, a następnie postępować zgodnie ze wskazówkami instalatora. Aby upewnić się, że JPL działa prawidłowo można skompilować i uruchomić następujący prosty predykat:
integer_to_float(A,B):- jpl_new( 'java.lang.Integer', [A], H), jpl_call( H, floatValue,[], B).
Po skompilowaniu i uruchomieniu, w konsoli SWI-Prologu powinniśmy ujrzeć mniej więcej coś takiego:
1 ?- integer_to_float(5,A). % Added [C:\Program Files\Java\jdk1.6.0\jre\bin\client, C:\Program Files\Java\jdk1.6.0\jre\bin, C:\Program Files\Java\jdk1.6.0\bin] to %PATH% A = 5.0 2 ?-
Cały proces jest dokładnie opisany w pliku README.txt umieszczonym wewnątrz paczki z iCommand'em. Należy wykonać wszystkie czynności zgodnie z punktami: 2.1, 2.2, 2.3 pliku README.txt
Po ich prawidłowym wykonaniu powinniśmy być w stanie uruchamiać przykładowe klasy Javowe, sterujące robotem via iCommand.
Moje uwagi dot. instalacji:
1. Nie przejmować się tym, że punkt instalacji 2.3.1.6 nie działa! Po przyjrzeniu się kodom źródłowym iCommand widać, że wykonanie komendy:
java -jar icommand.jar
nie ma prawa działać.
2. Plik konfiguracyjny icommand.properties:
a) Skopiować go do katalogu użytkownika. W moim przypadku: C:\Documents and Settings\gutek\icommand.properties Okazuje się, że iCommand szukał pliku konfigracyjnego tylko w tym katalogu - wbrew dokumentacji, wg której plik jest szukany również w kataogu roboczym (.)
b) W moim przypadku plik icommand.properties ostatecznie składał się z trzech linijek:
nxtcomm.type=rxtx nxtcomm=COM40 rxtx.port=COM40
COM40 - na takim wirtualnym porcie Toshiba bluetooth stack ustanowił mi połączenie
3. Firma LEGO nie udostępniła informacji o tym, że klocki NXT będą działały z bluetoothem Toshiby. Co więcej - przegląd internetu wykazał, że klocki NXT mają problemy z komunikowaniem się via bluetooth z niektórymi laptopami Toshiby i Dell'a - faktycznie były z tym problemy, niemniej ostatecznie udało się wszystko uruchomić.
4. Łączenie iCommanda z klockami składa się z dwóch etapów: w pierwszym należy „sparować” dwa urządzenia (tak samo jak dla wszystkich urządzeń bluetooth - z podaniem PINu itd.).
Następnie Należy z klasy NXTCommand uruchomić metodę open() - po kilku sekundach na wyświetlaczu bricka powinna pojawić się następująca ikona: <> W moim przypadku te dwa etapy były najtrudniejsze - jako, że pojawiały się liczne problemy z Bluetoothem.
5. Przed przejściem do kolejnego kroku warto jest przetestować iCommanda z poziomu Eclipse'a - np uruchamiając przykładowe klasy.
Jeżeli poprawnie wykonaliśmy punkty 3.1 i 3.2 to z tym nie powinniśmy mieć problemów. Ważne jest, żeby ścieżki do wszystkich wspomnianych bibliotek *.jar znalazły się w zmiennej CLASSPATH
Można już pisać predykaty sterujące robotem, np. ustanowienie komunikacji i odczytanie wartości z ultradźwiękowego czujnika wyglądać będzie następująco:
nxt_iCmd_open:- writeln('Opening connection...'), jpl_call( 'icommand.nxt.comm.NXTCommand' , 'open', [], _), writeln('Configuring connection...'), jpl_call( 'icommand.nxt.comm.NXTCommand' , 'setVerify', [@(true)], _), writeln('Connection established!'). nxt_iCmd_distance(PortName, Dist):- writeln('Getting port handle...'), jpl_get('icommand.nxt.SensorPort', PortName, PortHandle), writeln('Creating ultrasonic sensor object...'), jpl_new('icommand.nxt.UltrasonicSensor', [PortHandle], UltraSonic), writeln('Reading distance from ultrasonic sensor...'), jpl_call( UltraSonic, 'getDistance', [], Dist), writeln('Reading finished.').
Zaś odpowiadające wywołanie w Prologu to:
nxt_iCmd_open. nxt_iCmd_distance('S4', X).