Import von String in Funktion

Guten Morgen zusammen,

ich habe nun mal endlich Zeit und Lust gefunden ein wenig mit meinem Arduino Leonardo zu basteln.

Aufgabenstellung:
Aktuell sind an den Arduino zwei Servos angeschlossen, diese gilt es zu steuern. Quelllcode:
Nun möchte ich das ganze so bauen, dass ich mehrere Servos dynamisch über eine Funktion steuern kann. Dazu soll die Servobezeichnung an die Funktion übergeben und dann dynamisch im Code verwendet werden. Leider klappt das so nicht:

#include <Servo.h>
Servo servo_x;          // Erzeugen eines Servo Objekts zur Servosteuerung
Servo servo_y;
char servoposdebug;

void setup(){
  servo_x.attach(5); 
  servo_y.attach(6);
  Serial.begin(9600);          //Starte serielle Schnittstelle für Debugging
}

// Hauptprogramm
void loop(){
  servoposition(90,servo_x);
  servoposition(90,servo_y);
  delay(1000);
}

void servoposition(int servopos,char servo_axis){
  //Funktion dient zum anfahren der Position unter Berücksichtigung
  //eines Korrekturfaktors und der maximalen mechanischen Achsgrenze
  int tempservpos;          //temporäre Variable zur Positionsbestimmung
  int servoposcor = -10;          //Variable zur Positionskorrektur des Getriebes   
  int servoposmax = 170;          //Maximaler mechanischer Anschlag des Servos
  int servoposmin = 0;          //Minimaler mechanischer Anschlag des Servos
  int servolastposition;          //Letzte angeforderte Position des Servos

  tempservpos = servopos+servoposcor;          //Verrechne angeforderte Position mit Positionskorrektur
  if((tempservpos) > servoposmin || (tempservpos) < servoposmax){          //Prüfe ob angeforderte Position innerhalb mechanischer Grenzen
    Serial.print("Fahre Servo auf Position ");
    Serial.print(servopos);
    Serial.println(" Grad");
      servolastposition = servo_axis.read();          //Entprellen des Servos
      if(servopos != servolastposition){
        servo_axis.write(tempservpos);
    }
  }
  else
  {
    Serial.print("Position ausser Reichweite: ");
    Serial.print(servopos); 
    Serial.println(" Grad");
  }
}

Leider funktioniert das nicht, denn ich bekomme die Fehlermeldung

Servoexperimente.ino: In function ‘void loop()’:
Servoexperimente:14: error: cannot convert ‘Servo’ to ‘char’ for argument ‘2’ to ‘void servoposition(int, char)’
Servoexperimente:15: error: cannot convert ‘Servo’ to ‘char’ for argument ‘2’ to ‘void servoposition(int, char)’
Servoexperimente.ino: In function ‘void servoposition(int, char)’:
Servoexperimente:35: error: request for member ‘write’ in ‘servo_axis’, which is of non-class type ‘char’

Woran liegt das?

Hoi,

Servoexperimente:14: error: cannot convert ‘Servo’ to ‘char’ for argument ‘2’ to ‘void servoposition(int, char)’
Servoexperimente:15: error: cannot convert ‘Servo’ to ‘char’ for argument ‘2’ to ‘void servoposition(int, char)’

Hier versuchst Du, der INT Servo einen CHAR Wert zu übergeben - das geht natürlich nicht.
Du musst die Variable wie z.B. Winkel oder Position verwenden, die du dann an INT Servo übergibst.

Hier ein kleiner Beispiel-Sketch dazu, den kannst Du dann einfach anpassen:

#include <Servo.h>

Servo servo1; Servo servo2; 

void setup() {
  servo1.attach(A8);  
  servo2.attach(A9);

  Serial.begin(9600);
  Serial.println("Ready");
}

void loop() {

  static int v = 0;

  if ( Serial.available()) {
    char ch = Serial.read();

    switch(ch) {
      case '0'...'9':
        v = v * 10 + ch - '0';
        break;
      case 's':
        servo1.write(v);
        v = 0;
        break;
      case 'w':
        servo2.write(v);
        v = 0;
        break;
      case 'd':
        servo2.detach();
        break;
      case 'a':
        servo2.attach(10);
        break;
    }
  }
}

A.R.Ty: Hier versuchst Du, der INT Servo einen CHAR Wert zu übergeben

Nein. Noch schlimmer. Er versucht ein Servo Objekt an einen char zu übergeben

Aber so wie ich das sehe wird dieser char gar nicht mit Serial o.ä. verwendet:

servolastposition = servo_axis.read(); //Entprellen des Servos if(servopos != servolastposition){ servo_axis.write(tempservpos);

Statt dessen übergibt man einen Pointer auf den Servo:

void loop(){
  servoposition(90, &servo_x);
  servoposition(90, &servo_y);
  delay(1000);
}

