Arduino ile bilgisayarımdaki işleme çizimi arasındaki gecikmeyi azaltma


13

Şu anda Arduino proje kitabının 14. projesinde bulunuyorum.

Arduino'yu kullanarak dizüstü bilgisayarımdaki bir işleme taslağını kontrol etmeye çalışıyorum. Bu, bir görüntünün arka planını kontrol etmek için bir potansiyometre kullanılarak gerçekleştirilir.

Arduino kodu:

void setup(){
  Serial.begin(9600);
}

void loop(){
  Serial.write(analogRead(A0)/4);
}

İşleme:

//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);
}

Şimdi, kod çalışırken ve potansiyometreyi döndürdüğümde arka plan rengi değişirken, potansiyometreyi döndürmek ve arka plan rengini görmek ve işlemin seri monitöründeki Arduino / potansiyometreden gelen değerler arasında büyük bir gecikme var.

Ne denedim:

  • Seri iletişim hızını değiştirme

Seri iletişimin hızını düşürdüğümde, örneğin 100 civarında, potansiyometreyi döndürmek ve dizüstü bilgisayarımda değiştiğini görmek arasındaki gecikmenin yaklaşık 1 saniyeye düştüğünü fark ettim. Ancak Seri iletişimin hızını daha da düşürdüğümde, örneğin 1 değeri, gecikme tekrar artar.

Flip tarafında, standart 9600 hızında, potansiyometredeki değişiklikler dizüstü bilgisayarda / işlemede görünmeden önce gecikme çok büyüktür, kabaca 5sn ++.

İletişim hızını azaltmak (belirli bir noktaya kadar) neden gecikmeyi azaltır ve arttırmak zaman gecikmesini artırır? Ayrıca, anında yakın yapabileceğim bir şey var mı?


3
Arduino'da her seferinde bir okuma yapıyorsunuz loop(). İşleme programınızın buna ayak uyduracak kadar hızlı çalışmaması oldukça olasıdır. loop()Yavaşlatmak için Arduino kodunuza bir gecikme koymayı deneyin ; örn delay(50).
Peter Bloomfield

Merhaba peter, hızlı cevap için teşekkürler, küçük bir gecikme ekleyerek gerçekten sorunumu çözdü. Yine de başka bir küçük soru, bu tekrar olmasını önlemek için gelecekte benim işleme programı hızını belirlemek için herhangi bir yolu var mı, ya da daha iyi bir dizüstü bilgisayar / işlem hızı elde sorunu çözmek? ? Bir iletişim 250 hızını veya Arduino okumaları 300 mess giren etmez neden Ayrıca, (I elde edilen okuma, okuma ve sıfır Örneğin 147,0,147,0 arasında alternatif olarak)
Kenneth .J

Yanıtlar:


11

Arduino'da her seferinde bir okuma yapıyorsunuz loop(), bu yüzden İşleme programınız buna ayak uyduracak kadar hızlı çalışmıyor gibi görünüyor. loop()Yavaşlatmak için Arduino kodunuzdaki bir gecikmeyi koymayı deneyin , örneğin:

void loop(){
    Serial.write(analogRead(A0)/4);
    delay(50);
}

Bildiğim kadarıyla, Processing frameRate()işlevi kullanarak değiştirebileceğiniz tutarlı bir kare hızında çalışmayı amaçlamaktadır . Varsayılan olarak, eski sistemlerde (veya yoğun bir program çalıştırdığınız yerde) daha yavaş çalışmasına rağmen, saniyede 60 karedir. frameRateDeğişkeni okuyarak ne kadar hızlı çalıştığını kontrol edebilirsiniz .

Arduino döngüsüne 50 milisaniye gecikme eklenmesi, saniyede 20 kereden biraz daha az güncelleneceği anlamına gelir. Bu, kullanıcı arayüzü amaçları için yeterince hızlı olması gerektiği gibi, aynı zamanda İşleme programınızın yetenekleri dahilinde de olması gerektiği anlamına gelir.

