background image

Miniporadnik do „kosiarki” 

Czyli pomoc w zrozumieniu symulatora mobilnego RobSym napisanego przez 
doktora inżyniera Macieja Horczyczaka 

 

1.

 

Wstęp 

 

Poradnik przeznaczony dla osób mających po raz pierwszy styczność z symulatorem RobSym. 

 

Po pierwsze: zszywka (robsym.pdf) jest podstawowym źródłem informacji. W ramach poradnika postaram się 

wyjaśnić krzatające się w niej treści w sposób zrozumiały dla nas, studentów. Wybiorę z niej rzeczy warte 

objaśnienia, a nie wszystkie. 

Poradnik zawiera przykłady działających części programów, co w obliczu braku dostepu do RobSym poza salą 

laboratoryjną powinno być cenną pomocą. Informacje zweryfikowane empirycznie. 

 

Po drugie: przed przystąpieniem do pisania programu warto zaplanować wstępnie jak podejść do problemu i 

przemyśleć, co potrafi nasza kosiarka i jakie ograniczenia mają czujniki i dane intrukcje. (Źródła wiedzy to 

przykładowo: ograniczenia pętli while opisane są w tym poradniku, ograniczenie czujnika ultradźwiękowego 

można wyczytać ze zszywki) 

 

Rada ogólna: polecam pisanie programu w windowsowym notatniku, po czym wczytywanie go do symulatora. 

Znacznie ułatwia to edycję programu i stosunkowo płynne poruszanie się w chmarze literek itp.  

 

 

2.

 

Rady i przykłady 

 

a)

 

Zadanie następujące: Robot stoi w losowym miejscu, chcemy obórcić go w miejscu tak, by „patrzył się” 

prosto na marker. Niech będzie to marker 2. (położenie markera można ustawić w pliku 

konfiguracyjnym środowiska, chyba, że prowadzący sam ustawi marker) 

Przykładowy program: 

 

let kat 0 

Deklaruję zmienną “kat” przez podstawienie do niej dowolnej wartości, dla 
wygody 0. Deklaracja jest niezbędna przed użyciem zmiennej do innych 
celów. 

get 6 kat 

Po pierwsze pobieram wartość z portu 6. Port ten mówi mi, pod jakim 
kątem przód robota jest obrócony względem markera 2.  Wartość podaje w 
stopniach podzielonych przez 3, czyli od 0 do 119. Kąt rośnie przeciwnie do 
ruchu wskazówek zegara. Nidgy nie wystąpi liczba ujemna ani większa od 
119, zawsze będzie całkowita. Następnie wartość kąta wpisuję w zmienną 
„kat”. 

while kat :m2 

While rozpoczyna pętlę, która wykonuje się, dopóki zmienna (w tym 
przypadku „kat”) osiągnie wartość 0. „:m2” to nazwa miejsca, w którym 
pętla się kończy i z którego powróci na początek lub wyjdzie w razie 
spełnienia warunku zmienna=0. Po dwukropku może się znajdować 
dowolna nazwa. Nie wolno stosować tego samego ciągu znaków po 
dwukropku do więcej niż do jednej pętli w programie. Oczywistym jest, że 
w pętli należy uaktualniać zmienną tak, aby kiedyś uzyskała wartość 0, 
inaczej nasz program nigdy z pętli nie wyjdzie. 

set 1 34 

Wysyłam wartość 34 na port nr 1. Port ten odpowiada za uruchamianie 

background image

napędów kół. Wzór na obliczenie wartości podany jest w zszywce. W tym 
przypadku na koło lewe podaję wartość 1, na koło prawe -1 co daje 
równanie (1+3)*8+(-1+3) = 34, skutkiem jest obrót robota wokół swojego 
środka w prawo. Podanie na któreś koło wartości 0 skutkowałoby obrotem 
wokół tego koła co zazwyczaj nie jest pożądane. Zakładam, że w zadaniu 
nie ma różnicy, czy obracam się w lewo czy w prawo. 

get 6 kat 

Robot przed chwilą obrócił się nieco, muszę więc sprawdzić, czy może już 
osiągnął kąt równy 0. 

write "Kat na M2 to: " 

Komenda wyświetli na ekranie zdanie podane między znakami ””. Spacje 
też się liczą. 

write kat 

Wyświetli na ekranie liczbę kryjącą się pod zmienną kąt. 

