Hrvatsko društvo za robotiku - Uvod u robotiku - vježbe

LED 8x8 matrica

Cilj

Naučimo kako koristiti 8x8 LED displej.

Ispis teksta

void RobotLine::loop() {
	display("Hello, world!");
	end();
}
Prvo lakši zadatak: ispis teksta.

display je funkcija za ispis teksta na 8x8 LED displej.

Budući da je displej može ispisati tek jedno slovo, tekst će se pomicati, u 2 boje.

Ispis na ekran je koristan za poruke upozorenja ili druge poruke koje nam omogućavaju da lakše shvatimo u kojem je stanju robot ili da nađemo grešku u programu.

Video

Ispis "Hello world".

Prikaz slike

void RobotLine::loop() {
	uint8_t red[8];
	uint8_t green[8];
	
	for (uint8_t i = 0; i < 8; i++)
		red[i] = 0;
	
	green[0] = 0b11111111;
	green[1] = 0b10000001;
	green[2] = 0b10000001;
	green[3] = 0b10000001;
	green[4] = 0b10000001;
	green[5] = 0b10000001;
	green[6] = 0b10000001;
	green[7] = 0b11111111;

	store(red, green, 1);
	display(1);

	end();
}
Kad bi sve bilo tako jednostavno kao ispis teksta, ova bi se vježba našla na početku. Nažalost, nije. Ispis slike je znatno kompliciraniji.

Štoviše, jedna od najkompliciranijih operacija dosad jer će nas prisiliti na učenje više novosti nego u 5 prosječnih vježbi.

Lijevo je cijeli program. Zaronimo u detalje.

"uint8_t" je tip varijable - to je cjelobrojna varijabla koja se može sprema u 8 bitova.

Pretpostavit ćemo da znate što je "bit" jer se taj pojam danas dosta rano uči u školi. Najveći broj koji se može prikazati pomoću 8 bitova je 255. Znači, "uint8_t" označava cijele brojeve od 0 do 255. Nešto kao "int", ali ne može biti ni negativan, niti veći od 255.

Nadalje, [8] - uglate zagrade. Označavaju važan koncept "polja". Polje je niz vrijednosti. Kad bi pisalo:
uint8_t red;
, to bi značilo da se deklarira varijabla koja može spremiti jednu vrijednost.

Broj, koji slijedi u uglatim zagradama, označava koliko vrijednosti varijabla može spremiti odjednom. U našem slučaju, 8.

Zašto uopće uvoditi pojam polja? 8 se vrijednosti može spremiti u 8 običnih varijabli. Nepotrebna komplikacija? Objašnjenje slijedi uskoro.

"for" petlja

void RobotLine::loop() {
	...
	
	for (uint8_t i = 0; i < 8; i++)
		red[i] = 0;
	
	...
}
Proučimo sljedeće 2 linije. Kod je isti kao i gore, samo smo označili s "..." dijelove koji nam trenutno nisu u fokusu proučavanja.

"for" petlja je jedna od 2 petlje koje se koriste u C++. 2. je već korišteni "while".

Prisjetimo se, petlja se izvršava beskonačno, dok ne bude zadovoljen neki uvjet.

"for" se sastoji uvijek od 3 dijela. Pogledajmo naš primjer. Dijelovi su odvojeni znakom ";".
  • "uint8_t i = 0" - naredba koja se izvrši jednom, prije prvog prolaza kroz petlju. U našem slučaju, deklariramo varijablu "i" i spremimo u nju broj 0.
  • "i < 8" - srednji dio je logički izraz. Dok je "istina", petlja se izvršava. Čim postane "laž", petlja prekida izvršavanje. Petlja se vrti sve dok je "i" strogo manji od 8.
  • "i++" - naredba koja se izvrši nakon svakog ponavljanja petlje. U našem primjeru, poveća svaki put vrijednost "i" za 1.
Rezultat "for" petlje? "i" će poprimati vrijednosti od 0 do 7.
void RobotLine::loop() {
	uint8_t red0;
	uint8_t red1;
	uint8_t red2;
	uint8_t red3;
	uint8_t red4;
	uint8_t red5;
	uint8_t red6;
	uint8_t red7;
}
Sad dolazi trenutak spoznaje. Zamislite da imate 8 varijabli, npr. kao što je lijevo.

Zamislite dalje da je zadatak svima pridružiti vrijednost 0 u 2 programske linije. Nemoguće, zar ne? Trebate 8 linija.

Kad bi bilo 10000 varijabli (potpuno uobičajen primjer), kako biste pridružili 10000 vrijednosti?