Baud hızı (iletişim hızı) söz konusu olduğunda, bunu keyfi miktarlara ayarlamak muhtemelen öngörülemeyen sonuçlara yol açacaktır. Bunun nedeni, donanımın yalnızca belirli hızları desteklemesi ve başka bir şey kullanmaya çalışmak, diğer tarafta bozuk görünmesine neden olabilir. Serial.begin()Dokümantasyon desteklenen baud oranları hakkında biraz daha bilgi vardır.


14

Daha önce de belirtildiği gibi, Arduino'nuz çok hızlı diyor. Ekleme delay()işlemi yavaşlatır, ancak yine de İşleme sırasında bağırmaya devam eder. İdeal olarak, İşleme'nin uygun olduğunda değeri istemesini ve ardından Arduino'nuzdan bir cevap almasını istersiniz.

Enter SerialEvent().

Aksine loop()sizin Arduino üzerinde ve draw()içindeki her şey, Hazırlamada serialEvent()sadece excutes seri tampon yeni bir şey olduğunda. Bu yüzden mümkün olduğunca hızlı soru sormaktan ve Arduino'nuzdan daha hızlı geri bağırmak yerine, hoş, kibar (eşzamansız) bir konuşma yapabilirler.

Hem Processing hem de Arduino'da serialEvent bulunur. Bu Arduino üzerinde serialEvent () ve bu İşleme içinde serialEvent (). Her iki tarafta da serialEvent kullanıldığında şunlar olur:

  1. İşleme, seri bağlantıya bir karakter gönderir. Bu herhangi bir karakter olabilir, ancak birini önceden belirlersek, örneğin gürültülü bir sinyalin neden olduğu istenmeyen istekleri filtreleyebiliriz. Bu örnek için, Vpotansiyometrenizle ilgili her yeni okuma istediğimizde gönderelim. Karakter gönderildikten sonra, her zamanki gibi işimize devam ediyoruz. Burada bir cevap beklemek değil!

  2. Arduino tarafında seri tamponda veri alana kadar hiçbir şey olmuyor. Gelen karakterin bir olup olmadığını Vve bize şanslı olup olmadığını kontrol eder . Arduino, potmetrenin değerini bir kez okur, bu değeri bir kez seri olarak verir ve soğumaya geri döner, tüm serinlemeyi en üst düzeye çıkarır. Protip: değeri bir karakterle sonlandırır ( *bizim durumumuzda). Bu, bir sonraki adımda size yardımcı olacaktır.

  3. İşlem, aniden seri arabellekteki yeni verileri zorlamakta bir rahatsızlık olduğunda düzenli arayüzler arası piksel işini yapıyor . serialEvent()Sonlandırmamızla *karşılaşana kadar seri verilere geçer ve okumaya başlar . Bunun okumaya değer son karakter olduğundan emin olarak, gelen değeri artık Arduino'nun okumasını depolayan bir değişkente saklayabiliriz.

  4. Bu kadar. İşlem artık yeni sensör değerini biliyor ve yapmasını söylediğimiz her şeyi sürdürüyor. Bu arada, Arduino'nuz gelen seri veriler gelene kadar havanın tadını çıkarıyor veya varlığını düşünüyor.


1
Ve siz oradayken, potmetrenize paralel bir kapasitör koyun. Bu, DAC'nizin girişindeki küçük değişiklikleri düzeltir ve muhtemelen İşleme'deki gergin hareketleri önler.
Tom

Bu güzel (ve biraz antropomorfik) cevap için teşekkürler!
Zeta.Investigator

Aslında, USB üzerinden soru sormak bir fikir olabilir. Bunun nedeni, USB'nin seri bağlantı noktasından çok daha fazla gecikme süresine sahip olmasıdır, bu nedenle bir soru sormak ve bir yanıt beklemek, özellikle yüksek baud hızlarında yapılabileceklere kıyasla, normalde olduğundan daha fazla zaman alan bir işlemdir. Arduino'nun biraz daha hızlı çalışmasına izin vermek iyidir (ancak bağlantının seri kısmını doyurmamalıdır); yakalama, işleme çiziminin Arduino verilerini kullanılabilir olduğunda boşaltması ve gerektiğinde kullanmak için son tam değeri tutması gerektiğidir.
Chris Stratton

7

Yoklama döngünüz işlemcinizin tam hızında çalışır ve her turdaki seri bağlantı noktasına yazar.