write „stopni kosiarkowych.” 

Jak wcześniej. Write jest przydatny do oceny na bieżąco, czy program działa 
dobrze i co w rzeczywistości widzą czujniki kosiarki. Kilka write pod rząd 
wyświetli się ciągiem w jednej linii, tutaj jako: „Kat na M2 to: 12 stopni 
kosiarkowych.” Liczba 12 jest przypadkowa.  

newl 

Związane z write, wymusza przejście do kolejnego wiersza (lub wciśnięcie 
„entera” jak kto woli). Bez tego czytelność byłaby znikoma. 

:m2 

Oznacza koniec pętli, po napotkaniu tej komendy program wróci na 
początek odpowiedniej pętli while, sprawdzi warunek, po czym kontynuuje 
działanie pętli lub w razie spełnienia warunku wyjdzie z niej i wykona 
instrukcję stojącą za tym znakiem. 

set 1 27 

W tym momencie nasz robot jest już obrócony na marker 2, lecz na silniki 
nadal jest podawana wartość 34 czyli obrót. Tą komendą zatrzymamy 
obrót kół, a robot stanei w miejscu. 

stop 

Komenda kończąca cały program. Koniecznie musi występować na końcu 
programu. 

 

b)

 

 

W dowolnym miejscu programu można wstawić pusty wiersz (lub wiele takich pod rząd), zostanie on 

ominięty przez program. Innym wyborem jest komentarz, zaczyna się on od symbolu # , po nim może 

występować dowolny ciąg znaków i zostanie zignorowany przez program. Nie można stawiać 

komentarzy w tej samej linii co inna komenda, przykładowo: 

 

set 1 34 #obracam sie 
get 6 kat #pobieram kat 
write "Kat na M2 to: " #wyswietlam napis 

set 1 34  
#obracam sie 
 
get 6 kat  
                      #pobieram kat 
write "Kat na M2 to: "  
   #wyswietlam napis 

Błędnie dodane komentarze 

Poprawnie dodane komentarze  
(specjalnie ułożyłem je w mało czytelny sposób) 

 

 

 

c)

 

Za zadanie postawmy sobie dojazd do markera 2. Zacząć należy programem z podpunktu a) 

(przesuwając instrukcję stop na faktyczny koniec programu), dzięki temu robot patrzy się prosto na 

marker. Zdawać by się mogło, że wystarczy zastosować pętlę while, w której jako zmienną zastosujemy 

odległość od markera (gdy dojedziemy do markera zmienna powinna osiągnąć wartość 0 i zakończyć 

jazdę) a w środku pętli umieścimy instrukcję set 1 xx, gdzie xx oznacza jazdę do przodu (z równą 

prędkością na oba koła). Niestety, robot po zastosowaniu programu a) nie jest obrócony idealnie 

prosto na marker, może się mylić w ustawieniu nawet o 3 standardowe stopnie. W praktyce oznacza 

to, że nasz robot prawie na pewno ominie marker. Przejechanie nawet o 1 jednostkę za daleko od 

markera oznacza niemożność wyjścia z pętli a tym samym dalszą jazdę robota do przodu aż do kresu 

background image

planszy. W poniższym przykładzie pokażę, jak można zaprogramować korekcję kąta w trakcie jazdy z 

jednoczesnym badaniem odległości. Dzieki temu robot nie przejedzie obok markera, tylko wjedzie 

prosto na niego. 

 

#dojazd do wierzcholka m2 

komentarz 

let odl 0 

Deklaruję zmienną „odl”, jak wspomniałem jest to niezbędne.  

get 9 odl 

Wartość z portu 9 wpisuję do zmiennej odl. Port 9 podaje odległość 
robota od markera 2. Odległość ta jest liczbą całkowitą nieujemną. Jej 
mianem niech będą jednostki [j], trudno móić tu o metrach i tym 
podobnych. 

while odl :stoje_w_m2 

Początek pętli. Kończy się w linijce „:stoje_w_m2” w momencie, gdy 
nasz czujnik odległości wykryje wartość 0, czyli gdy robot będzie stał 
na/przed markerem m2. 

set 1 45 

Jazda do przodu, na obu kołach wartość 2. Niezalecane jest 
poruszanie się szybsze niż 2, w takim wypadku robot mógłby pominąć 
jakieś wskazanie czujnika kąta i za mocno się w jednej chwili obrócić. 
Niby nic poważnego, ale słyszałem o problemach mogących z tego 
wyniknąć. 

