Mengurangi jeda antara Arduino dan sketsa pemrosesan di komputer saya

13

Saat ini saya sedang mengerjakan proyek # 14 dari buku proyek Arduino.

Saya mencoba mengendalikan sketsa pemrosesan di laptop saya menggunakan Arduino saya. Ini dilakukan dengan menggunakan potensiometer untuk mengontrol latar belakang suatu gambar.

Kode Arduino:

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

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

Pengolahan:

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

Sekarang, ketika kode bekerja, dan warna latar belakang berubah ketika saya mengaktifkan potensiometer, ada jeda yang sangat besar antara memutar potensiometer dan melihat warna latar belakang berubah, dan nilai-nilai dari Arduino / potensiometer berubah pada monitor serial pemrosesan.

Apa yang saya coba:

  • Mengubah kecepatan komunikasi serial

Saya perhatikan bahwa ketika saya mengurangi kecepatan komunikasi serial, misalnya sekitar 100, penundaan antara memutar potensiometer dan melihatnya berubah pada laptop saya berkurang sekitar 1 detik. Namun, ketika saya mengurangi kecepatan komunikasi Serial lebih jauh, misalnya nilai 1, penundaan meningkat lagi.

Di sisi lain, pada kecepatan standar 9600, penundaan sangat besar, kira-kira 5 detik ++ sebelum perubahan potensiometer muncul di laptop / pemrosesan.

Mengapa mengurangi kecepatan komunikasi (hingga titik tertentu) mengurangi jeda waktu, dan meningkatkannya meningkatkan jeda waktu? Juga, adakah di sana saya bisa membuatnya dekat sesaat?

Kenneth .J
sumber
3
Anda menghasilkan bacaan setiap saat sepanjang Arduino loop(). Sangat mungkin bahwa program Pemrosesan Anda tidak berjalan cukup cepat untuk mengikutinya. Coba tunda loop()kode Arduino Anda untuk memperlambatnya; mis delay(50).
Peter Bloomfield
Hai peter, terima kasih atas jawaban yang cepat, menambahkan penundaan kecil benar-benar menyelesaikan masalah saya. Hanya pertanyaan kecil lainnya, apakah ada cara saya dapat menentukan kecepatan program pemrosesan saya di masa depan untuk mencegah hal ini terjadi lagi, atau apakah mendapatkan kecepatan pemrosesan laptop / yang lebih baik menyelesaikan masalah? Juga, mengapa memasukkan kecepatan komunikasi 250 atau 300 mengacaukan pembacaan dari Arduino? (Bacaan yang saya dapatkan adalah bergantian antara pembacaan dan nol Eg 147.0.147,0)
Kenneth. J

Jawaban:

11

Anda menghasilkan bacaan setiap saat di sekitar Arduino loop(), jadi sepertinya program Pemrosesan Anda tidak berjalan cukup cepat untuk mengikutinya. Coba tunda loop()kode Arduino Anda untuk memperlambatnya, misalnya:

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

Sejauh yang saya tahu, Memproses bertujuan untuk berjalan pada framerate yang konsisten, yang dapat Anda modifikasi menggunakan frameRate()fungsi. Secara default, ini 60 frame per detik, meskipun mungkin berjalan lebih lambat pada sistem yang lebih lama (atau di mana Anda menjalankan program intensif). Anda dapat memeriksa seberapa cepat itu berjalan dengan membaca frameRatevariabel.

Memperkenalkan penundaan 50 milidetik ke dalam loop Arduino berarti akan memperbarui sedikit di bawah 20 kali per detik. Itu berarti harus cukup cepat untuk keperluan antarmuka pengguna, tetapi juga harus sesuai dengan kemampuan program Pemrosesan Anda.

Sejauh baud rate (kecepatan komunikasi) yang bersangkutan, menyesuaikannya dengan jumlah yang sewenang-wenang cenderung memiliki hasil yang tidak terduga. Itu karena perangkat keras hanya akan mendukung kecepatan tertentu, dan mencoba menggunakan hal lain dapat menyebabkan data tampak kacau di ujung yang lain. The Serial.begin()dokumentasi memiliki beberapa informasi lebih lanjut tentang tarif baud yang didukung.

