sâmbătă, 18 ianuarie 2014

INTERFATA GRAFICA PC - ARDUINO


     Dupa ce am trimis comenzi lui Arduino utilizand in mod direct interfata seriala m-am tot gandit cum s-ar putea realiza o interfata grafica in care printr-un simplu click de mouse sa controlam placuta de dezvoltare.
     Teoretic acest lucru se poate realiza utilizand instrumente mai complexe cum ar fi mediul de programare .NET, insa pentru cineva care nu doreste sa utilizeze mijloace atat de complicate si care vrea sa vada rezultatele imediat .NET-ul poate venii un pic peste mana.

     Tot sapand pe internet am data peste o unealta absolut superba :PROCESSING. Jucaria asta este un limbaj de programare care are la baza Java. Este foarte usor de invatat, mai ales ca IDE-ul este aproape identic cu cel al lui Arduino. Processing permite crearea de interfete grafice foarte usor fara a utiliza forme si clase complicate. Totodata helpul este foarte bine structurat, pagina de net a aplicatiei fiind plina da exemple si de tot soiul de librari. Cum java este un limbaj de programare orientat 100% pe obiect asa este si Processing insa dezvoltatorii au ales (si bine au facut) sa mascheze acesta parte mai complicata user-ului de rand, lasand totusi posibilitatea celor care vor sa creeze propriile clase. Programrea in Processing are la baza evenimentele. De exemplu : daca se da click undeva anume - programul executa ceva, daca primesti ceva pe portul serial -  altceva etc. Ca tot venii vorba de portul serial, Processing are o librarie dedicata acestui port care ne ofera controlul asupra acestui protocol in mod direct utilizand functii foarte apropiate de cele din libraria  pentru Arduino.

     Aplicatia pe care o propun pentru astazi este una foarte simpla deschide noi orizonturi in comunicarea PC - Arduino. Utilizand 8 leduri conectate la pinii unei placute AT MEGA 2560 si programand-o in mod corespunzator s-a reusit trimiterea de comenzi prin portul serial de la o interfata grafica creata in Processing.

1. Programarea in Processing.

     Nu voi zabovii foarte mult asupra acestui acestui subiect insa trebuie mentionate cateva aspecte. In primul rand iata codul pentru programul propriuzis:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import processing.serial.*;

int xd =550;
int yd =100;
String[] led={"L1","L2","L3","L4","L5","L6","L7","L8"};
led[] led_array = new led[8];
int cmd=0;
int sign=32;
int nibble=15;
int h_nibble=240;
int old_cmd;
Serial arduino;

void setup(){
  noLoop();
  arduino=new Serial(this,Serial.list()[0],9600);
  size(xd,yd);
  for(int i=0;i<8;i++){
    led_array[i]=new led(30,50,i);
  }
  for(int i=0;i<8;i++){
    led_array[i].center(xd,i);
  }
}
void draw(){
  

  for(int i=0;i<8;i++){
    if(led_array[i].state==false){
      fill(90,0,0);
    }
    else if(led_array[i].state==true) {
      fill(255,0,0);
    }
    ellipse(led_array[i].x_center,led_array[i].y_center,led_array[i].diameter,led_array[i].diameter);
    textSize(15);
    fill(0,0,0);
    text(led[i],led_array[i].x_center-7,led_array[i].y_center+30);
  } 
}
String twobytes(int k){
  int low_byte= sign|(k&nibble);
  int high_byte=(sign|((k&h_nibble)>>4));
  char a =(char) low_byte;
  char b=(char) high_byte;
  String send=new String (""+a+b);
  return send;
}
void mouseClicked(){
  old_cmd=cmd;
  for(int i=0;i<8;i++){
    if(led_array[i].x_center-15<mouseX && mouseX<led_array[i].x_center+15 && led_array[i].y_center-15<mouseY && mouseY<led_array[i].y_center+15){
      if (led_array[i].state==false){
        led_array[i].state=true;
        cmd=cmd|(1<<(led_array[i].index));
      }
      else if(led_array[i].state==true){
        led_array[i].state=false;
        cmd=cmd^(1<<led_array[i].index);
      }
    }
  }
  if (old_cmd!=cmd){
    arduino.write(twobytes(cmd));
    redraw();
  }  
}