get 9 odl 
get 6 kat 

Robot przed chwilą pojechał nieco do przodu, należy więc pobrać 
aktualne wartości odległości i kąta względem markera 2, by za chwilę 
móc dokonać ewentualnych korekcji lub skończyć program w razie 
dojechania do celu. 

write "Do markera nr 2 pozostalo: " 
write odl 
write "jednostek." 
newl 

Wyświetla pozostałą drogę. 

 

Przerwa dla czytelności ☺ 

goifzero :jade_prosto kat 

Poniższe 3 linijki napisane zostały po to, aby ocenić czy robot nie 
odchylił się za bardzo od markera. Są miejscem decyzji co robić w 
przypadku braku odchylenia, odchylenia w lewo lub odchylenia w 
prawo. 
Ta linia (goifzero :jade_prosto kat) wysyła nas na koniec głównej pętli 
jeśli robot nie odchylił się od zadanego położenia a jazda przebiega 
poprawnie (kat=0). 

goifminus :lewo kat - 6 

Jeśli program wszedł do tej instrukcji to oznacza, że robot odczytał 
niewłaściwy kąt na marker 2.  
W tym przypadku instrukcja wyłapuje kąty w zakresie <1, 5>. 
Pojawienie się takich kątów oznacza, że robot patrzy się nieco w 
prawo od markera, musi więc wejść w pętlę, która pozwoli mu 
obrócić się w lewo aż do skorygowania kąta. 

goifplus :prawo kat  

Wysyła program do pętli korygującej robota w prawo. Po przejściu 
przez dwie poprzednie instrukcje możliwe kąty to 119 i ewentualnie 
od niego troszkę mniejsze. Na pewno są dodatnie, więc instrukcja 
zadziała. Mimo to wystarczyłaby instrukcja goto :prawo, która 
bezwzględnie wysłałaby program w żądane miejsce.  

 

Przerwa dla czytelności ☺ 

#korekcja w prawo 

komentarz 

:prawo 

Początek korekcji w prawo. W ninejszym przykładzie można 
wykasować tą linię i cały warunek „goifplus :prawo kat” bez szkody 
dla poprawności działania. Instrukcje pozostawiam w razie, gdyby 
potrzeba było dopisać jakieś instrukcje pomiędzy goifplus i :prawo ( 
daje to możliwość ominięcia tych instrukcji). 

while kat :obrprawo 

Poczatek pętli  

set 1 34 

Skręt w prawo wokół własnej osi 

get 6 kat 

Pobranie aktualnego kąta po minimalnym obrocie 

background image

write " Korekcja w prawo, kat na M2: " 
write kat 
newl 

Wyświetla na ekranie podstawowe info 

:obrprawo 

Koniec pętli 

 

Przerwa dla czytelności ☺ 

goto :2 

Bezwarunkowo skacze do instrukcji „:2” Zastosowane, by ominąć 
korekcję w lewo po zakończeniu korekcji w prawo. 

#korekcja w lewo 

komentarz 

:lewo 

Początek korekcji w lewo 

while kat :obrlewo 

Początek pętli 

set 1 20 

Obrót w lewo 

get 6 kat 

Pobranie aktualnego kąta 

write " Korekcja w lewo, kat na M2: " 
write kat 
newl 

Wyświetlanie przydatnych info 

:obrlewo 

Koniec pętli 

 

Przerwa dla czytelności ☺ 

:jade_prosto 

Punkt po ominięciu obu korekcji 

:2 

Punkt po ominięciu jednej z korekcji 

 

Przerwa dla czytelności ☺ 

set 1 36 

Jazda prosto 

:stoje_w_m2  

Koniec głównej pętli 

 

Przerwa dla czytelności ☺ 

#zatrzymanie 

komentarz 

set 1 27 

Zatrzymanie robota 

#stoimy w M2 

komentarz 

 

 

d)

 

W tym przykładzie chcę pokazać prosty sposó rozwiązania pewnego problemu. Problem jest 

następujący: w linijce zaczynającej pętlę while nie możemy umieścić operacji arytmetycznej. 

Akceptowalna jest jedynie zmienna.  

 

Zapis nieprawidłowy: 

While b – 10 :koniec 

