Styr servon med PWM Shield

PWM-shielden som finns för Arduino är ett praktiskt sätt att utöka antalet PWM-utgångar och för att styra många lysdioder, servon etc. samtidigt, och utan att ta upp anslutningar på Arduino-kortet. Shielden använder kretsen PCA9685 och detta kodexempel fungerar därför även för lösa moduler som använder samma chip. PCA9685 använder protokollet I²C för att kommunicera med Arduino-kortet och det behövs därmed bara två ledningar, förutom ström, mellan kretsen och Arduino-kortet.

Kobiblioteket

Det finns flera bibliotek tillgänliga som gör det lättare att arbeta med PWM-shielden. Det bibliotek vi använder i den här guiden heter Adafruit-PWM-Servo-Driver-Library. Installera det genom att leta upp det i bibliotekshanteraren i Arduino IDE och klicka install-knappen.

Beskrivning av koden

Inkludera kobiblioteket

Först måste vi tala om att vi vill använda kodbiblioteket som vi installerade tidigare. Det gör vi med #include.

#include <Adafruit_PWMServoDriver.h>

Konstanta värden

Servon styrs inte av en standard PWM-signal som gåt mellan 0 och 100 %, utan behöver pulser av en specifik tidslängd, 50 till 100 gånger i sekunden. Eftersom biblioteket och kretsen vi använder är gjorda för vanlig PWM behöver vi beräkna och ställa in PWM-inställingarna själva så att vi får rätt pulslängd. För att vi ska kunna justera dessa på ett lätt sätt så skapar vi några konstanta värden överst i vår kod där vi lätt kan hitta och ändra dem om vi skulle behöva det. De värden vi behöver är antal pulser per sekund samt kortaste och längst längden på pulserna. Pulslängden kan variera från olika servo-modeller, som om dina servo inte rör sig ut till ändlägena, eller verkar röra sig för mycket så kan du behöver justera dessa värden.


#define PWM_FREQUENCY 50
#define MIN_SERVO_PULSE_LENGTH 600
#define MAX_SERVO_PULSE_LENGTH 2400

Variabel för PWM-kretsen

För att använda biblioteket måste vi skapa en variabel (ett s.k. objekt) som representerar vår krets. Om du kopplat in flera shields eller moduler så behöver du skapa en variabel för varje. Parametern 0x40 är adressen för kortet och 0x40 är grundadressen. Om du ändrat adressen på shielden/modulen behöver du använda den adress som du ändrat till.

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

Funktion för att röra på servo

Om du använt servo kopplade direkt till ett Arduino-kort så vet du att det är väldigt lätt att ändra på servots position. Det behövs bara en enda kodrad. För PCA9685 är det inte lika lätt. Vi behöver själva räkna ut värden. Det första vi gör är att kontrollera att vinkeln vi fick som parameter verkligen ligger mellan 0 och 180 grader. Detta gör vi med funktionen constrain. Sen räknar vi ut hur lång hela PWM-cykeln är i microsekunder. Därefter använder vi funktionen map() för att räkna om vinkeln till puls-längd i microsekunder. Vi använder värdena för minsta och längsta pulsbredd som vi definierade först i vår kod för detta. Vi använder även map()-funktionen för att räkna om pulslängden till en position i PWM-cykeln. PCA9685-kretsen använder 12 bitar för att generera PWM-signaler och den interna räknaren som används går därför från 0 till 4095. Det sista vi gör är att ställa in den valda pinnen (utgången) till detta värde.

PWM-kretsen räknar hela tiden från 0 upp till 4095. I vår kod säger vi till den att slå på utgången när den börjar om på noll. Kretsen kommer sedan räkna upp och när den når det värde som vi räknade ut så kommer den att stänga av utgången. Sen fortsätter den räkna tills den når 4095, och där börjar den om från noll igen. Detta gör den om och om igen. Hastigheten ställer vi in i setup() nedan och i vår kod använder vi 50 Hz, dvs kretsen räknar från 0 till 4095 femtio gånger i sekunden.

void setServo(uint8_t pin, int angle) {
  angle = constrain(angle, 0, 180);
  float cycle_length = 1000000.0 / PWM_FREQUENCY;
  long pulse_length = map(angle, 0, 180, MIN_SERVO_PULSE_LENGTH, MIN_SERVO_PULSE_LENGTH + MAX_SERVO_PULSE_LENGTH);
  long pulse_pos = map(pulse_length, 0, cycle_length, 0, 4095);
  pwm.setPWM(pin, 0, pulse_pos);
}

Setup()

Setup() körs ju först när Arduino-kortet startar eller nollställs. Det enda vi gör här är att aktivera PWM-shielden och ställa in uppdateringsfrekvensen, dvs hur många pulser per sekund som vi vill skicka ut. Vi använder det namngivna värdet PWM_FREQUENCY som vi skapade överst i koden.

void setup() {
  pwm.begin();
  pwm.setPWMFreq(PWM_FREQUENCY);
}

Loop()

Själva programmet ligger i loop(). Detta program är bara en demo för att visa hur det fungerar och som du kan använda som grund för dina egna program. Det enda programmet gör är att röra servot som är anslutet till utgång 0 på shielden, fram och tillbaka mellan mittenläget och ytterlägena. Vi gör det genom att använda funktionen setServo() som vi skapade tidigare i koden.

void loop() {
  setServo(0, 90);
  delay(2000);
  setServo(0, 0);
  delay(2000);
  setServo(0, 90);
  delay(2000);
  setServo(0, 180);
  delay(2000);
}

Hela koden

#include <Adafruit_PWMServoDriver.h>

#define PWM_FREQUENCY 50
#define MIN_SERVO_PULSE_LENGTH 600
#define MAX_SERVO_PULSE_LENGTH 2400

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

void setServo(uint8_t pin, int angle) {
  angle = constrain(angle, 0, 180);
  float cycle_length = 1000000.0 / PWM_FREQUENCY;
  long pulse_length = map(angle, 0, 180, MIN_SERVO_PULSE_LENGTH, MIN_SERVO_PULSE_LENGTH + MAX_SERVO_PULSE_LENGTH);
  long pulse_pos = map(pulse_length, 0, cycle_length, 0, 4095);
  pwm.setPWM(pin, 0, pulse_pos);
}


void setup() {
  pwm.begin();
  pwm.setPWMFreq(PWM_FREQUENCY);
}

void loop() {
  setServo(0, 90);
  delay(2000);
  setServo(0, 0);
  delay(2000);
  setServo(0, 90);
  delay(2000);
  setServo(0, 180);
  delay(2000);
}

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *