Precisie Servo Kalibratie met Arduino UNO & Adafruit PWM Shield
Onderdelen en benodigdheden
| Arduino UNO | × | 1 |
| Adafruit PWM Servo Driver Shield | × | 1 |
| M3 bout | × | 8 |
| M3 ring | × | 8 |
| LM2596 DC-DC Step-down spanningconverter | × | 1 |
| Rood PLA | × | 1 |
| Wit PLA | × | 1 |
| 180 graden heldere wiskundige gradeboog | × | 1 |
| Draaipotentiometer (standaard) | × | 1 |
| 9g servomotor | × | 1 |
Nodige tools en machines
- 3D-printer (standaard)
Apps en online diensten
- Arduino IDE
- Autodesk Fusion 360
Over dit project
In een eerdere post op Hackster schreef ik over hoe ik een opstelling maakte om te vergelijken hoe verschillende servo's uit dezelfde partij draaien, en toonde aan dat het sturen van dezelfde PWM-signalen naar verschillende servo's leidt tot significante verschillen - de onderstaande afbeelding toont servo's die allemaal in hun verste gegenwijzerse positie begonnen en hetzelfde PWM-signaal ontvingen - ze gedragen zich allemaal iets anders.

Waarom geen bestaande servo-bibliotheken voor de Arduino gebruiken?
Ik gebruik de Adafruit PWM Servo Driver om een reeks servo's aan te sturen, en dit stelt me in staat om een ander PWM-signaal naar elke servo te sturen. Ik zou de ingebouwde Servo-bibliotheek van Arduino kunnen gebruiken - maar ik heb een paar redenen om dit niet te doen:
- Met de Adafruit PWM Servo Driver kan ik mijn servo's besturen met slechts twee pinnen via I2C, in plaats van een pin op mijn Arduino te wijden aan elke servo.
- Ik heb soms ontdekt met de Arduino Servo-bibliotheek dat wanneer ik aan een servo koppel en een signaal stuur om naar de nulgradenpositie te draaien, deze naar de begrenzing van de beweging draait en de tandwielen in de servo laat knarsen.
Natuurlijk zijn de 9g servo's die ik gebruik goedkoop en niet ontworpen voor nauwkeurigheid - maar ik denk dat ik er nog meer waarde uit kan halen. Ik wil ze gebruiken voor een lopende robot, en heb hun gedrag iets preciezer en voorspelbaarder nodig.
Hoe kan ik mijn hobby-servo's nauwkeuriger besturen?
De bevestiging dat mijn servo's zich allemaal iets anders gedragen, maakte me ervan verlangen om een apparaat te bouwen waarmee ik een servo kan kalibreren - welke PWM-waarden moet ik naar een servo sturen om naar een 0-gradenpositie te bewegen? Of het 90-graden middenpunt? Hoe vermijd ik het sturen van een PWM-waarde die de servo naar een extreme positie katapulteert met veel gekraak en tandwielverslissing?
Ik besloot een paar eenvoudige concepten te combineren.
- Mijn servo uitlijnen met het midden van een eenvoudige gradeboog, zodat ik de positie kan meten terwijl de wiper van de servo draait.
- Een potentiometer verbinden met een analoge ingang van de Arduino, zodat ik de positie van de servo-wiper kan besturen door de PWM-waarde aan te passen terwijl ik de as van de potentiometer draai.
Voor deze versie was ik tevreden met het gebruik van de Seriële Monitor van mijn Arduino IDE om me de waarde van het PWM-signaal te vertellen, die ik handmatig kan noteren.
Ik gebruikte Autodesk 123D om een eenvoudige opstelling te ontwerpen die de potentiometer, de gradeboog, een enkele servo, mijn Arduino en de Adafruit PWM-servodriver samen met een voeding zou vasthouden.
Ik wil de Adafruit PWM-servodriver blijven gebruiken voor mijn kalibratie, omdat dat wat ik waarschijnlijk in mijn eindproject ga gebruiken. Als ik de servo rechtstreeks vanaf een pin op de Arduino zou besturen, zou ik dat in het apparaat repliceren en de servo kalibreren tegen PWM van de Arduino.

Het apparaat bouwen
Ik printte elk van de onderdelen en bevestigde ze samen met de M3 bouten en ringen.
De montagegaten in mijn ontwerp zijn aangepast aan mijn componenten - verschillende componenten kunnen varianties in gatdiameters en posities hebben.
Voor de elektronica verbond ik de middenpin van de potentiometer met de A0-pin van de Arduino, en de andere pennen met 0V en 5V op de Arduino. Ik bevestigde de PWM-servomotordriver op de Arduino, en verbond daarna de DC-DC buck-converter (die ik had afgesteld om de 9V voedingingang om te zetten in een 5V uitgang). Ik verbond de 9g servo met de eerste sleuf op het servomotordriver shield, en uploadde mijn sketch naar de Arduino.
Het eindresultaat is te zien in de foto's hieronder. Door de knop linksboven op het apparaat te draaien, kan ik de positie van de servo besturen, en met de Seriële Monitor in de Arduino IDE kan ik het PWM-signaal dat naar de servomotor wordt gestuurd voor een gegeven hoek aflezen.


Wat vertelt het apparaat me?
Voor mijn servo draaide ik hem naar zijn verste linkerwaartse limiet, en plaatste de wiper op de servo zodat deze net buiten de 180-gradenmarkering op de gradeboog van mijn kalibratieapparaat zou staan.
Ik verbond de voeding met het apparaat, en draaide de potentiometerknop tot de servonaald was uitgelijnd met de 0-gradenmarkering op de gradeboog, en noteerde de PWM-waarde die in de Seriële Uitvoer van mijn Arduino IDE werd geschreven. Daarna draaide ik de potentiometer tot de servonaald naar 10 graden wees, en noteerde de PWM-waarde opnieuw. Ik herhaalde dit proces elke 10 graden tot ik 180 graden bereikte, en deel de resultaten in de onderstaande tabel.

