Atualmente, estou no projeto nº 14 do livro do projeto Arduino.
Estou tentando controlar um esboço de processamento no meu laptop usando meu Arduino. Isso é feito usando um potenciômetro para controlar o fundo de uma imagem.
Código Arduino:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.write(analogRead(A0)/4);
}
Em processamento:
//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);
}
Agora, enquanto o código funciona e a cor de fundo muda à medida que eu ligo o potenciômetro, há um grande atraso entre girar o potenciômetro e ver o fundo mudar de cor, e os valores do Arduino / potenciômetro mudam no monitor serial do processamento.
O que eu tentei:
- Alterando a velocidade da comunicação serial
Percebi que quando diminuo a velocidade da comunicação serial, por exemplo, cerca de 100, o atraso entre girar o potenciômetro e vê-lo mudar no meu laptop diminui para cerca de 1 segundo. No entanto, quando diminuo ainda mais a velocidade da comunicação serial, por exemplo, um valor 1, o atraso aumenta novamente.
Por outro lado, na velocidade padrão de 9600, o atraso é enorme, aproximadamente 5s ++, antes que as alterações no potenciômetro apareçam no laptop / processamento.
Por que diminuir a velocidade da comunicação (até um certo ponto) diminui o intervalo de tempo e aumenta-o? Além disso, existe alguma maneira que eu possa torná-lo quase instantâneo?
fonte
loop()
. É bem possível que seu programa de processamento não esteja funcionando rápido o suficiente para acompanhá-lo. Tente colocar um atraso noloop()
código do Arduino para reduzi-lo; por exemplodelay(50)
.Respostas:
Você está produzindo uma leitura sempre do Arduino
loop()
, portanto, parece provável que o seu programa de processamento não esteja sendo executado rápido o suficiente para acompanhá-lo. Tente colocar um atraso noloop()
código do Arduino para reduzi-lo, por exemplo:Tanto quanto eu sei, o processamento visa executar em uma taxa de quadros consistente, que você pode modificar usando a
frameRate()
função Por padrão, são 60 quadros por segundo, embora possa ser mais lento em sistemas mais antigos (ou onde você está executando um programa intensivo). Você pode verificar a velocidade da execução lendo aframeRate
variávelIntroduzir um atraso de 50 milissegundos no loop do Arduino significa que ele será atualizado um pouco menos de 20 vezes por segundo. Isso significa que deve ser rápido o suficiente para fins de interface com o usuário, mas também deve estar dentro dos recursos do seu programa de processamento.
No que diz respeito à taxa de transmissão (velocidade de comunicação), é provável que o ajuste por valores arbitrários tenha resultados imprevisíveis. Isso ocorre porque o hardware suporta apenas velocidades específicas, e tentar usar qualquer outra coisa pode resultar na exibição de dados ilegíveis na outra extremidade. A
Serial.begin()
documentação possui mais informações sobre taxas de transmissão suportadas.fonte
Como já apontado, seu Arduino está dizendo muito rápido demais. A adição
delay()
diminuirá a velocidade, mas continuará gritando com o processamento. Idealmente, você deseja que o Processing solicite o valor quando for conveniente e receba uma resposta do seu Arduino.Enter
SerialEvent()
.Ao contrário do
loop()
Arduino edraw()
do Processing, tudo oserialEvent()
que existe no interior só funciona quando há algo novo no buffer serial. Portanto, em vez de Processar, fazer perguntas o mais rápido possível e seu Arduino gritando ainda mais rápido, eles podem ter uma conversa agradável e educada (assíncrona).O Processing e o Arduino têm um serialEvent. Este é serialEvent () no Arduino e é serialEvent () no Processing. Usando serialEvent nos dois lados, é isso que aconteceria:
O processamento envia um caractere para a conexão serial. Pode ser qualquer caractere, mas se predeterminarmos um, podemos filtrar quaisquer solicitações indesejadas causadas por, por exemplo, um sinal barulhento. Neste exemplo, vamos enviar
V
sempre que desejamos uma nova leitura do seu medidor de potenciômetro. Depois que o personagem é enviado, continuamos nossos negócios como de costume. Não estou esperando por uma resposta aqui!No lado do Arduino, nada está acontecendo, até receber dados no buffer serial. Ele verifica se o personagem recebido é um
V
e, para nossa sorte, é. O Arduino lê o valor do medidor de potenciômetro uma vez, gera esse valor para serial uma vez e volta a relaxar, maximizando o descontração. Protip: finalize o valor com um caractere (*
no nosso caso). Isso o ajudará na próxima etapa.O processamento está realizando seus negócios regulares de pixel de interface quando, de repente, ocorre
uma perturbação na força denovos dados no buffer serial. Ele muda paraserialEvent()
e começa a ler os dados seriais, até que nosso término*
seja encontrado. Sabendo com certeza que esse foi o último caractere que vale a pena ler, agora podemos armazenar o valor recebido em uma variável que armazena a leitura do Arduino.É isso aí. O processamento agora conhece o novo valor do sensor e continua com o que pedimos. Enquanto isso, seu Arduino está aproveitando o tempo ou contemplando sua existência até que haja dados seriais recebidos.
fonte
Seu loop de pesquisa é executado na velocidade máxima do seu processador e grava na porta serial em cada rodada.
Dessa forma, você está gravando com mais frequência na porta serial do que ela pode suportar.
A porta grava os dados o mais rápido que você o configurou e armazena em buffer os dados que chegam do seu programa com muita rapidez , para gravá-los o mais rápido possível. O buffer está cheio, apenas lança novos dados.
O importante aqui é que ele manterá a ordem dos valores: é um buffer FIFO , trabalhando na ordem de entrada / saída.
O que acontece é:
O loop preenche o buffer da porta e o mantém 100% cheio.
Se você girar o potenciômetro, o valor alterado será gravado no final do buffer , a porta funcionará o mais rápido possível para gravar todos os elementos no buffer, que ainda possuem o valor antigo.
E, finalmente, o valor em que você está interessado. O valor mais atual que queríamos ver imediatamente era no final do FIFO, e primeiro a entrar / primeiro a sair também significa último a entrar / sair a última. O oposto do que queremos.
A frequência máxima em que faz sentido ler seus dados é a frequência em que você pode gravá-los; portanto, você deve usar pelo menos um atraso que seja longo o suficiente para gravar os bytes na velocidade atual da porta.
Como outra medida independente para evitar esse tipo de atraso em geral,
você pode definir adicionalmente o buffer de gravação da porta para um mínimo.
Isso faria com que os dados fossem descartados muito antes, em vez de armazenar muito em buffer primeiro.
Obviamente, em muitos aplicativos, não é disso que você precisa; Com má sorte, ele poderia funcionar de qualquer maneira no começo e ficar instável em algumas situações quando o tempo muda com base em coisas como carga do processador e existem apenas algumas amostras aleatórias de dados que são descartadas. Um buffer grande geralmente se comporta muito mais determinístico, portanto, use um buffer grande por padrão .
fonte
Em vez de enviar constantemente dados seriais, envie dados apenas quando o valor do potenciômetro tiver mudado acima de um determinado limite.
fonte
loop()
não é preencher o buffer de saída com amostras iguais, isso é bom. Mas ele ainda roda na velocidade máxima do processador, o que pode ser 100 vezes mais rápido que o necessário. Isso significa que pode ainda preencher o tampão para o limite rapidamente se a entrada muda frequentemente, por exemplo, a partir de ruído acimathreshold
, ou uma mudança contínua de alta resolução (o que não é o caso no exemplo de aplicação aqui)Duas soluções simples que garantem o funcionamento de quem ainda procura: -
Aumente o atraso para 50 a 100 milissegundos.
Adicione isso após o
Serial.begin(9600)
insetup()
;O segundo passo é o mais importante. Funcionou para mim somente depois que adicionei o código acima. Isso não é mencionado com muita frequência em muitos outros fóruns que procurei quando tive exatamente o mesmo problema.
fonte