Bu şekilde, seri bağlantı noktasına işleyebileceğinden daha sık yazıyorsunuz.

Bağlantı noktası, verileri yapılandırdığınız kadar hızlı yazar ve programınızdan gelen verileri çok hızlı bir şekilde yazmak için tamponlar . Arabellek dolu, sadece yeni veri bırakıyor.

Burada önemli olan, değerlerin sırasını koruyacağıdır: İlk Giriş / İlk Çıkış düzeninde çalışan bir FIFO tamponudur .

Ne olur:
Döngü bağlantı noktası arabelleğini doldurur ve% 100 dolu tutar.
Potansiyometreyi çevirirseniz, değiştirilen değer ara belleğin sonuna yazılır , bağlantı noktası arabellekteki hala eski değere sahip tüm öğeleri yazmak için olabildiğince hızlı çalışır.

Ve son olarak ilgilendiğiniz değer. Hemen görmek istediğimiz en güncel değer FIFO'nun sonundaydı ve ilk giriş / ilk çıkış da son giriş / son çıkış anlamına geliyor. İstediğimizin tam tersi.

Verilerinizi okumak için mantıklı olan maksimum frekans, yazabileceğiniz frekanstır, bu nedenle mevcut port hızında baytları yazmak için en az bir gecikme kullanmalısınız.


Genel olarak bu tür bir gecikmeyi önlemek için başka bir bağımsız önlem olarak,
ek olarak bağlantı noktasının yazma arabelleğini en aza indirebilirsiniz.

Bu, ilk önce çok arabelleğe almak yerine verilerin çok daha erken bırakılmasına neden olur.

Tabii ki, birçok uygulamada ihtiyacınız olan şey bu değil; Kötü şans ile, başlangıçta yine de işe yarayabilir ve zamanlama işlemci yükü gibi şeylere bağlı olarak değiştiğinde ve karartılabilen bazı rastgele veri örnekleri olduğunda bazı durumlarda kararsız olabilir . Büyük bir tampon genellikle çok daha belirleyici davranır, bu nedenle varsayılan olarak büyük bir tampon kullanın .


Doğru fikir, ama "Bu tampon dolu, sadece yeni veri bırakır." Arabellek doldurulduktan sonra veriler bırakılmaz, bunun yerine yazılanlar arabellekte boşluk olana kadar bloke olur. Bu, giriş ve çıkışın yakında aynı ortalama hızda akacağı anlamına gelir, ancak aralarında bir arabellek gecikme süresi vardır.
Chris Stratton

6

Seri verileri sürekli olarak göndermek yerine, yalnızca potansiyometrenin değeri belirli bir eşik değerinde değiştiğinde veri gönderin.

int oldValue = 0;
const int threshold = 5;

void setup()
{
  Serial.begin(9600);
  pinMode(A0, INPUT)
}

void loop()
{
  if(oldValue >= analogRead(A0)+threshold || oldValue <= analogRead(A0)-threshold)
  {
    Serial.println(analogRead(A0));
    oldValue = analogRead(A0);
  }
}

1
Bu loop()iyi eşit örnekleri ile çıkış tamponu, dolgu değildir. Ancak hala işlemcinin tam hızında çalışıyor, bu da gerektiğinden 100 kat daha hızlı olabilir. Bu, eğer giriş sık sık değişiyorsa, örneğin yukarıdaki gürültüden thresholdveya yüksek çözünürlükte sürekli bir değişime (buradaki örnek uygulamada böyle değildir) rağmen, tamponu hızla sınırına kadar doldurabileceği anlamına gelir
Volker Siegel

0

Hala arayan herkes için çalışması garanti edilen iki basit çözüm: -

  1. Gecikmeyi 50 ila 100 milisaniyeye artırın.

  2. Sonra bu ekleme Serial.begin(9600)de setup();

    Serial.setTimeout(50);

İkinci adım en önemlisidir. Sadece yukarıdaki kodu ekledikten sonra benim için çalıştı. Aynı problemi yaşadığımda baktığım diğer birçok forumda bu çok sık belirtilmiyor.


Bu biraz yanlış. SetTimeout () yöntemi çıktı için değil girdi için geçerlidir - arduino.cc/en/Serial/SetTimeout
Chris Stratton
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.