Arduino ile servo yavaşlatıcı

Sumer Yamaner

Moderator
Katılım
17 Eyl 2013
Mesajlar
8,789
Tepkime puanı
23,175
Yaş
61
Konum
İstanbul
Web sitesi
www.sumeryamaner.com
İlgi Alanı
Uçak
Bu da servo yavaşlatıcı projesi... Compiler hatasız işliyor ama tabii gerçek hayatta test edemedim henüz. Kimbilir ne saçmalıklar çıkacak. Ama olsun. Zihin jimnastiği oluyor. :)

Kod:
//Servo yavaşlatıcı


int rxpin = 12; //Sinyal girişi 12 nolu digital pin
int servopin = 1; //Servo çıkışı 1 nolu digital pin
int sollwert = 1500; //Hedef servo değeri mikrosaniye cinsinden
int istwert = 1500; //Aktüel servo değeri mikrosaniye cinsinden
int stepvalue = 1024; //Hız parametresi
int pot = 0; //Hız ayar potansiyometresi 1 nolu analog girişte
unsigned long timer1; //Servo sinyal çıkış zamanlaması için kullanılacak değişken


void setup()
{
  pinMode(servopin, OUTPUT); //Servo çıkışı OUTPUT olarak ayarlanıyor. INPUT deklarasyonu gerekmiyor
}

