Benutzer-Werkzeuge

Webseiten-Werkzeuge


techniken:datenaustausch:serialchars

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
techniken:datenaustausch:serialchars [2015/01/14 11:40]
fbonowski
techniken:datenaustausch:serialchars [2016/01/21 12:45] (aktuell)
Zeile 1: Zeile 1:
-==== Kommandos in Form von einzelnen Zeichen an den Arduino ​senden ​====+====== Übermittlung ​von Kommandos und Daten vom PC zum Arduino ====== 
 +In diesem Artikel ist beschrieben,​ wie ihr 
 +  * Arduino-Programme mittels einfacher Kommandos vom PC aus '​fernsteuern'​ könnt. 
 +  * Zahlen vom PC an den Arduino übermitteln könnt.
  
 +Beide Mögglichkeiten können problemlos mit dem [[techniken:​datenaustausch:​processingserialread|Senden von Daten vom Arduino zum PC]] kombiniert werden.
  
-Die einfachste Art und Weiseeinen Befehl vom PC an den Arduino zu übermittelnistihm einzelne Zeichen über die Serielle Schnittstelle ​zu schickendie ein Programm auf dem Arduino ​auswertet.+Dazu verwenden wir die Serielle Schnittstelle des Arduinos, die ihr bereits aus dem '​Serial Monitor'​ kennt. Ihr könnt also einfach den Serial-Monitor nutzenum manuell Daten an den Arduino zu schicken - z.B. um zu testenob er auf Kommandos so reagiert wie ihr es erwartet. Wirklich spannend wird es aberwenn ihr ein eigenes Programm (z.B. ein Processing-Sketch) schreibt, welches ​die Serielle Schnittstelle ​verwendetum dem Arduino ​vollautomatisch Befehle zu übermitteln.
  
-Dabei kann z.Bder Buchstabe ''​f''​ für "fahre los" ​und der Buchstabe ''​s''​ für "​stop"​ stehen.+In allen Fällen muss der Arduino mit einem Kabel mit dem PC verbunden sein - denn über dieses Kabel werden die Daten in Form von Elektrischen Impulsen übertragen..
 +===== Kommandos in Form von einzelnen Zeichen an den Arduino senden ===== 
 +Die einfachste Art und Weise, einen Befehl vom PC an den Arduino zu übermitteln,​ ist, ihm einzelne Zeichen über die Serielle Schnittstelle zu schicken, die ein Programm auf dem Arduino auswertet
  
-Das Arduino Programm muss dazu nur+Dabei kann z.B. der Buchstabe ''​f''​ für "fahre los" und der Buchstabe ''​s''​ für "​stop"​ stehen.  
 + 
 +Das Arduino Programm muss zum Empfang der Befehle ​nur:
   * Überprüfen,​ ob neue Daten angekommen sind (mit ''​Serial.available()''​)   * Überprüfen,​ ob neue Daten angekommen sind (mit ''​Serial.available()''​)
