Analóg visszajelzésű szervók

A „feedback”(visszajelzéses) szervók négy vezetékkel vannak ellátva a sima három vezetékes szervókkal szemben, itt a negyedik szál az analóg visszajelzést biztosítja.
A szervó kimenő tengelyéről visszatáplált belső potméter ad egy visszajelzés a szervó aktuális pozíciójáról, amit a szervó vezérlőáramkörén keresztül tud elküldeni a mikrovezérlőnek.
„Open loop” rendszernél nincs visszacsatolás, itt nem lehet ellenőrizni a kiadott utasítás megfelelő teljesülését (nyílt hurok).
„Closed loop” rendszer használ visszacsatoló jelet, hogy be állítható legyen a motor sebessége, forgásiránya illetve elfordulása. Ilyen motor a szervó is, itt a beépített poti leköveti a szervó kar pontos helyzetét és ezt adja vissza.

Visszacsatolás nélkül csak egyszerűbb alkalmazásoknál használhatók megbízhatóan a szervók, bonyolultabb programoknál csak is visszacsatolással érdemes alkalmazi őket, főleg az időzítések, több szervós kapcsolások illetve elemes táplálás esetén(csökkenő tápfesz).

Kapcsolás:

szervó fekete – GND
szervó piros – 5V
szervó sárga – vezérlő jel kifelé D9
szervó fehér – visszajelzés a szervótol A0

Kód


Először lássuk a visszajelzés kezelését:

void loop()
{
val = analogRead(potpin); // beolvassa a val változóba a szervó pozicióját
val = map(val, 0, 1023, 0, 179); // az analóg értéket 0-1023 átalakitja fokokká 0-179
myservo.write(val); // kiiratja a szervóra a val változó értékét
delay(15); // várakozás
}

kalibráljuk a szervót:

#include <Servo.h>
Servo myservo;
// szervó vezérlő pin d9
//szervó visszajelzését fogadó pin A0
int servoPin = 9;
int feedbackPin = A0;

// változók létrehozása a kalibrációs értékekhez
int minDegrees;//elfordulás minimum
int maxDegrees;//elfordulás max
int minFeedback;//visszajelzás min
int maxFeedback;//visszajelzés max
int tolerance = 2; //max mérési hiba visszacsatolásnál

/*
evvel a funkcióval beállítjuk a szervó elmozdulásának határértékeit


*/
void calibrate(Servo servo, int analogPin, int minPos, int maxPos)
{
// a szervót minimális pozícióba mozgatjuk és rögzítjük az értékét
servo.write(minPos);//min pozícióba mozgatjuk a szervót
minDegrees = minPos;
delay(2000); //2mp várakozás
minFeedback = analogRead(analogPin);//beolvassuk az analóg értéket

// a szervót maximális pozícióba mozgatjuk és rögzítjük az értékét
servo.write(maxPos);
maxDegrees = maxPos;
delay(2000); // 2mp várakozás
maxFeedback = analogRead(analogPin);
}


void setup()
{
myservo.attach(servoPin);
calibrate(myservo, feedbackPin, 20, 160); // 20-160 fokig kalibrálja a szervó elmozdulását
}

void loop()
{
}


Pozícióra állítás:

void Seek(Servo servo, int analogPin, int pos)
{

servo.write(pos);

// a visszajelzés alapján kikalkulálja a pozíciót
int target = map(pos, minDegrees, maxDegrees, minFeedback, maxFeedback);

// várakozik amíg pozícióba nem áll a szervónk
while(abs(analogRead(analogPin) - target) > tolerance){} // wait...
}


Aktuális pozíció:

int getPos(int analogPin)
{
return map(analogRead(analogPin), minFeedback, maxFeedback, minDegrees, maxDegrees);
}


Szervó használata beviteli eszközként:

a kapcsolás



és a kód:

// http://www.adafruit.com/products/1404

#include <Servo.h>
#include <EEPROM.h>

#define CALIB_MAX 512
#define CALIB_MIN 100
#define SAMPLE_DELAY 25 // in ms, 50ms seems good

uint8_t recordButtonPin = 12;
uint8_t playButtonPin = 7;
uint8_t servoPin = 9;
uint8_t feedbackPin = A0;
uint8_t ledPin = 13;

Servo myServo;

void setup() {
Serial.begin(9600);
pinMode(recordButtonPin, INPUT);
digitalWrite(recordButtonPin, HIGH);
pinMode(playButtonPin, INPUT);
digitalWrite(playButtonPin, HIGH);
pinMode(ledPin, OUTPUT);

Serial.println("Servo RecordPlay");
}
void loop() {
if (! digitalRead(recordButtonPin)) {
delay(10);
// wait for released
while (! digitalRead(recordButtonPin));
delay(20);
// OK released!
recordServo(servoPin, feedbackPin, recordButtonPin);
}

if (! digitalRead(playButtonPin)) {
delay(10);
// wait for released
while (! digitalRead(playButtonPin));
delay(20);
// OK released!
playServo(servoPin, playButtonPin);
}
}

void playServo(uint8_t servoPin, uint8_t buttonPin) {
uint16_t addr = 0;
Serial.println("Playing");


myServo.attach(servoPin);
while (digitalRead(buttonPin)) {
uint8_t x = EEPROM.read(addr);
Serial.print("Read EE: "); Serial.print(x);
if (x == 255) break;
// map to 0-180 degrees
x = map(x, 0, 254, 0, 180);
Serial.print(" -> "); Serial.println(x);
myServo.write(x);
delay(SAMPLE_DELAY);
addr++;
if (addr == 512) break;
}
Serial.println("Done");
myServo.detach();
delay(250);
}


void recordServo(uint8_t servoPin, uint8_t analogPin, uint8_t buttonPin) {
uint16_t addr = 0;

Serial.println("Recording");
digitalWrite(ledPin, HIGH);


pinMode(analogPin, INPUT);
while (digitalRead(buttonPin)) {
uint16_t a = analogRead(analogPin);

Serial.print("Read analog: "); Serial.print(a);
if (a < CALIB_MIN) a = CALIB_MIN;
if (a > CALIB_MAX) a = CALIB_MAX;
a = map(a, CALIB_MIN, CALIB_MAX, 0, 254);
Serial.print(" -> "); Serial.println(a);
EEPROM.write(addr, a);
addr++;
if (addr == 512) break;
delay(SAMPLE_DELAY);
}
if (addr != 512) EEPROM.write(addr, 255);
digitalWrite(ledPin, LOW);
Serial.println("Done");
delay(250);
}


A sketch inditása után nyomjuk meg a felső gombot, hogy elindítsuk a felvételt (led világít)
mozgassuk a szervót ahogy szeretnénk, hogy mozogjon visszajátszáskor.
Nyomjuk meg ismét a felső gombot a felvétel befejezéséhez. Az alsó gomb megnyomására elindul
a lejátszás. Minden gombnyomásra újra lejátsza a mozgássort.
A felső gombbal új felvételeket vehetünk fel, a minta 12,8 mp lehet (ennyi fér az eepromba) ha
elérjük a határt a felvétel automatikusan leáll, a felvétel jelző led kialszik.

Mivel EEPROMban tárolódik a felvétel ezért még nullázás után illetve kikapcsolás után is megmarad a mozgássor.