void loop()
{
  stepvalue = 1 + analogRead(pot); //Devredeki potansiyometre okunuyor ve 1 - 1024 arasında olması için 1 artırılıyor
  sollwert = pulseIn(rxpin, HIGH, 25000); //Alıcı sinyali okunuyor
  if(sollwert > istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden büyükse potansiyometre ayarına göre bir değer istwert değerine ekleniyor
  {
    istwert = istwert + stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
    if(istwert > sollwert)
    {
      istwert = sollwert;
    }
  }
  else if(sollwert < istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden küçükse potansiyometre ayarına göre bir değer istwert değerinden çıkartılıyor
  {
    istwert = istwert - stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
    if(istwert < sollwert)
    {
      istwert = sollwert;
    }
  }
  digitalWrite(servopin, HIGH); //Sonra aktüel değer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < istwert))
  {
    
  }
  digitalWrite(servopin, LOW);
}
 
Arduino ile servo yavaşlatıcı

Bu kod ise servo sinyalini hem yavaşlatıyor hem de ikinci bir çıkışa reverse sinyal veriyor. Bu devrenin en güzel uygulaması simetrik servolu flaplarda olur. Yani iki servo hem yavaş hareket eder hem de birbirine ters çalışır. Bir sonraki edımda ise kapanma ve açılma yönünde farklı hızların seçilmesi mümkün olacak...


Kod:
//Servo yavaşlatıcı


int rxpin = 12; //Sinyal girişi 12 nolu digital pin
int servopin = 1; //Servo çıkışı 1 nolu digital pin
int revservopin = 2; //Reverse çıkış 2 nolu digital pin
int sollwert = 1500; //Hedef servo değeri mikrosaniye cinsinden
int istwert = 1500; //Aktüel servo değeri mikrosaniye cinsinden
int revistwert = 1500; //Ters servo aktüel değeri
int stepvalue = 1023; //Hız parametresi
int pot = 0; //Hız ayar potansiyometresi 1 nolu analog girişte
unsigned long timer1; //Servo sinyal çıkış zamanlaması için kullanılacak değişken


void setup()
{
  pinMode(servopin, OUTPUT); //Servo çıkışı OUTPUT olarak ayarlanıyor. INPUT deklarasyonu gerekmiyor
}

void loop()
{
  stepvalue = 1 + analogRead(pot); //Devredeki potansiyometre okunuyor ve 1 - 1024 arasında olması için 1 artırılıyor
  sollwert = pulseIn(rxpin, HIGH, 25000); //Alıcı sinyali okunuyor
  if(sollwert > istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden büyükse potansiyometre ayarına göre bir değer istwert değerine ekleniyor
  {
    istwert = istwert + stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
    if(istwert > sollwert)
    {
      istwert = sollwert;
    }
  }
  else if(sollwert < istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden küçükse potansiyometre ayarına göre bir değer istwert değerinden çıkartılıyor
  {
    istwert = istwert - stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
    if(istwert < sollwert)
    {
      istwert = sollwert;
    }
  }
  digitalWrite(servopin, HIGH); //Sonra aktüel değer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < istwert))
  {
    
  }
  digitalWrite(servopin, LOW);
  revistwert = 3000 - istwert;
  digitalWrite(revservopin, HIGH); //Sonra aktüel değerin tersi diğer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < revistwert))
  {
    
  }
  digitalWrite(revservopin, LOW);
}
 
Arduino ile servo yavaşlatıcı

Biri Sümer bey'i durdursun :). İngilizce kaynakları tüketip Almanca kaynaklara da göz dikmiş...

 
Arduino ile servo yavaşlatıcı

Zafer SAHIN' Alıntı:
Biri Sümer bey'i durdursun :). İngilizce kaynakları tüketip Almanca kaynaklara da göz dikmiş...


Yok aslında temel teknik eğitimim Almanca temelli. Algoritma eğitimim de 70'li yıllarda Almanca olarak gerçekleşti. Istwert, Sollwert oradan kalma alışkanlık. :D
 
Arduino ile servo yavaşlatıcı

Sümer Yamaner' Alıntı:
Yok aslında temel teknik eğitimim Almanca temelli. Algoritma eğitimim de 70'li yıllarda Almanca olarak gerçekleşti. Istwert, Sollwert oradan kalma alışkanlık. :D
Bu arada hangi arada TIP eğitimi de aldın abi :laugh: :D
 
Arduino ile servo yavaşlatıcı

Ne yalan söyleyeyim benim de çok merak ettiğim bir husus oldu bu :).
 
Arduino ile servo yavaşlatıcı

Evet test edilip çalışan kod aşağıda. Sistemde bir potansiyometre var. Onun pozisyonuna göre servo hızı değişiyor. Ayrıca servo reverser de içeriyor. Simetrik servolu flaplar için ideal bir devre.

Şimdi Zafer Bey'den "map" işlevini nasıl logaritmik yapabileceğime dair bir ipucu bekliyorum. :D

Kod:
//Servo yavaşlatıcı


int rxpin = 12; //Sinyal girişi 12 nolu digital pin
int servopin = 2; //Servo çıkışı 2 nolu digital pin
int revservopin = 3; //Reverse çıkış 3 nolu digital pin
int sollwert = 1500; //Hedef servo değeri mikrosaniye cinsinden
int istwert = 1500; //Aktüel servo değeri mikrosaniye cinsinden
int revistwert = 1500; //Ters servo aktüel değeri
int stepvalue = 1023; //Hız parametresi
int pot = 0; //Hız ayar potansiyometresi 0 nolu analog girişte
unsigned long timer1; //Servo sinyal çıkış zamanlaması için kullanılacak değişken


void setup()
{
  pinMode(servopin, OUTPUT);
  pinMode (revservopin, OUTPUT); //Servo çıkışları OUTPUT olarak ayarlanıyor. INPUT deklarasyonu gerekmiyor
}

void loop()
{

  stepvalue = analogRead(pot); //Devredeki potansiyometre okunuyor
  stepvalue = map(stepvalue, 0, 1023, 1, 20);
  if(stepvalue == 20) stepvalue = 1024;
  sollwert = pulseIn(rxpin, HIGH, 25000); //Alıcı sinyali okunuyor
  if(sollwert >= 800 && sollwert <= 2200)
  {
      if(sollwert > istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden büyükse potansiyometre ayarına göre bir değer istwert değerine ekleniyor
      {
        istwert = istwert + stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
        if(istwert > sollwert)
        {
          istwert = sollwert;
        }
      }
      else if(sollwert < istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden küçükse potansiyometre ayarına göre bir değer istwert değerinden çıkartılıyor
      {
        istwert = istwert - stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
        if(istwert < sollwert)
        {
          istwert = sollwert;
        }
    }
  }
  digitalWrite(servopin, HIGH); //Sonra aktüel değer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < istwert))
  {
    
  }
  digitalWrite(servopin, LOW);
  revistwert = 3000 - istwert;
  digitalWrite(revservopin, HIGH); //Sonra aktüel değerin tersi diğer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < revistwert))
  {
    
  }
  digitalWrite(revservopin, LOW);
  delay(15);
}
 
Arduino ile servo yavaşlatıcı

Bu da aynı kodun analog servolarda daha net çalışması için düşünülmüş 20 ms frame'i tam tutturan versiyonu.

Kod:
//Servo yavaşlatıcı


int rxpin = 12; //Sinyal girişi 12 nolu digital pin
int servopin = 2; //Servo çıkışı 1 nolu digital pin
int revservopin = 3; //Reverse çıkış 2 nolu digital pin
int sollwert = 1500; //Hedef servo değeri mikrosaniye cinsinden
int istwert = 1500; //Aktüel servo değeri mikrosaniye cinsinden
int revistwert = 1500; //Ters servo aktüel değeri
int stepvalue = 1023; //Hız parametresi
int pot = 0; //Hız ayar potansiyometresi 1 nolu analog girişte
unsigned long timer1; //Servo sinyal çıkış zamanlaması için kullanılacak değişken
unsigned long timer2; //Servo frame zamanlayıcısı


void setup()
{
  pinMode(servopin, OUTPUT);
  pinMode (revservopin, OUTPUT); //Servo çıkışları OUTPUT olarak ayarlanıyor. INPUT deklarasyonu gerekmiyor
}

void loop()
{
  timer2 = micros();
  stepvalue = analogRead(pot); //Devredeki potansiyometre okunuyor
  stepvalue = map(stepvalue, 0, 1023, 1, 20);
  if(stepvalue == 20) stepvalue = 1024;
  sollwert = pulseIn(rxpin, HIGH, 25000); //Alıcı sinyali okunuyor
  if(sollwert >= 800 && sollwert <= 2200)
  {
      if(sollwert > istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden büyükse potansiyometre ayarına göre bir değer istwert değerine ekleniyor
      {
        istwert = istwert + stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
        if(istwert > sollwert)
        {
          istwert = sollwert;
        }
      }
      else if(sollwert < istwert) //Eğer alıcının komut sinyali o anki sinyal değerinden küçükse potansiyometre ayarına göre bir değer istwert değerinden çıkartılıyor
      {
        istwert = istwert - stepvalue; //Aktüel değerin istenen değeri aşmadığından emin olunuyor
        if(istwert < sollwert)
        {
          istwert = sollwert;
        }
    }
  }
  digitalWrite(servopin, HIGH); //Sonra aktüel değer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < istwert))
  {
    
  }
  digitalWrite(servopin, LOW);
  revistwert = 3000 - istwert;
  digitalWrite(revservopin, HIGH); //Sonra aktüel değerin tersi diğer servoya bir pulse olarak gönderiliyor
  timer1 = micros();
  while((micros() - timer1 < revistwert))
  {
    
  }
  digitalWrite(revservopin, LOW);

  while((micros() - timer2) < 20000)
  {
  }
  
}
 
Arduino ile servo yavaşlatıcı

Math library'de fscale işlevi var ancak ben koda Math library'yi ekleyemedim bir türlü. Zafer Bey'den yarsım bekliyorum. :)
 
Arduino ile servo yavaşlatıcı

Sümer bey fscale işlevi math kütüphanesinde bulunmuyor. Fscale fonksiyonunu kopyala-yapıştır metodu ile kodunuza eklemeniz gerekiyor, tabii "math" kütüphanesini de beraber.

Kod:
#include <math.h>

void setup() {
  // some code ..
}

void loop(){
    // Run Forrest run... 
}

float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve){

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;


  // condition curve parameter
  // limit range

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output 
  curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function

  /*
   Serial.println(curve * 100, DEC);   // multply by 100 to preserve resolution  
   Serial.println(); 
   */

  // Check for out of range inputValues
  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  // Zero Refference the values
  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin){ 
    NewRange = newEnd - newBegin;
  }
  else
  {
    NewRange = newBegin - newEnd; 
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal  =  zeroRefCurVal / OriginalRange;   // normalize to 0 - 1 float

  /*
  Serial.print(OriginalRange, DEC);  
   Serial.print("   ");  
   Serial.print(NewRange, DEC);  
   Serial.print("   ");  
   Serial.println(zeroRefCurVal, DEC);  
   Serial.println();  
   */

  // Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine 
  if (originalMin > originalMax ) {
    return 0;
  }

  if (invFlag == 0){
    rangedValue =  (pow(normalizedCurVal, curve) * NewRange) + newBegin;

  }
  else     // invert the ranges
  {   
    rangedValue =  newBegin - (pow(normalizedCurVal, curve) * NewRange); 
  }

  return rangedValue;
}
 
Arduino ile servo yavaşlatıcı

Bir de şu fonsiyonu niye kullandığınızı pek anlamadım.

Kod:
  timer1 = micros();
  while((micros() - timer1 < istwert))
  {
    
  }

"delay" fonksiyonu gibi "blocking" bir kod olduğundan multitasking bir iş yapmanızı, delay kadar olmasa da engelleyecek ya da sadece "while" içinde kod çalışabileceğinden, kodu zorlaştıracaktır. Ama aşağıdaki gibi bir kod, LED'in yanmasını beklerken arada istediğiniz işleri yapmayı sağlayacak "non-blocking" şekilde davranacaktır. (BlinkWithoutDelay)

Kod:
const int ledPin =  13;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 1000;           // interval at which to blink (milliseconds)

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

void loop() {
  // MY CODE BLOCK
  // MY CODE BLOCK
  // MY CODE BLOCK
  // MY CODE BLOCK
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;   
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}

Hoş bu şekilde kod yazıldığında, bunlardan iki ya da üç tane koyduğunuzda, kod arapsaçına dönüyor (bkz. Retract projesi - timer varkenki versiyonlar .. ). O yüzden "SimpleTimer" ya da "Timer" gibi kütüphanelere yönelmek kodu son derece rahatlatıyor.

 
Arduino ile servo yavaşlatıcı

Zafer Bey çok teşekkürler. Math library ve fscale işlevi ile epey bir uğraşmam gerekecek anlamak için.
O kodu neden kullandığıma gelince...
Birincisi delay işlevinden uzak durmak için. Haa diyorsunuz ki sonuç farklı olmayacak. Haklısınız. Sonuçta benim yazdığım kodda o aşamada sadece bekleme var. Başka bir işlem yapılamıyor. Ama zaten bu projede başka bir işlem yapılması da gerekmiyor. O nedenle şimdilik sorun yok. Ama "non-blocking" kod konusunu iyice anlamaya çalışıp ileride uygulayacağım. Benden emeklemeden koşmamı beklemeyin. :D :D :D
Bu arada dikkat ederseniz bir de tüm loop'u içine alan bir timer check var. Bunu da delay ile kolayca yapabilirdim ama hassas olmazdı. Zira aradaki kodların ne kadar süreceğini bilmem zor. Ama tüm loop'u içine alan bir timer check ile servolara her 20 ms'de bir sinyal gönderilmesini garantilemiş olduğumu düşünüyorum. Bu da özellikle analog servolar için olmazsa olmaz bir gereklilik (geçen gün servo tester denemeleri sırasında farkettim bunu).
 
Arduino ile servo yavaşlatıcı

Sümer bey, sizin kodlarınızı görünce şu şekilde bir izlenime kapıldığımdan dolayı bunları önerdim. Sadece ben değil bir çok kişinin de böyle düşündüğüne eminim :).