:koniec 

 

Zapis prawidłowy: 

Let c b -10 

While c :koniec 

:koniec 

 

Aby pokazać wykorzystanie powyższego w praktyce, zamieszczam przykład zadania polegającego na 

obrocie robota jak w a) z tą róznicą, że pętlę while uzależniamy od różnicy kątów (a nie od wartości 

pojedynczego kąta). 

 

let kat_aktualny 0 

Deklaracja zmiennej 

get 4 kat_aktualny 

Z portu 4 pobieram wartość kąta będącego odchyleniem osi robota 
od osi X planszy, wartość tą zapisuję jako kat_aktualny. 

let mleko 0 

Deklaracja zmiennej 

let mleko kat_staly – kat_aktualny 

Zmienna „mleko” posłuży nam jako zastąpienie operacji 
arytmetycznej tak, aby kompilator się nie czepiał.  
„kat_aktualny” został wyjaśniony wyżej.  
„kat_staly” to zmienna, którą na przykład pobraliśmy z portu 4  

background image

wcześniej w programie, gdy robot był obrócony o inny kąt 
względem osi X (nie ujęte w przykładzie). Teraz chcemy robota 
obrócić z powrotem na ten kąt określony nie przez marker, a przez 
oś X. Z tego powodu badamy różnicę między tymi kątami i kończymy 
pętlę, gdy wyniesie ona zero. 

 

 

while mleko :czekolada 

Początek pętli 

set 1 34 

Obrót (kierunek dowolny, tutaj: w prawo) 

get 4 kat_aktualny 

Tak jak we wsześniejszych przykładach, pobieram aktualny kąt 
zmieniony nieco po niedawnym obrocie w prawo. 

let mleko kat_staly – kat_aktualny 

W środku pętli musimy zaktualizować zmienną mleko. Zmiana 
aktualnego kąta nie aktualizuje nam automatycznie zmiennej 
„mleko”, która warunkuje nam wykonywanie pętli. 

write "Kat: " 
write mleko 
newl 

Wyświetlanie info. 

:czekolada 

Koniec pętli 

 

 

#zatrzymanie 

 

set 1 27 

Zatrzymanie silników 

 

 

 

3.

 

Powyżej omówione programy zamieszczam ponownie bez tabelki i moich komentarzy: 

 

a) 
 

 

c) 
 

let kat 0 
get 6 kat 
while kat :m2 
set 1 34 
get 6 kat 
write "Kat na M2 to: " 
write kat 
write „stopni kosiarkowych.” 
newl 
:m2 
set 1 27 
stop 

  

#dojazd do wierzcholka m2 
let odl 0 
get 9 odl 
while odl :stoje_w_m2 
set 1 45 
get 9 odl 
get 6 kat 
write "Do markera nr 2 pozostalo: " 
write odl 
write "jednostek." 
newl 
goifzero :jade_prosto kat 
goifminus :lewo kat - 6 
goifplus :prawo kat  
#korekcja w prawo 
:prawo 
while kat :obrprawo 
set 1 34 
get 6 kat 
write " Korekcja w prawo, kat na M2: " 
write kat 
newl 
:obrprawo 
goto :2 
#korekcja w lewo 
:lewo 
while kat :obrlewo 
set 1 20 

background image

get 6 kat 
write " Korekcja w lewo, kat na M2: " 
write kat 
newl 
:obrlewo 
:jade_prosto 
:2 
set 1 36 
:stoje_w_m2  
#zatrzymanie 
set 1 27 
#stoimy w M2 
stop 

 

d) 

 
let kat_aktualny 0 
get 4 kat_aktualny 
let mleko 0 
let mleko kat_staly – kat_aktualny 
while mleko :czekolada 
set 1 34 
get 4 kat_aktualny 
let mleko kat_staly – kat_aktualny 
write "Kat: " 
write mleko 
newl 
:czekolada 
#zatrzymanie 
set 1 27 

 

 

 

4.

 

Zakończenie 

 

Za literówki i ewentualne nieścisłości przepraszam. Poradnik modyfikujcie i rozprzestrzeniajcie wedle uznania. 

W razie chęci kontaktu ze mną – autorem, proszę wysyłać email’e na adres: 

aningan@poczta.onet.pl

 (doceniam 

sugestie i komentarze!) 

 

Aningan, listopad 2012r.