Heute bin ich bei Arduino über die erste richtige Knacknuss gestolpert. Die Aufgabenstellung schien einfach: die Geschwindigkeit eines Spielzeug-Gleichstrommotors soll über die serielle Schnittstelle mit Werten von 0 bis 255 verändert werden. Die Hardware ist dieselbe wie gestern, der Pushbutton bleibt ohne Funktion. Hier noch einmal der Bestückungsplan für das Schaltbrett:
Solange Arduino am PC hängt und die Entwicklungumgebung läuft, kann man das direkt über Tools – Serial monitor ausprobieren. Die erste Hürde waren die Datentypen und die Typenkonversion. Arduino versteht eben kein Java, auch wenn es zuerst fast so aussieht. Also musste ich mich erst mal schlau machen, welche Datentypen die Arduino-Sprache kennt und was mir die serielle Schnittstelle eigentlich schickt. Während bei den Zahlen mein Javawissen funktionierte, gab es bei den Strings ein paar Hürden. Hier sind die Typen, die für die Aufgabe eine Rolle spielten:
- char: einzelnes Zeichen, Länge 1 Byte; aus der seriellen Schnittstelle kommen einzelne chars zurück
- Array of char (string): Array von Einzelzeichen mit fixer Länge; das ist der gängige Typ, um Strings in Arduino zu verarbeiten; klein, schlank und tückisch, unten mehr davon
- String-Objekt: würde eigentlich wieder Java entsprechen, mit komfortablen Methoden. Allerdings ist es mir nicht gelungen, die chars aus der Schnittstelle in einen String zu verketten. Die Werte waren absolut wild, ich vermute ein Zeichensatzproblem.
Soweit war alles klar: aus der Schnittstelle mit Serial.read() in einer Schleife einzelne Zeichen abfischen, in ein Array of char füllen, mit der Funktion atoi in einen Integer umwandeln und mit analogWrite an den Motor senden.
Ich öffne also den Monitor, gebe 70 ein. Das Motörchen beginnt tatsächlich zu schnurren. Nun erhöhe ich auf 120, das Surren schwillt an. 150, 170, 190, alles klappt wie am Schnürchen. Dann gehe ich zurück auf 60. Upps! Statt abzubremsen läuft der Motor so schnell wie noch nie!
Nun kommt der harte Teil, debuggen mit Arduino. Die einzige Methode, die ich bis jetzt kenne, erinnert ans gute alte ASP: mit Serial.println Werte auf dem Monitor ausgeben und nachdenken. Bald ist mir klar, dass bei der Eingabe von zweistelligen Zahlen die dritte Stelle aus dem vorangegangenen Durchlauf erhalten bleibt. Aus 60 wird somit 600.
Wie dumm von mir, ich habe das Zurücksetzen der Array-Variable vergessen. Und genau hier laufe ich in den Hammer. Sämtliche Syntaxvarianten, die mir in Anlehnung an andere Sprachen in den Sinn kommen, funktionieren nicht. Entweder sie lassen sich nicht kompilieren oder sie werden ignoriert oder der Motor setzt sich gar nicht in Bewegung. Erst memset, das alle Stellen eines Array auf 0 setzt, bringt die Erlösung. Und dann muss ich noch merken, dass
char incoming[4] = {}; ... if (sizeof(incoming) > 0) {...}
eine absolut sinnlose Bedingung ist für einen Array mit fixer Länge, weil die definierte Länge des Arrays zurückgeliefert wird, und nicht etwa die tatsächliche Anzahl Zeichen darin. Damit hatte ich nun alles beisammen für eine fehlertolerante Motorsteuerung. Übrigens funktioniert der Code auch bei der Eingabe von Buchstaben. In diesem Fall wird der Motor angehalten.
Hier nun also der vollständige Code:
/* * Motorengeschwindigkeit über serielle Schnittstelle regeln * Author: Silvia Rothen, rothen ecotronics, Bern, Switzerland */ int motorPin = 9; // an diesem Pin hängt der Motor int val = 0; //zuerst steht der Motor char incoming[4] = {}; //wegen Endzeichen void setup() { Serial.begin(9600); // connect to the serial port pinMode(motorPin, OUTPUT); } void loop() { int i = 0; if (Serial.available() > 0) { //sonst bleiben die 0 erhalten 60 -> 600 memset(incoming, 0, sizeof(incoming)); while (Serial.available() > 0 && i < sizeof(incoming) - 1) { incoming[i] = Serial.read(); i++; delay(3); } //array of char in int wandeln val = atoi(incoming); //Geschwindigkeit limitieren if (val < 0) { val = 0; } else if (val > 255) { val = 255; } Serial.print("Umlaufgeschwindigkeit "); Serial.println(val); //Motorgeschwindigkeit setzen analogWrite(motorPin, val); } }