Servo Ansteuern über die Serielle Schnittstelle ---> Probleme

Moin Leute,

ich bin gerade dabei einein Servo über mein Arduino per PC und später mal per Handy anzusteuern,
soweit sogut.

mit diesem Code:

#include <Servo.h>

Servo servo;


void setup(){
  servo.attach(9);  //Pin für den Servo
  servo.write(90);  //Ausgangsposition
  Serial.begin(9600);
}

void loop()
{
  // erst mal serielle Schnittstelle auswerten
  if(Serial.available()){
    byte zustand = Serial.read();
    
    //rauf
  if(zustand == '1'){
    servo.write(0);
    Serial.println("Servo auf ");
    Serial.println(0);
  }
  
    //runter
  if(zustand == '2'){
    servo.write(180);
    Serial.println("Servo auf ");
    Serial.println(180);
  }
}

}

Dieser Code Funktioniert schonmal. Wenn ich 1 eingebe fährt er auf 0 Grad und wenn ich die 2 eingebe auf 180.

nun will ich es aber so machen das wenn ich 0 eingebe er auch auf 0 Grad Fährt und bei 1 auf 1 Grad Fährt.
nur spätestens bei der 10 ist Ende, ich weis auch das Arduino das als 1 und dannach erst als 0 Empfängt also habe ich geschaut wegen anderer Übertragung/Auswertung, aber ich steige leider nicht dahinter.

Und wenn ich es Scripten würde das 0 auch 0 Grad sind 1 auch 1Grad sind bis 180 würde der Text ewig lang sein, da gibt es bestimmt eine lösung mit der Funktion +1 bis <180 oder?

Ich hoffe ihr könnt mir bei meinem seriellen Problem helfen,
Das mit dem Zählen bis zur 180 das Versuche ich jetzt noch weiter zu Führen.

LG Domryk

Teste mal folgendes

#include <Servo.h>
Servo servo;
byte zustand;


void setup(){
  servo.attach(9);  //Pin für den Servo
  servo.write(90);  //Ausgangsposition
  Serial.begin(9600);
}

void loop()
{
  // erst mal serielle Schnittstelle auswerten
  if(Serial.available()){
    byte incByte = Serial.read();
    if(incByte >= 0 && incByte <= 180) zustand = incByte;
  }

  servo.write(zustand);

  if(zustand >= 0 && zustand < 90) {
    Serial.print("Servo auf : ");
    Serial.println(zustand);
  }
  else if(zustand >= 90 && zustand <= 180) {
    Serial.print("Servo zu : ");
    Serial.println(zustand);
  }
}

Auf dem seriellen Monitor tippt man ASCII ein und damit immer nur ein Zeichen. Wenn man mehr will muss man auch mehr Zeichen einlesen und diese dann entsprechend umrechnen.

Am besten man fragt dabei am Ende auf das Linefeed ab (und stellt den Serial Monitor so ein, dass er immer ein LF sendet):

const int STRING_BUFFER_SIZE = 11;
char serialBuffer[SERIAL_BUFFER_SIZE];

void loop()
{
   if(checkSerial())
   {
           //Auswertung
   }
}

bool checkSerial()
{
	static byte index;
	if(Serial.available())
	{
		char c = Serial.read();
		if(c != '\n' && index < SERIAL_BUFFER_SIZE)
		{
			serialBuffer[index++] = c;
		}
		else
		{
			serialBuffer[index] = '\0';
			index = 0;
			return true;
		}
	}
	return false;
}

Das kann man dann z.B. mit atoi() oder per Hand in eine Zahl umrechnen. Oder man nimmt strcmp() und vergleicht mit einem String. z.B.:

int value = atoi(serialBuffer);

oder:

if(strcmp(serialBuffer, "10") == 0)        //gibt 0 zurück wenn gleich
{
}

atoi() ist hier besser, da man so z.B. auch gleich die Grad eingeben könnte. Aber bitte nicht versuchen einen string mit == zu vergleichen! Damit vergleicht man nur die Zeiger. Das geht nur mit einzelnen chars.

Man kann natürlich auch ein Programm schreiben, das nicht Text, sondern Binär sendet. Dann kann man mit read() auch Zahlen von 0-255 einlesen. Aber mit dem Serial Monitor geht das nicht.

@ sschultewolter

Komm schon etwas Näher an mein Ende ran danke aber der Servo geht nicht auf 0 oder andere Positionen, Praktisch 0 = 48 und 9 ist 57 und wenn ich A schreibe bin ich bei 97.