U ovom času dolazi naš izbavitelj, "for" petlja.
void RobotLine::loop() {
	...
	
	for (uint8_t i = 0; i < 8; i++)
		red[i] = 0;
	
	...
}
Ponovljeni kod je lijevo. Ovaj put je akcent na 2. redu.

Isti par znakova kao i prije, uglate zagrade, ovaj put označava nešto drugo: da smo izabrali jednu, određenu vrijednost (od 8 mogućih). Tako je:
  • red[0] prva vrijednost,
  • red[1] druga vrijednost,
  • itd.
Rezultat? U svakom koraku petlje se spremi 0 u sljedeću vrijednost.

Kao što smo se hvalili, u 2 linije se spremi 8 vrijednosti.

Ovo je bio jednostavan primjer. Često se pojavljuju ponavljajući problemi, koji bi bilo teško ili zapravo nemoguće napisati bez polja.

Svih 8 vrijednosti varijable "red" je postalo 0 zato što nećemo ispisivati crvene točke.

void RobotLine::loop() {
	...
	
	green[0] = 0b11111111;
	green[1] = 0b10000001;
	green[2] = 0b10000001;
	green[3] = 0b10000001;
	green[4] = 0b10000001;
	green[5] = 0b10000001;
	green[6] = 0b10000001;
	green[7] = 0b11111111;

	...
}
Crvene točke nismo, ali zelene točke želimo ispisati.

Sljedeći, novi koncept je upis binarnog broja. Pretpostavit ćemo da ste u školi učili izgled broja u raznim bazama. Kad je baza 2, broj je binaran, i ima znamenke 0 i 1.

Kako izgleda 255 u bazi 10 (uobičajenih 255) prikazan kao binarni broj? Ovako:

255(10) = 11111111(2)

Dodajte "0b" na početak i dobili ste 1. liniju koda: 0b11111111. Znači, ako prije broja upišete "0b", upisujete binarni broj.

Prvu liniju ste komotno mogli upisati kao:

	green[0] = 255;
U većini slučajeva je glupo upisivati binarni broj, ali ovdje nije tako. Svaka jedinica u binarnom zapisu je upaljen crveni LED dane linije i kolone.

To znači da:
  • "green[0] = 0b11111111;" pali sve LE diode prvog rade.
  • "green[1] = 0b10000001;" pali prvu i zadnju LE diodu drugog reda.
  • ...
Sve zajedno - kvadrat.
void RobotLine::loop() {
	...

	store(red, green, 1);
	display(1);

	end();
}
Još malo.

store je funkcija koja sprema sliku u memoriju displeja. Ova memorija nije stalna i potrebno je spremanje svaki put kad se uključi robot.

1. i 2. argument funkcije su 2 polja, prvo za crvene, potom za zelene točke.

3. argument je redni broj slike. Počnite od 0 i spremajte redom slike, svaki put u sljedeći veći broj.

display ispisuje sliku, redni broj koje je u zagradama. Broj 1 smo spremili, 1 i ispisujemo.

Uobičajeno je na početku programa spremiti sve slike pa ih onda pozivati kad zatreba.

Ovaj je način brži od verzije u kojoj se ne bi ništa spremalo unaprijed, nego bi se svaki put slala cijela slika - ali i taj način je moguć. Nećemo ga opisivati ovdje.

Video

Ispis kvadrata.

Hm?

Čekajte! Nešto ne valja! Istu smo funkciju koristili 2 puta. Kako će robot znati koju smo željeli upotrijebiti kad je ime isto?

Srećom, može i ovako. Isto ime u C++-u se može koristiti za razne stvari. Štoviše, to je jako, jako dobro.

Ovo je jednostavniji od načina da se funkcija zove isto, a radi razne stvari, ali svejedno je dosta zgodan. Kako C++ zna koju funkciju želimo? Jedino što je ostalo je argument, koji je ujedno i rješenje zagonetke: C++ bira funkciju po tipu argumenta.

Ako je string, kao što je "Hello, world!", pozvat će funkciju koja je definirana za takav tip argumenta. U našem slučaju, ispisat će taj tekst.

Ako je vrijednost cijeli broj, ispisat će sliku čija je to adresa.

Zadatak: semafor.

Napravite semafor, koji će svake sekunde mijenjati svjetlo: crveno, narančasto i zeleno. Narančasta se dobije kad se upale zelena i crvena točka, premda razlika do crvene boje može biti vrlo slaba.

Primjedbe



Projekt "Uvod u robotiku" sufinanciran je iz Europskog socijalnog fonda, poziv "Jačanje kapaciteta organizacija civilnoga društva za popularizaciju STEM-a". Relevantne stranice: Sadržaj vježbe za virtualne radionice isključiva je odgovornost Hrvatskog društva za robotiku.