Robot IRp-6 w zadaniu rysowania

Transkrypt

Robot IRp-6 w zadaniu rysowania
Rok akademicki 2014/2015
POLITECHNIKA WARSZAWSKA
WYDZIAŁ ELEKTRONIKI I TECHNIK INFORMACYJNYCH
INSTYTUT AUTOMATYKI I INFORMATYKI STOSOWANEJ
PRACA DYPLOMOWA INŻYNIERSKA
Anna Wujek
Robot IRp-6 w zadaniu rysowania
Opiekun pracy:
dr inż. Tomasz Winiarski
Ocena pracy: . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.........................................
Data i podpis Przewodniczącego
Komisji Egzaminu Dyplomowego
Streszczenie
Tytuł: Robot IRp-6 w zadaniu rysowania
Celem pracy było stworzenie oprogramowania dla robota IRp-6 z zamontowaną
kamerą, które wykona następujące zadania: analizę obrazu wejściowego w celu stworzenia obrazu konturowego oraz sterowanie ramieniem robota w celu narysowania na
kartce utworzonego wcześniej obrazu. System znajduje kartkę z rysunkiem, wyznacza
jej położenie oraz krawędzie obrazu względem układu bazowego robota, a następnie
rysuje obraz krawędziowy na czystej kartce. W skład systemu wchodzą dwie główne
części. Pierwsza to moduł wizyjny, stworzony przy użyciu programowej struktury
ramowej DisCODe i biblioteki OpenCV, odpowiedzialny za detekcję kartki oraz krawędzi obrazu. Druga część to aplikacja sterująca robotem, wykorzystująca interfejs
IRPOS oraz system ROS/OROCOS.
Słowa kluczowe: Robot IRp-6, ROS, IRPOS, DisCODe, OpenCV, znajdowanie
konturów
Abstract
Title: IRp-6 robot performing a drawing
The aim of a bachelor thesis was to design and create a software for IRp-6 robot
able to perform the following tasks: analysis of an input image to create contour
image and control of a robot arm to draw previously created image. The system detects a sheet of paper with a drawing, determines its position and contours of a drawing in base coordinate system of a robot and draws contour image on a blank sheet
of paper. System consists of two modules. A vision module, created using DisCODe
framework and OpenCV library, is responsible for shapes and contours detection.
Second part of a system is an application to control a robot, created using IRPOS
interface and ROS/OROCOS system.
Keywords: IRp-6 robot, ROS, IRPOS, DisCODe, OpenCV, contours detection
4
Spis treści
1 Wstęp
1.1 Wprowadzenie
1.2 Motywacja . .
1.3 Cel pracy . .
1.4 Układ pracy .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7
7
7
7
8
2 Wykorzystane technologie
2.1 Sprzęt . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Robot . . . . . . . . . . . . . . . . . . .
2.1.2 Kamera . . . . . . . . . . . . . . . . . .
2.2 Oprogramowanie . . . . . . . . . . . . . . . . .
2.2.1 System ROS . . . . . . . . . . . . . . . .
2.2.2 OROCOS . . . . . . . . . . . . . . . . .
2.2.3 IRPOS . . . . . . . . . . . . . . . . . . .
2.2.4 DisCODe . . . . . . . . . . . . . . . . .
2.2.5 OpenCV . . . . . . . . . . . . . . . . . .
2.2.6 Użyte algorytmy przetwarzania obrazów
2.2.7 Dodatkowe biblioteki . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
9
9
10
10
11
11
13
14
15
17
.
.
.
.
.
.
19
19
19
21
22
22
24
.
.
.
.
.
.
.
.
.
.
.
27
27
27
28
28
30
31
33
36
37
38
38
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Projekt systemu
3.1 Przebieg zadania . . . . . . . . . . . .
3.2 Założenia projektowe . . . . . . . . . .
3.3 Struktura rozwiązania . . . . . . . . .
3.3.1 Komunikacja między modułami
3.3.2 Moduł wizyjny . . . . . . . . .
3.3.3 Moduł sterowania . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Realizacja
4.1 Moduł wizyjny . . . . . . . . . . . . . . . . . . . . .
4.1.1 Struktura modułu wizyjnego . . . . . . . . . .
4.1.2 Akwizycja obrazu . . . . . . . . . . . . . . . .
4.1.3 Usunięcie zakłóceń i zniekształceń . . . . . . .
4.1.4 Segmentacja . . . . . . . . . . . . . . . . . . .
4.1.5 Wyznaczenie położenia kartki w obrazie . . .
4.1.6 Wyznaczenie konturów . . . . . . . . . . . . .
4.1.7 Znalezienie przekształcenia do układu kamery
4.1.8 Wysyłanie danych . . . . . . . . . . . . . . .
4.2 Komunikacja między modułami . . . . . . . . . . . .
4.2.1 Wysyłanie danych . . . . . . . . . . . . . . .
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
SPIS TREŚCI
4.3
4.4
4.2.2 Odbieranie danych . . . . . . . .
Moduł sterowania . . . . . . . . . . . . .
4.3.1 Obliczenie i wykonanie trajektorii
4.3.2 Użycie biblioteki IRPOS . . . . .
Modyfikacja stanowiska robotycznego . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Wyniki i testy
5.1 Strojenie systemu . . . . . . . . . . . . . . . . .
5.1.1 Parametry działania modułu wizyjnego .
5.1.2 Wybranie funkcji opuszczającej narzędzie
5.2 Wyniki działania i testy . . . . . . . . . . . . .
5.2.1 Weryfikacja wykrycia kartki . . . . . . .
5.2.2 Jakość rysunku . . . . . . . . . . . . . .
5.2.3 Test grubości linii . . . . . . . . . . . . .
5.2.4 Test gęstości linii . . . . . . . . . . . . .
5.2.5 Sterowanie . . . . . . . . . . . . . . . . .
5.3 Podsumowanie . . . . . . . . . . . . . . . . . .
5.3.1 Wnioski . . . . . . . . . . . . . . . . . .
5.3.2 Perspektywy rozwoju . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
40
40
41
43
.
.
.
.
.
.
.
.
.
.
.
.
45
45
45
47
47
47
49
50
51
52
52
52
52
Rozdział 1
Wstęp
Pierwszy rozdział stanowi wstęp do pracy. Obejmuje wprowadzenie do tematyki
pracy (sekcja 1.1), motywację do jej napisania (sekcja 1.2), jej cel (sekcja 1.3) oraz
jej układ (sekcja 1.4).
1.1
Wprowadzenie
Robotyka, a także związane z nią wizja komputerowa i przetwarzanie obrazów,
są dziedzinami bardzo silnie rozwijającymi się i wchodzącymi w coraz więcej sfer
naszego życia. Początkowo roboty były konstruowane w celu odciążenia ludzi w pracach żmudnych, wymagających dużej siły lub precyzji. Dzisiaj ich wykorzystanie jest
znacząco szersze - roboty zaczynają znajdować zastosowanie w życiu codziennym,
a nawet w sztuce czy rozrywce. Dlatego istotne jest zdobywanie wiedzy z zakresu
robotyki i dziedzin z nią związanych, aby móc w przyszłości je rozwijać.
1.2
Motywacja
Silną motywacją do zajęcia się pracą Robot IRp-6 w zadaniu rysowania była
wartość dydaktyczna tego projektu. Pozwoliła mi zdobyć wiedzę i umiejętności z zakresu robotyki i przetwarzania obrazu oraz integracji tych dwóch dziedzin. Praca
stanowiła także praktyczną weryfikację wiedzy z zakresu programowania i projektowania, zdobytej na studiach. Działający system jest ciekawą atrakcją, która może
zostać wykorzystana podczas promocji Wydziału i Uczelni. Dodatkowo, projekt ten
ma duży potencjał i może być rozwinięty, na przykład w ramach pracy magisterskiej.
1.3
Cel pracy
Celem pracy było zaprojektowanie i zaimplementowanie systemu realizującego
zadanie rysowania dla robota IRp-6. Obejmowało to dwa główne zagadnienia:
• analizę obrazu, na podstawie którego powstanie rysunek,
• sterowanie manipulatorem, którego efektem będzie rysunek jak najlepiej oddający kontury obrazu wejściowego.
7
8
1.4
ROZDZIAŁ 1. WSTĘP
Układ pracy
Praca składa się z pięciu rozdziałów, łącznie z niniejszym. Rozdział drugi opisuje
wykorzystane technologie, zarówno sprzętowe, jak i programowe. Trzeci rozdział to
projekt systemu, zawierający założenia, dokładny opis zadania oraz zaproponowane
rozwiązanie. W rozdziale czwartym udokumentowana została realizacja systemu.
Wyniki końcowe i wnioski stanowią rozdział piąty.
Rozdział 2
Wykorzystane technologie
Praca została zrealizowana przy wykorzystaniu wielu technologii: manipulatora
IRp-6 i kamery (sekcja 2.1) oraz licznych bibliotek i systemów (sekcja 2.2).
2.1
Sprzęt
2.1.1
Robot
Wykonanie założonego zadania wymaga manipulatora z zamontowanym pisakiem w końcówce roboczej. Wybór manipulatora wynika z wyposażenia laboratorium robotyki 012 na Wydziale Elektroniki i Technik Informacyjnych Politechniki
Warszawskiej[5]. Użytym robotem jest manipulator IRp-6. Jest to przemysłowy robot elektryczny wykorzystujący silniki prądu stałego. Dzięki użyciu enkoderów do
precyzyjnego ustalania położenia możliwa jest realizacja skomplikowanych operacji
takich jak ruch po prostej, ruch po łuku, osiągnięcie konkretnej pozycji we współrzędnych kartezjańskich, ruch przy stałym nacisku z daną prędkością.
Robot wykorzystywany w pracy - Track - posiada 7 stopni swobody, kamerę
oraz czujnik siły[16]. Ramię robota zostało pokazane na rysunku 2.1(a), a sposób
zamocowania kamery na rysunku 2.1(b). Drugi laboratoryjny robot, Postument, posiadający 6 stopni swobody (nie posiada toru jezdnego), przy zapewnieniu kalibracji
kamery także mógłby wykonać zadanie postawione w tej pracy. Wybór robota Track
wynika z lepszego przystosowania chwytaka do zadania. W przypadku użycia robota
Postument konieczne byłoby usunięcie przedłużenia szczęk chwytaka.
2.1.2
Kamera
Zadanie akwizycji obrazu wykonuje kamera cyfrowa Blackfly w wariancie BFLYPGE-14S2C-CS firmy Point Grey o rozdzielczości 1,4 MPix[2]. Dodatkowo kamera
posiada obiektyw firmy LG Security w wersji LC-M13VM2812IRD o przesłonie F1.4
i ogniskowej zmiennej w zakresie 2,8 - 12 mm. Kamera posiada możliwość regulacji
szerokości otwarcia przesłony, długości ogniskowej oraz ostrości przy pomocy ruchomych pierścieni, które można zablokować śrubami. Kamera zamontowana jest
bezpośrednio w kiści robota[9]. Dołączony do niej jest sterownik umożliwiający regulację parametrów akwizycji, takich jak jasność, długość otwarcia migawki i liczba
klatek na sekundę.
9
10
ROZDZIAŁ 2. WYKORZYSTANE TECHNOLOGIE
(a) Ramię robota
(b) Zamocowanie kamery
Rysunek 2.1: Robot IRp-6 Track
2.2
Oprogramowanie
Zadanie rysowania wymaga wielu różnych technologii i platform oraz ich integracji. Niezbędne jest oprogramowanie analizujące obraz i sterujące robotami. Wybór
konkretnych technologii, opisanych w tym podrozdziale, wynika z wykorzystania ich
w już istniejącym oprogramowaniu w laboratorium. Wszystkie wykorzystane biblioteki i platformy mają otwarty kod, zapewniają fachową dokumentację oraz wiele
materiałów i są wspierane przez liczne społeczności internetowe.
2.2.1
System ROS
System ROS[4] (Robot Operating System) jest programową strukturą ramową
do tworzenia oprogramowania dla robotów. Zawiera zbiór bibliotek, narzędzi i konwencji ułatwiających zadanie tworzenia złożonych aplikacji sterujących robotami na
różnych platformach i sprzęcie. Zapewnia usługi niezbędne do tworzenia aplikacji
sterujących robotami[14], takie jak abstrakcja sprzętu, powszechnie używane funkcje, przesyłanie wiadomości, wielowątkowość, zarządzanie pakietami. Wielką zaletą
systemu ROS jest jego powszechne wykorzystanie w ośrodkach naukowo-badawczych
na całym świecie. Dzięki temu możliwe jest współtworzenie kodu, dynamiczny rozwój oraz wsparcie techniczne. System ROS przeznaczony jest na platformę Ubuntu,
wykorzystaną w tej pracy.
Podstawowe elementy, udostępniane przez system ROS i wykorzystywane w niniejszej pracy to:
• Węzły (ang. Nodes) - odpowiadają wątkom systemu operacyjnego. Dzięki
systemowi złożonemu z wielu wątków możliwe jest przeprowadzanie równoległych działań i obliczeń. Węzły mogą być połączone i komunikować się ze sobą
2.2. OPROGRAMOWANIE
11
bez ograniczeń - każdy z nich może być jednocześnie zarówno serwerem, jak
i klientem.
• Wiadomości (ang. Messages) - podstawowe struktury przechowujące dane,
które mogą być wykorzystane w czasie komunikacji. Istnieje możliwość definiowania własnych typów danych oraz zagnieżdżanie już istniejących.
• Tematy (ang. Topics) - kanały komunikacyjne, identyfikowane przez nazwy,
dzięki którym węzły mogą wymieniać się informacjami. Służą do rozgłaszania
danych. Węzły anonimowo publikują i subskrybują dane z tematu. Dzięki takiej strukturze informacje z danego tematu mogą być odczytane przez wiele
węzłów.
2.2.2
OROCOS
OROCOS[3] jest narzędziem wspomagającym tworzenie aplikacji sterujących robotami, działających w czasie rzeczywistym[7] przy użyciu modułowych, konfigurowalnych komponentów. Wspiera wiele platform: Windows, Linux, Mac OS. Zawiera rozszerzenia pozwalające na współpracę z innymi systemami i strukturami,
m.in. ROS. Pozwala na spełnienie twardych ograniczeń czasowych, używanie własnych typów danych, generowanie kodu oraz logowanie zdarzeń i komunikacji między
komponentami.
2.2.3
IRPOS
IRPOS[12] jest interfejsem operatorskim dla sterownika ROS/OROCOS, napisanym w języku Python, stworzonym w Zespole Programowania Robotów i Systemów
Rozpoznających. Został opracowany w celu sterowania robotami IRp-6 Track oraz
Postument. Posiada zaimplementowane funkcje, ułatwiające realizację złożonych ruchów, m.in. ruch końcówki roboczej wzdłuż zadanej listy punktów, ustawienie ramienia robota w konkretnych położeniach poszczególnych stawów czy też sterowanie siłowe. IRPOS współpracuje z systemem ROS, a dzięki komponentom systemu
OROCOS pozwala na sterowanie robotem w czasie rzeczywistym. Poniżej znajduje
się opis najważniejszych funkcji biblioteki IRPOS, wykorzystanych w pracy:
• Inicjalizacja
1
irpos = IRPOS ( nodeName , robotName , robot JointN umbers )
Utworzenie obiektu klasy IRPOS tworzy węzeł ROS, a następnie inicjuje komunikację pozwalającą na włączanie i wyłączanie komponentów OROCOS,
tworzy tematy ROS, na które publikowane są dane na temat położenia robota
i odczyty z czujnika siły. Inicjowana jest także komunikacja pozwalająca na
używanie generatorów trajektorii. Jako argumenty konstruktora podawane są
nodeName - nazwa tworzonego węzła ROS, robotName - nazwa robota oraz
robotJointNumbers - liczba stawów robota.
• Ruch do pozycji relatywnej w przestrzeni kartezjańskiej
1
m o v e _ r e l _ t o _ c a r t e s i a n _ p o s e ( time_from_start , rel_pose )
12
ROZDZIAŁ 2. WYKORZYSTANE TECHNOLOGIE
Pozwala na przemieszczenie końcówki roboczej w zadanym czasie
time from start do określonego położenia rel pose w przestrzeni względem aktualnej pozycji robota.
• Ruch do pozycji w przestrzeni kartezjańskiej
1
m o v e _ t o _ c a r t e s i a n _ p o s e ( time_from_start , pose )
Pozwala na przemieszczenie końcówki roboczej w zadanym czasie
time from start do konkretnego miejsca w przestrzeni pose w układzie
bazowym robota.
• Odczytanie aktualnej pozycji końcówki roboczej
1
ge t_ ca rt es ia n_ po se ()
Funkcja odczytuje aktualną pozycję końcówki roboczej, podając przemieszenie
oraz orientację względem układu bazowego.
• Ruch wzdłuż trajektorii
1
m o v e _ a l o n g _ c a r t e s i a n _ t r a j e c t o r y ( points )
Funkcja ta wykonuje trajektorię zadaną wektorem punktów points typu CartesianTrajectoryPoint, zawierających współrzędne punktu w przestrzeni i czas,
w jakim punkt ma zostać osiągnięty.
• Funkcje sterowania siłowego
1
2
3
s e t _ t o o l _ p h y s i c a l _ p a r a m s ( weight , m a s s _ c e n t e r _ p o s i t i o n )
s t a r t _ f o r c e _ c o n t r o l l e r ( inertia , reciprocaldamping , wrench ,
twist )
s t o p _ f o r c e _ c o n t r o l l e r ()
Pierwsza z funkcji pozwala na zdefiniowanie parametrów narzędzia, takich jak
masa (weight) oraz środek ciężkości (mass center position). Druga uruchamia
sterowanie pozycyjno - siłowe. Argument intertia określa zadaną bezwładność
końcówki roboczej, reciprocaldamping odwrotność tłumienia końcówki roboczej, wrench zadaną siłę uogólnioną w końcówce narzędzia, twist zadany wektor prędkości, z jaką ma się poruszać końcówka. Ostatnia funkcja zatrzymuje
sterowanie siłowe.
• Ruch do pozycji relatywnej w przestrzeni kartezjańskiej z ograniczeniem siłowym
1
m o v e _ r e l _ t o _ c a r t e s i a n _ p o s e _ w i t h _ c o n t a c t ( time_from_start ,
rel_pose , wr ench_c onstra int )
Funkcja ta działa bardzo podobnie do move rel to cartesian pose z tą różnicą,
że kończy ruch w momencie odczytania z czujnika siły wartości przekraczającej
ograniczenie siłowe, zdefiniowane w argumencie wrench constraint.
• Zaciskanie chwytaka
1
t f g _ t o _ j o i n t _ p o s i t i o n ( joint_position , time_from_start )
Funkcja ta w zadanym czasie time from start zaciska lub rozszerza szczęki
chwytaka do pozycji joint position.
2.2. OPROGRAMOWANIE
13
• Ruch do pozycji w przestrzeni współrzędnych wewnętrznych
1
m o v e _ t o _ j o i n t _ p o s i t i o n ( joint_positions , time_from_start )
Pozwala na wykonanie ruchu w zadanych czasie time from start do zadanego
położenia. Argument joint position jest wektorem pozycji poszczególnych stawów robota.
2.2.4
DisCODe
DisCODe[10] (Distributed Component Oriented Data Processing) jest programową strukturą ramową, utworzoną w Zespole Programowania Robotów i Systemów Rozpoznających. Platforma ta jest wykorzystywana do tworzenia i rozwijania aplikacji przetwarzających dane z czujników. Napisana głównie w języku C++,
pozwala na tworzenie komponentów i bibliotek komponentów, wykorzystywanych
w wielostopniowych algorytmach przetwarzania danych. Dzięki modułowej strukturze budowanie aplikacji przy jej użyciu jest proste, a cały proces przetwarzania może
zostać przedstawiony na grafie. Najważniejsze elementy struktury to komponenty,
egzekutory i zadania.
Komponenty
Komponenty (ang. Components) odpowiedzialne są za przetwarzanie danych.
Posiadają porty wejściowe i wyjściowe, definiujące typy danych, jakie przez nie
przepływają. Komponent może mieć zero lub więcej portów wejściowych i wyjściowych. Informacje przetwarzane są w funkcjach (ang. Handlers) zaimplementowanych
w komponentach. Zwykle funkcja realizuje trzy główne zadania: odebranie danych
z portów wejściowych, przetworzenie ich i zapisanie do portów wyjściowych. Funkcja może być wywoływana w momencie pojawienia się w porcie wejściowym nowych
danych. Możliwe jest łączenie komponentów w celu stworzenia bardziej skomplikowanych sekwencji przetwarzania danych. Szczegółowa budowa komponentu przedstawiona została na rysunku 2.2. Komponenty mogą mieć także właściwości (ang.
Properties), które pozwalają na zmianę parametrów komponentu, zarówno przy wywołaniu jak i w trakcie pracy. Komponenty są zgrupowane w bibliotekach, zwanych
DCL (DisCODe Component Library).
Priorytet funkcji
Kolejność
Komponent
Argument funkcji
Strumień danych
Port wejściowy
k
Komponent
Funkcja p
Funkcja przejścia
Wartość funkcji
Strumień danych
Port wyjściowy
Rysunek 2.2: Struktura komponentu DisCODe[11]
14
ROZDZIAŁ 2. WYKORZYSTANE TECHNOLOGIE
Egzekutory
Egzekutory (ang. Executors) odpowiadają wątkom systemu operacyjnego. Komponenty, które są zgrupowane w danym egzekutorze, są wykonywane sekwencyjnie.
Dzięki tej konstrukcji można wykonywać przetwarzanie równolegle oraz ustalić kolejność wykonywania się komponentów. Dla każdego egzekutora wyznaczana jest
częstotliwość, z jaką ma działać.
Zadania
Zadanie (ang. Task ) definiowane jest w pliku XML za pomocą znaczników określających zadanie, podzadania (grupujące egzekutory w logiczne moduły, które mogą
być włączane i wyłączane), egzekutory, komponenty i ich właściwości oraz połączenia
portów wejściowych i wyjściowych. XML jest uniwersalnym językiem znaczników,
przeznaczonym do reprezentowania różnych struktur, wymagającym poprawności
składniowej, m.in. domykania znaczników. Szczegółowa struktura zadania została
przedstawiona na rysunku 2.3.
Kolejność
Komponent
Nazwa
podzadania
Nazwa
egzekutora
Nazwa
k
Egzekutor
Podzadanie
Typ komponentu
Strumień danych
Port wejściowy
Strumień danych
Port wyjściowy
Rysunek 2.3: Struktura zadania DisCODe[11]
2.2.5
OpenCV
OpenCV[1] (Open Source Computer Vision) jest biblioteką typu open-source,
udostępniającą struktury i funkcje niezbędne do przetwarzania obrazu w aplikacjach działających w czasie rzeczywistym. Zawiera ponad 2500 zoptymalizowanych
algorytmów, wśród których, jako najistotniejsze dla tej pracy, można wyróżnić: rozpoznawanie obiektów w obrazach, algorytmy poprawy jakości obrazów, zmiana przestrzeni barw obrazu, znajdowanie macierzy przekształceń pomiędzy różnymi obrazami, usuwanie zniekształceń geometrycznych. Biblioteka OpenCV posiada wsparcie
dużej społeczności internetowej i jest wykorzystywana przez wielkie firmy informatyczne, takie jak Google, Microsoft czy Intel. Dzięki temu dynamicznie się rozwija
oraz dostępnych jest wiele materiałów dotyczących użycia tej biblioteki, zarówno na
oficjalnych stronach OpenCV, jak i na różnego rodzaju forach i blogach. OpenCV
wspiera wiele języków programowania, m.in. C, C++ (używany w niniejszej pracy
do przetwarzania obrazu), Python, Java, Matlab, jak również wiele systemów opera-
2.2. OPROGRAMOWANIE
15
cyjnych: Windows, Mac OS, Android oraz Linux, w którym utworzony został system
realizujący zadanie rysowania.
W czasie przetwarzania obrazu wykorzystywana jest struktura cv::Mat. Struktura ta jest typem udostępnianym przez bibliotekę OpenCV, pozwalającym na przechowywanie obrazu. Jest bardzo wygodna do przetwarzania, gdyż oferuje łatwy dostęp do składowych każdego piksela. Warto zauważyć, że wszystkie funkcje OpenCV
przetwarzające obraz jako argumentu wejściowego używają tej struktury.
2.2.6
Użyte algorytmy przetwarzania obrazów
Przetwarzanie obrazu, zrealizowane w ramach tej pracy, korzysta z wielu algorytmów przetwarzania obrazów, zaimplementowanych w bibliotece OpenCV[8]. Poniżej
znajduje się ich lista oraz krótki opis każdego z nich:
Rozmycie Gaussa
Jest stosowane w celu usunięcia wysokoczęstotliwościowych zakłóceń. Polega na
wykonaniu operacji splotu każdego piksela obrazu z elementem strukturalnym, czyli
macierzą, której elementy odpowiadają temu pikselowi (element środkowy macierzy) i jego sąsiadom. W tym przypadku obliczana jest suma iloczynów elementów
macierzy z jasnościami odpowiadających im pikseli. Po znormalizowaniu obliczona
wartość jest docelową jasnością danego piksela.
Zwykle macierz filtru Gaussa na postać podobną do macierzy przedstawionej
poniżej:


1 2 1


 2 4 2 
1 2 1
co odpowiada wykresowi dyskretnej funkcji Gaussa. Łatwo zauważyć, że jeśli
dany piksel będzie miał wartość bardzo różniącą się od swoich sąsiadów (czyli będzie
to najprawdopodobniej piksel zakłócony), to jego wartość zostanie zamieniona na
dużo bardziej zbliżoną do właściwej.
Nastąpi jednakże jeden niepożądany efekt - rozmycie krawędzi, co jest nieuniknione we wszystkich algorytmach usuwania szumu. Jednak przy niezbyt dużym
rozmiarze filtru rozmycie krawędzi nie będzie zbyt wielkie. Dodatkowo filtr ten ze
względu na swoje właściwości mniej zniekształca krawędzie niż inne algorytmy o tej
samej funkcji, np. filtr medianowy.
Usuwanie dystorsji przy użyciu punktów kluczowych
Posiadając obraz obiektu o znanych rozmiarach i łatwych do wyznaczenia punktach kluczowych (np. szachownica) można w przybliżeniu określić macierz przekształcenia z obrazu źródłowego (ze zniekształceniem) do docelowego (bez zniekształcenia). Posiadając to przekształcenie można dla każdego punktu nowego obrazu obliczyć odpowiadający mu punkt obrazu zniekształconego, zgodnie ze wzorem:
dst(x, y) = src(mapx (x, y), mapy (x, y))
gdzie:
dst(x, y) - piksel obrazu docelowego o współrzędnych (x, y),
(2.1)
16
ROZDZIAŁ 2. WYKORZYSTANE TECHNOLOGIE
src(x, y) - piksel obrazu źródłowego o współrzędnych (x, y),
mapx (x, y) i mapy (x, y) - struktury zawierające opisaną wyżej macierz przekształcenia dla piksela o współrzędnych (x, y).
Punkty, które nie mają swoich odpowiedników, pozostają czarne.
Progowanie binarne
Progowanie binarne jest operacją, która dla wybranego progu jasności zamienia
kolor pikseli o jasności powyżej wartości progowej na biały, a pozostałych na czarny,
zgodnie z poniższym wzorem:
(
dst(x, y) =
maxV al jeśli src(x, y) > thresh
0
w p. p.
(2.2)
gdzie:
dst(x, y) - piksel obrazu docelowego o współrzędnych (x, y),
src(x, y) - piksel obrazu źródłowego o współrzędnych (x, y),
maxV al - kolor biały,
thresh - wartość progowa, ustalona arbitralnie.
Efektem działania tej operacji jest obraz binarny, w którym białe piksele wskazują obszary, których oryginalne jasności były wyższe od wartości progowej. Algorytm ten jest często wykorzystywany do segmentacji, jeśli obiekt jest kontrastowy
w stosunku do tła. Ze względu na to, że piksele progowane są pod kątem jasności,
przed wykonaniem tej operacji obraz należy przekształcić z kolorowego na obraz
w skali odcieni szarości.
Morfologiczne otwarcie i zamknięcie
Operacje te służą do usuwania zakłóceń w obrazie binarnym. Zwykle są stosowane razem i mają antagonistyczne działanie:
• morfologiczne zamknięcie (dylacja i erozja) - powoduje rozrastanie się obszaru
obiektu, niwelując małe dziury (czarne obszary) w obiekcie i na jego krawędziach,
• morfologiczne otwarcie (erozja i dylacja) - działa odwrotnie niż zamknięcie,
powoduje rozrastanie się tła, niwelując małe obiekty.
Erozja - operacja splotu każdego piksela obrazu z elementem strukturalnym.
W tym przypadku istotny jest kształt elementu strukturalnego (zwykle zbliżony do
kwadratu lub okręgu, z elementem centralnym odpowiadającym danemu pikselowi),
a operacja splotu polega na obliczeniu lokalnego minimum jasności wśród pikseli
odpowiadającym elementowi strukturalnemu i podstawieniu tej wartości pod dany
piksel.
Dylacja - operacja analogiczna do erozji, jedyna różnica polega na obliczaniu
lokalnego maksimum, a nie minimum jasności.
2.2. OPROGRAMOWANIE
17
Szkieletyzacja
Szkieletyzacja jest operacją pozwalająca wyodrębnić osiowe punkty (szkielety)
figur w analizowanym obrazie. Szkielet składa się z linii o grubości jednego piksela,
które, choć dużo mniejsze od początkowej figury, odzwierciedlają jej topologię. Algorytm szkieletyzacji wykorzystany w tej pracy jest uproszczony i korzysta z operacji
morfologicznych, co pozwala zaoszczędzić czas, kosztem dokładności szkieletu (linie
mają grubość większą niż jeden piksel). Polega on na zastosowaniu poniższych operacji aż do uzyskania zadowalającego szkieletu, przy założeniu że obiekty są czarne,
a tło białe:
1. Utworzenie czarnego obrazu, w którym zapisywany będzie szkielet.
2. Utworzenie obrazu poprzez zastosowanie morfologicznego otwarcia na obrazie
początkowym.
3. Odwrócenie kolorów obrazu utworzonego w poprzednim kroku.
4. Wykonanie operacji AND dla obrazu początkowego i wyniku poprzedniego
kroku.
5. Wykonanie operacji OR dla obrazu ze szkieletem i wyniku poprzedniego kroku.
6. Wykonanie erozji na obrazie początkowym.
7. Powtórzenie kroków od 2. do 6., za każdym razem przyjmując jako obraz początkowy wynik kroku 6.
2.2.7
Dodatkowe biblioteki
math, numpy, transformations
Biblioteki języka python zawierające funkcje matematyczne oraz umożliwiające
korzystanie z macierzy i działań na macierzach. W szczególności ostatnia biblioteka
pozwala na bardziej skomplikowane działania na macierzach jednorodnych i kwaternionach.
threading, std msgs
Biblioteki języka python zawierające narzędzia do obsługi wielowątkowości
w aplikacji i komunikacji za pomocą tematów.
18
ROZDZIAŁ 2. WYKORZYSTANE TECHNOLOGIE
Rozdział 3
Projekt systemu
Rozdział ten opisuje przebieg zadania rysowania (sekcja 3.1), przyjęte założenia
projektowe (sekcja 3.2) oraz strukturę rozwiązania (sekcja 3.3).
3.1
Przebieg zadania
1. Robot przyjmuje pozycję roboczą, trzymając pisak w chwytaku.
2. Użytkownik systemu umieszcza kartkę z rysunkiem w polu widzenia kamery.
3. Obraz z kamery jest analizowany pod kątem położenia kartki oraz rysunku na
kartce.
4. Użytkownik systemu usuwa kartkę z rysunkiem i umieszcza czystą kartkę
w polu widzenia kamery.
5. Obraz z kamery jest analizowany pod kątem położenia kartki.
6. Robot przerysowuje rysunek na kartkę.
7. Robot przyjmuje pozycję roboczą.
Przebieg zadania został także przedstawiony na rysunku 3.2. Stanowisko robocze,
wykorzystywane w zadaniu, zostało pokazane na rysunku 3.1.
3.2
Założenia projektowe
W celu określenia warunków pracy systemu przyjęte zostały następujące założenia odnośnie środowiska:
1. Cechy kartki (dotyczą kartki z rysunkiem oraz czystej kartki, na której robot
rysuje):
(a) posiada kształt prostokąta o znanych wymiarach (w szczególności nie
może być pozaginana ani uszkodzona); jeżeli nie jest określone inaczej,
system zakłada kartkę formatu A4 (wymiary: 210 × 297mm),
(b) ma jasny kolor (najlepiej biały) i leży na ciemnym tle (najlepiej czarnym),
(c) leży na płaszczyźnie poziomej,
19
20
ROZDZIAŁ 3. PROJEKT SYSTEMU
KIŚĆ
RAMIĘ GÓRNE
KAMERA
PISAK
RAMIĘ DOLNE
KARTKA
KORPUS
Rysunek 3.1: Stanowisko robocze
(d) dopóki spełniony jest poprzedni punkt, orientacja kartki może być dowolna.
2. Cechy rysunku:
(a) wykonany w ciemnym kolorze wyróżniającym się na białym tle; cały rysunek powinien być wykonany w tym samym kolorze,
(b) linie na rysunku powinny mieć podobną grubość,
(c) linie mogą się przecinać, tworzyć otwarte i zamknięte kontury, w szczególności kontury mogą być we wnętrzu innych zamkniętych konturów,
(d) rysunek nie powinien zawierać obszarów zapełnionych kolorem.
3. Wzajemne położenie kartki i robota:
(a) przez cały czas wykonywania zadania robot przyjmuje pozycję z chwytakiem i kamerą skierowanymi pionowo w dół,
(b) przez czas obserwacji kartki (przed rozpoczęciem rysowania) kartka powinna znajdować się całkowicie w polu widzenia kamery,
(c) kartka, na której robot rysuje musi znajdować się całkowicie w przestrzeni
dostępnej dla końcówki roboczej z zamontowanym chwytakiem (przy założeniu pozycji robota opisanej w punkcie (a)),
(d) kartka w trakcie rysowania nie może zmienić swojego położenia,
(e) kartka z obrazem wejściowym oraz czysta kartka nie muszą leżeć w tym
samym miejscu.
3.3. STRUKTURA ROZWIĄZANIA
act Zadanie rysowania
21
Użytkownik umieszcza
kartkę z rysunkiem
Użytkownik umieszcza
czystą kartkę
sygnał
Przyjęcie pozycji
roboczej przez robota
Rysowanie
Analiza obrazu:
kontury i położenie kartki
sygnał
Analiza obrazu:
położenie kartki
Przyjęcie pozycji
roboczej przez robota
Rysunek 3.2: Przebieg zadania rysowania
3.3
Struktura rozwiązania
Struktura rozwiązania przedstawiona w niniejszej pracy wynika z doboru technologii. Wykorzystano dostępny w laboratorium sprzęt, czyli robota IRp-6 z zamontowaną kamerą oraz rozwijane oprogramowanie, jakim są platforma DisCODe do
przetwarzania obrazu oraz sterownik robota ROS/OROCOS. Umożliwiło to dekompozycję systemu na dwa moduły: wizyjny oraz sterowania, co zostało przedstawione
na rysunku 3.3.
ibd Struktura systemu (ogólna)
«block»
Moduł wizyjny
Dane obrazu
«block»
Moduł sterowania
Rysunek 3.3: Schemat struktury systemu
• Moduł wizyjny - odpowiada za przetwarzanie obrazu. Korzysta z kamery i platformy DisCODe. Odbiera obraz z kamery i wysyła do modułu sterowania dane
powstałe podczas przetwarzania, na podstawie których wyznaczany jest ruch
robota.
• Moduł sterowania - odpowiada za sterowanie robotem. Korzysta z robota
IRp-6 oraz systemu ROS/OROCOS i biblioteki IRPOS. Odbiera dane z modułu wizyjnego i na ich podstawie wyznacza, jaki ruch powinien wykonać robot.
22
ROZDZIAŁ 3. PROJEKT SYSTEMU
3.3.1
Komunikacja między modułami
Moduł sterowania korzysta z informacji dostarczonych przez moduł wizyjny, dlatego niezbędne jest zapewnienie przepływu danych z modułu wizyjnego do modułu
sterowania. Przepływ powinien zawierać wszelkie dane obliczone w module wizyjnym, konieczne do wykonania sterowania i narysowania rysunku. Ustalone zostało,
że komunikacja będzie obejmować następujące dane:
• położenie kartki,
• kontury rysunku.
Przepływ jest jednokierunkowy, ponieważ moduł wizyjny działa niezależnie od sterowania i nie potrzebuje z niego żadnych danych.
3.3.2
Moduł wizyjny
Moduł wizyjny odpowiedzialny jest za akwizycję, poprawę jakości oraz analizę
obrazu w celu wyznaczenia położenia kartki względem kamery oraz wykrycia konturów. Dekompozycja zadania przetwarzania obrazu pozwala na użycie systemu o architekturze komponentowej. Schemat struktury modułu wizyjnego został przedstawiony na rysunku 3.4.
ibd Moduł wizyjny
«block»
Akwizycja
obrazu
Obraz surowy
«block»
Poprawa
jakości obrazu
Obraz bez zakłóceń
«block»
Przetwarzanie
Położenie kartki
Kontury
Rysunek 3.4: Schemat struktury modułu wizyjnego
Akwizycja obrazu
Akwizycja obrazu dokonywana jest przy użyciu kamery zamontowanej w kiści robota, skierowanej wzdłuż palców chwytaka (pozycja kamery została przedstawione
na rysunku 3.1). Takie umiejscowienie pozwala na bardzo wygodną obserwację przestrzeni roboczej przed robotem oraz ewentualną korekcję położenia kamery poprzez
zmianę pozycji robota. Rozwiązanie to jednak może generować błędy w dalszym
przetwarzaniu obrazu wynikające z założeń, że osie Z kamery i chwytaka są idealnie
równoległe oraz że podczas pracy robota oś Z chwytaka jest idealnie równoległa do
osi Z układu związanego z podstawą robota. Błędy te można minimalizować poprzez
precyzyjne ustawienia robota i dokładne zamontowanie kamery.
Istotny jest wybór odpowiednich parametrów akwizycji, takich jak ogniskowa kamery, jasność i czas otwarcia migawki, wybranych doświadczalnie, aby obraz był jak
3.3. STRUKTURA ROZWIĄZANIA
23
najlepszej jakości. Dzięki temu dalsze przetwarzanie będzie łatwiejsze i bardziej efektywne. Ze względu na konieczność kalibracji kamery, rozpoczęcie akwizycji powinno
zostać poprzedzone obliczeniem parametrów kalibracji.
Poprawa jakości obrazu
Obraz z kamery w formie surowej nie nadaje się do przetwarzania z powodu
zakłóceń i zniekształceń, które mogłyby bardzo utrudnić lub uniemożliwić dalszą
analizę. W celu poprawienia jakości obrazu z kamery stosowane są następujące operacje:
• Usunięcie szumu, czyli drobnych, wysokoczęstotliwościowych zakłóceń typu
„sól i pieprz” (ang. „salt&pepper”). Efektem tych zakłóceń są pojedyncze piksele o innym kolorze niż ich otoczenie. Może to negatywnie wpłynąć na dalsze
przetwarzanie obrazu, dlatego niezbędne jest ich usunięcie, na przykład przy
pomocy rozmycia Gaussa i operacji morfologicznych.
• Usunięcie dystorsji, czyli zniekształcenia geometrycznego w postaci wklęsłej lub wypukłej poduszki lub beczki. Surowy obraz z kamery zawiera zniekształcenie geometryczne w postaci wypukłej poduszki. W celu prawidłowego
wykrycia kartki na obrazie oraz wiernego odwzorowania rysunku niezbędne
jest usunięcie tego zniekształcenia.
Przetwarzanie
Przetwarzanie obrazu jest procesem wieloetapowym. Na wejściu otrzymujemy
obraz pobrany z kamery i poddany działaniu algorytmów poprawy jakości. Na wyjściu powinien znaleźć się abstrakcyjny opis krawędzi wykrytych na obrazie oraz
wyznaczone położenie kartki względem kamery. Sekwencja przetwarzania została
przedstawiona poniżej:
1. Segmentacja obrazu[6] - odrzucenie tła i pozostawienie do dalszego przetwarzania jedynie interesującego nas obszaru, czyli kartki z obrazkiem.
2. Wykrycie dokładnego położenia kartki na obrazie.
Zgodnie z założeniami projektowymi kartka z rysunkiem jest prostokątem
o znanych wymiarach. Cztery punkty kluczowe - rogi kartki - są wystarczające
do stworzenia modelu kartki i wyznaczenia jej położenia i orientacji[13].
3. Wykrycie dokładnego położenia kartki względem kamery - na podstawie modelu kartki, jej położenia na obrazie oraz parametrów kamery wyznaczane jest
przekształcenie z układu związanego z kartką:
• punkt (0,0) znajduje się w rogu kartki,
• osie X i Y wyznaczane są przez krawędzie kartki,
• oś Z jest prostopadła do płaszczyzny kartki
do układu związanego z układem optycznym kamery.
24
ROZDZIAŁ 3. PROJEKT SYSTEMU
4. Wyznaczenie kolejnych punktów na obrazie, jak najlepiej przybliżających rzeczywiste kontury.
Każdy kontur reprezentowany jest przez uporządkowany ciąg punktów połączonych liniami prostymi. Punkty powinny być położone są na tyle blisko
siebie, aby wystarczająco dobrze aproksymować rzeczywiste kształty konturów.
3.3.3
Moduł sterowania
Zadaniem modułu sterowania jest na podstawie:
• położenia kartki względem kamery,
• położenia konturów na kartce,
• pozycji robota,
• wzajemnego położenia kamery i chwytaka
wyznaczyć takie sterowanie, aby narysować na kartce wejściowy rysunek za pomocą
pisaka umieszczonego w chwytaku. Schemat działania tego modułu został przedstawiony na rysunku 3.5.
ibd Moduł sterowania
Położenie kartki
«block»
Wyznaczenie
przekształcenia
Przekształcenie
«block»
Obliczenie
trajektorii
Trajektoria
«block»
Wykonanie
trajektorii
Kontury
Rysunek 3.5: Schemat struktury modułu sterowania
Pierwszym krokiem jest wyznaczenie przekształcenia base
k T z układu związanego
z kartką do układu związanego z podstawą robota[15]. Mając macierze przekształcenia:
•
opt
k T
•
cam
opt T
•
tl6
cam T
- macierz przekształcenia z układu kartki do układu optycznego kamery
(obliczona w procesie przetwarzania obrazu),
- macierz przekształcenia z układu optycznego kamery do układu kamery
zamontowanej na robocie (układ optyczny jest obrócony względem kamery
o kąt π wokół osi Z),
- macierz przekształcenia z układu kamery do układu ostatniego stawu
robota (ze względu na to, że kamera jest na stałe zamontowana na robocie,
macierz ta jest stała),
3.3. STRUKTURA ROZWIĄZANIA
•
25
base
tl6 T
- macierz przekształcenia z układu ostatniego stawu robota do układu
bazowego robota, względem którego wykonywane jest sterowanie (macierz obliczona na podstawie aktualnego położenia i orientacji robota)
można obliczyć przekształcenie z układu związanego z kartką do układu związanego
z podstawą robota za pomocą poniższego równania:
base
k T
=
base
tl6 T
tl6
cam T
cam
opt T
opt
k T
(3.1)
W celu uzyskania punktów w układzie bazowym robota dla każdego punktu konturu
w układzie związanym z kartką należy przeprowadzić operację:
pbase
=
base
k T
pk
(3.2)
gdzie:
pbase - punkt w układzie bazowym robota,
pk - punkt w układzie związanym z kartką.
Po wykonaniu tej operacji należy przemieścić końcówkę pisaka przez kolejne
punkty wszystkich konturów.
26
ROZDZIAŁ 3. PROJEKT SYSTEMU
Rozdział 4
Realizacja
Rozdział ten opisuje implementację systemu stworzonego na potrzeby tej pracy.
Obejmuje to moduł wizyjny (sekcja 4.1), komunikację między modułami (sekcja 4.2)
oraz moduł sterowania (sekcja 4.3). Opisana została także modyfikacja chwytaka
(sekcja 4.4).
4.1
Moduł wizyjny
Moduł wizyjny implementuje sekwencję przetwarzania obrazu, na którą składają
się akwizycja, poprawienie jakości obrazu oraz jego analiza. Został zrealizowany przy
użyciu systemu ROS, platformy DisCODe oraz biblioteki OpenCV. Użyte zostały
gotowe biblioteki DCL CvCoreTypes oraz ROSProxy i CvBasic (z niewielkimi modyfikacjami), a także stworzono dwie nowe biblioteki DCL o nazwach EdgeDetection
oraz FindPaperSheet.
4.1.1
Struktura modułu wizyjnego
Cały ciąg przetwarzania został zawarty w zadaniu DisCODe, składającym się
z jednego podzadania i dwóch egzekutorów o następującym działaniu:
• Egzekutor Processor ma za zadanie pobrać obraz i przeprowadzić analizę; cały
proces przetwarzania odbywa się w jednym wątku ze względu na to, że algorytm jest sekwencyjny i nie ma potrzeby wprowadzać wielowątkowości. Dodatkowym atutem tego rozwiązania jest uniknięcie ryzyka buforowania się danych
pomiędzy egzekutorami. Dzięki temu rozwiązaniu kolejna klatka z kamery zostanie pobrana dopiero, gdy poprzednia zostanie przetworzona. Decyzja ta
została podjęta ze względu na fakt, że priorytetem zadania jest jakość przetwarzania, a nie jak najkrótszy czas wykonania.
• Egzekutor Proxy ma za zadanie utworzyć tematy ROS i publikować na nich
dane, które następnie zostaną odczytane przez moduł sterowania.
Struktura zadania wykonującego powyższe działania została pokazana na rysunku 4.1. Przedstawia on egzekutory, etapy przetwarzania oraz przekazywane dane.
W dalszej części rozdziału poszczególne etapy zostaną dokładnie omówione, łącznie
z wyszczególnieniem użytych komponentów DisCODe, ich portów wejściowych i wyjściowych oraz właściwości.
27
28
ROZDZIAŁ 4. REALIZACJA
Processor
Processor
Akwizycja
Akwizycja
obrazu
obrazu
surowy obraz
Poprawa
Poprawa jakości
jakości
obrazu
obrazu
Segmentacja
Segmentacja
obraz bez zakłóceń
obraz w skali odcieni szarości
obraz binarny kartki
Wyznaczenie
Wyznaczenie
położenia
położenia kartki
kartki
lista wierzchołków kartki
Wyznaczenie
Wyznaczenie
przekształcenia
przekształcenia
macierz przekształcenia
z układu kartki
do układu kamery
Wyznaczenie
Wyznaczenie
konturów
konturów
lista konturów
w układzie kartki
Proxy
Proxy
Wysyłanie
Wysyłanie danych
danych
Rysunek 4.1: Struktura zadania DisCODe
4.1.2
Akwizycja obrazu
Obraz z kamery pobierany jest poprzez uruchomienie przez narzędzie roslaunch
pliku pgr camera.launch, który:
• tworzy węzeł ROS związany z kamerą,
• pobiera obraz z kamery,
• pobiera obraz z danymi parametrami (jasność, czas otwarcia migawki; zostały
one ustalone wcześniej doświadczalnie dla typowych warunków oświetlenia
w laboratorium),
• publikuje obraz na temacie ROS o zadanej nazwie; możliwy jest dostęp do surowego obrazu, kolorowego, monochromatycznego i do aktualnych parametrów
kamery.
Następnie uruchamiany jest gotowy komponent o nazwie CameraSubscriber
z DCL ROSProxy (rys. 4.2), który pobiera obraz z tematu ROS o zadanej nazwie i przekazuje do portu wyjściowego strukturę cv::Mat z obrazem. Właściwością
komponentu jest nazwa tematu, z którego pobierany jest obraz.
4.1.3
Usunięcie zakłóceń i zniekształceń
Etap poprawy jakości obrazu ma zniwelować wszelkie zniekształcenia i elementy
obrazu, które mogłyby zaburzyć dalsze przetwarzanie. Komponenty odpowiedzialne
za ten etap zostały przedstawione na rysunku 4.3.
4.1. MODUŁ WIZYJNY
29
Akwizycja
Akwizycja obrazu
obrazu
Source
Source
ROSProxy:
CameraSubscriber
out_img
surowy obraz
Rysunek 4.2: Komponent odpowiedzialny za akwizycję obrazu
Poprawa
Poprawa jakości
jakości obrazu
obrazu
GaussianBlur
GaussianBlur
CvBasic:
CvGaussianBlur
surowy obraz
in_img
out_img
rozmyty obraz
Undistort
Undistort
CvBasic:
CvUndistort
in_img
in_camera_info
out_img
obraz bez
zakłóceń
CameraInfo
CameraInfo
CvCoreTypes:
CameraInfoProvider
out_camera_info
parametry
kamery
Rysunek 4.3: Komponenty odpowiedzialne za poprawę jakości obrazu
Rozmycie Gaussa
Zadanie usunięcia szumu wykonuje gotowy komponent o nazwie CvGaussianBlur
z DCL CvBasic. Opakowuje on funkcję cv::GaussianBlur, która implementuje algorytm rozmycia Gaussa. Na wejściu komponentu znajduje się surowy obraz z kamery,
na wyjściu obraz rozmyty.
Jako właściwości komponentu podawane są: rozmiar elementu strukturalnego
oraz wartości σx i σy , odpowiadające standardowemu odchyleniu funkcji Gaussa
używanej do rozmycia. W praktyce im większe są te wartości, tym bardziej obraz
zostanie rozmyty.
Usunięcie dystorsji
W celu usunięcia zniekształcenia geometrycznego używane są dwa gotowe komponenty. Pierwszy z nich, o nazwie CameraInfoProvider z DCL CvCoreTypes, dostarcza informacji o parametrach kamery, które są podane jako właściwości. Komponent ten nie ma żadnego wejścia, przekazuje jedynie na wyjściu strukturę Types::CameraInfo zawierającą powyższe dane.
Drugi wykorzystywany komponent to CvUndistort z DCL CvBasic. Opakowuje
on funkcję cv::undistort, której zadaniem jest obliczenie na podstawie podanych
parametrów przekształcenia z obrazu zniekształconego do prawidłowego. Następnie
tworzy ona prawidłowy obraz poprzez przeliczenie dla każdego piksela odpowiadającego mu koloru z pierwotnego obrazu. Komponent CvUndistort na wejściu otrzymuje
strukturę z właściwościami kamery oraz zniekształcony obraz, a na wyjście zwraca
prawidłowy obraz.
Obraz źródłowy ze zniekształceniami został przedstawiony na rysunku 4.4(a).
Wyraźnie widoczne są zakrzywione krawędzie kartki, które powinny być proste.
30
ROZDZIAŁ 4. REALIZACJA
Efekt działania komponentów usuwających to zniekształcenie został pokazany na
rysunku 4.4(b).
(a) Obraz źródłowy
(b) Obraz po rozmyciu Gaussa i usunięciu dystorsji
Rysunek 4.4: Etapy usuwania zakłóceń i zniekształceń
4.1.4
Segmentacja
Obraz z kamery zawiera interesujący nas obiekt - kartkę - oraz tło, które może
zawierać zakłócenia, odbłyski i obiekty mogące zakłócić dalsze przetwarzanie. Dlatego bardzo istotnym krokiem jest segmentacja, czyli oddzielenie obiektu od tła.
Struktura komponentów wykonujących zadanie segmentacji została przedstawiona
na rysunku 4.5.
Segmentacja
Segmentacja
Conv2gray
Conv2gray
obraz bez
zakłóceń
Thresholding
Thresholding
CvBasic:
CvColorConv
in_img
obraz w skali
odcieni szarości
out_img
Morphology1
Morphology1
wstępny obraz
binarny kartki
CvBasic:
CvMorphology
in_img
out_img
CvBasic:
CvThreshold
in_img
out_img
Morphology2
Morphology2
poprawiony obraz
binarny kartki
CvBasic:
CvMorphology
in_img
out_img
obraz binarny
kartki
Rysunek 4.5: Komponenty odpowiedzialne za segmentację
Konwersja barw
Pierwszym krokiem przed segmentacją jest konwersja przestrzeni barw obrazu
do skali odcieni szarości. Realizowane jest to przez gotowy komponent CvColorConv
z DCL CvBasic, zawierający funkcję cv::cvtColor. Jako właściwość podawany jest
rodzaj konwersji, jaka ma być przeprowadzona - w tym wypadku cv rgb2gray. Tej
4.1. MODUŁ WIZYJNY
31
konwersji wymaga kolejny krok przetwarzania. Na wejściu i wyjściu komponentu
znajdują się odpowienio - obraz przed i po konwersji.
Progowanie
Właściwą segmentację przeprowadza gotowy komponent CvThreshold z DCL
CvBasic, opakowujący funkcję cv::threshold. Implementuje ona algorytm progowania. Na wejściu komponent otrzymuje obraz w skali odcieni szarości, na wyjściu tworzony jest obraz binarny, na którym kolorem białym określony jest obszar kartki,
natomiast tło jest czarne. Właściwością komponentu jest wartość progowa jasności.
Operacje morfologiczne
Przed przejściem do następnego etapu należy jeszcze poprawić jakość uzyskanego obrazu poprzez zastosowanie operacji morfologicznych. Odpowiedzialne za to
zadanie są dwa gotowe komponenty typu CvMorphology, który opakowuje funkcję
cv::morphologyEx. Ich zadaniem jest usunięcie małych obiektów i dziur w obiekcie
oraz nierówności krawędzi, które mogły pozostać po progowaniu. Na wejściu i wyjściu komponentów znajdują się odpowiednio obraz przed operacją morfologiczną
i po. Jako właściwości podawany jest rodzaj operacji oraz liczba iteracji. Obraz
po zastosowaniu operacji progowania został przedstawiony na rysunku 4.6(a), natomiast po operacjach morfologicznych na rysunku 4.6(b).
(a) Obraz po progowaniu
(b) Obraz po operacjach morfologicznych
Rysunek 4.6: Segmentacja obrazu
4.1.5
Wyznaczenie położenia kartki w obrazie
Wyznaczenie położenia kartki w obrazie, przy założeniu, że ma ona kształt prostokąta, polega na określeniu współrzędnych jej narożników. Ponieważ kartka nie
zawsze leży idealnie poziomo względem kamery, niezbędne jest wyznaczenie wszystkich czterech narożników. Dokładność jest bardzo istotna, ponieważ na podstawie tej
informacji odbywa się dalsze przetwarzanie oraz wyznaczenie sterowania w celu narysowania rysunku. Strukturę komponentów odpowiedzialnych za to zadanie przedstawia rysunek 4.7.
32
ROZDZIAŁ 4. REALIZACJA
Wyznaczenie
Wyznaczenie położenia
położenia kartki
kartki
FindEdges
FindEdges
DrawEdges
DrawEdges
EdgeDetection:
FindEdges
obraz binarny
kartki
in_img
out_edges
krawędzie
in_edges
out_corners
obraz krawędzi
kartki
out_lines
in_img
FindPaperSheet:
ImprovedCorners
FindPaperSheet:
FindCorners
in_lines
out_img
CvBasic:
CvHoughLines
ImproveCorners
ImproveCorners
FindCorners
FindCorners
linie
proste
Lines
Lines
EdgeDetection:
DrawEdges
przybliżone
wierzchołki
in_corners
out_corners
lista
wierzchołków
kartki
in_img
obraz w skali
odcieni szarości
Rysunek 4.7: Komponenty odpowiedzialne za wyznaczenie położenia kartki na obrazie
Znalezienie krawędzi
Pierwszym krokiem jest znalezienie krawędzi w obrazie, czym zajmuje się przygotowany do tego zadania komponent FindEdges z utworzonego na potrzeby pracy
DCL EdgeDetection. Wykorzystuje on funkcję OpenCV cv::FindContours, która
w wejściowym obrazie szuka krawędzi i zwraca je w postaci listy wektorów punktów.
Na wejściu komponent ten otrzymuje obraz binarny, natomiast na wyjściu zwraca
znaleziony wektor konturów w strukturze Types::Edges.
Narysowanie krawędzi
Zadaniem następnego przygotowanego komponentu, DrawEdges z DCL EdgeDetection, jest narysowanie na pustym obrazie znalezionych wcześniej krawędzi. Na
wejściu przyjmuje on wektor konturów, natomiast na wyjściu otrzymywany jest pusty obraz, z narysowanymi krawędziami. Efekt działania tego komponentu został
przedstawiony na rysunku 4.8(a).
Znalezienie prostych, opisujących krawędzie
Mając krawędzie, następnym krokiem realizowanym przez gotowy komponent
CvHoughLines z DCL CvBasic (zmodyfikowanym na potrzeby tej pracy) jest znalezienie linii prostych, odpowiadającym bokom kartki. Komponent ten korzysta z funkcji cv::HoughLinesP, która implementuje probabilistyczną transformatę Hough’a. Na
wejściu funkcja otrzymuje obraz binarny, zwraca natomiast wektor linii, z których
każda reprezentowana jest jako 4-elementowy wektor (x1 , y1 , x2 , y2 ) opisujący współrzędne punktów początkowego i końcowego. Wektor zwracany przez funkcję zawiera
dużo więcej niż cztery linie. Na każdym boku kartki znajdowanych jest wiele linii wynika to z faktu, że krawędź kartki nie jest idealnie prosta. Dlatego w komponencie
CvHoughLines została dodana funkcja checkDuplicate, która znajduje po jednej linii
na bok. Funkcja dla każdej wykrytej linii wyznacza parametry A oraz b, zgodnie ze
wzorem y = Ax + b, a następnie na tej podstawie oblicza kąt nachylenia prostej
4.1. MODUŁ WIZYJNY
33
wyznaczonej przez tę linię oraz jej punkty przecięcia z osiami X i Y . Jeżeli dwie
linie są do siebie wystarczająco podobne, jedna z nich jest usuwana. W ten sposób
wektor linii zawiera po jednej na każdy bok kartki.
Komponent CvHoughLines na wejściu przyjmuje binarny obraz z narysowanymi
krawędziami, natomiast na wyjściu podaje wektor linii, z których każda reprezentowana jest przez współrzędne punktów początkowego i końcowego i każda opisuje
jedną z krawędzi kartki znalezionej na obrazie. Znalezione linie dla przykładowego
obrazu wejściowego zostały przedstawione na rysunku 4.8(b).
Znalezienie narożników
Wstępnym wyznaczeniem położenia rogów kartki na obrazie zajmuje się komponent FindCorners z DCL FindPaperSheet. Na wejściu otrzymuje on wektor linii
z poprzedniego kroku przetwarzania, a na wyjściu podaje listę wierzchołków, obliczanych jako punkty przecięcia każdych dwóch nierównoległych linii. Na koniec są one
sortowane - kolejność wierzchołków jest istotna dla dalszych etapów przetwarzania.
Korekta współrzędnych narożników
Ze względu na to, że dokładne wyznaczenie położenia wierzchołków jest kluczowe
dla dalszego przetwarzania, kolejny komponent, ImprovedCorners z DCL FindPaperSheet, poprawia znalezione w poprzednim kroku współrzędne narożników kartki na
obrazie. Jest to konieczne z dwóch względów. Po pierwsze, funkcja cv::HoughLinesP
jest probabilistyczna i w kolejnych wykonaniach może się zachowywać w różny sposób i wyznaczać różne linie nawet dla tego samego obrazu, co wpływa na dalsze
wyznaczanie wierzchołków. Po drugie, boki kartki na obrazie nie są idealnie proste,
a linie użyte do obliczania przecięć mogą być dość krótkie, co sprawia, że obliczone
w ten sposób współrzędne są niedokładne. W efekcie, bez poprawienia wyników
otrzymywane są nieprecyzyjne wierzchołki, które zmieniają swoje położenie w kolejnych wykonaniach algorytmu dla tego samego obrazu.
Komponent ImprovedCorners otrzymuje na wejściu obraz w skali odcieni szarości oraz wektor znalezionych wcześniej wierzchołków. Następnie wycina z obrazu
prostokątne fragmenty zawierające wierzchołki wraz z otoczeniem (obszary zainteresowania, ang. region of interest, ROI ). Dla każdego z tych obszarów wykonywana jest
funkcja OpenCV cv::goodFeaturesToTrack, której zadaniem jest znalezienie rogów na
obrazie; jako argumenty przyjmuje obraz oraz liczbę rogów, jakie na znaleźć. Dobrze znajduje ona współrzędne wierzchołka na obrazku wyciętym z głównego obrazu
(ROI ), gdzie znajduje się tylko jeden wierzchołek. Jako właściwości komponentu
podawany jest rozmiar ROI (wybrano kwadrat o boku 100 pikseli) oraz parametry funkcji cv::goodFeaturesToTrack. W efekcie działania powyższych komponentów
otrzymywany jest uporządkowany wektor dokładnie wyznaczonych wierzchołków, co
zostało przedstawione na rysunku 4.8(c).
4.1.6
Wyznaczenie konturów
Znajdowanie konturów w obrazie jest najbardziej złożoną częścią przetwarzania
i wymagało najwięcej modyfikacji i implementacji. Strukturę komponentów wykonujących to zadania przedstawiono na rysunku 4.9.
34
ROZDZIAŁ 4. REALIZACJA
(a) Krawędzie obrazu
(b) Proste wyznaczone przez (c) Znalezione narożniki kartki
krawędzie
Rysunek 4.8: Położenie kartki na obrazie
Wyznaczenie
Wyznaczenie konturów
konturów
CornerMask
CornerMask
obraz w skali
odcieni szarości
lista
wierzchołków
kartki
ImageThresholding
ImageThresholding
FindPaperSheet:
ApplyCornerMask
in_img
in_corners
obraz
szkieletu
rysunku
Skeleton
Skeleton
CvBasic:
CvThreshold
obraz kartki
out_img
Morphology3
Morphology3
CvBasic:
CvMorphology
in_img
out_img
in_img
poprawiony
obraz
szkieletu
rysunku
FindPaperSheet:
Skeleton
obraz
rysunku
out_img
in_img
out_img
ImageCornerMask
ImageCornerMask
FindPaperSheet:
ApplyCornerMask
in_img
out_img
in_corners
poprawiony
obraz
szkieletu
rysunku
Contour
Contour
HomographyPoints
HomographyPoints
CvBasic:
CvContour
in_img
out_contours
FindPaperSheet:
HomographyPoints
lista
konturów
in_points
in_corners
out_points
lista konturów
w układzie
kartki
Rysunek 4.9: Komponenty odpowiedzialne za wyznaczenie konturów rysunku na
obrazie
Maska w kształcie kartki
W celu całkowitego zniwelowania tła w komponencie ApplyCornerMask z DCL
FindPaperSheet tworzony jest obraz binarny w kolorze czarnym, z białym prostokątem, którego wierzchołki zgodne są z rogami kartki. Następnie przygotowany rysunek
wykorzystywany jest jako maska, która odrzuca całkowicie z obrazu z kamery tło
dookoła kartki. Dzięki temu jest pewne, że żadne obiekty spoza kartki nie zostaną
włączone do dalszego przetwarzania. Komponent ten na wejściu przyjmuje obraz
z kamery oraz listę wierzchołków, a na wyjściu podaje obraz po zastosowaniu maski.
Progowanie
Zgodnie z założeniami projektowymi rysunek jest kontrastowy w stosunku do
kartki, więc przy użyciu gotowego komponentu CvThreshold z DCL CvBasic można
dokładnie znaleźć obszary konturów, co zostało pokazane na rysunku 4.10(a).
4.1. MODUŁ WIZYJNY
35
Szkieletyzacja
Kontury narysowane nawet cienkim pisakiem mają grubość kilku pikseli, przez
co są traktowane jako zamknięte, wypełnione obiekty, a nie linie. W celu ułatwienia
dalszego przetwarzania zastosowana została operacja szkieletyzacji w komponencie
Skeleton z DCL FindPaperSheet. Na wejściu przyjmuje on obraz zawierający grube
kontury, a na wyjściu podaje obraz z ich szkieletem. Efekt ten został pokazany na
rysunku 4.10(b). W celu poprawy jakości obrazu szkieletowego zostały zastosowane
jeszcze dwa komponenty: CvMorphology, mający wypełnić niewielkie dziury w konturach oraz ApplyCornerMask, którego zadaniem jest pozbycie się krawędzi kartki,
które zostały potraktowane jak kontury.
Znalezienie konturów
Wyznaczeniem konturów zajmuje się zmodyfikowany komponent CvContour
z DCL CvBasic. W wersji podstawowej korzysta on z funkcji cv::findContours. Funkcja ta zwraca jednak zawsze kontury zamknięte, co dla obrazu po szkieletyzacji
oznacza, że znalezione kontury będą podwójne. Dlatego należy zredukować kontury
tak, aby stanowiły pojedyncze linie. W tym celu do komponentu CvContour została
dodana funkcja ReduceContours, która wykonuje trzy kroki:
1. Usunięcie podwójnych konturów poprzez wykonanie dla każdego konturu następujących operacji:
(a) Dodanie pierwszego punktu do pustego wektora i dołączenie go do końcowej listy konturów.
(b) Niech L będzie odległością kolejnego punktu od ostatnio dodanego do
końcowej listy konturów, thresh1 minimalną odległością pomiędzy kolejnymi punktami, thresh2 maksymalną odległością między kolejnymi punktami tego samego konturu:
• jeśli L < thresh1 , punkt jest pomijany,
• jeśli thresh1 < L < thresh2 , punkt jest dodawany do ostatniego
wektora końcowej listy konturów,
• jeśli L > thresh2 , punkt jest dodawany do nowego pustego wektora
i dołączany do końcowej listy konturów.
(c) Powtórzenie kroku (b) dla wszystkich punktów konturu.
2. Połączenie konturów, których końce leżą blisko siebie.
3. Usunięcie zbyt krótkich kontury.
Po zastosowaniu powyższych kroków otrzymywana jest lista konturów, które są
pojedyncze i możliwie najdłuższe. Komponent CvContour na wejściu przyjmuje binarny obraz ze szkieletem konturów, natomiast na wyjściu przekazuje listę konturów,
z których każdy jest wektorem punktów. Jako właściwości podawane są wartości
progowe wykorzystywane przy redukcji punktów i łączeniu konturów. Znalezione
kontury dla przykładowego obrazu zostały pokazane na rysunku 4.10(c).
36
ROZDZIAŁ 4. REALIZACJA
(a) Progowanie
(b) Szkielet
(c) Kontury
Rysunek 4.10: Znalezienie konturów
Wyznaczenie konturów w układzie kartki
Współrzędne punktów wyznaczone w poprzednim kroku odnoszą się do układu
współrzędnych obrazu. Ostatnim krokiem tego etapu jest przekształcenie punktów
do układu współrzędnych związanego z kartką.
Zadanie to wykonuje komponent HomographyPoints z DCL FindPaperSheet.
Wykorzystuje on funkcję cv::findHomography, która znajduje macierz przekształcenia między dwoma układami współrzędnych, zdefiniowanymi poprzez odpowiadające
sobie punkty kluczowe. Punkty wybrane w tym przypadku to narożniki kartki.
Komponent HomographyPoints na dwa porty wejściowe - jeden otrzymuje listę
znalezionych konturów w układzie obrazu, a drugi współrzędne narożników kartki.
Najpierw obliczana jest macierz przekształcenia z układu obrazu do układu kartki,
a następnie wszystkie punkty są wymnażane przez tę macierz. Gotowe dane są wysyłane na port wyjściowy. Komponent posiada dwie właściwości: height oraz width,
które są wymiarami kartki. Dzięki temu możliwe jest działanie systemu dla kartki
w formacie innym niż A4.
4.1.7
Znalezienie przekształcenia do układu kamery
Po wcześniejszym przetwarzaniu do znalezienia położenia kartki względem kamery wystarczyło zastosowanie trzech komponentów, których struktura została
przedstawiona na rysunku 4.11.
Model kartki
Pierwszym krokiem jest utworzenie modelu kartki przy użyciu komponentu Create3DModel z DCL FindPapeSheet. Jego zadaniem jest zbudowanie modelu kartki na
podstawie jej wymiarów (podanych jako właściwości komponentu: height oraz width)
i wyznaczonych wcześniej współrzędnych wierzchołków znalezionych na obrazie (odebranych w porcie wejściowym). Model jest strukturą Types::Objects3D::Object3D
zdefiniowaną w DCL CvBasic. Pozwala ona na przechowywanie punktów kluczowych modelu oraz odpowiadających im punktów obrazu.
Wyznaczenie przekształcenia
Gotowy komponent CvSolvePnP z DCL CvBasic na podstawie podanych na
porty wejściowe modelu kartki utworzonego w poprzednim kroku oraz struktury z in-
4.1. MODUŁ WIZYJNY
37
Wyznaczenie
Wyznaczenie przekształcenia
przekształcenia
zz układu
układu kartki
kartki do
do układu
układu kamery
kamery
Model
Model
lista
wierzchołków
kartki
FindPaperSheet:
Create3DModel
in_corners
out_model
model
kartki
CvBasic:
CvSolvePnP
CameraInfo2
CameraInfo2
CvCoreTypes:
CameraInfoProvider
out_camera_info
SolvePnP
SolvePnP
in_object3D
parametry
kamery
out_matrix_rvec_tvec
macierz przekształcenia
z układu kartki
do układu kamery
in_camera_matrix
Rysunek 4.11: Komponenty odpowiedzialne za wyznaczenie przekształcenia z układu
kartki do układu kamery
formacjami o kamerze wyznacza macierz przekształcenia z układu kartki do układu
kamery. Wykorzystuje przy tym funkcję cv::solvePnP, która dla modelu i odpowiadających mu punktów na obrazie oraz danych kamery wyznacza wektor rotacji oraz
przesunięcia. Komponent oprócz tego oblicza macierz jednorodną przekształcenia,
która jest równoważna tym dwóm wektorom. Dzięki komponentom DrawCoordinateSystem z DCL CvBasic oraz DrawSystem z DCL EdgeDetection możliwe jest
narysowanie układu związanego z kartką na obrazie z kamery i zweryfikowanie poprawności obliczeń, co zostało pokazane na rysunku 4.12.
Rysunek 4.12: Znaleziony układ współrzędnych związany z kartką
4.1.8
Wysyłanie danych
Ostatnim krokiem wykonywanym przez moduł wizyjny jest wysłanie danych
do modułu sterowania. Wykorzystywany przy tym jest specjalnie przygotowany
komponent Float32MultiArrayProxy z DCL ROSProxy. Przy inicjalizacji tworzy on
temat ROS o zadanej nazwie oraz węzeł ROS. Typem danych przesyłanych jest
Float32MultiArray, co jest odpowiednikiem wektora liczb zmiennoprzecinkowych.
Jako wejście komponent przyjmuje wektor liczb. Przygotowuje on wiadomość ROS
38
ROZDZIAŁ 4. REALIZACJA
i dodaje do niej dane z wektora, a następnie publikuje na temacie, uruchamiając
funkcję ros::spinOnce(). Komponent używany jest w zadaniu dwa razy: przy wysyłaniu listy konturów oraz przy macierzy przekształcenia jednorodnego, co zostało
przedstawione na rysunku 4.13.
Wysyłanie
Wysyłanie danych
danych
lista konturów
w układzie
kartki
macierz przekształcenia
z układu kartki
do układu kamery
proxyPoints
proxyPoints
ROSProxy:
Float32MultiArrayProxy
in_data
proxy
proxy
ROSProxy:
Float32MultiArrayProxy
in_data
Rysunek 4.13: Komponenty odpowiedzialne za wysyłanie danych
4.2
Komunikacja między modułami
Moduły komunikują się między sobą za pomocą tematów, udostępnianych przez
ROS. Rozwiązanie to zostało przyjęte z następujących względów:
• tematy umożliwiają przesyłanie danych różnych typów i różnej wielkości, co
jest szczególnie istotne w tej pracy - ze względu na właściwości wybranych algorytmów, fakt, że obraz z kamery nie zawsze jest idealny oraz możliwe zmiany
oświetlenia i położenia kartki liczba i rozmiar konturów mogą się zmieniać nawet dla tego samego położenia kartki i robota,
• wiadomości są publikowane na temacie w sposób cykliczny - dzięki temu w razie braku wiadomości przez pewien określony czas można wykryć, że część
systemu nie działa prawidłowo, np. moduł wizyjny nie wykrywa kartki albo
konturów w obrazie,
• wiadomości publikowane na temacie mogą być odczytane przez wielu różnych
odbiorców, co umożliwia różnym aplikacjom korzystanie z tych samych danych.
4.2.1
Wysyłanie danych
Dane wysyłane przez moduł wizyjny dotyczą położenia kartki względem kamery
oraz współrzędnych punktów konturów na kartce. Wykorzystywany do tego zadania
komponent Float32MultiArrayProxy przy każdym wywołaniu przyjmuje wektor liczb
zmiennoprzecinkowych i przepisuje je do struktury std msgs::Float32MultiArray,
która może przechowywać tablicę liczb dowolnego rozmiaru, a następnie publikuje
na odpowiednim temacie ROS.
4.2. KOMUNIKACJA MIĘDZY MODUŁAMI
39
Jednorodna macierz przekształcenia z układu związanego z kartką do
układu optycznego kamery
Macierz ta zawsze ma poniższą postać:




T =
rx px y x dx
ry py yy dy 


rz pz yz dz 
0 0 0 1

reprezentującą orientację względem osi X, Y i Z, przesunięcie d, perspektywę (w tym
przypadku [0, 0, 0]) i skalę (w tym przypadku 1). Publikowana jest przez moduł
wizyjny na temacie o nazwie pnp jako wektor 12 liczb, reprezentujących kolejno
trzy pierwsze wiersze macierzy, czyli:
[rx , px , yx , dx , ry , py , yy , dy , rz , pz , yz , dz ]
Ostatni wiersz zawsze jest taki sam, więc nie ma potrzeby go wysyłać. Publikowanie następuje przy każdym obiegu głównej pętli modułu wizyjnego - dzięki temu
macierz publikowana na temacie jest zawsze aktualna. W momencie gdy moduł wizyjny nie znajduje kartki na obrazie, macierz nie jest publikowana. Dzięki temu
możliwe jest wykrycie, że w polu widzenia kamery nie znajduje się kartka.
Kontury
Ze względu na to, że liczba konturów oraz ich długość jest zmienna, współrzędne
kolejnych punktów konturów są publikowane na temacie points jako wektor liczb,
będących kolejnymi współrzędnymi punktów konturów.
4.2.2
Odbieranie danych
Funkcja subscriber
Dane odbierane są w module sterowania przy użyciu funkcji Subscriber dostępnej w systemie ROS. Wymaga ona podania nazwy tematu, typu danych publikowanych w temacie oraz nazwy funkcji wykonywanej za każdym razem, gdy na temacie
pojawią się nowe dane. Ponieważ odczytywane dane pochodzą z dwóch tematów,
zainicjowano dwóch subskrybentów:
1
2
rospy . Subscriber ( " pnp " , Float32MultiArray , callbackPnp )
rospy . Subscriber ( " points " , Float32MultiArray , callbackPoints )
Funkcja callback jako argument otrzymuje odebrane dane. Bardzo istotne jest, że
dla każdej funkcji związanej z subskrybentem tworzony jest odrębny wątek, dzięki
czemu wykonywana jest za każdym razem, gdy pojawią się nowe dane, nawet gdy
główny program wykonuje inne zadania.
Zmienne globalne
W ciele funkcji związanej z danym subskrybentem odebrane dane są zapisywane
do zmiennej globalnej, do której ma dostęp główny program. Ze względu na to,
że nie jest znana częstotliwość wykonywania się tej funkcji (w szczególności może
40
ROZDZIAŁ 4. REALIZACJA
nastąpić niewielkie opóźnienie i kilka wiadomości może przyjść w bardzo krótkim
odcinku czasu), nie jest wskazane umieszczanie skomplikowanej logiki w jej wnętrzu.
Funkcje związane z subskrybentami działają w osobnych wątkach, lecz korzystają
z tych samych zmiennych globalnych co program główny. Z tej przyczyny wszelkie
operacje dotyczące tych zmiennych (zarówno odczytywanie, jak i modyfikowanie) są
zabezpieczone przed jednoczesnym wykonaniem za pomocą struktury Lock, która
umożliwia blokowanie zasobów.
W przypadku macierzy jednorodnej przekształcenia z układu związanego z kartką
do układu optycznego kamery zmienną globalną jest macierz o wymiarach 4 × 4. Po
odebraniu danych z tematu pnp w postaci wektora 12 liczb są one dzielone na trzy
części i wstawiane odpowiednio w trzy pierwsze wiersze macierzy. Czwarty wiersz
jest uzupełniany liczbami [0 0 0 1]. Dla danych dotyczących współrzędnych punktów
tworzących kontury zmienna globalna jest tablicą jednowymiarową, której elementami są wektory zawierające współrzędne x i y kolejnych punktów. W pętli znajdującej się w funkcji związanej z subskrybentem punktów wektor ten jest odczytywany
i odpowiednio przepisywany do zmiennej globalnej.
Oczekiwanie na dane z modułu wizyjnego
Po uruchomieniu skryptu program czeka jedną sekundę, aby upewnić się, że macierz przekształcenia została przynajmniej raz odebrana. Następnie przez 5 sekund
zbiera listy przesyłanych konturów w celu wybrania najlepszej wersji (wynika to
z zastosowania algorytmów probabilistycznych w module wizyjnym oraz możliwych
zmian oświetlenia, wpływających na algorytmy). Następnie wybierana jest najlepsza
lista konturów (kryterium jakości jest tutaj liczba konturów - im mniej, tym lepiej,
gdyż oznacza to, że moduł wizyjny prawidłowo je połączył).
4.3
Moduł sterowania
Moduł sterowania otrzymuje dane z modułu wizyjnego dotyczące wzajemnego
położenia kartki i robota oraz współrzędne konturów, które ma narysować, a następnie oblicza trajektorię i ją wykonuje. Decyzje dotyczące momentu zebrania danych
oraz rozpoczęcia ruchu są podejmowane przez użytkownika systemu poprzez klawiaturę.
4.3.1
Obliczenie i wykonanie trajektorii
Pierwszym krokiem obliczenia trajektorii jest obliczenie macierzy przekształcenia
z układu związanego z kartką do układu bazowego robota, zgodnie ze wzorami 3.1
i 3.2:
1
2
# z ukladu kartki do ukladu optycznego kamery - odczytane z tematu
/ pnp do zmiennej globalnej matrix
current_matrix = matrix
3
4
5
# z ukladu optycznego kamery do ukladu kamery
opt ical_t o_came ra =
numpy . matrix ([[ -1 ,0 ,0 ,0] ,[0 , -1 ,0 ,0] ,[0 ,0 ,1 ,0] ,[0 ,0 ,0 ,1]])
6
7
# z ukladu kamery do ukladu ostatniego stawu
4.3. MODUŁ STEROWANIA
8
41
camera_to_tl6 =
numpy . matrix ([[0 , -1 ,0 , -0.0551] ,[1 ,0 ,0 ,0] ,[0 ,0 ,1 ,0.13] ,[0 ,0 ,0 ,1]])
9
10
11
12
13
14
# z ukladu ostatniego stawu do ukladu bazowego
quaternion = irpos . ge t_ ca rt es ia n_ po se () . orientation
pos = irpos . ge t_ ca rt es ian_p os e () . position
tl6_to_base = quat ernion _matri x ( quaternion )
tl6_to_base = tl6_to_base +
numpy . matrix ([[0 ,0 ,0 , pos . x ] ,[0 ,0 ,0 , pos . y ] ,[0 ,0 ,0 , pos . z ] ,[0 ,0 ,0 ,0]])
15
16
17
# obliczenie przektszalcenia
transformation = tl6_to_base * camera_to_tl6
* current_matrix
* op tical_ to_cam era
Następnie każdy punkt każdego konturu jest wymnażany przez macierz tego
przekształcenia. W ten sposób uzyskiwana jest lista konturów, których współrzędne
XY Z są określone względem układu bazowego robota. Następnie wykonywana jest
poniższa sekwencja:
1. Przenieś końcówkę roboczą nad pierwszy punkt pierwszego konturu.
2. Opuść chwytak w kierunku kartki aż do zanotowania odpowiednio dużej siły
nacisku.
3. Dla każdego punktu konturu:
• oblicz czas potrzebny na ruch od poprzedniego punktu do aktualnego
z daną prędkością,
• utwórz obiekt typu CartesianTrajectoryPoint zawierający czas ruchu oraz
współrzędne punktu,
• dodaj utworzony obiekt do trajektorii.
4. Wykonaj trajektorię utworzoną w poprzednim kroku.
5. Podnieś chwytak.
6. Jeśli nie był to ostatni kontur, przenieś końcówkę roboczą nad pierwszy punkt
kolejnego konturu i przejdź do punktu 2. Jeśli ostatni, wróć do pozycji roboczej.
4.3.2
Użycie biblioteki IRPOS
Inicjalizacja
Na początku tworzony jest obiekt klasy IRPOS, inicjalizujący węzeł ROS oraz
komunikację z komponentami OROCOS. Dzięki temu możliwe jest przesyłanie rozkazów uruchamiających generatory trajektorii i wykonywanie skomplikowanych ruchów robotem. Konstruktor jest wywoływany dla robota Track.
1
irpos = IRPOS ( " rysowanie " , " Irp6ot " , 7)
42
ROZDZIAŁ 4. REALIZACJA
Przyjmowanie pozycji roboczej
Pozycja robocza osiągana jest poprzez wykonanie funkcji move to joint position,
co gwarantuje zawsze tę samą pozycję i stałe warunki początkowe zadania. Jako
argument podawany jest taki wektor położeń poszczególnych stawów, aby uzyskać
pozycję, w której ramię robota jest wychylone nad kartką, a chwytak skierowany
prosto w dół.
Przenoszenie pisaka nad pierwszy punkt konturu
Przenoszenie chwytaka nad pierwszy punkt konturu realizowane jest za pomocą
funkcji move to cartesian pose - jako argumenty podawane są współrzędne punktu.
Do wysokości dodawana jest odległość 5cm aby upewnić się, że pisak nie uderzy
w powierzchnię kartki.
Opuszczanie pisaka w kierunku kartki
Zadanie opuszczania pisaka w kierunku kartki może być zrealizowane na dwa
sposoby, z których lepszy zostanie wybrany na etapie weryfikacji. Pierwszym sposobem jest zastosowanie funkcji move rel to cartesian pose with contact poprzez zadanie ruchu w dół i ograniczenia siłowego. W momencie dotknięcia kartki czujnik
siły wykryje nacisk i ruch zostanie zatrzymany. Drugi sposób polega na zastosowaniu sterowania siłowego. Przy użyciu funkcji start force controller należy zadać siłę
skierowaną w dół, co wymusi ruch robota do momentu napotkania kartki. Jednocześnie trzeba monitorować siłę odczytywaną przez czujnik siły i publikowaną na
temacie irp6ot arm/wrist wrench. Kiedy siła wzrośnie, należy zatrzymać ruch.
Rysowanie konturu
Za rysowanie konturu odpowiada funkcja move along cartesian trajectory, która
wcześniej wymaga włączenia komponentu OROCOS o nazwie mForceTransformation. Jako argument podawany jest wektor kolejnych punktów danego konturu.
Współrzędne x i y punktów zostały obliczone na podstawie danych z modułu wizyjnego, natomiast współrzędna z została ustalona na podstawie pozycji robota
po opuszczeniu pisaka do kartki. Założono, że powierzchnia kartki jest pozioma,
a wszelkie nierówności lub pochylenie powierzchni zostanie skompensowane przez
podatność chwytaka.
Podnoszenie pisaka
Podnoszenie pisaka jest bardzo prostym zadaniem, realizowanym przez funkcję
move rel to cartesian pose. Jako argument podawana jest odległość, o jaką robot ma
podnieść swoje narzędzie.
Zaciskanie chwytaka
Do tego zadania używana jest funkcja tfg to joint position. Wykonywana jest ona
raz przed rozpoczęciem zadania rysowania, ponieważ wymaga interakcji z użytkownikiem, który musi podać robotowi pisak umieszczony w zmodyfikowanym chwytaku
(opisanym w sekcji 4.4).
4.4. MODYFIKACJA STANOWISKA ROBOTYCZNEGO
4.4
43
Modyfikacja stanowiska robotycznego
Zamontowany na robocie chwytak nie jest przystosowany do trzymania przedmiotów wąskich, takich jak pisak. Dodatkowo konieczne jest zapewnienie kilkucentymetrowej podatności, aby odpowiednio reagować na niewielkie pochylenie
płaszczyzny kartki. Dlatego wykonany został specjalny chwytak, trzymający pisak.
Umożliwia on ruch pisaka w górę i w dół w zakresie 2cm. Projekt oraz wykonanie
chwytaka zostały zaprezentowane na rysunku 4.14.
Konstrukcja chwytaka, zapewniającego podatność wpłynęła znacząco na implementację przy wyznaczaniu wysokości, na jakiej ma znajdować się końcówka robocza
podczas rysowania konturu. Istotny przy tym ruchu jest ciągły kontakt z płaszczyzną kartki, ale niezbyt silny nacisk. Zastosowanie sztywnego chwytaka skutkowałoby
koniecznością zaimplementowania regulatora, ustalającego wysokość położenia końcówki roboczej. Podatność chwytaka pozwoliła na rozwiązanie, w którym dla każdego konturu wysokość jest sprawdzana raz, na początku, a ewentualne nierówności
kartki są kompensowane mechanicznie.
(a) Model 3D chwytaka
(b) Przekrój modelu
(c) Rysunek
chwytaka:
pół-przekrój
(d) Wykonany chwytak
Rysunek 4.14: Projekt i wykonanie chwytaka
techniczny
pół-widok,
44
ROZDZIAŁ 4. REALIZACJA
Rozdział 5
Wyniki i testy
Ostatni rozdział poświęcony jest prezentacji wyników. Zawiera opis strojenia
systemu (sekcja 5.1), wyniki (sekcja 5.2) oraz podsumowanie (sekcja 5.3).
5.1
5.1.1
Strojenie systemu
Parametry działania modułu wizyjnego
Komponenty modułu wizyjnego wymagają podania właściwości, które wpływają
na ich działanie. Dla części z nich przeprowadzono eksperymenty w celu ustalenia,
jakie są prawidłowe wartości tych właściwości. Należy zaznaczyć, że część właściwości silnie zależy od warunków oświetlenia. Dobrane zostały takie wartości, aby
system działał prawidłowo dla możliwie najszerszego zakresu warunków. Poniżej
zostało opisane dobieranie właściwości tych komponentów, które wymagały eksperymentów.
Poprawa jakości obrazu
Zadaniem poprawy jakości obrazu po akwizycji zajmują się dwa komponenty.
Pierwszy z nich, CvGaussianBlur, implementuje rozmycie Gaussa, które jako parametry przyjmuje rozmiar elementu strukturalnego (odpowiada za wielkość okna)
oraz wartości σx i σy (odpowiadają za kształt funkcji używanej do rozmycia). Wybrana wielkość elementu strukturalnego to 3, co daje okno w kształcie kwadratu
o boku trzech pikseli. Jest to optymalna wielkość, która usuwa zakłócenia, ale nie
powoduje zbyt dużego rozmycia krawędzi. Dobrano doświadczalnie wartości σx = 2
i σy = 2. Drugi komponent to CvUndistort, który korzystając z parametrów kalibracji kamery dostarczonych przez komponent CameraInfoProvider usuwa zakłócenie
geometryczne. W skład tych parametrów wchodzą informacje o ogniskowej kamery
i jej punkcie centralnym oraz wektor współczynników dystorsji. Zostały one dobrane
przy użyciu specjalnej szachownicy oraz programu dostępnego w systemie ROS.
Segmentacja
Do oddzielenia kartki od tła używany jest komponent CvThresholding, który
wykonuje algorytm progowania dla zadanej wartości jasności. Jeśli jasność piksela
jest powyżej progu, piksel staje się biały, w przeciwnym przypadku staje się czarny.
45
46
ROZDZIAŁ 5. WYNIKI I TESTY
Jako właściwości komponentu podawane są: wartość progowa (ustalona doświadczalnie dla typowych warunków oświetlenia panujących w laboratorium i dobrana
tak, aby jak najlepiej wyodrębniała kartkę na ciemnym tle; ustalona została wartość
100, która dla różnych warunków oświetlenia daje tak samo dobre efekty), wartość
maxVal, jaką przyjmuje piksel jeśli jego jasność jest wyższa niż wartość progowa
(przyjęto 255, czyli kolor biały) oraz typ progowania (binarne). Kolejnym krokiem są
operacje morfologiczne w komponencie CvMorphology, mające usunąć małe obiekty
i dziury w obiekcie po progowaniu. Jako jego właściwości podawane są: typ operacji (odpowiednio morfologiczne zamknięcie morph close i otwarcie morph open)
oraz liczba iteracji - im większa, tym lepsze wyniki, ale i większe zniekształcenie
obrazu. W tym przypadku wystarczyła jedna iteracja, ponieważ bardzo ważne było
zachowanie kształtu narożników.
Wyznaczenie położenia kartki
Pierwszy komponent wykonujący to zadanie to FindEdges, który szuka krawędzi
w obrazie. Jako właściwości podawany jest tryb wyszukiwania konturów (cv retr external, co zwraca tylko najbardziej zewnętrzne kontury - spodziewane jest, że kontur
kartki będzie właśnie takim konturem) oraz metoda (cv chain approx none, co znaczy, że kolejne punkty w wektorze nie będą oddalone od siebie o więcej niż jeden
piksel). Kolejnym komponentem, który wymagał eksperymentów był CvHoughLines,
który w obrazie krawędziowym wyszukuje linie proste. Konieczne było ustalenie, jakie linie wykryte przez funkcję biblioteki OpenCV należą do tej samej krawędzi
kartki. Używane do tego są parametry to kąt nachylenia linii oraz punkty przecięcia
(linii lub jej przedłużenia) z osiami X i Y . Dwie linie należą do tej samej krawędzi,
jeśli różnica kątów nachylenia jest mniejsza niż 5◦ oraz różnica miejsc przecięcia osi
jest mniejsza niż 100 pikseli.
Wyznaczenie konturów
Pierwszym komponentem tego etapu wymagającym eksperymentów był cvThresholding, wyodrębniający rysunek od kartki przez algorytm progowania. Ustalono
wartość progową jasności na 130, co działa bardzo dobrze dla różnych warunków
oświetlenia. Niezbędne było także ustalenie liczby iteracji komponentu Skeleton,
który tworzy szkielet konturów. Wybrano 20, gdyż wystarcza do stworzenia dobrego
szkieletu, a nie trwa zbyt długo. Bardzo ważne było dobranie parametrów komponentu CvContour, który na podstawie obrazu z konturami wyznacza kolejne punkty
linii do narysowania. Jako właściwości podawane są wartości progowe wykorzystywane przy redukcji punktów:
• thresh1 - minimalna odległość między punktami; odległość 2 pikseli jest wystarczająca do zniwelowania podwójnych konturów i nie zniekształca obrazu.
thresh2 - maksymalna odległość między dwoma kolejnymi punktami należącymi do tego samego konturu; ustalona zawsze jako thresh1 + 4.
• thresh3 - maksymalna odległość między końcami konturów, które mają zostać
połączone; wybrano odległość 10 pikseli; powinna to być wartość większa niż
thresh1 .
5.2. WYNIKI DZIAŁANIA I TESTY
47
Dobranie tych parametrów było bardzo istotne, ponieważ ich zbyt małe wartości
powodują rysowanie podwójnych konturów i powstawanie przerw w liniach ciągłych,
natomiast zbyt duże wartości zniekształcają obraz i łączą kontury, które powinny
zostać oddzielnie.
5.1.2
Wybranie funkcji opuszczającej narzędzie
Funkcja move rel to cartesian pose with contact dostępna w bibliotece IRPOS
umożliwia wykonanie ruchu do momentu zanotowania odpowiednio dużej siły, jednak okazała się nieodpowiednia dla zadania opuszczania pisaka do kartki. Wynikało
to z konieczności ustalenia siły progowej o dużej wartości, która powodowała zbyt
mocne wbijanie się pisaka w kartkę. Zakłócenia oraz bezwładność robota powodowały, że funkcja działała prawidłowo dopiero dla wartości progowej 5N. Stanowiło
to zbyt dużą wartość dla powierzchni styku ok. 1mm2 . Rozwiązaniem okazało się
zastosowanie sterowania siłowego. Umożliwia ono zadanie prędkości robota oraz zdefiniowanie, z jaką siła ma działać w osiach XYZ. W tym przypadku zadawane są
zerowe prędkości oraz siła o wartości 5N wzdłuż osi Z w dół. Dzięki temu robot
porusza się w dół do kartki.
W skrypcie sterującym robotem znajduje się subskrybent tematu irp6ot arm/
wrist wrench, na który publikowane są odczyty czujnika siły w chwytaku. Związana
z nim funkcja callbackWrench, wykonywana przy odebraniu nowych danych z tematu, uzupełnia wcześniej utworzoną 5-elementową tablicę odczytami wartości siły
działającej w osi Z. Dzięki temu w tablicy zawsze znajdują się najnowsze odczyty.
W czasie ruchu robota, gdy ma zostać opuszczony do kartki, inicjalizowane jest sterowanie siłowe i zadawane sa opisane powyżej parametry. Zostaje ono zakończone
w momencie, gdy średnia arytmetyczna ostatnich odczytów sił w tablicy przekroczy wartość 3N. Dzięki temu rozwiązaniu pojedyncze, zakłócone odczyty o większej
wartości nie spowodują przedwczesnego zatrzymania robota.
5.2
Wyniki działania i testy
5.2.1
Weryfikacja wykrycia kartki
Aby zweryfikować poprawne zlokalizowanie kartki przez moduł wizyjny, zastosowano program RViz z pakietu ROS, który umożliwia wizualizację aktualnego położenia i ruchu robotów. Wykorzystano przy tym gotowe modele robotów IRp-6. Dodatkowa wizualizacja położenia kartki w tym programie, pokazująca jej umiejscowienie
względem robota jest ciekawym uzupełnieniem, a także pozwala na sprawdzenie
poprawności działania modułu wizyjnego oraz jego szybkości działania. Widok wizualizacji został przedstawiony na rysunku 5.1.
Niezbędne okazało się uzupełnienie pliku irp6pboth.urdf.xacro, zawierającego opis
modeli robotów dla programu RViz. Plik ten zawiera informacje dotyczące kolejnych
stawów i członów robotów (ich wymiary i wzajemne położenie) oraz definiuje układy
współrzędnych z nimi związane. Plik został uzupełniony o dwa układy współrzędnych dla każdego robota (t dla Tracka, p dla Postumenta):
• układ związany z kamerą (t c, p c) - obrócony o kąt − π2 oraz przesunięty
o 0.0551m wzdłuż osi X i o 0.13m wzdłuż osi Z względem ostatniego stawu
robota,
48
ROZDZIAŁ 5. WYNIKI I TESTY
• układ optyczny kamery (t c optical frame, p c optical frame) - obrócony o kąt
π względem układu związanego z kamerą.
System ROS udostępnia specjalny typ danych Marker, który może być odbierany
z tematu przez program RViz. Służy on do przesyłania informacji w celu wizualizacji
podstawowych brył i kształtów, taki jak kule, walce, sześciany, linie i płaszczyzny.
Możliwe jest także wysłanie tablicy typu MarkerArray w celu wizualizacji wielu elementów naraz. Element Marker musi zostać uzupełniony informacjami dotyczącymi
bryły, która ma być pokazana, wśród których najważniejsze to:
• dane dotyczące geometrii i wyglądu bryły - typ, wymiary, kolor,
• skala w poszczególnych osiach,
• położenie i układ współrzędnych, w którym to położenie jest wyznaczane,
a następnie opublikowany w odpowiednim temacie. W programie RViz należy dodać
dany temat do elementów wizualizowanych.
W celu wizualizacji kartki przygotowano skrypt napisany w języku Python.
Tworzy on subskrybenta odbierającego macierz przekształcenia z układu związanego z kartką do układu optycznego kamery z tematu pnp. Następnie zgodnie ze wzorem 5.1 oblicza współrzędne punktów {0.0, 0.0, 0.0}, {0.21, 0.0, 0.0},
{0.21, 0.297, 0.0}, {0.0, 0.297, 0.0}, odpowiadających rogom kartki A4 wykrytej przez
system.
popt
=
opt
k T
pk
(5.1)
gdzie:
popt - punkt w układzie optycznym kamery,
pk - punkt w układzie związanym z kartką,
opt
k T - macierz przekształcenia z układu kartki do układu optycznego kamery.
Po obliczeniu współrzędnych punktów są one zapisywane w elemencie Marker
typu TRIANGLE LIST, który umożliwia wizualizację powierzchni poprzez siatkę
trójkątów. Kartka może być pokazana jako siatka składająca się z dwóch trójkątów,
których wierzchołki znajdują się w rogach kartki. Model kartki jest obliczany i wysyłany na temat kartka co 0.1 sekundy, za każdym razem do obliczeń używana jest
ostatnio odebrana macierz przekształcenia, co zapewnia aktualność położenia kartki.
Początkowy kolor kartki jest intensywnie zielony. Za każdym kolejnym wysłaniem informacji o jej położeniu kolor jest przyciemniany o 1%, co daje 10% na sekundę. Gdy
kolor zostanie przyciemniony do 70%, zmieniany jest na czarny. Natomiast w funkcji
wykonywanej przez subskrybenta za każdym razem, gdy nadejdą nowe dane z tematu pnp oprócz odczytania aktualnej macierzy przekształcenia uaktualniany jest
kolor kartki na intensywnie zielony. Dzięki temu rozwiązaniu uzyskany został efekt
przygasania kartki, jeśli przez pewien czas nie otrzymano aktualnej macierzy przekształcenia oraz zmiany koloru kartki na czarny jeśli dłużej niż przez 3 sekundy nie
otrzymano aktualnej macierzy. W takiej sytuacji czarna kartka pokazuje ostatnio
wykryte położenie kartki. Brak aktualnej macierzy przekształcenia jest sygnałem,
że moduł wizyjny nie wykrył kartki.
5.2. WYNIKI DZIAŁANIA I TESTY
49
Rysunek 5.1: Widok wizualizacji kartki i robota w programie RViz
5.2.2
Jakość rysunku
W celu przetestowania działania systemu narysowanych zostało kilkanaście rysunków, różniących się stopniem skomplikowania, zawierających różne kształty różnej grubości, m.in. linie, okręgi, przecięcia, kropki. Dla prawidłowo przygotowanych
obrazów wejściowych rysunki przygotowane przez robota wiernie oddają kształt
i wielkość. Wszystkie elementy zostają odrysowane z dużą dokładnością, w szczególności kropki i przecięcia. Efekt działania systemu został zaprezentowany na rysunku 5.2.
(a) Obraz wejściowy
(b) Znalezione kontury
(c) Narysowane kontury
Rysunek 5.2: Porównanie ręcznie przygotowanego obrazka, znalezionych konturów
oraz gotowego rysunku, wykonanego przez robota
Istnieją jednak trzy rodzaje błędów, jakie pojawiają się na rysunkach:
• Przerwane krawędzie - wynikają z błędów w analizie obrazu. Kontury wykryte
przez funkcję OpenCV cv::findContours czasem zawierają niepożądane przerwy, co jest skutkiem zbyt cienkich lub zbyt mało kontrastowych linii. Błąd
ten nie zawsze jest korygowany w dalszym przetwarzaniu, co wynika z koniecz-
50
ROZDZIAŁ 5. WYNIKI I TESTY
ności kompromisu między jak najlepszym łączeniem końców krawędzi a zachowaniem dokładności rysunku. Efekt pokazano na rysunku 5.3.
• Ciemne kropki na liniach - pojawiają się w miejscach, gdzie pisak był opuszczany w dół do kartki. Wynika to z zastosowania dość dużej siły progowej, wymaganej do zatrzymania ruchu. Mniejsza wartość mogłaby zostać odczytana
przez czujnik w trakcie ruchu w dół. Efekt ten zaprezentowano na rysunku 5.4.
• Przesunięcie rysunku na kartce o ok. 1cm - wynika z założenia, że osie Z kamery
oraz chwytaka są idealnie równoległe. W rzeczywistości występują niewielkie
różnice między ich osiami Z, co w przetwarzaniu skutkuje tym przesunięciem.
(a) Oryginalny rysunek
(b) Błąd - przerwany kontur
Rysunek 5.3: Brak połączenia konturów
(a) Oryginalny rysunek
(b) Błąd - ciemne kropki
Rysunek 5.4: Ciemnie kropki w miejscach opuszczenia pisaka
5.2.3
Test grubości linii
Przeprowadzony został test sprawdzający zakres grubości linii rysunku, dla
którego system działa poprawnie. W tym celu przygotowano rysunek testowy
(rys. 5.5(a)), zawierający osiem linii prostych o grubości od ok. 0.5mm do ok. 1cm
w celu sprawdzenia, które z nich zostaną prawidłowo narysowane. Otrzymano następujące wyniki (rys. 5.5(b)):
• Linie cieńsze niż 1mm nie są wykrywane przez system. W trakcie przetwarzania
obrazu są usuwane, gdyż są zbyt mało widoczne.
5.2. WYNIKI DZIAŁANIA I TESTY
51
• Dla linii grubszych niż 5mm na końcach pojawiają się rozgałęzienia. Powstają
one na etapie szkieletyzacji - gruba linia jest traktowana jak długi, cienki
prostokąt, a szkielet prostokąta to linia, rozgałęziona na końcach.
Po wykonaniu tego testu można wyciągnąć wniosek, że system najlepiej działa
dla linii o grubości 1-5mm. Cieńsze linie zostaną pominięte, natomiast grubsze spowodują powstanie niechcianych rozgałęzień na końcach.
(a) Oryginalny rysunek
(b) Efekt działania
Rysunek 5.5: Test grubości linii
5.2.4
Test gęstości linii
Wykonano test w celu określenia, jak blisko siebie mogą znajdować się linie, które
następnie zostaną poprawnie wykryte i narysowane. W tym celu przygotowany został
specjalny rysunek testowy (rys. 5.6(a)), zawierający 8 linii znajdujących się w odległościach od 3cm do 2mm w celu sprawdzenia, jaka jest minimalna odległość między
narysowanymi liniami, które system prawidłowo wykrywa. Okazało się (rys. 5.6(b)),
że końce linii znajdujących się bliżej niż 4mm zostają nieprawidłowo połączone. Stąd
wniosek, że system działa najlepiej dla linii znajdujących się w większej odległości,
niż 4mm.
(a) Oryginalny rysunek
(b) Efekt działania
Rysunek 5.6: Test gęstości linii
52
5.2.5
ROZDZIAŁ 5. WYNIKI I TESTY
Sterowanie
Jednym z testowanych elementów systemu było poruszanie ramieniem robota.
Podczas działania nie nastąpiła sytuacja, w której sterowanie byłoby niewłaściwe.
Robot zawsze wykonywał prawidłowo zadane ruchy. Kolejne etapy zadania, wykonywane przez robota zostały pokazane na rysunkach 5.7(a), 5.7(b), 5.7(c), 5.7(d).
5.3
5.3.1
Podsumowanie
Wnioski
W ramach pracy stworzony został system realizujący zadanie rysowania dla robota IRp-6. Osiągnięty został cel, który obejmował dwa główne zagadnienia: analizę obrazu, na podstawie którego ma powstać rysunek, oraz wykonanie sterowania
manipulatorem. Spełnione zostały założenia projektowe. Modyfikacja stanowiska
robotycznego poprzez zastosowanie specjalnego chwytaka ułatwiła implementację
i wpłynęła na jakość wykonywanego rysunku. W trakcie testów wykazane zostało
prawidłowe funkcjonowanie systemu. Wykryte zostały pewne niedoskonałości, które
nie wpływają znacząco na jego działanie.
5.3.2
Perspektywy rozwoju
Projekt realizujący zadanie rysowania dla robota IRp-6 może zostać rozwinięty
i udoskonalony. Ciekawą modyfikacją mogłoby być wprowadzenie rozpoznawania obszarów zapełnionych na obrazie wejściowym i kreskowanie ich podczas rysowania.
Innym pomysłem jest używanie różnych kolorów do rysowania, odpowiadających kolorystyce obrazu wejściowego. Dodatkową funkcją byłoby umożliwienie rysowania na
pochylonej kartce lub nierównej powierzchni. Dekompozycja systemu na moduły wizyjny i sterowania umożliwia wykorzystanie różnych robotów do wykonania zadania
rysowania.
5.3. PODSUMOWANIE
53
(a) Pozycja robocza
(b) Opuszczenie chwytaka
(c) Rysowanie konturu
(d) Przechodzenie do kolejnego konturu
Rysunek 5.7: Etapy ruchu robota
54
ROZDZIAŁ 5. WYNIKI I TESTY
Bibliografia
[1] Oficjalna strona biblioteki OpenCV. http://opencv.org/.
[2] Oficjalna strona firmy Point Grey. http://www.ptgrey.com.
[3] Oficjalna strona OROCOSa. http://orocos.org/.
[4] Oficjalna strona systemu ROS. http://ros.org.
[5] Oficjalna strona Zakładu Programowania Robotów i Systemów Rozpoznających. http://robotyka.ia.pw.edu.pl/twiki/bin/view/Main.
[6] P. Arbelaez, M. Maire, C. Fowlkes, J. Malik. Contour detection and hierarchical image segmentation. Pattern Analysis and Machine Intelligence, IEEE
Transactions on, 33(5):898–916, May 2011.
[7] H. Bruyninckx, P. Soetens, B. Koninckx. The real-time motion control core
of the orocos project. Robotics and Automation, 2003. Proceedings. ICRA ’03.
IEEE International Conference on, wolumen 2, strony 2766–2771 vol.2, Sept
2003.
[8] Adrian Kaehler Gary Bradski. Learning OpenCV. Computer Vision with the
OpenCV library. O’REILLY, 2008.
[9] Mikołaj Kojdecki. Podejmowanie pionów za pomocą robota manipulacyjnego
IRp-6 korzystającego z chwytaka podciśnieniowego, 2014.
[10] Tomasz Kornuta, Maciej Stefańczyk. DisCODe: a component oriented framework for procesing of sensory data (in Polish). Pomiary Automatyka Robotyka,
16(7-8):76–85, 2012. (DisCODe: komponentowa struktura ramowa do przetwarzania danych sensorycznych).
[11] Tomasz Kornuta, Maciej Stefańczyk, Michał Laszkowski, Maksym Figat, Jan
Figat, Cezary Zieliński. Asynchronous data flow handling in component-based
robot perception subsystems (in Polish). Pomiary – Automatyka – Robotyka PAR, 18(5):127–133, 2014. Obsługa asynchronicznego przepływu danych
w komponentowych podsystemach percepcji robotów.
[12] Tomasz Pokorski. Robot grający w kości w systemie ROS/OROCOS, 2014.
[13] Long Quan, Zhongdan Lan. Linear n-point camera pose determination. Pattern
Analysis and Machine Intelligence, IEEE Transactions on, 21(8):774–780, Aug
1999.
55
56
BIBLIOGRAFIA
[14] Morgan Quigley, Ken Conley, Brian Gerkey, Josh Faust, Tully Foote, Jeremy
Leibs, Rob Wheeler, Andrew Y Ng. Ros: an open-source robot operating system. ICRA workshop on open source software, wolumen 3, 2009.
[15] Wojciech Szynkiewicz. Rozszerzony konspekt wykładu: „Wstęp do robotyki”,
2014.
[16] T. Winiarski, C. Zieliński. Podstawy sterowania siłowego w robotach. Pomiary
Automatyka Robotyka, 12(6):5–10, Czerwiec 2008.