RCK Ruđera Boškovića - mobilna / uslužna robotika

Vježbe - Objektno programiranje

Zadatak

Upoznati se s konceptom objektnog programiranja na primjeru korištenih robota.

Priprema

Za vježbu nisu potrebni roboti.

Klase robota

Program je objektno orijentiran.

Za početak to znači da su razni subjekti organizirani u klase.

Počnimo sa životinjskim primjerom. Mogli bismo pisati kod koji opisuje psa, ne ulazeći sad u problematiku zašto. Kod bi mogao u sebi imati opisne elemente (osobine, atribute) psa (masa, boja, spol) i akcije (hoda, reži, laje). Jedno je od bitnih obilježja objektno orijentiranog koda da se i jedna i druga vrsta nalaze unutar opisa klase. Znači, ako želimo bilo što od tog koda, on je na jednom mjestu. Ovu klasu nazovemo "Pas".

Na sličan način možemo imati kod za mačku. Klasu nazovemo "Mačka".

Sljedeći korak je generalizacija: i mačka i pas su sisavci. Prateći dalje objektni dizajn, možemo uvesti klasu "Sisavac". Obrnuto, možemo reći da su mačka i pas specijalni primjeri sisavaca. U objektnom rječniku kažem da je Sisavac nadklasa od Pas i Mačka. S druge strane Pas i Mačka su izvedene klase od Sisavac.

Pogledajmo jednu od radnji. Npr. hoda. I mačka i pas mogu hodati. Na stranu što možda svi sisavci ne mogu hodati, naša 2 mogu. Tako da možemo akciju "hoda" staviti u nadklasu Sisavac. Anologno s osobinama, npr. masom.

S druge strane, ima radnji i osobina koje im nisu zajedničke, npr. reži. Ona ne može ići u nadklasu.

Klase

Pogledajmo sad primjer našeg koda. Imamo baznu klasu "Robot", iz koje su izvedene klase "RobotLine", "RobotMaze" i "RobotSoccer".

To znači da je npr. "RobotLine" vrsta "Robot" (ne dekliniramo jer se imena klasa ne mijenjaju).

Robot ima neke zajedničke osobine za sve:
  • name (osobina),
  • blink (radnja),
  • delayMs (radnja),
  • firmwarePrint (radnja),
  • goAhead() (radnja).
Posljednja je radnja posebno zanimljiva. Sve druge se izvršavaju jednako na svakom robotu i nema razlike je li robot RobotMaze ili RobotLine, npr.

goAhead() je za svaki robot drugačiji. Očito da se motori ne mogu pokretati na isti način na Soccer robotu kao na Maze robotu. Međutim, ime funkcije je isto.

Slijedi izuzetno bitan opis koncepta u objektnom programiranju pa ga dobro proučite, da uočite o čemu se radi.

Za svaki od robota definiramo njegovu funkciju koja pokreće robota naprijed i spremimo goAhead() u svaku od klasa.

Ista funkcija se pojavljuje i u baznoj klasi, Robot, ali tamo neće biti definirana.

Mi sad možemo razvijati kod koji je baziran na klasi robot. Kad želimo da robot ide naprijed, u kodu pozovemo goAhead(). U tom času, razvoja općenitog programa, mi ne znamo koji će to robot biti. To je bit. Mi razvijamo općeniti program za bilo kojeg robota. Kod više ne ovisi o svakom pojedinom robotu i svaki od njih može imati potpuno nezavisan razvoj, sve dok postoji definicija funkcije goAhead().

Nakon toga možemo imati posebnog programera za klasu Robot, posebnog za RobotLine, itd. Njihovi su razvoji nezavisni, svatko ispravlja svoje greške i radi nezavisno od drugih. To je jedan odličan način podjele rada i radikalno olakšava pronalaženje problema.

Implementacija u baznoj klasi

	...
	/** Orders the robot to go ahead
	*/
	virtual void goAhead() = 0;
	...
Proučimo sad kako je konkretno izvedena ova funkcija u kodu. U "mrm-robot.h" postoji lijevi dio koda, koji deklarira funkciju. Konkretni kod označava da je ova (virtualna) funkcija samo deklarirana u baznoj klasi, ali da tu neće biti nikakvog koda, nego da će konkretna implementacija morati biti u svim izvedenim klasama.

Implementacija u 1. izvedenoj klasi

/** Test - go straight ahead using a defined speed.
*/
void RobotLine::goAhead() {
	const uint8_t speed = 40;
	go(speed, speed);
	end(); // This command will cancel actions and the robot will return in the default idle loop, after displaying menu.
}
U drugoj datoteci, "mrm-robot-line.cpp", u kojoj je provedena implementacija funkcija, nalazi se kod koji konkretno pokreće robota Line.

Implementacija u 2. izvedenoj klasi

/** Test - go straight ahead.
*/
void RobotSoccer::goAhead() {
	const uint8_t speed = 60;
	motorGroup->go(speed);
	end();
}
U trećoj datoteci, "mrm-robot-soccer.cpp", je funkcija istog imena, ali ovaj put s drugačijim kodom, jer se nogometaš pokreće drugačije.

Na isti način, u ".cpp" datotekama ostalih robota, treba definirati što ta funkcija radi za svakog od njih.

Poziv funkcije

...
Robot robot = new RobotSoccer();
robot->goAhead();
...
U ovom primjeru biramo da je robot robot za nogomet i pokrenemo ga.
...
Robot robot = new RobotLine();
robot->goAhead();
...
Uočite da je jedina razlika u cijelom kodu (naravno da je u praksi puno veći) taj da smo u varijablu robot spremili drugi tip robota i cijeli će ostatak koda funkcionirati.

Klase pločica

×
Pločice, uglavnom fizički odvojeni, gradivi elementi robota su isto organizirane u klase.

Bazna klasa je "Board".

Dijeli se u 2 izvedene klase "MotorBoard" i "SensorBoard".

Nakon toga na niz podklasa koje predstavljaju pojedine pločice, dio kojih je naveden u dijagramu.

Zadatak: naći virtualnu funkciju

Nađite jednu virtualnu funkciju u klasi Board. Npr. neka to bude funkcija za izmjenu CAN Bus poruka.

Funkcije su deklarirane u datoteci "mrm-board.h".

Pogledajte kako je implementirana u pojednim pločicama.

Zadatak: naći implementaciju u izvedenoj klasi

Sad nađite implementaciju u izvedenoj klasi.

Pogledajte dijagram klasa. Implementacija može biti u međuklasi, npr. MotorBodard, ili u krajnjoj izvedenoj klasi, npr. Mrm_mot4x3_6_can".

Zadatak: naći zajednički dio implementacije

Uočite da gornji kod poziva funkciju "messageDecodeCommon()".

Ova funkcija je zajednička za sve pločice. Nađite i njenu implementaciju.

Opisan je način kako koristiti zajedničku funkcionalnost za sve klase, s varijacijama za pojedinu izvedenu klasu.

Primjedbe