void servoposition(int servopos, Servo* servo_axis)
{
   servolastposition = servo_axis->read();
      if(servopos != servolastposition){
          servo_axis->write(tempservpos);
}

Hierbei beachten, dass der Referenz Operator bei Pointern ein "->" und kein Punkt ist. Und statt dem Objekt übergibt man in loop() mit dem & Operator die Adresse.

the_bang_2: void servoposition(int servopos,char servo_axis)

Leider funktioniert das nicht

Woran liegt das?

Ändere die Funktionsdeklaration so, dass das Servo-Objekt "by Reference" an die Funktion übergeben wird:

void servoposition(int servopos, Servo &servo_axis)

Übrigens zu Deinen Drehwinkel-Korrekturen: Du kannst auch in der attach-Initialisierung die Impulslängen in Mikrosekunden für den 0° und 180° Drehwinkel Deines Servos vorgeben: http://arduino.cc/de/Reference/ServoAttach

So dass Du mit einem Aufruf wie:

servo_x.attach(5, 1000, 2000);

oder womit sich Dein Servo auf 0° und 180° positioniert, gleich die Drehwinkelkorrektur durchführen kannst, ohne im Programm großartig herumrechnen zu müssen.

Oder das. Mit Referenz-Variablen kann man weniger machen als mit Pointern (und sind dadurch auch sicherer), aber hier reichen sie vollkommen und die Syntax ändert sich nicht.

Serenifly:

A.R.Ty:
Hier versuchst Du, der INT Servo einen CHAR Wert zu übergeben

Nein. Noch schlimmer. Er versucht ein Servo Objekt an einen char zu übergeben

Aber so wie ich das sehe wird dieser char gar nicht mit Serial o.ä. verwendet:

servolastposition = servo_axis.read(); //Entprellen des Servos
if(servopos != servolastposition){
servo_axis.write(tempservpos);

Statt dessen übergibt man einen Pointer auf den Servo:

void loop(){

servoposition(90, &servo_x);
 servoposition(90, &servo_y);
 delay(1000);
}

void servoposition(int servopos, Servo* servo_axis)
{
  servolastposition = servo_axis->read();
     if(servopos != servolastposition){
         servo_axis->write(tempservpos);
}




Hierbei beachten, dass der Referenz Operator bei Pointern ein "->" und kein Punkt ist. Und statt dem Objekt übergibt man in loop() mit dem & Operator die Adresse.

Vielen Dank, dass war es wonach ich gesucht habe, wobei das auch mit servo_axis.write(tempservpos) anstatt mit → funktioniert(warum?) :slight_smile:

@jurs:

vielen Dank für den Tipp, das spart doch ein wenig Rechnerei und einige Variablen. :slight_smile: Hast du zufällig ein Beispiel, wie du genau auf die Werte kommst? Das Problem ist hier, das die Anflanschung des Servos an die Welle des Getriebes nur an einer Position geht, dadurch verschiebt sich der 0-Punkt der Positionierung um 10 Grad(z.B. aus 90° wird 80°).

the_bang_2: Vielen Dank, dass war es wonach ich gesucht habe, wobei das auch mit servo_axis.write(tempservpos) anstatt mit -> funktioniert(warum?) :)

Hast du meine Version oder das von jurs? Das sind zwei verschiedene Sachen, auch wenn es sehr ähnlich aussieht und am Ende das gleiche passiert.

Bei der Version von jurs hast du eine Referenz als Parameter. Damit braucht man den -> Operator nicht. Wenn du wie bei mir einen Zeiger als Parameter hast, kommt ein Fehler wenn man das anders macht:

error: request for member 'read' in 'servo_axis', which is of non-class type 'Servo*' error: request for member 'write' in 'servo_axis', which is of non-class type 'Servo*'

Eine Referenz ist nur die Adresse des Objekts. Sie kann auf nichts anderes verweisen und man kann damit nichts machen als auf den Inhalt der Variablen zuzugreifen. Zeiger sind Variablen die eine Adresse enthalten. Daher kann man ihnen auch andere Dinge zuweisen, man kann sie abspeichern und arithmetische Operation darauf verwenden. Das wird hier nicht gebraucht, weshalb eine Referenz in diesem Fall einfacher ist.

the_bang_2: Hast du zufällig ein Beispiel, wie du genau auf die Werte kommst? Das Problem ist hier, das die Anflanschung des Servos an die Welle des Getriebes nur an einer Position geht, dadurch verschiebt sich der 0-Punkt der Positionierung um 10 Grad(z.B. aus 90° wird 80°).

Die Werte sind abhängig vom Servohersteller, die müßtest Du ausprobieren.

Praktisch alle Servos haben bei 1500 us Impulslänge ihre Mittelstellung, aber die Impulsbreite bei 0° und 180° weichen von Hersteller zu Hersteller ab.

Meist liegt die 0° Position bei Werten zwischen 600 und 1000. Und die 180° Position bei Werten zwischen 2000 und 2500. Oder so. Am besten schreibst Du Dir einen Sketch, der sowohl die 0° als auch die 180° Position anfährt, z.B. mit 5 Sekunden Zeitabstand dazwischen, und dann probierst Du mit verschiedenen Initialisierungen aus:

servo_x.attach(5, 800, 2200);

Und wenn Du die richtigen Werte für 0° und 180° gefunden hast, die für Deinen Servo zutreffen, verwendest Du diese. Oder korrigierst diese nochmal.

Mal angenommen 800 entspricht 0° und 2200 entspricht bei Dir 180°, dann ist die Differenz 2200-800= 1400, wobei eine Verschiebung des Drehwinkels von 10° entspricht: 1400/18= 78 und Du kannst eine Initialisierung versuchen mit:

servo_x.attach(5, 722, 2122);

oder

servo_x.attach(5, 878, 2278);

(je nachdem, in welche Richtung der Winkel verschoben werden soll)

Wenn Du den Drehwinkel so verschiebst, müßtest Du allerdings auch kontrollieren, ob der Servo in der Extremposition nicht vielleicht gegen eine mechanische Begrenzung gefahren wird.