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

Druge sabirnice i periferija - PWM

Zadatak

Upravljati motorom PWM (širina pulsa) bibliotekom.

Priprema

Za vježbu je potrebno:

Spajanje pločica

×
PWM (pulse width modulation - upravljanje širinom impulsa) je vrlo raširen način kontrole elektromotora. Implementiran je punim H mostom.

Na slici je primjer spoja kontrolera za 4 motora (mrm-mot4x3.6) s ESP32 pločicom, koja je sastavni dio svih robota u ovim vježbama.

Veze ostvarimo standardnim Dupont 0.1" (2.54 mm) žicama i konektorima.

Konstante

      
#define GPIO_A1 25
#define GPIO_A2 33
#define GPIO_B1 32
#define GPIO_B2 26
#define GPIO_C1 12
#define GPIO_C2 14
#define GPIO_D1 27
#define GPIO_D2 13

#define FREQUENCY_HZ 500

#define RESOLUTION_BITS 7 // 1 - 16
#define MAXIMUM_DUTY_CYCLE ((1 << RESOLUTION_BITS) - 1)
...
Ovaj put nećemo koristiti programsku infrastrukturu kao dosad, nego ćemo program napisati na standardan Arduino način, u .ino datoteci, u kojoj su "setup()" i "loop()" funkcije.

Kreirajmo u Arduino IDE .ino datoteku proizvoljnog naziva, npr. "Test.ino" i upisujmo u nju kod s lijeve strane.

Proučimo kod.

Prvo definirajmo neke konstante.

"GPIO_XX" je niz konstanti koje daju razumljivije nazive brojevima pinova na pločici. Tako je npr. "GPIO_A1" prvi pin prvog kontrolera motora, koji je zapravo pin broj 25. "GPIO_A2" je drugi pin istog kontrolera. Ukupno su označena 4 kontrolera, slovima od A do D.

"FREQUENCY_HZ" je frekvencija signala.

"RESOLUTION_BITS" je broj bitova koji određuju kako fino možemo upravljati impulsom. Moguće su vrijednosti od 1 do 16. Mi smo izabrali 7, što daje 27 = 128 raznih vrijednosti.

"MAXIMUM_DUTY_CYCLE" je vrijednost binarnog broja sastavljenog od 6 jedinica, znači 127.

Polje

#define GPIO_A1 25
#define GPIO_A2 33
#define GPIO_B1 32
#define GPIO_B2 26
#define GPIO_C1 12
#define GPIO_C2 14
#define GPIO_D1 27
#define GPIO_D2 13

#define FREQUENCY_HZ 500

#define RESOLUTION_BITS 7 // 1 - 16
#define MAXIMUM_DUTY_CYCLE ((1 << RESOLUTION_BITS) - 1)

uint8_t pins[][2] = {{GPIO_A1, GPIO_A2}, {GPIO_B1, GPIO_B2}, {GPIO_C1, GPIO_C2}, {GPIO_D1, GPIO_D2}};
...
"pins" je dvodimenzionalno polje u kojem su poredani parovi pinova za sva 4 motora.

Koristimo ga za lakši test motora, unutar "for" petlje.

setSpeed()

#define GPIO_A1 25
#define GPIO_A2 33
#define GPIO_B1 32
#define GPIO_B2 26
#define GPIO_C1 12
#define GPIO_C2 14
#define GPIO_D1 27
#define GPIO_D2 13

#define FREQUENCY_HZ 500

#define RESOLUTION_BITS 7 // 1 - 16
#define MAXIMUM_DUTY_CYCLE ((1 << RESOLUTION_BITS) - 1)

uint8_t pins[][2] = {{GPIO_A1, GPIO_A2}, {GPIO_B1, GPIO_B2}, {GPIO_C1, GPIO_C2}, {GPIO_D1, GPIO_D2}};

void setSpeed(uint8_t motor, int8_t speed){
    ledcWrite(2 * motor, speed > 0 ? speed : 0);
    ledcWrite(2 * motor + 1, speed < 0 ? -speed : 0);
}

...
"setSpeed()" je pomoćna funkcija, koja je srce upravljanja motorom PWMom.

