Obecnie pracuję nad projektem nr 14 książki projektowej Arduino.
Próbuję kontrolować szkic przetwarzania na laptopie za pomocą Arduino. Dokonuje się tego za pomocą potencjometru do sterowania tłem obrazu.
Kod Arduino:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.write(analogRead(A0)/4);
}
Przetwarzanie:
//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);
}
Teraz, gdy kod działa, a kolor tła zmienia się, gdy obracam potencjometr, istnieje ogromne opóźnienie między obróceniem potencjometru a widokiem zmiany koloru tła, a wartości z Arduino / potencjometru zmieniają się na monitorze szeregowym przetwarzania.
Co próbowałem:
- Zmiana prędkości komunikacji szeregowej
Zauważyłem, że kiedy zmniejszam prędkość komunikacji szeregowej, np. Około 100, opóźnienie między obróceniem potencjometru a jego zmianą na moim laptopie zmniejsza się do około 1 sekundy. Gdy jednak jeszcze bardziej zmniejszę prędkość komunikacji szeregowej, np. Wartość 1, opóźnienie ponownie wzrasta.
Z drugiej strony, przy standardowej prędkości 9600 opóźnienie jest ogromne, około 5 sekund ++, zanim zmiany w potencjometrze pojawią się na laptopie / procesorze.
Dlaczego zmniejszenie prędkości komunikacji (do pewnego punktu) zmniejsza opóźnienie czasowe, a zwiększenie go zwiększa opóźnienie czasowe? Poza tym, czy w ogóle mogę sprawić, że będzie to prawie natychmiastowe?
źródło
loop()
. Całkiem możliwe, że Twój program przetwarzania nie działa wystarczająco szybko, aby nadążyć za nim. Spróbuj opóźnićloop()
kod Arduino, aby go spowolnić; npdelay(50)
.Odpowiedzi:
Odczytujesz odczyt za każdym razem w Arduino
loop()
, więc wydaje się prawdopodobne, że twój program przetwarzania nie działa wystarczająco szybko, aby nadążyć za nim. Spróbuj wprowadzić opóźnienieloop()
w kodzie Arduino, aby go spowolnić, np .:O ile mi wiadomo, Przetwarzanie ma działać ze stałą szybkością klatek na sekundę, którą można modyfikować za pomocą tej
frameRate()
funkcji. Domyślnie jest to 60 klatek na sekundę, chociaż może działać wolniej na starszych systemach (lub tam, gdzie działa intensywny program). Możesz sprawdzić, jak szybko działa, czytającframeRate
zmienną.Wprowadzenie 50-milisekundowego opóźnienia w pętli Arduino oznacza, że będzie aktualizować się nieco poniżej 20 razy na sekundę. Oznacza to, że powinien być wystarczająco szybki do celów interfejsu użytkownika, ale powinien również mieścić się w zakresie możliwości Twojego programu przetwarzającego.
Jeśli chodzi o szybkość transmisji (prędkość komunikacji), dostosowanie jej o dowolne kwoty może mieć nieprzewidywalne skutki. Jest tak, ponieważ sprzęt obsługuje tylko określone prędkości, a próba użycia czegokolwiek innego może spowodować zniekształcenie danych na drugim końcu.
Serial.begin()
Dokumentacja ma trochę więcej informacji na temat obsługiwanych szybkości transmisji.źródło
Jak już wspomniano, twoje Arduino mówi za dużo za szybko. Dodanie
delay()
go spowolni, ale nadal będzie krzyczeć na przetwarzanie. Idealnie byłoby, gdyby Processing poprosił o wartość, gdy jest to wygodne, a następnie otrzymał jedną odpowiedź z Arduino.Enter
SerialEvent()
.W przeciwieństwie do
loop()
Arduino idraw()
Przetwarzania, wszystko w środkuserialEvent()
wzbudza się tylko wtedy, gdy w buforze szeregowym jest coś nowego. Zamiast przetwarzać pytania tak szybko, jak to możliwe, a Twoje Arduino krzyczy jeszcze szybciej, mogą odbyć miłą, uprzejmą (asynchroniczną) rozmowę.Zarówno Processing, jak i Arduino mają serialEvent. Jest to serialEvent () na Arduino i jest to serialEvent () w przetwarzaniu. Używając serialEvent po obu stronach, tak by się stało:
Przetwarzanie wysyła znak do połączenia szeregowego. Może to być dowolny znak, ale jeśli go z góry ustalimy, możemy odfiltrować wszelkie niepożądane żądania spowodowane np. Głośnym sygnałem. W tym przykładzie wysyłajmy za
V
każdym razem, gdy chcemy nowego odczytu twojego potencjometru. Po wysłaniu postaci kontynuujemy naszą działalność jak zwykle. Nie czekam tu na odpowiedź!Po stronie Arduino nic się nie dzieje, dopóki nie odbierze danych w buforze szeregowym. Sprawdza, czy nadchodząca postać jest i
V
, na szczęście, jest. Arduino odczytuje raz wartość potencjometru, raz przekazuje tę wartość do numeru seryjnego i wraca do relaksu, maksymalnie relaksując się całkowicie. Protip: zakończ wartość znakiem (*
w naszym przypadku). Pomoże ci to w następnym kroku.Przetwarzanie działa jak zwykle w przypadku interfejsów pikseli, gdy nagle dochodzi
do zakłócenia w wymuszaniunowych danych w buforze szeregowym. Przełącza się naserialEvent()
i zaczyna odczytywać dane szeregowe, aż do*
napotkania naszego zakończenia . Wiedząc na pewno, że był to ostatni znak, który warto przeczytać, możemy teraz zapisać przychodzącą wartość w zmiennej przechowującej odczyt Arduino.Otóż to. Przetwarzanie zna teraz nową wartość czujnika i kontynuuje wszystko, co mu każemy. Tymczasem Twoje Arduino cieszy się pogodą lub rozważa jej istnienie, dopóki nie pojawią się nadchodzące dane szeregowe.
źródło
Pętla odpytywania działa z pełną prędkością procesora i zapisuje do portu szeregowego w każdej rundzie.
W ten sposób piszesz znacznie częściej do portu szeregowego, niż może obsłużyć.
Port wypisuje dane tak szybko, jak je skonfigurowałeś, i buforuje dane, które przychodzą z twojego programu zbyt szybko , aby zapisać je jak najszybciej. Gdy bufor jest pełny, po prostu upuszcza nowe dane.
Ważne jest tutaj, aby zachował kolejność wartości: jest to bufor FIFO , działający w kolejności pierwsze wejście / pierwsze wyjście.
Co się dzieje:
Pętla wypełnia bufor portu i utrzymuje go w 100%.
Jeśli przekręcisz potencjometr, zmieniona wartość zostanie zapisana na końcu bufora , port działa tak szybko, jak to możliwe, aby zapisać wszystkie elementy w buforze, które nadal mają starą wartość.
I wreszcie wartość, którą jesteś zainteresowany. Najbardziej aktualną wartością, którą chcieliśmy zobaczyć od razu, było na końcu FIFO, a pierwsze wejście / pierwsze wyjście oznacza również ostatnie wejście / ostatnie wyjście. Przeciwieństwo tego, czego chcemy.
Maksymalna częstotliwość, którą ma sens odczytanie danych, to częstotliwość, którą możesz zapisać, więc powinieneś użyć przynajmniej opóźnienia, które jest wystarczająco długie, aby zapisać bajty przy bieżącej prędkości portu.
Jako kolejną niezależną metodę zapobiegania tego rodzaju opóźnieniom
można dodatkowo ustawić bufor zapisu portu na minimum.
To spowodowałoby, że dane byłyby upuszczane znacznie wcześniej, zamiast buforować dużo wcześniej.
Oczywiście w wielu aplikacjach nie jest to potrzebne; Przy nieszczęściu może i tak działać na początku i stać się niestabilny w niektórych sytuacjach, gdy czas zmienia się w zależności od takich rzeczy, jak obciążenie procesora, a tylko niektóre losowe próbki danych są upuszczane. Duży bufor zwykle działa znacznie bardziej deterministycznie, więc domyślnie używaj dużego bufora .
źródło
Zamiast ciągłego wysyłania danych szeregowych, wysyłaj dane tylko wtedy, gdy wartość potencjometru zmieniła się powyżej określonego progu.
źródło
loop()
nie wypełnia bufora wyjściowego równymi próbkami, to dobrze. Ale nadal działa z pełną prędkością procesora, która może być 100 razy szybsza niż jest to potrzebne. Oznacza to, że nadal może szybko wypełnić bufor do limitu, jeśli dane wejściowe często się zmieniają, np. Z szumu powyżejthreshold
lub ciągła zmiana wysokiej rozdzielczości (co nie ma miejsca w przykładowej aplikacji tutaj)Dwa proste rozwiązania, które z pewnością będą działać dla każdego, kto wciąż szuka: -
Zwiększ opóźnienie do 50 do 100 milisekund.
Dodaj to po
Serial.begin(9600)
wsetup()
;Najważniejszy jest drugi krok. Działa to dla mnie dopiero po dodaniu powyższego kodu. Nie jest to często wspominane na wielu innych forach, na które patrzyłem, gdy miałem dokładnie ten sam problem.
źródło