Pages: [1]   Go Down
Author Topic: Servomotor über serielle Konsole steuern  (Read 978 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo

Ich wollte meinen kleinen Servo mithilfe der seriellen Konsole von Arduino steuern.
Also flugs Servomotor angeschlossen und Programm geschrieben. Soweit keine Probleme, nur mein Programm funktioniert nicht so wie es soll.
Code:
#include <Servo.h>
Servo servo1;
int position = 0;


void setup(){
  Serial.begin(9600);
  servo1.attach(9);
}

void loop(){
  if (Serial.available()){
  position = Serial.read();
  servo1.write(position);
  Serial.print("Fahre auf ");
  Serial.print(position);
  Serial.print(" Grad");
  Serial.println("");
  }
  delay(100);
}

In der seriellen Konsole gebe ich 90 ein, aber als Ausgabe in der Konsole erscheint etwas ganz anderes
Code:
Fahre auf 57 Grad
Fahre auf 48 Grad
und der Servo fährt brav auf diese Winkel.

Aber wie kommen die zwei Winkel 57 und 48 Grad zustande, wenn ich einmal 90 eingebe?


Wenn ich hingegen einen Buchstaben eingebe, fährt der Servo auf die der ASCII-Nummer entsprechende Gradzahl. Bei z.B. A fährt der Servo auf 65 und bei a auf 97 Grad. Stimmt da was mit dem Datentyp Integer nicht?


Gruß
Atalanttore
Logged

0
Offline Offline
Faraday Member
**
Karma: 24
Posts: 3496
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Du hast das Problem schon korrekt erkannt. Dein Program liest wie folgt ein:

position = Serial.read();

Serial.read() liefert als Ergebnis Zeichen bzw. Bytes. Wenn Du sowas einer int Variablen zuweist, dann steht danach darin der ASCII Code des Zeichens.

Das ist alles so richtig. Deine Erwartungen sind falsch. Entweder Du benutzt das so oder Du musst den Input parsen. Ein guter Anfang ist das hier: http://arduino.cc/playground/Code/CmdMessenger
Logged

Check out my experiments http://blog.blinkenlight.net

Freiburg
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Atalanttore

... falls es funktioniert hat, kannst du bitte nochmal eine antwort posten, und eventuelle programmänderungen ?

würd mich interessieren ob es jetzt funktioniert.

grüssle
Logged

Frühes Scheitern erspart weiteres Leiden smiley-grin

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Du hast das Problem schon korrekt erkannt. Dein Program liest wie folgt ein:

position = Serial.read();

Serial.read() liefert als Ergebnis Zeichen bzw. Bytes. Wenn Du sowas einer int Variablen zuweist, dann steht danach darin der ASCII Code des Zeichens.

Das ist alles so richtig. Deine Erwartungen sind falsch. Entweder Du benutzt das so oder Du musst den Input parsen.

Nach meinem Verständnis müsste ich jedes eingegebene Zeichen - '0', also minus 48 rechnen und zum Schluss alle Zeichen der Reihe nach zusammenfügen.


Ein guter Anfang ist das hier: http://arduino.cc/playground/Code/CmdMessenger

Huch, ganz schöner Brocken. Geht das nicht einfacher?


Gruß
Atalanttore
Logged

0
Offline Offline
Faraday Member
**
Karma: 24
Posts: 3496
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Aehm, das ist eine einfache Lösung. Noch einfacher ist es bei der bestehenden Lösung zu bleiben. D.h. Du kannst ja genausogut auf der PC Seite alles in ASCII Codes umrechnen. D.h. falls Du eh per Computer mit dem Arduino redest ist es fast immer einfacher dem Arduino die Daten "mundgerecht" zu liefern anstatt im Arduino sich zu verkünsteln.
Logged

Check out my experiments http://blog.blinkenlight.net

Weinsberg, Germany
Offline Offline
God Member
*****
Karma: 3
Posts: 773
A Coder's Tale
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Probier mal was in der Richtung:
Code:
void loop(){
  if (Serial.available()) { // Wenn ueberhaupt irgendwas zum Lesen ansteht
    position = 0; // Damit wir keine Vermischung mit alten Werten bekommen
    while (Serial.available()){ // Dann lies jedes Zeichen dass Du bekommen kannst
      position = position*10 + Serial.read()-'0'; // Und zwar den Zahlenwert, nicht ASCII, und verknuepfe es!
      delay(1); // Warte auf das ggf. naechste Zeichen
    } // Wenn nichts mehr kommt mach weiter
    servo1.write(position);
    Serial.print("Fahre auf ");
    Serial.print(position);
    Serial.print(" Grad");
    Serial.println("");
  }
}
Mit dem delay(1) solltest Du dem Computer genug Zeit zur Übertragung des nächsten Zeichens geben um nicht aus der while auszubrechen wenn er noch nicht fertig ist. Da er immer nur ein Zeichen (eine Zahl) einlesen kann musst Du die dann noch verknüpfen.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Die eingegebenen Zahlen stimmen mit der Änderung zwar mit der Ausgabe überein, aber immer noch werden die eingegebenen Zahlen meistens einzeln betrachtet.

10 wird zu 1 und 0 Grad. 150 hingegen wird zu 1 und 50 Grad.


Code:
void loop(){
  if (Serial.available()) { // Wenn ueberhaupt irgendwas zum Lesen ansteht
    position = 0; // Damit wir keine Vermischung mit alten Werten bekommen
    while (Serial.available()){ // Dann lies jedes Zeichen dass Du bekommen kannst
      position = position*10 + Serial.read()-'0'; // Und zwar den Zahlenwert, nicht ASCII, und verknuepfe es!
      delay(1); // Warte auf das ggf. naechste Zeichen
    } ...
  }
}

Was hat es mit diesem position*10 auf sich? Warum mal zehn?


Gruß
Atalanttore
Logged

Weinsberg, Germany
Offline Offline
God Member
*****
Karma: 3
Posts: 773
A Coder's Tale
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Die eingegebenen Zahlen stimmen mit der Änderung zwar mit der Ausgabe überein, aber immer noch werden die eingegebenen Zahlen meistens einzeln betrachtet.
Vergrößer das delay() und probiers nochmal. 2 oder 3 sollten theoretisch reichen...

Was hat es mit diesem position*10 auf sich? Warum mal zehn?
Na Du willst doch die Zahlen zusammensetzen, und wenn Du z.B. 1, 5 und 0 zu 150 zusammensetzen willst, dann musst Du (1*10+5)*10+0 machen. Daher die 10.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Die eingegebenen Zahlen stimmen mit der Änderung zwar mit der Ausgabe überein, aber immer noch werden die eingegebenen Zahlen meistens einzeln betrachtet.
Vergrößer das delay() und probiers nochmal. 2 oder 3 sollten theoretisch reichen...
Juhu, mit delay(3) funktionierts smiley

Was hat es mit diesem position*10 auf sich? Warum mal zehn?
Na Du willst doch die Zahlen zusammensetzen, und wenn Du z.B. 1, 5 und 0 zu 150 zusammensetzen willst, dann musst Du (1*10+5)*10+0 machen. Daher die 10.

Ja schon. So habe ich das verstanden:

Der ASCII-Wert der eingegebenen Zahl wird eingelesen. Damit der ASCII-Wert zum Zahlenwert passt wird minus dem ASCII-Wert von '0' gerechnet. Dieses Ergebnis wird dann zu position*10 addiert.

Am Anfang ist position=0. Also position*10 auf jeden Fall auch 0. Der Wert von Serial.read()-'0' wird der neue Wert von position. Beim nächsten Durchlauf wird der neue Wert von position mit 10 multipliziert, damit die Zahl im Dezimalsystem zum Zehnerwert wird bzw. um eine Stelle nach links geschoben wird. Das ganze läuft solange durch bis keine eingegebenen Zahlen mehr da sind.


Gruß
Atalanttore
Logged

Weinsberg, Germany
Offline Offline
God Member
*****
Karma: 3
Posts: 773
A Coder's Tale
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Genau. smiley
Logged

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 270
Posts: 21860
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

es geht auch so:

Quote
int incomingByte;   
char Data[6];
int i;
unsigned int Tempo;

void setup()
{
  Serial.begin(9600);
}

void loop(){
 
   do {
     if (Serial.available()) {       
       Data = Serial.read();
       i++;
       }     
     if(i<1)Tempo = millis();
     } while (i<5&&(millis()-Tempo) < 500);
 
   Data = 0;   
   incomingByte = atoi(Data); 
   i=0;
   Serial.println(incomingByte);
}
Der Kode erwartet bis zu 5 Ashii-Zahlen oder wartet 0,5 Sekunden und übersetzt dann den String in eine Integerzahl.
Dies ist nützlich, damit bei manueller Eingabe nicht führene Nullen eingegeben werden müssen.
Grüße Uwe
Logged

Pages: [1]   Go Up
Jump to: