Ich bin derzeit auf Projekt # 14 des Arduino-Projektbuchs.
Ich versuche, mit meinem Arduino eine Verarbeitungsskizze auf meinem Laptop zu steuern. Dies wird erreicht, indem ein Potentiometer verwendet wird, um den Hintergrund eines Bildes zu steuern.
Arduino-Code:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.write(analogRead(A0)/4);
}
Wird bearbeitet:
//imports serial library
import processing.serial.*;
//setups the serial object
Serial myPort;
//creates an object for the image
PImage logo;
//variable to store background color
int bgcolor = 0;
void setup(){
colorMode(HSB,255);
logo = loadImage("http://arduino.cc/logo.png");
size(logo.width,logo.height);
println("Available serial ports");
println(Serial.list());
myPort = new Serial(this,Serial.list()[0],9600);
}
//equivalent of arduino's loop function
void draw(){
if(myPort.available() > 0)
{
bgcolor = myPort.read();
println(bgcolor);
}
background(bgcolor,255,255);
image(logo,0,0);
}
Nun, während der Code funktioniert und sich die Hintergrundfarbe ändert, wenn ich das Potentiometer drehe, gibt es eine große Verzögerung zwischen dem Drehen des Potentiometers und dem Erkennen der Hintergrundänderungsfarbe, und die Werte vom Arduino / Potentiometer ändern sich auf dem seriellen Monitor der Verarbeitung.
Was ich versucht habe:
- Ändern der Geschwindigkeit der seriellen Kommunikation
Ich habe festgestellt, dass sich die Verzögerung zwischen dem Drehen des Potentiometers und der Änderung auf meinem Laptop auf etwa 1 Sekunde verringert, wenn ich die Geschwindigkeit der seriellen Kommunikation verringere, z. B. um 100. Wenn ich jedoch die Geschwindigkeit der seriellen Kommunikation weiter absenke, z. B. auf den Wert 1, erhöht sich die Verzögerung erneut.
Auf der anderen Seite ist die Verzögerung bei der Standardgeschwindigkeit von 9600 sehr groß, ungefähr 5 Sekunden ++, bevor die Änderungen am Potentiometer auf dem Laptop / der Verarbeitung angezeigt werden.
Warum wird durch Verringern der Kommunikationsgeschwindigkeit (bis zu einem bestimmten Punkt) die Zeitverzögerung verringert und durch Erhöhen die Zeitverzögerung erhöht? Auch gibt es überhaupt ich kann es fast sofort machen?
quelle
loop()
. Es ist gut möglich, dass Ihr Verarbeitungsprogramm nicht schnell genug läuft, um damit Schritt zu halten. Versuchen Sie, eine Verzögerung inloop()
Ihren Arduino-Code einzufügen, um ihn zu verlangsamen. zBdelay(50)
.Antworten:
Sie geben jedes Mal einen Messwert auf dem Arduino aus
loop()
, sodass es wahrscheinlich ist, dass Ihr Verarbeitungsprogramm nicht schnell genug läuft, um damit Schritt zu halten. Versuchen Sie, eine Verzögerung inloop()
Ihren Arduino-Code einzufügen, um ihn zu verlangsamen, zB:Soweit ich weiß, zielt die Verarbeitung auf eine konsistente Bildrate ab, die Sie mit der
frameRate()
Funktion ändern können. Standardmäßig sind es 60 Bilder pro Sekunde, obwohl es auf älteren Systemen möglicherweise langsamer läuft (oder wenn Sie ein intensives Programm ausführen). Sie können überprüfen, wie schnell es läuft, indem Sie dieframeRate
Variable lesen .Das Einfügen einer Verzögerung von 50 Millisekunden in die Arduino-Schleife bedeutet, dass sie etwas weniger als 20 Mal pro Sekunde aktualisiert wird. Das bedeutet, dass es für Zwecke der Benutzeroberfläche schnell genug sein sollte, aber auch innerhalb der Fähigkeiten Ihres Verarbeitungsprogramms liegen sollte.
Wenn Sie die Baudrate (Kommunikationsgeschwindigkeit) beliebig anpassen, kann dies zu unvorhersehbaren Ergebnissen führen. Dies liegt daran, dass die Hardware nur bestimmte Geschwindigkeiten unterstützt und der Versuch, etwas anderes zu verwenden, dazu führen kann, dass die Daten am anderen Ende unkenntlich gemacht werden. In der
Serial.begin()
Dokumentation finden Sie weitere Informationen zu den unterstützten Baudraten.quelle
Wie bereits erwähnt, sagt Ihr Arduino zu viel zu schnell. Das Hinzufügen
delay()
verlangsamt die Verarbeitung, brüllt sie jedoch weiterhin an. Im Idealfall soll Processing nach dem gewünschten Wert fragen und dann eine Antwort von Ihrem Arduino erhalten.Eintreten
SerialEvent()
.Im Gegensatz zu
loop()
auf Ihrem Arduino unddraw()
in der Verarbeitung wird alles im InnerenserialEvent()
nur dann ausgeführt, wenn sich etwas Neues im seriellen Puffer befindet. Anstatt also Fragen so schnell wie möglich zu stellen und Ihr Arduino noch schneller zurückschreit, können sie eine nette, höfliche (asynchrone) Unterhaltung führen.Sowohl Processing als auch Arduino haben ein serialEvent. Dies ist serialEvent () auf dem Arduino und dies ist serialEvent () in der Verarbeitung. Wenn Sie serialEvent auf beiden Seiten verwenden, passiert Folgendes:
Die Verarbeitung sendet ein Zeichen an die serielle Verbindung. Dies kann ein beliebiges Zeichen sein. Wenn wir jedoch ein Zeichen vorgeben, können wir unerwünschte Anforderungen herausfiltern, die z. B. durch ein verrauschtes Signal verursacht werden. In diesem Beispiel senden
V
wir jedes Mal ein, wenn wir eine neue Anzeige Ihres Potentiometers wünschen. Nachdem der Charakter gesendet wurde, setzen wir unser Geschäft wie gewohnt fort. Ich warte hier nicht auf eine Antwort!Auf der Arduino-Seite passiert nichts, bis es Daten im seriellen Puffer empfängt. Es wird geprüft, ob der eingehende Charakter ein a ist
V
, und glücklicherweise ist es ein a. Der Arduino liest den Wert des Potentiometers einmal, gibt diesen Wert einmal seriell aus und kehrt zum Chillen zurück, wobei er sich maximal kühl entspannt. Protip: Beende den Wert mit einem Zeichen (*
in unserem Fall). Dies wird Ihnen im nächsten Schritt helfen.Die Verarbeitung erledigt ihr normales Geschäft mit Schnittstellenpixeln, wenn plötzlich
eine Störung in der Erzwingungneuer Daten im seriellen Puffer auftritt. Es wechselt zuserialEvent()
und beginnt mit dem Lesen der seriellen Daten, bis unsere Beendigung*
eintrifft. Da wir sicher sind, dass dies das letzte lesenswerte Zeichen war, können wir den eingehenden Wert in einer Variablen speichern, die den Arduino-Messwert speichert.Das ist es. Die Verarbeitung kennt nun den neuen Sensorwert und setzt fort, was wir ihm befehlen. Währenddessen genießt Ihr Arduino das Wetter oder denkt über seine Existenz nach, bis es eingehende serielle Daten gibt.
quelle
Ihre Abfrageschleife läuft mit der vollen Geschwindigkeit Ihres Prozessors und schreibt in jeder Runde auf den seriellen Port.
Auf diese Weise schreiben Sie viel häufiger an den seriellen Anschluss, als er verarbeiten kann.
Der Port schreibt Daten so schnell aus, wie Sie es konfiguriert haben, und puffert Daten , die von Ihrem Programm zu schnell eingehen , um sie so schnell wie möglich auszulesen. Wenn der Puffer voll ist, werden nur neue Daten abgelegt.
Wichtig ist hierbei, dass die Reihenfolge der Werte beibehalten wird: Es handelt sich um einen FIFO-Puffer , der in der Reihenfolge First In / First Out arbeitet.
Was passiert ist:
Die Schleife füllt den Port-Puffer und hält ihn zu 100% voll.
Wenn Sie das Potentiometer drehen, wird der geänderte Wert an das Ende des Puffers geschrieben . Der Port arbeitet so schnell wie möglich, um alle Elemente im Puffer auszuschreiben, die noch den alten Wert haben.
Und schließlich der Wert, an dem Sie interessiert sind. Der aktuellste Wert, den wir sofort sehen wollten, befand sich am Ende des FIFO, und first in / first out bedeutet auch last in / last out. Das Gegenteil von dem, was wir wollen.
Die maximale Häufigkeit, mit der das Lesen Ihrer Daten sinnvoll ist, ist die Häufigkeit, mit der Sie sie auslesen können. Verwenden Sie daher mindestens eine Verzögerung, die ausreicht, um die Bytes mit der aktuellen Portgeschwindigkeit auszuschreiben.
Als weitere unabhängige Maßnahme, um diese Art von Verzögerung im Allgemeinen zu verhindern, können
Sie den Schreibpuffer des Ports zusätzlich auf ein Minimum setzen.
Dies würde dazu führen, dass Daten viel früher gelöscht werden, anstatt viel zuerst zu puffern.
In vielen Anwendungen ist das natürlich nicht das, was Sie brauchen. Mit etwas Pech könnte es am Anfang trotzdem funktionieren und in einigen Situationen instabil werden, wenn sich das Timing aufgrund von Dingen wie der Prozessorauslastung ändert und nur einige zufällige Datenstichproben fallengelassen werden. Ein großer Puffer verhält sich im Allgemeinen sehr viel deterministischer. Verwenden Sie daher standardmäßig einen großen Puffer .
quelle
Anstatt ständig serielle Daten zu senden, senden Sie Daten nur, wenn sich der Wert des Potentiometers über einen bestimmten Schwellenwert geändert hat.
quelle
loop()
füllt den Ausgabepuffer nicht mit gleichen Samples, das ist gut. Es läuft jedoch immer noch mit der vollen Geschwindigkeit des Prozessors, die möglicherweise 100-mal so schnell ist, wie sie benötigt wird. Das heißt , es kann immer noch schnell den Puffer bis an die Grenze füllen , wenn die Eingabe häufig ändert, zB von Rauschen obenthreshold
, oder eine kontinuierliche Veränderung in hohen Auflösung (was nicht der Fall in der Beispielanwendung ist hier)Zwei einfache Lösungen, die für jeden, der noch auf der Suche ist, garantiert funktionieren:
Erhöhen Sie die Verzögerung auf 50 bis 100 Millisekunden.
Fügen Sie dies nach dem
Serial.begin(9600)
insetup()
;Schritt zwei ist der wichtigste. Es funktionierte nur für mich, nachdem ich den obigen Code hinzugefügt hatte. Dies wird in vielen anderen Foren, in denen ich nach genau dem gleichen Problem gesucht habe, nicht sehr oft erwähnt.
quelle