Difference between revisions of "Arduino - Een servo"

From SPAD-it Wiki
Jump to: navigation, search
(Beetje spelen)
 
(8 intermediate revisions by the same user not shown)
Line 8: Line 8:
 
|[[File:Servo.jpg]]
 
|[[File:Servo.jpg]]
 
|-
 
|-
|Een typische servo voor de modelbouw met drie aansluitdraden: zwart=0V, rood=5V, geel=input
+
|Een typische servo voor de modelbouw met drie aansluitdraden: zwart/bruin=0V, rood=5V, geel/oranje/wit=input
 
|}
 
|}
  
Line 34: Line 34:
  
 
<pre>
 
<pre>
int servoPin=11;
+
int servoPin=9;   // servo op pin digitale IO pin 9
int hoek_arm;
+
int potPin=0;     // potmeter op analoge pin A0
int PWM_signaal;
+
int cyclus=20000; // microsecondes van de hele PWM cyclus => 50Hz
int val;
+
int minPulse=50;   // microsecondes hoog voor minimale arm-stand
 +
int maxPulse=2500; // microsecondes hoog voor maximale arm-stand
  
void servoPulse(int servoPin, int hoek_arm)
+
void setServoPulse(float arm_stand)       // dient continu te worden aangeroepen
// define a servo pulse function
+
// arm-stand 0 => helemaal links
 +
// arm-stand 1 => helemaal rechts
 
{
 
{
   pulsewidth=(hoek_arm*11)+500; // convert angle to 500-2480 pulse width
+
   int pulseBreedte = (int)minPulse + arm_stand*(maxPulse-minPulse); // berekening duur pulse, als geheel getal
   digitalWrite(servoPin,HIGH);   // set the level of servo pin as “high”
+
   digitalWrite(servoPin,HIGH);           // signaal naar HIGH
   delayMicroseconds(pulsewidth); // delay microsecond of pulse width
+
   delayMicroseconds(pulseBreedte);       // wacht pulseWidth
   digitalWrite(servoPin,LOW);   // set the level of servo pin as “low”
+
   digitalWrite(servoPin,LOW);             // signaal naar LOW
   delay(20-pulsewidth/1000);
+
   delayMicroseconds(cyclus-pulseBreedte); // wacht de rest van de cyclus tijd
 
}
 
}
  
Line 52: Line 54:
 
{
 
{
 
   pinMode(servoPin,OUTPUT);
 
   pinMode(servoPin,OUTPUT);
  Serial.begin(9600);
 
  Serial.println("servo=o_seral_simple ready" ) ;
 
 
}
 
}
  
 
void loop()
 
void loop()
 
{
 
{
   val=Serial.read();// read serial port value
+
   float potVal=(float)analogRead(potPin)/1024; // stand van de pot, omgezet naar getal tussen 0 en 1
   if (val>='0'&&val<='9')
+
   for(int i=0;i<=10;i++)   // elke keer 10 cycli => duurt 0,2 seconde
 
   {
 
   {
     val=val-'0';     
+
     setServoPulse(potVal);                     // dient continu te worden aangeroepen
    val=val*(180/9);  
 
    Serial.print("moving servo to ");
 
    Serial.print(val,DEC);
 
    Serial.println();
 
    for(int i=0;i<=50;i++)
 
    {
 
      servopulse(servoPin,val);
 
    }
 
 
   }
 
   }
 
}
 
}
Line 75: Line 67:
  
 
===Uitleg===
 
===Uitleg===
 +
Allereerst wordt aangegeven aan welke digitale pin de servo hangt en aan welke analoge pin de potmeter van de joystick zit. Daarna worden de details van de servo-besturing opgegeven. Dit zijn de duur van de cyclus (20ms = 20000 microseconde), 50 microseconde voor de minimale puls en 2500 microseconde voor de maximale puls. De ''setup()'' is in dit geval buitegewoon simpel en stelt alleen de servo-pin in als output. Ook de ''loop()'' functie is vrij eenvoudig. Hij leest de analoge waarde van de potPin en zet dat getal meteen om in een floating point getal tussen 0 en 1. Daarna stuurt het die waarde 10 keer achter elkaar naar de functie ''setServoPulse()''. Dit duurt bij elkaar dus 10 cycli en dus 0,2 seconde. Het komt erop neer dat de analoge waarde 5 keer per seconde wordt gemeten, waarna de servo met de nieuwe waarde wordt aangestuurd.
  
 +
