• Welcome to LusoRobótica - Robótica em Português.
 

RGB Mixer - do Processing para o Arduino

Started by guibot, 22 de July de 2010, 14:53

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

guibot

Já faz tempo que ando a procura de uma maneira simples de enviar informação do Processing para o Arduino e de todas as bibliotecas e técnicas que experimentei não encontrei nenhuma que me agradasse. Como não sou programador pedi ajuda ao meu amigo @pauloricca, e ele deu-me uma solução muito simples de implementar e fácil de entender, todos os créditos da parte da comunicação serial vão para ele.

Para melhor exemplificar este exemplo usei um LED RGB, e liguei-o directamente aos pins do Arduino (NUNCA FAÇAM ISTO a não ser que queiram matar os vossos leds rapidamente). A maneira correcta é usar uma resistência em série nos pins dos leds, mas sobre esta matéria existem imensos tutoriais disponíveis e eu quero-me focalizar apenas na parte do envio de dados para o arduino.


Ainda no lado do Arduino foram definidos 3 pins de OUTPUT 9, 10, e 11, estes pins vão enviar PWM para cada um dos leds. O pin 8 é definido também como OUTPUT  e vai servir como pin de GROUND. Dentro da função loop() usa-se a função switch() que detecta qual é o caracter 'R', 'G', ou 'B' que foi enviado do processing. Este caracter é meramente de sincronização e serve para nos dizer qual é o valor que vem a seguir, veremos isso melhor no lado do Processing. Depois a função GetFromSerial() é chamada sempre que quizermos ver que informação é que vem a caminho.

void setup()
{
  // declare the serial comm at 9600 baud rate
  Serial.begin(9600);

  // output pins
  pinMode(9, OUTPUT); // red
  pinMode(10, OUTPUT); // green
  pinMode(11, OUTPUT); // blue

  // another output pin to be used as GROUND
  pinMode(8, OUTPUT); // ground
  digitalWrite(8, LOW);
}

void loop()
{
  // call the returned value from GetFromSerial() function
  switch(GetFromSerial())
  {
  case 'R':
    analogWrite(9, GetFromSerial());
    break;
  case 'G':
    analogWrite(11, GetFromSerial());
    break;
  case 'B':
    analogWrite(10, GetFromSerial());
    break;

  }
}

// read the serial port
int GetFromSerial()
{
  while (Serial.available()<=0) {
  }
  return Serial.read();
}


No lado do Processing, estou a usar uma classe para o slider adaptada de uma classe existente do anthonymatox.com. São criadas 3 instâncias desta classe (vou assumir que entendem o conceito de classe e seus derivados). Notem também que é importada a biblioteca Serial e a criação de uma instância chamada "port".
Na funcção setup() estou a ver qual é a porta de comunicação disponível, no meu caso e porque estou a usar mac é a 0, para quem usa pc há-de ser COM1, ou COM2, com COM# onde # é sempre um número.
Finalmente faço o envio de valores de cada slider através do comando port.write(valor). Notem que antes de enviar cada valor do slider envio sempre um caracter de sincronização 'R', 'G', ou 'B'.

import processing.serial.*;
Serial port;

sliderV sV1, sV2, sV3;

color cor;