si codul pentru clasa led:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class led{
  int diameter;
  int x_center;
  int y_center;
  boolean state;
  int index;
  static int number;
  public led(int _diameter,int _ycenter,int _index){
    this.diameter=_diameter;
    this.y_center=_ycenter;
    this.state =false;
    this.index=_index;
    number++;
  }
  void center(int xsize ,int led_number){
    int step=this.diameter*2;
    int margin=(xsize-((this.number-1)*step))/2;
    this.x_center=margin+step*(led_number);
  }
}


Poza 1 : Interfata grafica leduri
    Liniile care intereseaza pentru comunicarea cu Arduino sunt: linia de cod nr. 12 in care se defineste un obiect de tip "Serial" numit "arduino" si linia de cod nr. 16 in care se face initializarea propriuzisa  : "arduino=new Serial(this,Serial.list()[0],9600); ". In constructorul "Serial" - "Serial.list()[0]" reprezinta indexul vectorului care contine porturile seriale. Cum exista o singura placuta aceasta este evident  primul element din vector. In ceea ce privste "9600" acest numar reprezinta baudrate-ul comunicarii. Clasa led are rolul de a grupa informatiile necesare afisarii pe ecran. O ultima remarca ar mai trebui facuta: deoarece in codul ASCII se pot trimite in modul normal bytes care au valoarea maxima 127 iar noi dorim sa aprindem 8 leduri care reprezinta un byte intreg (0-255) este necesar un mic artificiu. Practic se trimit 2 bytes fiecare continand doar cate 6 biti de forma: 0b0010XXXX. Bitul nr. 5 trebuie sa fie 1 deoarce astfel ii spunem lui Arduino ca un byte valid urmeaza sa se primeasca. Bitii 3:0 reprezinta de fapt data utila. Cum am relizat acest lucru? Dupa fiecare apsare de led variabila "cmd" se modifica (liniile 55 si 59)devenind imaginea  in binar a ceea ce se vede pe ecran. Cum nu putem trimite valori mai mari de 127 este necesara prelucrarea variabilei astfel:
     Sa presupunem ca byte-ul care trebuie trimis este urmatorul: 0b11011101 adica 221 in decimal(vezi poza de mai sus). Dupa cum am spus mai sus "vom sparge" acest numar in cate 6 biti de forma : 0b101101. Acest lucru se realizeaza in functia "String twobytes(int k)" care returneaza un string format din doi bytes avand forma de mai sus. Ca o curiozitate uitandu-ne in tabelul ASCII acest numar corespunde caracterului "-", deci lui Arduino ii vom trimite un string care contine "--".

2.Programarea Arduino

Iata codul :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//
int led_array[8]={24,26,28,30,32,34,36,38};
int i;
char buffer[2];
void setup(){
 int i;
 for (i=0;i<8;i++){
  pinMode(led_array[i],OUTPUT);
  digitalWrite(led_array[i],LOW);
 }
 Serial.begin(9600);
}
void lit_led(byte port){
 Serial.println(port,BIN);
 for(i=0;i<8;i++){
  boolean test=port&(1<<i);
  if(test){
   digitalWrite(led_array[i],HIGH);
  }
  if(!test){
   digitalWrite(led_array[i],LOW);
  }
 }
}

void loop(){
 if(Serial.available()>0){
  Serial.readBytes(buffer,2);
  buffer[0]=buffer[0]^32;
  buffer[1]=buffer[1]^32;
  Serial.println(buffer[0],BIN);
  Serial.println(buffer[1],BIN);
  byte k=((buffer[1]<<4)|(buffer[0]));
  buffer[0]=0;
  buffer[1]=0;
  lit_led(k);
 }
}

    Nimic complicat. De cum ajung, datele sunt salvate in vectorul buffer (linia nr. 28). Apoi scapam de datele in exces  adica stergem bitul 5 (liniile 29, 30 ) iar in linia 33 construim byte-ul care ne intereseaza. Mai departe aprindem ledurile utilizand functia "void lit_led(byte port)".

Asta e tot. Codurile sursa se pot descarca de aici . Iata si si un filmulet demonstrativ:



Succes!


2 comentarii:

  1. Am incarcat codul pe arduino,dar programul cum il pornesc?

    RăspundețiȘtergere
  2. Poti sa faci un vumetru cu arduino,dar semnalul la vumetru sa fie trimis prin usb de pe pc?

    RăspundețiȘtergere