-  * Das erste Zeichen aus den angekommenen Daten lesen (mit ''​Serial.read()) +  * Das erste Zeichen aus den angekommenen Daten lesen (mit ''​Serial.read()''​
-  * Das erhaltene Zeichen untersuchen,​ um zu sehen, ob es ein bekannter Befehl ist (im Bedingungsteil (Runde Klammern) von ''​if''​ oder ''​switch case''​)+  * Das erhaltene Zeichen untersuchen,​ um zu erkennen, ob es ein bekannter Befehl ist(im Bedingungsteil (Runde Klammern) von ''​if''​ oder ''​switch case''​)
   * Eine Funktion aufrufen, die das erledigt, was dem Befehl entspricht (im Befehlsblock (geschweifte Klammern) von ''​if''​ oder ''​switch case''​)   * Eine Funktion aufrufen, die das erledigt, was dem Befehl entspricht (im Befehlsblock (geschweifte Klammern) von ''​if''​ oder ''​switch case''​)
  
-------> in Bearbeitung... +==== Ein Beispielprogramm mit 2 alternativen Befehlen (LED an/aus) ==== 
-Das Beispiel ​ ''​libraries/​Serial/​SimpleWrite''​ in Processing enthält sowohl ​den Processing, als auch den Arduino Code dafür.+Das Beispiel ''​libraries/​Serial/​SimpleWrite''​ in Processing enthält sowohl den Processing, als auch den Arduino Code, um mit der Maus eine LED auf dem Arduino einund ausschalten zu können. Hier ein kleiner Ausschnitt mit den wichtigsten Teilen auf Arduinoseite:​ 
 + 
 +<code Java> 
 +... 
 +if (Serial.available()) { // Wenn Daten empfangen wurden und zum Lesen bereitstehen 
 +  int val = Serial.read();​ // lese das erste Zeichen ​in der Warteschlange und speichere es in der Variable '​val'​ zwischen 
 +  if (val == '​H'​) { // Wenn das Zeichen den Wert '​H'​ hat... 
 +    ​digitalWrite(ledPin,​ HIGH); // schalte eine LED an 
 +  }  
 +  else { 
 +    digitalWrite(ledPin,​ LOW); // wenn es irgendein anderes Zeichen ist, schalte die LED aus. 
 +  } 
 +
 +... 
 +</​code>​ 
 +===== Erweiterung auf mehrere Befehle mit switch/case (verschiedene LEDs anschalten) ===== 
 +Sollen mehr als zwei unterschiedliche Befehle erkann werden können, so geht das am einfachsten mit dem ''​switch/​case''​. Die Sendeseite funktioniert ganz genau so wie in ''​libraries/​Serial/​SimpleWrite''​, nur dass eben mehrere unterschiedliche Zeichen gesendet werden können. 
 + 
 +Für die Arduino/ Empfängerseite gibt es ein gutes [[http://​www.arduino.cc/​en/​Tutorial/​SwitchCase2|Beispielprogramm ''​control/​switchCase2''​ aus dem Arduino IDE]], aus dem ich hier (mit deutschen Kommentaren) zitiere: 
 + 
 +<code Java> 
 +  if (Serial.available() > 0) { // Wenn Daten angekommen sind... 
 +    int inByte = Serial.read();​ // ...dann lies das erste Byte und speichere es in der Variable inByte 
 +    switch (inByte) {           // und nimm den Wertder übertragen wurde, genauer unter die Lupe. 
 +    case '​a': ​                  // wenn dieser das Zeichen '​a'​ ist... 
 +      digitalWrite(2,​ HIGH); ​   // ... dann schalte den pin 2 auf 5V   
 +      break; ​                   // Ohne '​break'​ würde das Programm auch den nächsten Teil ausführen, obwohl kein '​b'​ kam. (beliebter Fehler) 
 +    case '​b': ​                  // alle anderen Buchstaben funktionieren genauso wie '​a',​ nur passiert eben als Reaktion etwas anderes. 
 +      digitalWrite(3,​ HIGH); 
 +      break; 
 +    case '​c': ​    
 +      digitalWrite(4,​ HIGH); 
 +      break; 
 +    case '​d': ​    
 +      digitalWrite(5,​ HIGH); 
 +      break; 
 +    case '​e': ​    
 +      digitalWrite(6,​ HIGH); 
 +      break; 
 +    default: ​              //​wenn das Zeichen keinem der oben überprüften entspricht, passiert das Folgende: 
 +      // Schalte die Spannung an allen Pins aus. 
 +      for (int thisPin = 2; thisPin < 7; thisPin++) { 
 +        digitalWrite(thisPin,​ LOW); 
 +      } 
 +    }  
 +</​code>​ 
 +===== Übertragen von Zahlenwerten (als menschenlesbarer ASCII-Text) ===== 
 +In vielen Fällen wollen wir nicht nur ein Kommando übertragen ("​fahre geradeaus"​),​ sondern ​auch dazugehörige Zahlenwerte ("wie lange?"​ , "wie schnell?",​ "wie weit?"​).  
 + 
 +Das geht ganz einfach mit den beiden Befehlen [[http://​arduino.cc/​en/​Serial/​ParseInt|Serial.parseInt()]] (für Ganzzahlen) oder [[http://​arduino.cc/​de/​Reference/​StreamParseFloat|Serial.parseFloat()]] (Für Kommazahlen). 
 +Beide Befehle lesen solange Daten aus der seriellen Schnittstelle,​ bis entweder längere Zeit nichts mehr gekommen ist ("​timeout"​) oder das nächste Zeichen nicht mehr Teil einer Zahl sein kann (also irgendetwas ausser 0...9, '​+',​ '​-'​ oder '​.'​ ist). 
 + 
 +//​**Achtung**//:​ Als Dezimaltrennzeichen wird (wie eigentlich immer beim Programmieren) der **Punkt** (anstelle des **Kommas**) verwendet. 
 + 
 +Zum Steuern eines Roboters könnten wir z.B. die Kommandos '​l'​ für "​links"​ und '​r'​ für "​rechts"​ verwenden, die jeweils von einer Zahl gefolgt sind, die angibt, wieviel Gas der entsprechende Motor geben soll. Ein kompletter Befehl, der so in den Serial-Monitor eingegeben oder von Processing verschickt werden kann wäre also z.B. '​l100'​ oder '​r-20'​. 
 + 
 +Der Arduino Code dafür ​könnte z.B. so aussehen: 
 +<code C++> 
 +  if (Serial.available() > 0) { // Wenn Daten da sind... 
 +    int inByte = Serial.read();​ // ...dann lies das erste Byte und speichere es in der Variable inByte 
 +    switch (inByte) {           // und nimm den Wert, der übertragen wurde, genauer unter die Lupe. 
 +    case '​r': ​                  // wenn dieser das Zeichen '​r'​ für '​rechts'​ ist... 
 +      { 
 +      int inValue=Serial.parseInt(); ​            // dann lies erstmal eine Zahl ein (wenn irgendetwas anders kam, ist das Ergebnis 0 ) 
 +      digitalWrite(directionPinRight,​inValue>​0);​ // stelle den Motor auf '​vorwärts',​ wenn der wert größer 0 ist, sonst auf rückwärts 
 +      analogWrite(throttlePinRight,​ inValue); ​   // ... gib genau so viel Gas, wie gewünscht. 
 +      break; ​                   // höre hier auf. 
 +      } 
 +    case '​l': ​                  // ..links genauso: 
 +      { 
 +      int inValue=Serial.parseInt(); ​            // dann lies erstmal eine Zahl ein (wenn irgendetwas anders kam, ist das Ergebnis 0 ) 
 +      digitalWrite(directionPinLeft,​inValue>​0); ​ // stelle den Motor auf '​vorwärts',​ wenn der wert größer 0 ist, sonst auf rückwärts 
 +      analogWrite(throttlePinLeft,​ inValue); ​    // ... gib genau so viel Gas, wie gewünscht. 
 +      break; ​                   // höre hier auf. 
 +      } 
 +    default: // bei uns unbekannten Kommandos machen wir einfach garnichts... 
 +      break;  
 +   } 
 +</​code>​ 
 + 
 +Hier der passende Processing Code dazu: 
 + 
 +<code Java> 
 +/** 
 + * SendSomeInt 
 + *  
 + * Send numbers to a Serial Port 
 + * This example is in the public domain. 
 + */ 
 +import processing.serial.*; ​  //​verwende die '​Serial'​ Library
  
-Eine schöne Erweiterung auf mehrere verschiedene Kommandos ist durch Verwendung von switch/case möglich: +Serial myPort; ​  // Deklariere ein Object vom Typ 'Serial', mit dem Namen 'myPort'
-[[http://​www.arduino.cc/​en/​Tutorial/​SwitchCase2|Beispielprogramm ​''​control/​switchCase2'' ​aus dem Arduino IDE]] +
-=== Erweiterung auf Kommandos mit dazugehörigen Werten ===+
  
-Die Variante mit ''​switch/case'' ​lässt sich sehr schön ​mit dem hier Beschriebenen Empfang von Zahlen erweitern.+void setup() { 
 +  // Um den Namen der Schnittstelle herauszufinden,​ lassen wir uns von der Serial-Klasse zunächst 
 +  // eine Liste der Namen der am PC vorhandenen Ports geben ('Serial.list()'
 +  ​// Den x'ten Eintrag aus dieser Liste bekommen wir mit 'Serial.list()[x-1]'​ (die indices fangen ​mit 0 an) 
 +   
 +  // Bei den meisten PCs ist der Arduino der letzte Port in der Liste. 
 +  // Deshalb ermitteln wir zunächst die Länge der Liste (Serial.list().length)  
 +  // und nehmen uns den letzten Namen aus der Liste heraus (Serial.list()[Serial.list().length-1])  
 +   
 +  String portName = Serial.list()[Serial.list().length-1];​ // finde den Namen des letzten Serialports heraus. 
 +  int baudrate=115200; ​      // Diese Baudrate muss mit der in eurem Arduinoprogramm übereinstimmen. 
 +  //   ​String portName = "​COM1";​ // alternativ: verwende stattdessen einen bekannten Portnamen 
 +  myPort = new Serial(this,​ portName, baudrate); // Erzeuge ein Serial Objekt und stelle eine Verbindung her 
 +   
 +  size(300, 300); // mache das Fenster etwas größer 
 +}
  
-=== Beispielprogramm ===+void draw() { 
 +  int forwardSpeed(int)map(mouseY,​height,​ 0 , -127, 127); //rechne die y-Position des Mauszeigers in einen Schubwert zwischen -127 und 127 um. 
 +  // das (int) sorgt für die Umwandlung der Kommazahl in einen Ganzzahligen (integer) Wert. 
 +  int turnSpeed(int) map(mouseX, 0, height, -127, 127);   //​rechne die x-Position des Mauszeigers in ein Drehgeschwindigkeit zwischen -127 und 127 um. 
 +  int leftSpeed=forwardSpeed+turnSpeed; ​ //Zum Vorwärtsfahren drehen sich beide Motoren in die gleiche Richung, zum Drehen in Unterschiedliche 
 +  int rightSpeed=forwardSpeed-turnSpeed;​ 
 +  myPort.write('​l'​+str(leftSpeed)+"​\n"​); ​ //Sende erst '​l',​ dann die mit str() in eine Zeichenkette umgewandelte Zahl, dann einen Zeilenabschluss ("​\n"​) 
 +  myPort.write('​r'​+str(rightSpeed)+"​\n"​);​ //Sende erst '​r',​ dann die mit str() in eine Zeichenkette umgewandelte Zahl, dann einen Zeilenabschluss ("​\n"​) 
 +  println("​vor :"​+forwardSpeed+"​\tdreh:​ "​+turnSpeed+"​\t-->​ links:"​+leftSpeed+ "​\trechts:​ "​+rightSpeed);​ 
 +}
  
 +</​code>​
  
techniken/datenaustausch/serialchars.1421232036.txt.gz · Zuletzt geändert: 2016/01/21 12:45 (Externe Bearbeitung)