"ledcWrite()" je ESP32 funkcija koja daje PWM signal na izabrani pin.

Ova je ESP32 biblioteka namijenjena za upravljanje LEDom, ali jednako dobro može poslužiti za upravljanje motorom jer je signal identičan.

Prvi argument je broj pina, koji se izračuna iz broja motora (koji ide od 0 do 3).

Drugi je argument brzina. Svaki motor ima par pinova. Uvijek ide PWM impuls na jedan od njih, ovisno u koju stranu želimo okretati motor. O ovome se brine implicitni "if" u 2. argumentu.

setup()

#define GPIO_A1 25
#define GPIO_A2 33
#define GPIO_B1 32
#define GPIO_B2 26
#define GPIO_C1 12
#define GPIO_C2 14
#define GPIO_D1 27
#define GPIO_D2 13

#define FREQUENCY_HZ 500

#define RESOLUTION_BITS 7 // 1 - 16
#define MAXIMUM_DUTY_CYCLE ((1 << RESOLUTION_BITS) - 1)

uint8_t pins[][2] = {{GPIO_A1, GPIO_A2}, {GPIO_B1, GPIO_B2}, {GPIO_C1, GPIO_C2}, {GPIO_D1, GPIO_D2}};

void setSpeed(uint8_t motor, int8_t speed){
    ledcWrite(2 * motor, speed > 0 ? speed : 0);
    ledcWrite(2 * motor + 1, speed < 0 ? -speed : 0);
}

void setup() {
  for (uint8_t motor = 0; motor < 4; motor++){
    ledcSetup(2 * motor, FREQUENCY_HZ, RESOLUTION_BITS);
    ledcSetup(2 * motor + 1, FREQUENCY_HZ, RESOLUTION_BITS);
    ledcAttachPin(pins[motor][0], 2 * motor);
    ledcAttachPin(pins[motor][1], 2 * motor + 1);
  }
}

...
"setup()" se pokrene jednom, na početku izvšravanja Arduino programa.

U našem se slučaju, za svaki motor, postavi frekvencija i rezolucija PWM signala na njegov par pinova ("ledcSetup()").

Isto tako se pridruže fizički pinovi ("ledcAttachPin()").

loop()

#define GPIO_A1 25
#define GPIO_A2 33
#define GPIO_B1 32
#define GPIO_B2 26
#define GPIO_C1 12
#define GPIO_C2 14
#define GPIO_D1 27
#define GPIO_D2 13

#define FREQUENCY_HZ 500

#define RESOLUTION_BITS 7 // 1 - 16
#define MAXIMUM_DUTY_CYCLE ((1 << RESOLUTION_BITS) - 1)

uint8_t pins[][2] = {{GPIO_A1, GPIO_A2}, {GPIO_B1, GPIO_B2}, {GPIO_C1, GPIO_C2}, {GPIO_D1, GPIO_D2}};

void setSpeed(uint8_t motor, int8_t speed){
    ledcWrite(2 * motor, speed > 0 ? speed : 0);
    ledcWrite(2 * motor + 1, speed < 0 ? -speed : 0);
}

void setup() {
  for (uint8_t motor = 0; motor < 4; motor++){
    ledcSetup(2 * motor, FREQUENCY_HZ, RESOLUTION_BITS);
    ledcSetup(2 * motor + 1, FREQUENCY_HZ, RESOLUTION_BITS);
    ledcAttachPin(pins[motor][0], 2 * motor);
    ledcAttachPin(pins[motor][1], 2 * motor + 1);
  }
}

void loop() {
  for (uint16_t motor = 0; motor < 4; motor++){    
    int8_t step = 1;
    for (int8_t speed = 1; !(speed == 0 && step == 1); speed += step){
      setSpeed(motor, speed);
      delay(30);
      if (abs(speed) == MAXIMUM_DUTY_CYCLE)
        step = -step;
    }
  }
}
Na kraju, u funkciji "loop()" mijenjamo kontinuirano brzinu svakog od 4 motora.

Brzine će biti u intervalu od -127 do 127.

Primjedbe