De functie ''setServoPulse()'' doet het echte werk. Maar ook deze functie is relatief eenvoudig. Hij berekent de pulsebreedte. Bij ''arm_stand=0'' moet daar ''minPulse'' uit komen en ''maxPulse'' bij ''arm_stand=1''. Dat doet de berekening op de eerste regel. Daarna wordt de uitgang op ''servoPin'' hoog gemaakt. Dan volgt een wachttijd van ''pulseBreedte'' (in microsecondes), wordt ''servoPin'' laag gemaakt en wacht de functie de resterende tijd van de cyclus. Elke aanroep van ''setServoPulse()'' voert dus precies een cyclus uit.
  
 
===Beetje spelen===
 
===Beetje spelen===
Verdiepende opdrachtjes
+
* Bij het testen van de servo zul je al snel zien dat de arm niet netjes in het midden staat als je de joystick los laat. Dat kan voor het besturen van bijvoorbeeld een auto een probleem zijn; je wilt toch dat die auto rechtuit rijdt als je de joystick los laat. Kun je het programma zo aanpassen dat je de afwijking met een instelbare waarde kunt corrigeren?
 +
 
 +
* De joystick heeft twee potmeters. Je kunt dus gemakkelijk een tweede servo aansturen met dezelfde joystick. Als je een tweede servo hebt kun je dat eens proberen. Let er dan met name op dat de aansturing van de beide servo's in een nette functie ''setServoPulses()'' wordt gestopt waardoor beide PWM signalen goed tot hun recht komen. Die functie krijgt dan dus twee input-waarden:
 +
<pre>
 +
void setServoPulses(float arm_stand1, float arm_stand2) {
 +
}
 +
</pre>
 +
 
 +
* Als je de schakeling aansluit en aan de servo voelt, voel je een soort van trilling waaruit blijkt dat de servo inderdaad continu bezig is met de positie. De motor is dus continu bezig en verbruikt dus ook continu energie. Motoren verbruiken relatief veel energie, en dus is dit gedrag niet al te gunstig als energieverbruik belangrijk is. Nu is het zo dat als het inputsignaal wegvalt (continu 0 - geen pulsen), dat (de meeste) servo's hun positie niet meer veranderen maar vasthouden. Vanwege de tandwielen in de servo, zal die stand ook met een redelijke kracht worden vastgehouden. Het kan dus geen kwaad om het signaal uit te zetten als de positie niet veranderd. Wel moet je er rekening mee houden dat er best een aantal pulsen nodig is om de servo in de juiste positie te krijgen. Deze opdracht bestaat daarom uit twee delen. Stel vast hoeveel pulsen er nodig zijn om de arm van de servo van de ene uiterste stand naar de andere uiterste stand te bewegen. Pas daarna het programma zo aan dat de servo alleen wordt aangestuurd als het signaal van de joystick voldoende veranderd.
 +
 
 +
