Jeffrey Cross
Jeffrey Cross

Codebox: Behandlung von Ausnahmen bei der Verarbeitung

In der Codebox: Speichern Sie Sensordaten in Google Spreadsheets. Leser Stairs stellte fest, dass die Skizze explodierte, wenn kein Arduino-Gerät angeschlossen war. Als er das Gerät ausgegraben, eingesteckt und die Skizze neu gestartet hatte, funktionierte es einwandfrei.

Dies veranschaulicht einen großartigen Punkt in Bezug auf Verarbeitung, Programmierung und allgemeines Leben: Wir leben in einer unvollkommenen Welt. Nette kleine Skizzen beginnen, ohne dass ein Arduino angeschlossen ist, die Zahlen werden durch Null geteilt, die Leute laufen mit einer Schere und so weiter und so fort. In der Verarbeitung werden Bedingungen wie diese aufgerufen Ausnahmen, und dieser Beitrag bietet eine sanfte Einführung in den Umgang mit (oder offiziell Griff) Sie. (Achtung: Dieser Beitrag verhindert nicht das Laufen mit einer Schere.)

Also, wie lässt sich Processing zuerst wissen, wenn etwas wirklich schief gelaufen ist? Im Allgemeinen (es sei denn, etwas ist extrem schief gelaufen!), Beginnen Sie die Skizze und sehen dann etwas wie die folgende Abbildung:

Beachten Sie alle roten Fehlermeldungen im Meldungsbereich. Dort erfahren Sie, was bei einem Fehler aufgetreten ist. In diesem Fall lautet der Fehler PortInUseException ()Wenn Sie mit dem Googeln beginnen, werden Sie feststellen, dass Sie in der Verarbeitung einen etwas schlechten Ruf haben. (Mehr dazu später.) In der Meldung wird auch angegeben, in welcher Zeile der Fehler aufgetreten ist geworfen. Darüber hinaus wird die fehlerhafte Zeile im Texteditor gelb hervorgehoben. Je nachdem, wo der Fehler auftritt, wird das Skizzenfenster möglicherweise angezeigt oder nicht, und selbst wenn es sichtbar ist, wird es mit Sicherheit nicht das tun, was Sie erwarten.

Fügen Sie den Text für simple_port.pde in Processing ein, um diesen Fehler zu reproduzieren (oder einen ähnlichen Fehler - siehe den Abschnitt mit den Einschränkungen am Ende des Beitrags!). Wenn alles gut geht, liest die Skizze den seriellen Port einmal pro Sekunde und zeigt die verstrichene Zeit und den vom Port gelesenen Wert an.

Natürlich möchten wir nicht, dass alles gut geht (das ist der Sinn dieses Beitrags). Stellen Sie also sicher, dass Ihr Arduino beim Ausführen der Skizze nicht angeschlossen ist. Sie sollten etwas sehen, das der vorherigen Abbildung ähnelt. Jetzt können wir Code hinzufügen, mit dem (oder Griff, das ist der formale Begriff) das getrennte Gerät.

Um eine Ausnahme in Processing zu behandeln (und Java, von denen Processing eine Teilmenge ist), platzieren wir den verdächtigen Code in einem Block „try-catch-finally“. Die Verarbeitung „versucht“ dann, den Code auszuführen, und wenn Ausnahmen ausgelöst werden, werden sie von anderen Blöcken „erfasst“. Die Syntax sieht so aus:

Versuchen { Der verdächtige Code, den Sie ausführen möchten ...} catch (ExceptionType1 e1) { // Code, der ausgeführt werden soll, wenn ExceptionType1 im try-Block ausgelöst wird println (e1.getMessage ()); ...} catch (ExceptionType1 e2) { // Code, der ausgeführt werden soll, wenn ExceptionType2 im try-Block ausgelöst wird println (e2.getMessage ()); ...} catch (ExceptionType3 e3) { // Code, der ausgeführt werden soll, wenn ExceptionType3 im try-Block ausgelöst wird println (e3.getMessage ()); ... } endlich { // Code hier aufräumen ... }

Da Ausnahmen in Getting Started with Processing nicht behandelt werden, lassen Sie mich einige allgemeine Fragen beantworten, die Sie möglicherweise haben:

  • Was meinst du mit verdächtiger Code? Anfangs kann es sein, dass der gesamte Code verdächtig ist. Die Ausnahmebehandlung wird jedoch meistens in einigen wenigen wichtigen Situationen verwendet, z. B. Lesen oder Schreiben in eine Datei, Übertragen von Daten über ein Netzwerk oder Kommunikation mit einem Gerät (z. B. einer seriellen Schnittstelle). In vielen Bibliotheken müssen Sie bestimmte Methoden in einen try-catch-Block einschließen, da der Code überhaupt nicht kompiliert werden kann. Wenn Sie beispielsweise den try-Block aus dem Google-Tabellencode entfernt haben, wird das Programm nicht einmal kompilieren. Bibliotheksdesigner tun dies, um Programmierer in gute Gewohnheiten zu zwingen.
  • Worum handelt es sich bei all diesen Aussagen? Da Code auf vielerlei Weise schief gehen kann, müssen wir mit vielen verschiedenen Möglichkeiten umgehen können. Daher ist jede catch-Anweisung einem bestimmten Fehlertyp zugeordnet. Wenn diese bestimmte Art von Fehler auftritt, wird der entsprechende Codeblock ausgeführt. Angenommen, Sie haben versucht, einige Daten aus einer Datei zu lesen. Die Datei existiert möglicherweise einfach nicht, wodurch eine FileNotFoundException Ausnahme. Oder die Datei ist möglicherweise vorhanden, aber während des Lesens ist sie irgendwie nicht verfügbar. Das wirft ein EOFException. Oder im IO-Stream passiert etwas ganz Ungewöhnliches, das einen Hagel wirft IOException. Sie können für jeden dieser Umstände einen Fangblock erstellen. Die beste Analogie ist der auf Seite 64 des Handbuchs Erste Schritte beschriebene Wenn-dann-ander-Block.
  • Was bedeutet das Zeug in den Klammern nach catch? Dies sind Argumente für eine Funktion. Das erste Token gibt den Typ der Ausnahme an, die den Block auslösen soll, und das zweite ist eine Variable, mit der Sie auf die Daten und Methoden der Ausnahme zugreifen können. (Ausnahmen sind wie alles in Bearbeitung Objekte.) Zum Beispiel, wenn Sie eine solche Zeile hätten: catch (FileNotFoundException e)würde der Block ausgeführt, wenn der Code im try-Block eine gesuchte Datei nicht finden konnte. Innerhalb des Blocks müsste eine Variable aufgerufen werden e dass Sie verwenden könnten, um mehr darüber zu erfahren, was falsch lief. Zum Beispiel könnten Sie es verwenden getMessage () Methode, um die Details des Fehlers in den Meldungsbereich zu drucken
  • Ist die Reihenfolge der catch-Anweisungen von Bedeutung? Ja. Die Verarbeitung löst den ersten catch-Block aus, der der Klasse oder der Superklasse der Ausnahme entspricht. Da Objekte hierarchisch sind, bedeutet dies, dass einige Ausnahmen in der Nahrungskette höher sind als andere. Folglich passen sie fast alles zusammen. (Die höchste Ausnahmeklasse wird aufgerufen Ausnahme, das passt zu allem.) Daher müssen Sie die spezifischsten Ausnahmen zuerst und später allgemeine Ausnahmen setzen.
  • Was bedeutet "endlich"? Das endlich block ist optional und ermöglicht das Hinzufügen von Code, der dies tun soll immer führt aus, ob ein Fehler auftritt oder nicht. Dies wird normalerweise für Bereinigungscode verwendet. Wenn Sie beispielsweise eine Datei öffnen, möchten Sie sie möglicherweise im finally-Block schließen.
  • Was ist, wenn ich in meinen Fangblöcken nicht die genaue Art von Fehler habe? Die kurze Antwort ist, dass Ihr Programm explodiert. Dies ist eine Situation, genannt eine unbehandelte Ausnahmeversuchen Sie generell zu vermeiden. Als letzten Haken können Sie einfach eine catch (Ausnahme e) als letzter Fangblock. Dies ist der allgemeinste Typ von Ausnahmeobjekten, daher sollten die meisten Fehler erkannt werden.

Wütend. Genug Theorie. Kehren wir zum ursprünglichen Problem zurück, dass verhindert wird, dass unser Code explodiert. (Dennoch haben wir nur die Oberfläche zerkratzt. Wenn Sie mehr erfahren möchten, lesen Sie Lesson: Exceptions, ein großartiges Tutorial von Oracle.)

Da sprengt unser Code die Leitung port = new Serial (dies ist arduinoPort, 9600);Dies ist ein naheliegender Ort, um einen Try-Catch-Block zu setzen. Wir möchten, dass der Code testet, ob es überhaupt Ausnahmen in dieser Zeile gibt (es ist uns egal, was), und wenn dies der Fall ist, wird eine "Plug in Arduino" -Meldung angezeigt. Sobald ein Arduino angeschlossen ist, möchten wir den Zähler und den aktuellen Wert von der seriellen Schnittstelle anzeigen. Hier ist eine überarbeitete Version des Codes, simple_port2.pde, die dies tut.

Wenn Sie diesen Code ausführen, sollten Sie etwa die folgende Abbildung sehen.

Was passiert also hier? Das erste, was Sie bemerken werden, ist, dass ich die störende Linie aus der entfernt habe Konfiguration() Methode und in die zeichnen() Methode. Dadurch wird sichergestellt, dass die Skizze wiederholt überprüft wird, ob das Arduino gefunden wurde. den Test in durchführen Konfiguration() würde bedeuten, dass es nur einmal geschieht, wenn die Skizze beginnt. Als Nächstes habe ich eine Flagge mit dem Namen erstellt ardinoOK - Wenn dieses Flag "false" ist, möchten wir versuchen, den Port zu packen und die Fehlermeldung anzuzeigen. Wenn das Flag wahr wahr ist, möchten wir den Port lesen und die Werte anzeigen. Zum Schluss habe ich die eingebettet port = new Serial (dies ist arduinoPort, 9600); Zeile innerhalb eines Try-Catch-Blocks. Wenn der Befehl erfolgreich ist, setzen wir arduinoOK um wahr zu sein. Wenn eine Ausnahme auftritt, fangen wir sie mit catch (Ausnahme e) blockieren und setzen arduinoOK zu falsch Da ist dieser Code drin zeichnen()wiederholt es diese Logik immer wieder. Voila!

Vorsichtsmaßnahmen

Wie ich bereits angedeutet habe, war die Ausnahmebehandlung für dieses Projekt etwas schwierig. Zum Beispiel meldete Stairs (der Leser, dessen Kommentar mit diesem Beitrag begonnen hat) eine ArrayIndexOutOfBoundsExeption. Das implizierte, dass der Code in der Luft aufging String arduinoPort = Serial.list () [0]:zeigt an, dass es keine Geräte gab. "Ha", dachte ich, ich teste gerade diese Ausnahme. Als ich es jedoch auf meinem Mac ausführte, habe ich bereits mehrere Geräte in der Liste gefunden, so dass es nicht mit dem gleichen Fehler in der Luft ging, den Stairs bekam. Pluggin im Arduino fügte der Liste lediglich zwei neue Elemente hinzu (siehe folgende Tabelle).

Kein Arduino installiert Arduino installiert
Stabile Bibliothek ============================================== Native lib Version = RXTX-2.1 -7 Java lib Version = RXTX-2.1-7 [0] "/dev/tty.Bluetooth-Modem" [1] "/dev/cu.Bluetooth-Modem" [2] "/dev/tty.Bluetooth-PDA- Sync "[3]" /dev/cu.Bluetooth-PDA-Sync " Stabile Bibliothek ============================================== Native lib Version = RXTX-2.1 -7 Java lib Version = RXTX-2.1-7 [0] "/dev/tty.usbmodem1d11" [1] "/dev/cu.usbmodem1d11" [2] "/dev/tty.Bluetooth-Modem" [3] " /dev/cu.Bluetooth-Modem "[4]" /dev/tty.Bluetooth-PDA-Sync "[5]" /dev/cu.Bluetooth-PDA-Sync "Experimentell: JNI_OnLoad aufgerufen.

Ein wenig Googling hat gezeigt, dass Macs standardmäßig ein paar Prozesse ausführen, um neue Geräte wie Kameras oder Bluetooth-Geräte aufzunehmen. Ich dachte also, Treppen müssen auf einem PC sein, auf dem diese Gegenstände nicht vorhanden sind.

Mein Code wurde jedoch immer noch explodiert, allerdings mit einem anderen Fehler: gnu.io.PortInUseException. „Ha !,“ Ich kann das einfach fangen. Aber das hat auch nicht funktioniert. Beim Googeln entdeckte ich, dass es unter OS X einen seltsamen Fehler gibt, der das Auffinden dieser Ausnahme problematisch macht, und dass Sie verschiedene Teile der seriellen Bibliothek neu installieren oder löschen müssen, damit sie funktionieren. Das hat auch nicht funktioniert. Schließlich entschied ich mich gerade, das allgemeinste zu fangen Ausnahme um es zur Arbeit zu bringen.

Dann wollte ich noch ein bisschen mehr darüber erfahren, wie Sie Fehler beim Ausführen der Skizze feststellen. Insbesondere wollte ich den Fall behandeln, in dem das Arduino angeschlossen ist, die Skizze läuft und Sie sie während des Streams trennen. Als ich dies versuchte, erhielt ich jedoch eine Fehlermeldung, die vom Betriebssystem zu stammen schien:

Da es in der Nahrungskette höher gehandhabt wurde, floss der Fehler ausnahmsweise nie in die Verarbeitung, sodass die Skizze nur lustig summte. Hmmm, dachte ich. Ein bisschen Googling hat gezeigt, dass es sehr schlecht ist, das zu tun, was ich geplant habe, und dass es zu allen möglichen Problemen führen kann. Ich denke, der Mac hat Sicherheitsvorkehrungen eingebaut, um Downstream-Probleme zu vermeiden. Ich denke, ich sollte dankbar sein, aber es hat mich für dieses Beispiel beschimpft.

All dies zeigt, dass es wirklich sehr schwierig sein kann, Programmierfehler zu bestimmen, weil es so viele Komplexitäten und Abhängigkeiten gibt. Ich denke, das ist wahrscheinlich der Grund, warum so viele Programmierer zu Makern werden. In einem Beruf, in dem 6 Monate eine Ewigkeit sein können, ist es zufriedenstellend zu wissen, dass die Maschinen, die Sie aus Getrieben und Hebeln bauen, für Aristoteles wahrscheinlich verständlich sind. Ehrlich gesagt ist es unglaublich, dass die Welt genauso reibungslos läuft wie sie.

Danke, Ausnahmebehandler überall!

In der Schuppenhalle:


Erste Schritte mit Processing Lernen Sie die Computerprogrammierung auf einfache Weise mit Processing, einer einfachen Sprache, mit der Sie Code zum Erstellen von Zeichnungen, Animationen und interaktiven Grafiken verwenden können. Programmierkurse beginnen normalerweise mit der Theorie, aber in diesem Buch können Sie direkt in kreative und unterhaltsame Projekte einsteigen. Es ist ideal für alle, die grundlegende Programmierung erlernen möchten, und ist eine einfache Einführung in die Grafik für Personen mit Programmierkenntnissen.

Aktie

Leave A Comment