void setup() {
  size(500, 500);

  println("Available serial ports:");
  println(Serial.list());

  // check on the output monitor wich port is available on your machine
  port = new Serial(this, Serial.list()[0], 9600);

  // create 3 instances of the sliderV class
  sV1 = new sliderV(100, 100, 90, 255, #FF0000);
  sV2 = new sliderV(200, 100, 90, 255, #03FF00);
  sV3 = new sliderV(300, 100, 90, 255, #009BFF);
}

void draw() {
  background(0);

  sV1.render();
  sV2.render();
  sV3.render();

  // send sync character
  // send the desired value
  port.write('R');
  port.write(sV1.p);
  port.write('G');
  port.write(sV2.p);
  port.write('B');
  port.write(sV3.p);
}

/*
Slider Class - [url=http://www.guilhermemartins.net]www.guilhermemartins.net[/url]
based on [url=http://www.anthonymattox.com]www.anthonymattox.com[/url] slider class
*/
class sliderV {
  int x, y, w, h, p;
  color cor;
  boolean slide;

  sliderV (int _x, int _y, int _w, int _h, color _cor) {
    x = _x;
    y = _y;
    w = _w;
    h = _h;
    p = 90;
    cor = _cor;
    slide = true;
  }

  void render() {
    fill(cor);
    rect(x-1, y-4, w, h+10);
    noStroke();
    fill(0);
    rect(x, h-p+y-5, w-2, 13);
    fill(255);
    text(p, x+2, h-p+y+6);

    if (slide==true && mousePressed==true && mouseX<x+w && mouseX>x){
      if ((mouseY<=y+h+150) && (mouseY>=y-150)) {
        p = h-(mouseY-y);
        if (p<0) {
          p=0;
        }
        else if (p>h) {
          p=h;
        }
      }
    }
  }
}







GnGz


amando96

Também a reparei, a camera tem alta qualidade :D

Estás a usar o pino 8 do arduino com GND?  Se ligares todos os leds ao mesmo tempo não arriscas puxar corrente mais e queimar o pino?

msr

#3
Bom tutorial!

No entanto detectei aqui umas falhas:
Quoteif (slide==true && mousePressed==true && mouseXx)
O mouseXx não sei como corrigir, não percebo grande coisa de Processing.

No construtor da classe podes usar "this.x = x" em vez de usares nomes diferentes. Torna-se mais prático.

Edit: ok deve ser isto
Quoteif (slide==true && mousePressed==true && mouseX>this.x && mouseX<(this.x+w)){

guibot

@amando96   não sei e como disse no tópico não aconselho esta prática, fiz aquilo porque fui preguiçoso de usar uma breadboard  :)

@msr lol, bem visto, o script que usei para formatar o código no meu site alterou-me os ">" e os "<"... já corrigi e espero que agora esteja tudo bem. obrigado ;)

guibot

alterei os caracteres de sincronização para 'R', 'G' e 'B', fica mais fix

kerwac

Seleciono o codigo e...nao deixa colar no software.
Algum truque??
Sei que estou a ser (calão), mas sempre é uma ajudita srsr
Obrigado
Podemos não voltar.Mas vamos a todas.

ricardo-reis

dá de qualquer maneira, eu deixo-te as duas mais comuns:

para copiar:
1-seleccionas o código, clicas com o botão do lado direito do rato, copiar.
2-seleccionas o código e pressionas as teclas: ctrl  c.

para colar:
1-abres um novo scketch, clicas com o botão do lado direito do rato, paste.
2-abres um novo scketch e pressionas as teclas: ctrl v.

TigPT

Gostei bastante do teu tutorial!

Para efeitos de evolução, gostava de mensionar que essa comunicação não utiliza HandShaking ou qualquer outro mecanismo que permita recuperar no caso de o código perder uma das transmissões por ruído. Também seria interessante só avançar para dentro do switch se existissem 2 dados em serial e não 1, já que o arduino só vai tomar acções se existirem 2 dados para ser processados, evitando que entre no switch e não seja transmitido nenhum após a letra, pode causar um erro.

Também é saudável no processing meter um pequeno delay a enviar os dados para evitar que este vá acumulados dados na entrada do arduino e que passe a ter "Lag" por estar a processar os dados antigos que estavam em espera.

kerwac

Sempre que corro o codigo da me erro na biblioteca.
Alguem me pode ajudar?
Podemos não voltar.Mas vamos a todas.

kerwac

#10
ESte é o erro no processing.
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
processing.app.debug.RunnerException: ArrayIndexOutOfBoundsException: 0
at processing.app.Sketch.placeException(Sketch.java:1543)
at processing.app.debug.Runner.findException(Runner.java:582)
at processing.app.debug.Runner.reportException(Runner.java:558)
at processing.app.debug.Runner.exception(Runner.java:498)
at processing.app.debug.EventThread.exceptionEvent(EventThread.java:367)
at processing.app.debug.EventThread.handleEvent(EventThread.java:255)
at processing.app.debug.EventThread.run(EventThread.java:89)
Exception in thread "Animation Thread" java.lang.ArrayIndexOutOfBoundsException: 0
at sketch_jul25a.setup(sketch_jul25a.java:36)
at processing.core.PApplet.handleDraw(Unknown Source)
at processing.core.PApplet.run(Unknown Source)
at java.lang.Thread.run(Thread.java:619)
Podemos não voltar.Mas vamos a todas.