Probeer vooral even zelf tot een oplossing te komen, maar [[Twee servo's met correctie|hier]] is een oplossing waarin alle drie de opdrachtjes zijn geimplementeerd.
  
 
===Navigatie===
 
===Navigatie===

Latest revision as of 13:24, 1 February 2018

Een servo is een mechanisch element dat een as heeft die in bepaalde mate kan draaien. Heel vaak wordt aan de as van de servo een arm bevestigd die met de as meebeweegt. Daarmee kun je bijvoorbeeld het roer van een modelschip besturen of het stuur van een modelauto. Naast toepassingen in de modelbouw hebben servo's talloze andere toepassingen, zoals de cruisecontrol van een auto en het hoogteroer van vliegtuigen. Van binnen heeft een servo een motor die via een aantal tandwielen de stand van de as bediend. Die tandwielen zorgen voor vertraging, maar vergroten de kracht van de servo. Daarnaast wordt de stand van de as gemeten, doorgaans met een potmeter, waarmee de stand van de arm wordt omgezet in een spanning. Door elektronische terugkoppeling wordt die spanning, en dus de positie van de arm, geregeld naar gelang het inputsignaal. Dit mechanisme brengt wel met zich mee dat dit soort servo's relatief veel stroom verbruiken. In feite hebben zowel het inputsignaal als de meting van de stand van de arm steeds kleine afwijkingen, waardoor de elektronica continu zal proberen om de positie te verbeteren. Het gevolg is dat de motor bijna continu wordt aangestuurd en de servo relatief veel stroom verbruikt. Toch moet dat stroomverbruik ook niet worden overdreven; kleine servo's kunnen nog altijd rechtstreeks op een Arduino worden aangesloten.

Uiteraard werken verschillende servo's op verschillende spanningen, maar servo's hebben ook andere belangrijke karakteristieken. Zo hebben ze een maximaal draaibereik en leveren ze een beperkte maximale kracht. Ook de snelheid waarmee ze van het ene uiterste naar het andere uiterste kunnen bewegen kan een belangrijk kenmerk zijn. Als je een servo aanschaft is het altijd verstandig om te onderzoeken of jouw servo voldoet voor jouw specifieke toepassing. Naast dit soort analoge servo's bestaan er tegenwoordig overigens ook digitale servo's. Die hebben uiteraard een andere interne werking en worden ook anders aangestuurd. Hier gaat het echter over analoge servo's.


Servo.jpg
Een typische servo voor de modelbouw met drie aansluitdraden: zwart/bruin=0V, rood=5V, geel/oranje/wit=input

Door een servo aan te sluiten op een Arduino kunnen we de servo met een programma netjes laten bewegen. We kunnen dan natuurlijk ook die servo besturen met een [[joystick die ook op de Arduino wordt aangesloten. We sluiten daarom tegelijk een joystick en een servo aan op de Arduino en maken een programma waarmee de servo met de joystick wordt bestuurd.

Input signaal

Het inputsignaal heeft typisch de vorm van een puls-breedte-modulatiesignaal. De stand van de arm correspondeert dan met de pulsbreedte. Helaas is het niet zo dat we daarmee de PWM mogelijkheden van Arduino kunnen gebruiken. Servo's gebruiken namelijk een basisfrequentie van 50Hz, terwijl de frequentie van het PWM signaal van Arduino veel hoger ligt (afhankelijk van de versie). Daar komt bij dat de minimale en maximale stand van de arm niet overeenkomen met een duty cycle van 0 en 100%, maar meer in de buurt komt van 2,5% tot 12,5%. De arm van de servo kan dus helemaal naar links worden gestuurd met een signaal dat afwisselend 0,5ms hoog en 19,5ms laag is. De arm staat helemaal naar rechts met een signaal dat afwisselend 2,5ms hoog en 17,5ms laag is. Merk op dat de cyclus steeds 20ms duurt. Dit komt neer op 50 cycli per seconde, ofwel 50Hz. Deze details kunnen per type servo overigens wat afwijken.

Ondanks dat we niet direct PWM kunnen gebruiken, kunnen we een servo toch direct aansluiten op een digitale poort van Arduino en een programma maken dat de servo netjes laat bewegen. We moeten de pulse-breedte modulatie dan zelf programmeren.

De schakeling

Extra benodigdheden:

  • 1 5V servo
  • 8 joystick module
Servo schakeling.png
Schakeling met servo en joystick

Het programma

int servoPin=9;    // servo op pin digitale IO pin 9
int potPin=0;      // potmeter op analoge pin A0
int cyclus=20000;  // microsecondes van de hele PWM cyclus => 50Hz
int minPulse=50;   // microsecondes hoog voor minimale arm-stand
int maxPulse=2500; // microsecondes hoog voor maximale arm-stand

void setServoPulse(float arm_stand)       // dient continu te worden aangeroepen
// arm-stand 0 => helemaal links
// arm-stand 1 => helemaal rechts
{
  int pulseBreedte = (int)minPulse + arm_stand*(maxPulse-minPulse); // berekening duur pulse, als geheel getal
  digitalWrite(servoPin,HIGH);            // signaal naar HIGH
  delayMicroseconds(pulseBreedte);        // wacht pulseWidth
  digitalWrite(servoPin,LOW);             // signaal naar LOW
  delayMicroseconds(cyclus-pulseBreedte); // wacht de rest van de cyclus tijd
}

void setup()
{
  pinMode(servoPin,OUTPUT);
}

void loop()
{
  float potVal=(float)analogRead(potPin)/1024;  // stand van de pot, omgezet naar getal tussen 0 en 1
  for(int i=0;i<=10;i++)   // elke keer 10 cycli => duurt 0,2 seconde
  {
    setServoPulse(potVal);                      // dient continu te worden aangeroepen
  }
}

Uitleg

Allereerst wordt aangegeven aan welke digitale pin de servo hangt en aan welke analoge pin de potmeter van de joystick zit. Daarna worden de details van de servo-besturing opgegeven. Dit zijn de duur van de cyclus (20ms = 20000 microseconde), 50 microseconde voor de minimale puls en 2500 microseconde voor de maximale puls. De setup() is in dit geval buitegewoon simpel en stelt alleen de servo-pin in als output. Ook de loop() functie is vrij eenvoudig. Hij leest de analoge waarde van de potPin en zet dat getal meteen om in een floating point getal tussen 0 en 1. Daarna stuurt het die waarde 10 keer achter elkaar naar de functie setServoPulse(). Dit duurt bij elkaar dus 10 cycli en dus 0,2 seconde. Het komt erop neer dat de analoge waarde 5 keer per seconde wordt gemeten, waarna de servo met de nieuwe waarde wordt aangestuurd.

De functie setServoPulse() doet het echte werk. Maar ook deze functie is relatief eenvoudig. Hij berekent de pulsebreedte. Bij arm_stand=0 moet daar minPulse uit komen en maxPulse bij arm_stand=1. Dat doet de berekening op de eerste regel. Daarna wordt de uitgang op servoPin hoog gemaakt. Dan volgt een wachttijd van pulseBreedte (in microsecondes), wordt servoPin laag gemaakt en wacht de functie de resterende tijd van de cyclus. Elke aanroep van setServoPulse() voert dus precies een cyclus uit.

Beetje spelen

  • Bij het testen van de servo zul je al snel zien dat de arm niet netjes in het midden staat als je de joystick los laat. Dat kan voor het besturen van bijvoorbeeld een auto een probleem zijn; je wilt toch dat die auto rechtuit rijdt als je de joystick los laat. Kun je het programma zo aanpassen dat je de afwijking met een instelbare waarde kunt corrigeren?
  • De joystick heeft twee potmeters. Je kunt dus gemakkelijk een tweede servo aansturen met dezelfde joystick. Als je een tweede servo hebt kun je dat eens proberen. Let er dan met name op dat de aansturing van de beide servo's in een nette functie setServoPulses() wordt gestopt waardoor beide PWM signalen goed tot hun recht komen. Die functie krijgt dan dus twee input-waarden:
void setServoPulses(float arm_stand1, float arm_stand2) {
}
  • Als je de schakeling aansluit en aan de servo voelt, voel je een soort van trilling waaruit blijkt dat de servo inderdaad continu bezig is met de positie. De motor is dus continu bezig en verbruikt dus ook continu energie. Motoren verbruiken relatief veel energie, en dus is dit gedrag niet al te gunstig als energieverbruik belangrijk is. Nu is het zo dat als het inputsignaal wegvalt (continu 0 - geen pulsen), dat (de meeste) servo's hun positie niet meer veranderen maar vasthouden. Vanwege de tandwielen in de servo, zal die stand ook met een redelijke kracht worden vastgehouden. Het kan dus geen kwaad om het signaal uit te zetten als de positie niet veranderd. Wel moet je er rekening mee houden dat er best een aantal pulsen nodig is om de servo in de juiste positie te krijgen. Deze opdracht bestaat daarom uit twee delen. Stel vast hoeveel pulsen er nodig zijn om de arm van de servo van de ene uiterste stand naar de andere uiterste stand te bewegen. Pas daarna het programma zo aan dat de servo alleen wordt aangestuurd als het signaal van de joystick voldoende veranderd.

Probeer vooral even zelf tot een oplossing te komen, maar hier is een oplossing waarin alle drie de opdrachtjes zijn geimplementeerd.

Navigatie