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

Biblioteke - Motori

Zadatak

Proučiti izradu biblioteke za kontrolu motora.

Priprema

Za vježbu je potrebno:

Datoteke

U ovom prikazu ćemo se koristiti datotekama "mrm-board.h" i "mrm-board.cpp", koje se nalaze u biblioteci "mrm-board".

Biblioteku možemo uređivati iz Arduino IDE-a, na način koji je opisan u prethodnim vježbama.

Klase

/** Board is a class of all the boards of the same type, not a single board!
*/
class Board{
protected:
	uint32_t _alive; // Responded to ping, maximum 32 devices of the same class, stored bitwise. If bit set, that device was alive after power-on.
	bool _aliveReport = false;
	char _boardsName[12];
	BoardType _boardType; // To differentiate derived boards
	...
};

....

class MotorBoard : public Board {
protected:
	std::vector<uint32_t>* encoderCount; // Encoder count
	std::vector<bool>* reversed; // Change rotation
	std::vector<int8_t>* lastSpeed;
	...
};

....

class SensorBoard : public Board {
private:
	uint8_t _readingsCount; // Number of measurements, like 9 in a reflectance sensors with 9 transistors

protected:

	/** Standard deviation
	@param sampleCount - count.
	@param sample - values.
	@param averageValue - output parameter.
	@return - standard deviation.*/
	float stardardDeviation(uint8_t sampleCount, uint16_t sample[], float * averageValue);
	...
};
Bavit ćemo se klasama:
  • Board,
  • SensorBoard i
  • MotorBoard.
Lijevo su početni dijelovi deklaracije svake od njih.

Vidljivo je da je "Board" bazna klasa, iz koje su izvedene druge dvije.

Sve će ostale klase za senzore i efektore (motore) biti izvedene iz te 2, "MotorBoard" i "SensorBoard".

Cilj nam je napraviti funkciju za pokretanje motora određenom brzinom. Kako je ta brzina osobina svih motora, prirodno je programirati funkciju u klasi "MotorBoard", a ne u svakoj od izvedenih klasa za pojedine vrste pločica za kontrolu motora.

Deklaracija speedSet()

class MotorBoard : public Board {
	...
public:
	...
	/** Motor speed
	@param motorNumber - motor's number
	@param speed - in range -127 to 127
	*/
	void speedSet(uint8_t motorNumber, int8_t speed);
	...
};
Budući da je funkcija u klasi "MotorBoard", njena deklaracija mora biti u toj klasi.

I, stvarno, možemo ju naći tamo.

Zove se "speedSet()".

Dio od interesa je prikazan lijevo.

Želimo li napraviti neku drugu funkciju za sve motore, upisat ćemo potpis funkcije na isto mjesto.

Komentari opisuju ulazne parametre.

Broj motora je tu jer motora može biti više. Prvi je 0, drugi 1, itd.

Definicija speedSet() - 1

/** Motor speed
@param motorNumber - motor's number
@param speed - in range -127 to 127
*/
void MotorBoard::speedSet(uint8_t motorNumber, int8_t speed) {
	if (motorNumber >= nextFree) {
		sprintf(errorMessage, "Mot. %i doesn't exist", motorNumber);
		return;
	}
	...
}

Definicija se nalazi u "mrm-board.cpp".

Funkcija počinje provjerom broja motora.

Ako je taj broj veći od najveće adrese motora u robotu, kopirat ćemo poruku greške u varijablu te namjene. Nakon toga ćemo izaći iz funkcije bez ikakve akcije.

Pokušaj pokretanja nepostojećeg motora ne bi učinio štetu jer jedinica s tom CAN Bus adresom ne postoji pa se ne bi dogodilo ništa, ali dobro je korisniku javiti da je izabrao krivi broj.

Definicija speedSet() - 2

/** Motor speed
@param motorNumber - motor's number
@param speed - in range -127 to 127
*/
void MotorBoard::speedSet(uint8_t motorNumber, int8_t speed) {
	if (motorNumber >= nextFree) {
		sprintf(errorMessage, "Mot. %i doesn't exist", motorNumber);
		return;
	}

	if ((*lastSpeed)[motorNumber] == speed)
		return;
	(*lastSpeed)[motorNumber] = speed;
	...
}

Uspoređujemo traženu brzinu s trenutnom brzinom motora.

Ako su one iste, ništa ne činimo i izlazimo iz funkcije.