@Serenifly

Ich nehme für die Übertragung schon das HTerm. Wo man ja auch Binär oder Hex übertragen kann. Damit werde ich es mal Binär Versuchen das ich 0-255 eingeben kann das kommt mir sogar recht gut.

Und mit dem atoi() komme ich auch nicht recht klar, ich werde mich darüber mal mehr belesen.

Danke euch beiden.

atoi() (array to integer) wandelt einfach den Null-terminierten String der übergeben wird in einen Integer: http://www.cplusplus.com/reference/cstdlib/atoi/

Wenn du eine Möglichkeit hast direkt Binär zu übertragen, dann ist es wahrscheinlich am besten das auch zu verwenden. Das macht es in diesem Fall einfacher.

domryk:
Und wenn ich es Scripten würde das 0 auch 0 Grad sind 1 auch 1Grad sind bis 180 würde der Text ewig lang sein, da gibt es bestimmt eine lösung mit der Funktion +1 bis <180 oder?

Ich hoffe ihr könnt mir bei meinem seriellen Problem helfen,

Bei der seriellen Kommunikation steht am Anfang, dass Du Dir ein “Protokoll” ausdenkst.

Dein Protokoll soll wohl so aussehen, dass Du einen Zahlenwert und ein Zeilenende-Steuerzeichen senden möchtest, und daraufhin soll der gesendete Zahlenwert als Steuerwinkel für den Servo interpretiert werden.

Es gibt verschiedene Möglichkeiten, so etwas zu codieren. Am einfachsten wären Einleseroutinen mit “delay()”, die im Prinzip so funktionieren:

  • wenn mindestens ein Zeichen im seriellen Eingangspuffer ist
  • mache delay() und warte, bis alle Zeichen eingetroffen sind
  • werte die gesamte Zeile aus
    Nachteil: Jedes delay kostet Performance im Programm. Für ein interaktives Programm, das von Menschen bedient wird, mag bis zu einem delay(100) völlig problemlos sein. Aber bei einem Helikopter-Steuerprogramm mag das schon zu einem Crash im Flug führen, wenn das Programm in dieser Zeit nicht weiterarbeitet.

Je nachdem, kann es erforderlich sein, komplexere Einleseroutinen zu verwenden, die Zeichen für Zeichen abarbeiten, die Daten sammeln, und erst beim Eintreffen des Zeilenende-Zeichens wird ausgewertet.

Anbei mal ein Codebeispiel für so eine etwas aufwändiger Funktion:

#include <Servo.h>

Servo servo;


void setup(){
  servo.attach(9);  //Pin für den Servo
  servo.write(90);  //Ausgangsposition
  Serial.begin(9600);
}

int readSerial()
{
  static char str[4];
  static byte count=0;
  char c;
  if (Serial.available())
  {
    c=Serial.read();
    if (isdigit(c))
    {
      if (count==0) memset(str,0,sizeof(str));
      str[count]=c;
      if (count<sizeof(str)-2) count++;
    }
    else if (c=='\r')
    {
      if (count==0) return -1;
      int returnValue=atoi(str);
      count=0;
      return returnValue;
    }
  }
  return -1;
}

void loop()
{
  // erst mal serielle Schnittstelle auswerten
  int servoPos=readSerial();
  if (servoPos>=0)
  {
    servo.write(servoPos);
    Serial.println(servoPos);
  }
}

Dieser Einlesecode funktioniert so nicht nur im seriellen Monitor, sondern auch z.B. mit einem seriellen Terminalprogramm.

Ja genau so was.

Ich gebe meinetwegen die Zahl 10 im Terminal ein und der Servo soll auf 10 Grad Fahren.

Später soll das über einen Controller gesteuert werden, aber bis dahin ist es noch ein Weiter Weg...

also wenn ich nun Binär nehme also input für den Arduino muss ich einen Code Entwickeln der mir diesen 8 Bit Code auffängt und in eine Zahl umwandelt die ich dann für die Steuerung nehmen kann. Ohne mist es klingt Ganz einfach nur diesen Code muss ich nun schreiben, :)

Also ich brauche einen Code der sagt ach der erste bit ist eine 0 der Zweite auch und der Dritte ist eine 1 usw.

Dieses kann ich in einem Array Speichern oder? und dannach eine Binär auflösung schreiben die mir dann die Ganzzahl ausgibt.?

Ist meine Theorie soweit richtig?