Peter Bloomfield
sumber
14

Seperti yang sudah ditunjukkan, Arduino Anda mengatakan terlalu cepat. Menambahkan delay()akan memperlambatnya, tetapi tetap saja berteriak pada Pemrosesan. Idealnya, Anda ingin Memproses meminta nilai ketika itu nyaman, dan kemudian menerima satu jawaban dari Arduino Anda.

Masukkan SerialEvent().

Berbeda dengan loop()di Arduino Anda dan draw()di Pemrosesan, semua yang ada di dalamnya serialEvent()hanya mengeluarkan ketika ada sesuatu yang baru di buffer serial. Jadi, alih-alih Memproses mengajukan pertanyaan secepat mungkin dan Arduino Anda berteriak lebih cepat, mereka dapat melakukan percakapan yang baik, sopan (tidak sinkron).

Baik Processing dan Arduino memiliki serialEvent. Ini adalah serialEvent () pada Arduino dan ini adalah serialEvent () dalam Pemrosesan. Menggunakan serialEvent di kedua sisi, inilah yang akan terjadi:

  1. Memproses mengirim karakter ke koneksi serial. Ini bisa berupa karakter apa saja, tetapi jika kita menentukan sebelumnya, kita dapat menyaring permintaan yang tidak diinginkan yang disebabkan oleh misalnya sinyal berisik. Untuk contoh ini, mari kirim Vsetiap kali kami ingin membaca potmeter baru Anda. Setelah karakter dikirim, kami melanjutkan bisnis kami seperti biasa. Tidak menunggu jawaban di sini!

  2. Di sisi Arduino tidak ada yang terjadi, sampai menerima data dalam buffer serial. Ia memeriksa apakah karakter yang masuk adalah V, dan beruntung kita, itu. Arduino membaca nilai potmeter satu kali, menampilkan nilai itu ke serial sekali, dan kembali ke bersantai, maxing santai semua keren. Protip: mengakhiri nilai dengan karakter ( *dalam kasus kami). Ini akan membantu Anda pada langkah selanjutnya.

  3. Pemrosesan sedang melakukan bisnis pixel antarmuka-nya yang biasa ketika tiba-tiba ada gangguan pada kekuatan data baru di buffer serial. Itu beralih ke serialEvent(), dan mulai membaca data serial, sampai penghentian kami *ditemui. Mengetahui dengan pasti ini adalah karakter terakhir yang layak dibaca, kita sekarang dapat menyimpan nilai yang masuk dalam variabel yang menyimpan bacaan Arduino.

  4. Itu dia. Pemrosesan sekarang tahu nilai sensor baru dan melanjutkan dengan apa pun yang kami perintahkan. Sementara itu, Arduino Anda menikmati cuaca atau merenungkan keberadaannya hingga ada data serial yang masuk.

Tom
sumber
1
Dan saat Anda melakukannya, letakkan kapasitor secara paralel dengan potmeter Anda. Ini menghaluskan sedikit perubahan pada input DAC Anda, mungkin mencegah gerakan gelisah dalam Memproses.
Tom
Terima kasih atas jawaban yang bagus (dan agak antropomorfik) ini!
Zeta.Investigator
Sebenarnya, mengajukan pertanyaan melalui USB bisa menjadi ide. Ini karena USB memiliki latensi yang jauh lebih banyak daripada port serial, jadi mengajukan pertanyaan dan menunggu respons adalah operasi yang lebih memakan waktu daripada yang seharusnya, terutama dibandingkan dengan apa yang dapat dilakukan pada kecepatan baud yang tinggi. Membiarkan Arduino berjalan sedikit lebih cepat baik-baik saja (meskipun seharusnya tidak memenuhi bagian serial tautan); tangkapannya adalah sketsa pemrosesan harus mengeringkan data Arduino begitu tersedia, dan berpegang pada nilai lengkap terakhir untuk digunakan saat dibutuhkan.
Chris Stratton
7

