Laboratorium Inteligentnych Maszyn i Systemów Wydział Elektryczny Politechniki Warszawskiej Pioneer 3DX - zaawansowany robot mobilny o napędzie różnicowym Witold Czajewski 9 października 2011 Spis treści 1 Cel ćwiczenia 2 2 Sprzęt i oprogramowanie 2 2.1 Robot....................................... 2 2.1.1 Komputer pokładowy.......................... 3 2.2 Środowisko programistyczne.......................... 5 2.3 Podstawowy komendy sterujace robotem................... 5 2.4 Odczyt sonarów................................. 6 2.5 Podstawowy program.............................. 7 3 Przebieg ćwiczenia 8 3.1 Część pierwsza.................................. 8 3.2 Część druga.................................... 9 3.3 Część trzecia................................... 11 4 Sposób oceny 11
1 Cel ćwiczenia Celem ćwiczenia jest zapoznanie Studentów z zaawansowanym robotem mobilnym, a w szczególności z jego możliwościami jezdnymi, dynamika oraz zagadnieniem mapowania i nawigacji. Ponadto Studenci będa mieli za zadanie napisanie własnego programu sterujacego robotem. Ćwiczenie składa się z trzech zasadniczych części: 1. Poznanie robota, jego zachowania i reakcji na sterowanie oraz sygnały z czujników, 2. Mapowanie i nawigacja - wykorzystanie mapy pomieszczenia do lokalizacji robota, 3. Programowanie zachowania robota - rozszerzenie prostej aplikacji. Część pierwsza polega na obserwacji zachowania robota podczas autonomicznej jazdy po laboratorium. Następnie kontrolę nad robotem przejma Studenci i podczas jazdy zaobserwuja reakcje robota na otaczajace go przeszkody (ściany, narożniki, nogi stołów i krzeseł, nogi człowieka itd. itp.). Istotne jest stwierdzenie jakie przeszkody stanowia dla robota problem, a jakie nie. W drugiej części ćwiczenia należy wykorzystać mapę pomieszczenia i sprawdzić zdolność robota do lokalizacji w pomieszczeniu na jej podstawie. W szczególności należy przeprowadzić eksperymenty polegajace na podaniu robotowi fałszywej pozycji (bład położenia, bład orientacji, obydwa błędy jednocześnie) w dwóch częściach laboratorium (w części wiernie odwzorowanej na mapie oraz w części, gdzie znajduja się obiekty niezaznaczone na mapie). Interesujaca jest kwestia czy i po jak długim czasie ruchu robot będzie w stanie się prawidłowo zlokalizować mimo fałszywych danych poczatkowych. Ostatnia część ćwiczenia polega na napisaniu programu sterujacego zachowaniem robota na podstawie odczytu z czujników sonarowych. Bez względu na konkretne zadanie podane do realizacji przez prowadzacego, niezbędne będzie określenie największej i najmniejszej odległości zwracanej przez sonary, a także znalezienie pary sasiednich sonarów podajacych największa odległość (programowanie w języku C, konieczna znajomość instrukcji for i if). Bardziej szczegółowe instrukcje zostana udzielone przez prowadzacego. 2 Sprzęt i oprogramowanie 2.1 Robot Robotem mobilnym wykorzystywanym podczas ćwiczenia jest Pioneer 3DX firmy ActiveMedia (rys. 1). Jest on wyposażony jest w dwa koła napędowe o stałych osiach obrotu oraz jedno koło kastora stanowiace trzeci punkt podparcia. Wszystkie roboty firmy ActivMedia działaja jako serwery w architekturze klient-serwer. Kontrolery zainstalowane w pojazdach obsługuja wszystkie niskopoziomowe aspekty ich pracy, wliczajac w to min.: sterowanie praca silników, pobieranie wskazań czujników, zarzadzanie dodatkowymi akcesoriami. Dane te sa odpowiednio formatowane i przekazywane do klienta. Roboty Pioneer 3DX oparte sa na mikrokontrolerze Hitachi H8S, na którym zaimplementowano system operacyjny AROS (ActiveMedia Robotics Opertating System) spełniajacy rolę serwera. Poprzez oprogramowanie MobileSim umożliwiono tworzenie oprogramowania klienta bez przymusu fizycznego kontaktu z pojazdem. Jest to symulator pojazdu Pioneer 3DX. 2
Rysunek 1: Robot Pioneer 3DX wraz z komputerem nadrzednym. Aby uzupełnic architekture klient-serwer, pojazd potrzebuje połaczenia klienta oprogramowania działajacego na platformie komputera. Oprogramowanie, to poprzez połaczenie z kontrolerem pojazdu, zapewnia inteligentna nad nim kontrole. Zadania takie jak omijanie przeszkód, planowanie trasy, rozpoznawanie obiektów, lokalizacja i nawigacja w terenie wymagaja wyz szej mocy obliczeniowej, dostepnej na platformie PC. Oprogramowanie klienta dostepne jest pod systemami Windows i Linux Red Hat. Oprogamowanie klienta - ARIA (ActiveMedia Robotisc Interface for Applications) - oparte jest na je zyku C++ i zapewnia sprawny interfejs funkcji pojazdu Pioneer 3DX, pozwala na integracje własnych metod sterowania robotem oraz zapewnia kontrole nad wszystkimi szczegółami interakcji pomiedzy klientem a serwerem. 2.1.1 Komputer pokładowy Do sterowania robotem Pioneer 3DX niezbedny jest komputer klasy PC. W laboratorium Limis wykorzystano do tego jednopłytkowy komputer w obudowie przemysłowej firmy Advantech zamocowany na robocie i podłaczony do niego poprzez złacze szeregowe (rys. 2). Model PCI-6881 jest płyta komputera obsługujac a procesory rodziny Intel Pentium M lub Celeron M i umoz liwiajac a sterowanie kartami rozszerzen PCI. Wykorzystanie procesorów mobilnych powoduje zmniejszony pobór mocy, co waz ne jest w systemach zasilanych akumulatorowo, a takz e zmniejszona emisje ciepła. Technologia SpeedStep pozwala na dopasowanie czestotliwos ci pracy procesora do chwilowych potrzeb oprogramowania. Jak na współczesna karte procesorowa przystało PCI-6881 jest dostepny z gigabitowym portem ethernetowym oraz portami USB 2.0, wyjs ciem monitorowym oraz gniazdem myszy i klawiatury. Obecna konfiguracja komputera opiera sie na procesorze Intel Pentium Mobile 1,7 GHz i 2 GB pamie ci DDR RAM. Komputer ten zamontowany jest w obudowie firmy Advantech wraz z odpowiednim zasilaczem, skonstruowanym specjalnie do tego celu przez dr. inz. Dominika Sierociuka, 2,5 calowym dyskiem twardym o pojemnos ci 120 GB oraz karta akwizycji obrazu. 3
Nazwa Pioneer 3DX Długość 44,5 cm Szerokość 40 cm Wysokość 24,5 cm Masa (z jednym akumulatorem) 9 kg Maksymalne obciażenie 23 kg Zasilanie Akumulatory żelowe bezobsługowe 12V Czas ładowania 2-6 h Napęd 2 koła napędowe + koło podpierajace Koła napędowe nylonowe wypełnione pianka Koło podpierajace twarda guma Koła Średnica 19 cm, grubość 5 cm Sterowanie Mechanizm różnicowy Przekładnia 38.3:1 Promień skrętu 0 Maksymalna prędkość 1,2 m/s Pokonywalny kat wzniesienia 25% Pokonywany typ terenu Każdy dostępny dla wózków inwalidzkich Sonary 16 sonarów : po 6 skierowanych do przodu i do tyłu 4 boczne Zasięg sonarów 20 cm 5 m Głośniki Piezoelektryczne Mikrokontroler Hitachi H8S Układy wejścia/wyjścia 8 bitowa zewnętrzna szyna danych obsługujaca do 16 urzadzeń + obsługa kart PC104 Porty komunikacyjne 3 porty szeregowe RS-232 na mikrokontrolerze Pamięć Flash 1 MB Konstrukcja Aluminiowe płyty anodyzowane (płyta wierzchnia) i malowane proszkowo (reszta obudowy) Tabela 1: Właściwości i parametry robota Pioneer 3DX. 4
Rysunek 2: Wnętrze komputera przemysłowego sterujacego robotem. Na komputerze zainstalowany został system operacyjny Windows XP Professional firmy Microsoft wraz z pakietem bibliotek programistycznych.net FrameWork 2.0. Umożliwia to uruchamianie rozbudowanych aplikacji, wykorzystujacych interfejs Windows API. Praca na komputerze odbywa się poprzez program Microsoft terminal services client (mstsc.exe) program obsługi zdalnego pulpitu i aplikacji. Pozwala on na prace na zdalnym komputerze tak jakby był on bezpośrednio dostępny dla użytkownika. W ten sposób napisane na potrzeby projektu aplikacje moga być uruchamiane i testowane na komputerze umieszczonym na robocie bez potrzeby fizycznego z nim kontaktu. 2.2 Środowisko programistyczne Robot będacy na wyposażeniu laboratorium Limis jest programowany w środowisku Microsoft Visual Studio w języku C/C++. Wszystkie niezbędne biblioteki dostarcza producent robota. Oprogramowanie jest zainstalowane i gotowe do wykorzystania. Konkretnych wskazówek na temat aplikacji i szczegółów ich działania udzieli prowadzacy podczas zajęć. 2.3 Podstawowy komendy sterujace robotem Najprostsze, bezpośrednie komendy ruchowe będace metodami klasy ArRobot to: setvel(), setvel2(), setrotvel(). Polecenie setvel(double Velocity) ustawia zadana prędkość robota w milimeterach na sekundę, setvel2(double leftvelocity, double rightvelocity) działa podobnie, z tym że niezależnie dla każdego z kół, a setrotvel(double Velocity) zadaje prędkość obrotowa robota w stopniach na sekundę. W tym trybie sterowaina przyda się jeszcze metoda ArUtil::Sleep(double sleeptime), która wstrzymuje 5
wykonywanie kolejnych komend na dany czas (w milisekundach). Innym (wygodniejszym) sposobem sterowania robotem jest wykorzystanie metod: move(), setheading(), setdeltaheading(). Polecenie move(double distance) spowoduje ruch robota po linii prostej na zadana odległość (w mm), zaś pozostałe dwa: setheading(double angle) oraz setdeltaheading(double deltaangle) zmienia (odpowiednio) bezwzględna i względna orientację robota (w stopniach). Do zatrzymania robota służy metoda stop(). Często warto wiedzieć czy dana komenda ruchowa została już wykonana czy jeszcze nie. Można to sprawdzić metodami ismovedone() i isheadingdone() zwracajacymi logiczna prawdę po zakończeniu ruchu. Warto zauważyć, że możliwe jest programowanie znacznie bardziej złożonych sekwencji ruchów i zachowań robota z wykorzystaniem tzw. akcji, które dziecicza po klasie ArAction, niemniej wykracza to poza zakres niniejszego ćwiczenia. 2.4 Odczyt sonarów Bezpośredniego odczytu wartości z sonaru o zadanym numerze można dokonać za pomoca metody getsonarreading(int nr) klasy ArRobot. Metoda ta zwraca wskaźnik do obiektu klasy ArSensorReading, której metody getrange() i getsensorth() pozwalaja na odczyt odległości i kata ustawienia sonaru (patrz rys. 3). W przypadku, gdy interesuje nas tylko odległość mierzona przez dany sonar, można posłużyć się metoda getsonarrange() klasy ArRobot. W sytuacji, gdy wymagane jest wykrycie najmniejszej wartości zwracanej przez sonary (najbliższej przeszkody), można wykorzystać dwie metody: getclosestsonarrange(double startangle, double stopangle) oraz getclosestsonarnumber(double startangle, double stopangle). Niestety nie ma metody zwracajacej największa zarejestrowana przez sonary odległość. Rysunek 3: Rozmieszczenie sonarów na robocie. 6
2.5 Podstawowy program Poniżej znajduje się listing podstawowego programu, który porusza robotem i reaguje na odległość zmierzona sonarem. Pierwszym zadaniem zespołu będzie taka modyfikacja tego programu, aby robot jeździł po laboratorium nie wpadajac na przeszkody (w obecnej wersji robot korzysta tylko z jednego sonaru, co często prowadzi do kolizji z przeszkodami). Kolejne zadanie, nieco bardziej złożone zostanie podane przez prowadzacego. #include " Aria. h" ArRobot * robot ; void sonarprinter ( void ) { int i ; gotoxy (0,20); for ( i = 0; i < robot >getnumsonar ( ) ; i ++) p r i n t f ( " %4d", robot >getsonarrange ( i ) ) ; fflush ( stdout ) ; } int main ( int argc, char ** argv ) { Aria : : i n i t ( ) ; ArArgumentParser parser(&argc, argv ) ; ArSimpleConnector simpleconnector(& parser ) ; robot = new ArRobot ; ArKeyHandler keyhandler ; Aria : : setkeyhandler(&keyhandler ) ; robot >attachkeyhandler(&keyhandler ) ; // obsluga klawisza ESC ArGlobalFunctor sonarprintercb(& sonarprinter ) ; i f (! simpleconnector. connectrobot ( robot ) ) // polaczenie z robotem { p r i n t f ( " Could not connect to robot... exiting\n" ) ; Aria : : e x i t ( 1 ) ; } robot >runasync ( true ) ; //proces uzytkownika, wypisywanie odleglosci, uruchamiany co 50 ms w t l e robot >addusertask ( " Sonar printer ", 50, &sonarprintercb ) ; robot >enablemotors ( ) ; // uruchomienie silnikow while ( 1 ) //prosty ruch w p e t l i { i f ( robot >getsonarrange(4) >1000) { robot >move(800); while (! robot >ismovedone ( ) ) ; } robot >setdeltaheading ( 1 0 ) ; while (! robot >isheadingdone ( ) ) ; } } Aria : : e x i t ( ) ; return 0; // wylaczenie robota 7
3 Przebieg ćwiczenia 3.1 Część pierwsza Uruchomić robota i komputer pokładowy (każde urzadzenie ma osobny włacznik, niemniej włacznik robota jest nadrzędny i najczęściej komputer pokładowy nie jest wyła- czany). Po odczekaniu kilku minut potrzebnych na uruchomienie systemu operacyjnego i nawiazanie połaczenia sieciowego, należy połaczyć się z robotem przez zdalny pulpit. Adres robota: 10.44.29.21, login: robot1, hasło: 123. W razie odmowy nawia- zania połaczenia, należy chwilę odczekać i ponowić próbę. Jeśli po kilku minutach nie będzie połaczenia z robotem, należy powiadomić prowadzacego. Po nawiazaniu połaczenia należy uruchomić program Aria Demo. Jest to konsolowa aplikacja umożliwiajaca proste sterowanie robotem za pomoca klawiatury. Strzałki w lewo i prawo zmieniaja orientację robota z pewna prędkościa katow a tak długo jak długo sa naciśnięte. Strzałki do przodu i do tyłu inkrementuja badź dekrementuja wektor prędkości robota, który w chwili uruchomienia aplikacji jest równy zero. Tak więc, każde naciśnięcie strzałki do przodu zwiększa nieco prędkość robota, zaś strzałki do tyłu - zmniejsza. Aby zatrzymać robota należy użyć klawisza spacji - powoduje on łagodne zatrzymanie się robota (robot zatrzymuje się łagodnie, powoli zwalniajac do zera). Jeśli zajdzie potrzeba natychmiastowego zatrzymania robota, można to zrobić naciskajac klawisz ESC, jednak nie jest to sposób zalecany, gdyż gwałtowne zatrzymanie robota powoduje powstanie udaru mechanicznego, co może być powodem awarii systemu (obluzowanie styków) lub nawet uszkodzenia elementów elektronicznych ze względu na powstajace na płytkach naprężenia mechaniczne (komputer pokładowy nie jest przystosowany do pracy w warunkach silnych wstrzasów czy wibracji). Zadaniem wszystkich członków zespołu jest zapoznanie się z właściwościami jezdnymi robota, w szczególności ze zdolnościa do wykrywania przeszkód. Robot wyposażony jest w czujniki sonarowe, które wykryja większość przeszkód i nie pozwola robotowi na nie wjechać. Podczas badań należy sprawdzić zachowanie robota z różnymi przeszkodami takimi jak: ściana, narożnik wewnętrzny, narożnik zewnętrzny, moga od stołu, noga od krzesła, pochyła noga od stołu, własna noga itp. Badania należy wykonywać ostrożnie i nie z maksymalna prędkościa! Obserwacje zapisać. Kolejnym elementem do weryfikacji jest dokładność nawigacji odometrycznej. Aby ja zbadać, należy ustawić robota (w razie potrzeby przesuwajac go ręcznie) w oznaczonym na podłodze miejsscu, a następnie uruchomić (ponownie) program Aria Demo. Spowoduje to wyzerowanie pozycji robota, która w jest widoczna w aplikacji konsolowej jako współrzędne kartezjańskie X i Y oraz kat obrotu theta. Należy teraz przejechać robotem dookoła laboratorium, raz zgodnie z kierunkiem obrotu wskazówek zegara, a raz przeciwnie, cały czas starajac się zachować w miarę równy tor jazdy, nie wpadajac na przeszkody (bardzo pomaga tu obserwacja robota pod stołami - sprawdza się znacznie lepiej niż ktoś przekazujacy słownie informacje na temat położenia robota tudzież informacje typu "trochę w lewo, a potem prosto"). Po zrobieniu pętli, należy powrócić możliwie precyzyjnie do miejsca startowego i zanotować współrzędne robota (położenie i orientację) z aplikacji konsolowej. Całość powtórzyć, tym razem jadac zygzakiem, wpadajac (delikatnie) na przeszkody. Jakie sa współrzędne zwrócone przez robota w aplikacji konsolowej? Jakie powinny teoretycznie być? Z czego wynika różnica? Czy jest jednakowa w obu kierunkach? Dlaczego? Czy wyniki sa jednakowe w obydwu przypadkach (jazda równym tore oraz zygzakiem)? Dlaczego? 8
UWAGA! Podczas jazdy należy zwracać uwagę, by robot nie spadł ze schodów w laboratorium! 3.2 Część druga Druga część badań polega na sprawdzeniu zdolności nawigacyjnych robota. W tym celu należy uruchomić program nawigacja.bat, a następnie połaczyć się z robotem naciskajac klawisz Connect. W rezultacie tych działań powinna uruchomić się aplikacja Mobile Eyes, jak na rys. 4. Rysunek 4: Widok aplikacji Mobile Eyes służacej m.in. do sterowania robotem z użyciem mapy otoczenia. Robot (oznaczony czerwonym kółkiem) zazwyczaj nie pojawia się na mapie w tym miejscu, w którym znajduje się on w rzeczywistości (robot nie ma takiej informacji). Echa sonarowe zaznaczone sa niebieskimi trójkatami. Powinny one odpowiadać zaznaczonej na mapie geometrii, ale jedynie wtedy, gdy robot znajduje się rzeczywiście w miejscu, w którym sadzi, że się znajduje lub też w bardzo podobnym otoczeniu. Np. w długim waskim korytarzu, echa sonarów będa identyczne w wielu miejscach i nie będzie można stwierdzić, gdzie faktycznie robot się znajduje i czy jego pozycja jest błędna czy nie. W przypadku naszego laboratorium, najczęściej będzie widać, że zainicjowana pozycja robota nie odpowiada rzeczywistości. Teoretycznie robot mógłby samodzielnie 9
odnaleźć prawidłowa lokalizację poprzez porównanie wszystkich możliwych miejsc na mapie i wyliczonych w nich ech sonarowych z rzeczywistymi echami, jednak taka operacja byłaby bardzo czasochłonna, a w pewnych sytuacjach (wspomniany wyżej korytarz), nie dałaby jednoznacznej odpowiedzi. W zwiazku z powyższym, pierwsza czynnościa po uruchomieniu programu jest wskazanie robotowi jego rzeczywistej pozycji. W tym celu należy skorzystać z polecenia Tools->Robot Tools->Localize to Point i zaznaczyć myszka na mapie pozycję oraz orientację robota (tę ostatnia określa się poprzez przeciaganie myszka z przytrzymanym jej lewym klawiszem). Robota będzie także otaczać chmura różowych punktów, oznaczajacych jego prawdopodobna pozycję. Poczatkowo, chmura ta jest rozłożona mniej więcej równomiernie w pewnym otoczeniu robota, jednak wraz z pozyskiwaniem przez robota nowych informacji o otoczeniu (na podstawie odczytów z sonarów) zmienia swój kształt. Punkty przemieszczaja się, gromadzac w skupiska - im liczniejsze, tym większe prawdopodobieństwo, że oznaczaja rzeczywista pozycję robota. Każdy ruch robota jest źródłem dodatkowej informacji - jeśli wskazana pozycja robota nie jest idealna, ale dostatecznie bliska rzeczywistej, po wykonaniu dłuższej lub krótszej sekwencji ruchów, robot odnajdzie swoja rzeczywista pozycję i skoryguje pozycję na mapie, co objawi się charakterytycznym "przeskokiem" robota na mapie. Podczas kolejnych ruchów robota, będzie można zaobserwować, że chmura różowych punktów (tym razem bardzo skupiona) będzie podażać za robotem. Jej rozległość jest odwrotnie proporcjonalna do prawdopodobieństwa poprawnej lokalizacji robota. W ramach ćwiczenia należy przeprowadzić badania skuteczności samolokalizacji robota w następujacy sposób: 1. Wskazać pozycję i orientację robota możliwie blisko rzeczywistej, 2. Wskazać poprawna pozycję robota, ale błędna orientację (bład 90 stopni, 180 stopni), 3. Wskazać poprawna orientację robota, ale błędna pozycję (bład 0,5 m, 1 m), 4. Wskazać błędna pozycję robota, zarówno jeśli chodzi o pozycję, jak i orientację. W każdym z powyższych przypadków należy ręcznie (tzn. za pomoca aplikacji) przemieścić i obrócić robota, aż znajdzie on swoja prawidłowa pozycję i orientację. Jeśli po przejechaniu kilkunastu metrów w jedna i druga stronę i kilkunastu obrotach robot nie wyznaczy swej rzeczywistej pozycji, należy uznać, że w danym przypadku jest to niemożliwe. W pozostałych przypadkach należy oszacować łatwość wyznaczenia prawidłowej pozycji. Powyższe eksperymenty należy powtórzyć w dwóch miejscach laboratorium - w korytarzu z lewej strony, gdzie geometria laboratorium jest dobrze odzwierciedlona na mapie i nie jest zakłócona przez obiekty nieuwzględnione na mapie oraz w korytarzu z prawej strony, blisko drzwi wejściowych, gdzie mapa jest mniej dokładna, a dodatkowo robot będzie widział także wykonujacych ćwiczenie studentów. Uzyskane wyniki porównać. Ostatni etap drugiej części ćwiczenia polega na sprawdzeniu zdolności nawigacyjnych robota. Po prawidłowym zlokalizowaniu robota, należy wykorzystać polecenie Send Robot by wysłać go w dowolne miejsce na mapie. Należy sprawdzić czy robot jest w stanie osiagn ać zaznaczone miejsca w przypadku, gdy geometria pomieszczenia jest zgodna z mapa oraz gdy wprowadzi się w niej pewne zmiany (należy ustawić przeszkody z krzeseł i sprawdzić czy robot nadal będzie w stanie prawidłowo nawigować, nie majac tych przeszkód zaznaczonych na mapie). Jaka jest najmniejsza szerokość 10
korytarza, przez która robot zdoła przejechać? Jak zachowa się robot, jeśli przeszkoda będzie slalom z krzeseł? Jak zachowa się robot w przypadku, gdy ktoś będzie za nim szedł (wówczas tylne sonary będa wprowadzały robota w bład)? Jak zachowa się robot, gdy ktoś "złośliwie" będzie blokował mu drogę? 3.3 Część trzecia W ostaniej części ćwiczenia należy zmodyfikować przykładowy program zgodnie z wytycznymi prowadzacego. W programie konieczne będzie wykorzystanie informacji pochodzacej z sonarów, w szczególności znalezienie kierunku, w którym odległość zwracana przez sonary jest najmniejsza lub największa (najlepiej zrobić to odpowiednio skonstruowana pętla for). Niezbędna będzie też kontrola prędkości i kierunku jazdy robota, w zależności od odległości widzianych przez sonary. 4 Sposób oceny Zespoły będa oceniane na podstawie sprawozdania opisujacego przebieg ćwiczenia, a w szczególności zachowanie się robota wobec przeszkód oraz jego zdolności nawigacyjne. Strona edycyjna sprawozdania, ilustracje, zrzuty ekranu itp. będzie oceniana na równi ze strona merytoryczna (odpowiedni opis przeprowadzonych eksperymentów i wnioski). Ocenie podlegać będzie także aplikacja sterujaca robotem napisana podczas zajęć, której opis rówineż powinien znaleźć się w sprawozdaniu. Sprawozdanie należy przesłać w formie pliku PDF na adres w.czajewski@isep.pw.edu.pl przed rozpoczęciem kolejnych zajęć laboratoryjnych. 11