Ik maakte een grafiek van de resultaten (hieronder getoond), en zoals verwacht is er een sterke lineaire relatie tussen PWM en servo-hoek.

Nu heb ik PWM- en hoekwaarden die kenmerkend zijn voor deze specifieke servo - andere servo's kunnen vergelijkbare kenmerken hebben, maar zullen niet identiek zijn.
Ik heb nu een paar opties voor nauwkeurigere servo-prestaties:
- Deze waardeparen opslaan en in een array in mijn Arduino-sketch houden, en wanneer ik de servo-wiper naar 90 graden wil bewegen (bijvoorbeeld), gewoon kijken welke PWM-waarde bij die hoek hoort en die PWM-waarde naar de servo sturen. Dit heeft als nadeel dat ik alleen naar hoeken kan draaien die veelvouden van 10 zijn.
- Of als ik volledige controle wil over welke hoek ik instuur, kan ik lineaire regressie op de dataset gebruiken om uit te rekenen welke formule hoek en PWM-waarde verbindt (voor deze servo: PWM = 2,35 * Hoek + 159,4). Op deze manier kan ik de hoek die ik wil draaien als parameter doorgeven, en programmatisch de benodigde PWM berekenen om deze specifieke servo naar die positie te draaien.
Op beide manieren kan ik deze servo met meer nauwkeurigheid en vertrouwen besturen dan voorheen. Het kost redelijk meer moeite om elke servo precies te kalibreren, maar voor mijn project is het de moeite waard voor de extra nauwkeurigheid.
Natuurlijk, als ik de servo uit het apparaat haal, moet ik de servo-wiper bevestigd houden, want de metingen hebben betrekking op hoe de wiper bevestigd is tijdens de kalibratie.
Verbeteringen voor de volgende versie
Na het kalibreren van een paar servo's heb ik bedacht aan wat verbeteringen die ik in de volgende versie ga verwerken.
- De servo heeft een quick-release mechanisme nodig - misschien de servo bevestigen met een klem met neodymiummagneten, in plaats van het vast te zetten met M3 bouten.
- Ik wil het kleiner maken - misschien kan ik de Arduino en voeding heroriënteren om dit te bereiken.
- Ik heb een voedingschakelaar nodig tussen de 9V-batterij en de buck-converter, zodat ik de batterij niet elke keer volledig hoef los te koppelen als ik de machine wil uitschakelen.
- Ik wil de opstelling in minder stukken kunnen printen.
- In plaats van handmatig waarden van de gradeboog af te lezen, zou het beter zijn als een sensor kan detecteren wanneer de servo in specifieke hoekposities zit en dit terugkoppelt naar de Arduino - dit zou een deel van de parallaxfout kunnen elimineren.
- Tenslotte zou een LCD-scherm om resultaten weer te geven heel erg helpen, want dan hoef ik mijn computer niet aan het apparaat te koppelen.
Afsluiting
Dat is het dan - mijn hobby-servo's zijn goedkoop en niet ontworpen voor nauwkeurigheid - en voor veel toepassingen zijn ze prima. Toch wil ik er iets meer nauwkeurigheid en herhaalbare prestaties uit halen, en de opstelling in deze post helpt me dat te bereiken.
Code
Sketch voor servo-kalibratieapparaatC/C++
#include <Adafruit_PWMServoDriver.h>
#define analogIn A0
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
int inputValue = 0;
int tmpPwmValue = 0;
void setup() {
Serial.begin(9600);
pwm.begin();
pwm.setPWMFreq(60);
}
void loop() {
inputValue = analogRead(analogIn); // inputValue tussen 0 en 1024
// Uit observatie liggen servo min en max PWM-waarden meestal tussen 100 en 612
// De formule hieronder stelt ons in staat om analoge input eenvoudig om te zetten naar PWM
int pwmValue = (int)(100 + (inputValue / 2));
pwm.setPWM(0, 0, pwmValue);
// Controleren of we niet onnodig dubbele data tonen
if (pwmValue != tmpPwmValue) {
Serial.print("Potentiometer Input = ");
Serial.print(inputValue);
Serial.print(", PWM = ");
Serial.println(pwmValue);
}
tmpPwmValue = pwmValue;
delay(15);
}
Aangepaste onderdelen en behuizingen
Repo voor Servo Kalibratie onderdelen
Productieproces
- Real-time Pan/Tilt gezichtsvolging op een Raspberry Pi – Praktische Gids
- Walbi: Een Stable Tweevoetige Robot Gebouwd met Arduino en LX-16A Servo's
- Arduino Yun IoT-roboterarm (5 DOF) met Blynk-besturing
- Polylactzuur (PLA) 3D-printen: complete gids voor professionals
- PLA vs ABS vs Nylon: De Juiste 3D-print Filament Kiezen
- PLA vs. ABS in 3D-printen: Belangrijkste Verschillen en Wanneer Welk te Kiezen
- PLA: Is het werkelijk herbruikbaar en biologisch afbreekbaar?
- Lost PLA Op in Water? Voorwaarden & Waterdicht Maken Tips
- Kan PLA-filament elektriciteit geleiden? Conductieve varianten & printuitdagingen
- PLA-leidendheid begrijpen: Elektrische eigenschappen van 3D-printfilament
- Overschakelen naar DC-aandrijvingen: Betrouwbare Alternatief voor AC-servos in Industriële Bewegingbesturing