Jasno da je to najbolje rješenje jer bismo inače mogli generirati puno CAN Bus poruka, koje bi mogle zagušiti sabirnicu, a bez efekta.

Ako je brzina promijenjena, spremimo traženu kao posljednju.

Definicija speedSet() - 3

/** Motor speed
@param motorNumber - motor's number
@param speed - in range -127 to 127
*/
void MotorBoard::speedSet(uint8_t motorNumber, int8_t speed) {
	if (motorNumber >= nextFree) {
		sprintf(errorMessage, "Mot. %i doesn't exist", motorNumber);
		return;
	}

	if ((*lastSpeed)[motorNumber] == speed)
		return;
	(*lastSpeed)[motorNumber] = speed;

	if ((*reversed)[motorNumber])
		speed = -speed;
	...
}

"reversed" struktura drži informaciju treba li motor pokrenuti u suprotnom smjeru.

Ako je ovaj motor "okrenut", promijenimo predznak brzini, mijenjajući na taj način smjer rotacije u suprotan.

Definicija speedSet() - 4

/** Motor speed
@param motorNumber - motor's number
@param speed - in range -127 to 127
*/
void MotorBoard::speedSet(uint8_t motorNumber, int8_t speed) {
	if (motorNumber >= nextFree) {
		sprintf(errorMessage, "Mot. %i doesn't exist", motorNumber);
		return;
	}

	if ((*lastSpeed)[motorNumber] == speed)
		return;
	(*lastSpeed)[motorNumber] = speed;

	if ((*reversed)[motorNumber])
		speed = -speed;

	canData[0] = COMMAND_SPEED_SET;
	canData[1] = speed + 128;
	messageSend(canData, 2, motorNumber);
}

Na kraju pripremamo i šaljemo CAN Bus poruku po sabirnici.

"canData" je polje u koje upisujemo bajtove poruke.

Prvi je bajt "COMMAND_SPEED_SET", konstanta s vrijednošću koja definira poruku kao poruku za promjenu brzinu.

Drugi je bajt brzina. Dodaje se 128 da se dobije pozitivan broj. Kontroler motora će oduzeti 128.

Zadnja naredba šalje poruku. "2" znači da se šalju 2 bajta.

Želimo li napraviti svoju funkciju za kontrolu motora, načinimo funkciju na isti način.

Ostale funkcije

class MotorBoard : public Board {
protected:
...

	/** If sensor not started, start it and wait for 1. message
	@param deviceNumber - Device's ordinal number. Each call of function add() assigns a increasing number to the device, starting with 0.
	@return - started or not
	*/
	bool started(uint8_t deviceNumber);
public:

	...

	/** Changes rotation's direction
	@param deviceNumber - Devices's ordinal number. Each call of function add() assigns a increasing number to the device, starting with 0.
	*/
	void directionChange(uint8_t deviceNumber);

	/** Read CAN Bus message into local variables
	@param canId - CAN Bus id
	@param data - 8 bytes from CAN Bus message.
	@param length - number of data bytes
	@return - true if canId for this class
	*/
	bool messageDecode(uint32_t canId, uint8_t data[8], uint8_t length);

	/** Encoder readings
	@param deviceNumber - Devices's ordinal number. Each call of function add() assigns a increasing number to the device, starting with 0.
	@return - encoder value
	*/
	uint16_t reading(uint8_t deviceNumber);

	/** Print all readings in a line
	*/
	void readingsPrint();

	/** Motor speed
	@param motorNumber - motor's number
	@param speed - in range -127 to 127
	*/
	void speedSet(uint8_t motorNumber, int8_t speed);

	/** Stop all motors
	*/
	void stop();

	/**Test
	@param deviceNumber - Device's ordinal number. Each call of function add() assigns a increasing number to the device, starting with 0. 0xFF - all devices.
	@param betweenTestsMs - time in ms between 2 tests. 0 - default.
	*/
	void test(uint8_t deviceNumber = 0xFF, uint16_t betweenTestsMs = 0);
};
Ostale funkcije biblioteke se nalaze u istoj datoteci, "mrm-board.h".

Osim funkcije "stop()", druge se rjeđe koriste u praksi.

Korisnik može mijenjati i dodavati funkcije iz postojeće klase "MotorBoard".

Također može napraviti i potpuno novu klasu. Najlakši je način kopirati postojeći kod za "MotorBoard", promijeniti ime klase i sve drugo što je potrebno.

Primjedbe