Putaran polling Anda berjalan dengan kecepatan penuh dari prosesor Anda, dan menulis ke port serial di setiap putaran.

Dengan cara ini, Anda menulis lebih sering ke port serial daripada yang bisa ditangani.

Port menulis data secepat Anda mengkonfigurasinya, dan buffer data yang masuk dari program Anda terlalu cepat , untuk menuliskannya sesegera mungkin. Jika buffer sudah penuh, itu hanya akan menjatuhkan data baru.

Yang penting di sini adalah bahwa hal itu akan menjaga urutan nilai-nilai: Ini adalah buffer FIFO , bekerja dalam urutan First In / First Out.

Yang terjadi adalah:
Loop mengisi buffer port, dan membuatnya 100% penuh.
Jika Anda mengaktifkan potensiometer, nilai yang diubah dapat ditulis ke akhir buffer , port bekerja secepat mungkin untuk menuliskan semua elemen dalam buffer, yang masih memiliki nilai lama.

Dan akhirnya nilai yang Anda minati. Nilai terbaru yang ingin kami lihat segera adalah di akhir FIFO, dan first in / first out juga berarti last in / last out. Kebalikan dari yang kita inginkan.

Frekuensi maksimum yang masuk akal untuk membaca data Anda, adalah frekuensi Anda dapat menuliskannya, jadi Anda harus menggunakan setidaknya penundaan yang cukup lama untuk menulis byte pada kecepatan port saat ini.


Sebagai ukuran lain yang independen untuk mencegah keterlambatan semacam ini secara umum,
Anda juga dapat mengatur buffer penulisan port ke minimum.

Itu akan menyebabkan data akan turun lebih awal, daripada banyak buffer terlebih dahulu.

Tentu saja, dalam banyak aplikasi bukan itu yang Anda butuhkan; Dengan nasib buruk, itu bisa tetap bekerja di awal, dan menjadi tidak stabil dalam beberapa situasi ketika waktu berubah berdasarkan pada hal-hal seperti beban prosesor, dan hanya ada beberapa sampel data acak yang turun. Buffer besar umumnya berperilaku jauh lebih deterministik, jadi gunakan buffer besar secara default .

Volker Siegel
sumber
Ide yang benar, tetapi tidak tepat pada pernyataan "Itu buffer penuh, itu hanya menjatuhkan data baru." Setelah buffer diisi, data tidak dijatuhkan, melainkan blok tulis sampai ada ruang di buffer keluar. Ini berarti bahwa input dan output segera berakhir mengalir pada tingkat rata-rata yang sama, tetapi ada nilai latensi buffer di antara mereka.
Chris Stratton
6

Alih-alih terus mengirim data serial, hanya mengirim data ketika nilai potensiometer telah berubah pada ambang batas tertentu.

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);
  }
}
Daniel Eisterhold
sumber
1
Itu loop()tidak mengisi buffer output dengan sampel yang sama, itu bagus. Tetapi masih berjalan dengan kecepatan penuh dari prosesor, yang mungkin 100 kali lebih cepat dari yang dibutuhkan. Itu berarti masih dapat mengisi buffer ke batas dengan cepat jika input sering berubah, misalnya dari kebisingan di atas threshold, atau perubahan terus-menerus dalam resolusi tinggi (yang tidak terjadi dalam contoh aplikasi di sini)
Volker Siegel
0

Dua solusi sederhana yang dijamin bekerja untuk siapa saja yang masih mencari: -

  1. Tingkatkan penundaan hingga 50 hingga 100 milidetik.

  2. Tambahkan ini setelah Serial.begin(9600)di setup();

    Serial.setTimeout(50);

Langkah kedua adalah yang paling penting. Ini bekerja untuk saya hanya setelah saya menambahkan kode di atas. Ini tidak disebutkan sangat sering di banyak forum lain yang saya lihat ketika saya memiliki masalah yang sama persis.

Rishi Swethan
sumber
Ini agak keliru. Metode setTimeout () berlaku untuk input, bukan output - lihat dokumentasi di arduino.cc/en/Serial/SetTimeout
Chris Stratton