===== Labirynt ===== {{ :pl:miw:miw08_mindstormsdesign:labirynt.png?200|Labirynt}} Przed przystąpieniem do zadania należy przygotować labirynt (makietę). W celu lepszego sterowania robotem dobrze jest również pozbyć się kleszczy z przodu (patrz budowa robota TriBot). Kleszcze mogą utrudniać poruszanie się robota po planszy. W ramach prezentowanego niżej algorytmu przyjęto: - pola makiety po jakich poruszać się będzie robot są na tyle duże, że robot może się swobodnie obrócić - przyjmujemy budowę robota TriBot bez przednich kleszczy - robot nie wie nic o planszy - w algorytmie przyjęto ruch co określoną długość, w celu uproszczenia za długość kroku przyjęto szerokość jednego pola planszy (patrz rys. Labirynt) - każdej nowej pozycji przypisywany jest numer oraz parametry związane z tą pozycją Opis pozycji robota: {{ :pl:miw:miw08_mindstormsdesign:pomiar.png|Pomiar}} - pozycja robota zostaje opisana przez 8 pomiarów echosondy pobieranych co kąt 450. Otrzymane wyniki są zapisywane w bazie wiedzy robota o planszy. Kolejne pozycje są numerowane. Każda nowa pozycja znajduje się w odległości N cm od pozostałej (gdzie N jest szerokością jednego pola planszy). - Taka struktura danych mogłaby wyglądać następująco: pole(nr_pola,[nr_pomiaru,następne_pole,ultrasonic_value]) * nr_pola - numer pola dla którego przeprowadzane są pomiary * nr_pomiaru - numer przeprowadzanego pomiaru * następne_pole - jest to informacja o polu jakie znajduje się w danym kierunku * utrasonic_value - wartość echosondy w danym kierunku {{ :pl:miw:miw08_mindstormsdesign:pomiar2.png|Przechodzenie do następnego pola}} W ten sposób zdefiniowane pola można łączyć i budować prostą bazę wiedzy o otoczeniu robota. Czarne cyfry na rysunku przedstawiają numery poszukiwań. Pomiary przeprowadzane są co 450 więc jest ich 8. Czerwone cyfry oznaczają numery pól. Niebieskie cyfry są przypisanym numerem pola, do którego można się dostać podążając w kierunku pomiaru np. 3. Żółta cyfra 0 oznacza z kolei ścianę (przeszkodę), którą napotkamy w zadanym kierunku. Wartość ściany definiuje pomiar echosondy. Jeżeli odległość jest mniejsza niż ustalona wartość to wówczas przyjmujemy, że jest w tym miejscu ściana lub inna przeszkoda. Poniżej zaprezontowano algorytm, który przy wykorzystaniu takiej postaci wiedzy steruje robotem TriBot. ==== Zapis słowny === - Zbadaj otoczenie. - Spośród zbadanych wartości **ultrasonic_v** wybierz tą, która jest największa i nie ma przypisanego węzła. Obróć się tam, gdzie ona jest. - Jeżeli znaleziono wartość największą to: - Przypisz tej galezi jako nr następnego węzła kolejny wolny nr węzła. - Rusz się do przodu o N cm. - Jeżeli wszyskie pozostałe połaczenia są zablokowane to: - Wybierz kierunek z zaznaczonym węzłem następnym. - Rusz się do przodu o N cm. - Po przejściu do wezła zablokuj dostęp do węzła, z ostatniej pozycji robota. - Idź do (2). - Zbadaj otoczenie dla pomiaru 5 przypisz numer wcześniejszego węzła. ==== Zapis regułowy ==== Rule: 1 if listOfAddedNodes.has?(current_node) == false then listOfAddedNodes.add(current_node) and node.add(current_node,[1,0,ultras_v]) then turn = 45 and node.add(current_node,[2,0,ultras_v]) then turn = 45 and node.add(current_node,[3,0,ultras_v]) then turn = 45 and node.add(current_node,[4,0,ultras_v]) then turn = 45 and node.add(current_node,[5,previous_node,ultras_v]) then turn = 45 and node.add(current_node,[6,0,ultras_v]) then turn = 45 and node.add(current_node,[7,0,ultras_v]) then turn = 45 and node.add(current_node,[8,0,ultras_v]) Rule: 2 if listOfAddedNodes.has?(current_node) == true then goTo(Rule 5) Rule: 3 if messure_no in [0;8] then messure_no++ and goTo(Rule 5) Rule: 4 if messure_no not in [0;8] then messure_no := 0 and goTo(Rule 7) Rule: 5 if ultras_v(current_node,messure_no) > X and next_node(current_node,messure_no) == 0 then turn = messure_no*45 and goStepFoward and node_counter++ and node.update(current_node,[messure_no,node_counter,ultras_v]) and current_node = node_counter and goTo(Rule 1) else goTo(Rule 3) Rule: 6 if messure_no in [0;8] then messure_no++ and goTo(Rule 7) else STOP Rule: 7 if ultras_v(current_node,messure_no) > X and next_node(current_node,messure_no) > 0 then turn = messure_no*45 and goStepFoward and current_node = next_node(current_node,messure_no) and node.update(current_node,[messure_no,-1,0]) and goTo(Rule 2) else goTo(Rule 6) ==== Implementacja w Prologu ==== messured_nodes(node_no). node(node_no,messure_no,next_node,ultrasonic_val,messured). current_node(node_no,messure_no). current_messure(number). %---------------------- % dokonywanie pomiarów %---------------------- start :- current_node(X,_), node(X,Y,_,_), messured_nodes(Q), X \= Q, nxt_ultrasonic_sensor(port,Value1), assert(node(X,1,0,Value1), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value2), assert(node(X,2,0,Value2), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value3), assert(node(X,3,0,Value3), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value4), assert(node(X,4,0,Value4), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value5), assert(node(X,5,0,Value5), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value6), assert(node(X,6,0,Value6), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value7), assert(node(X,7,0,Value7), nxt_turn(speed,45), nxt_ultrasonic_sensor(port,Value8), assert(node(X,8,0,Value8) assert(messured_nodes(X)). %--------------------------- % szukanie najlepszej drogi %--------------------------- start :- current_node(X,M), node(X,Y,Next,U), messured_nodes(X), Next = 0, U <= number, % wartość progowa, ponad którą dokonywane jest przeszukiwanie retract(node(X,Y,_,_)), assert(node(X,Y,1000,U), % blokowanie połączenia current_messure(A), B is A + 1, retractall(current_messure(_)), assert(current_messure(B)). start :- current_node(X,M), node(X,Y,Next,U), messured_nodes(X), Next = 0, U > number, % wartość progowa, ponad którą dokonywane jest przeszukiwanie retract(node(X,Y,_,_)), nxt_ultrasonic_sensor(port,Value), assert(node(X,Y,X+1,Value), abs(M-Y,N), nxt_turn(speed,45*N), % przemieszczenie do nowego punktu nxt_go(1), retractall(current_node(X,_)), W is X + 1, assert(current_node(W,1)), assert(current_messure(1)). start :- current_node(X,M), node(X,Y,Next,U), messured_nodes(X), Next > 0, U > number, % wartość progowa, ponad którą dokonywane jest przeszukiwanie current_messure(D), D <= 8, % pominięcie punktu, zwiększenie licznika o 1 B is A + 1, retractall(current_messure(_)), assert(current_messure(B)). start :- current_node(X,M), node(X,Y,Next,U), messured_nodes(X), Next > 0, U > number, % wartość progowa, ponad którą dokonywane jest przeszukiwanie current_messure(D), D > 8, abs(M-Y,N), nxt_turn(speed,45*N), % przejscie do punktu, który już był wcześniej badany nxt_go(1), node(Next,P,X,U2), retractall(current_node(X,_)), assert(current_node(Next,P)), retractall(node(Next,P,_,_)), assert(node(Next,P,1000,U2)). % zablokowanie powrotu do poprzedniego punktu start :- go(0). ==== XTT ==== {{:pl:miw:miw08_mindstormsdesign:labirynt222.png|XTT}} FIXME * przy większych algorytmach pojawia się problem z zapętlaniem * podział na atrybuty, nie jest taki oczywisty, zwłaszcza w przypadku, gdy argumentami jest tablica argumentów * ponadto, nie jest oczywiste jak odczytywać argumenty. W tym algorytmie założyłem, że wszystkie atrybuty są odwzorowaniem jednego rekordu z tablicy atrybutów. Atrybuty zmieniają się w przypadku zwiększenia atrybutu current_node * nie jest jasne wykorzystanie akcji assert i retract. I pobieranie z nich wartości.