HobbyElectro

Petrescu Cristian . Un produs Blogger.

joi, 30 ianuarie 2014

DESENE CU ARDUINO SI PROCESSING...

2 comentarii | Read more...

     Chiar daca titlul suna putin cam pompos, in definitiv, cu aplicatia pe care o voi prezenta in cele ce urmeaza se poate face un desen. Ideea care sta la baza este o jucarie denumita "etch a sketch" cu care se pot face desene numai cu linii orizontale si verticale. Probabil ca veti zice ca nu e mare lucru. Cautati de curiozitate pe Google si veti gasi adevarate opere de arta facute cu aceasta jucarie. Dar mai bine sa revenim la oile noastre.
    In primul rand dovada :)


      Ca de obcei vom utiliza un Arduino Mega 2560 la care vom lega 4 butoane si 4 leduri. Fiecare buton comanda  miscarea intr-o anumita directie (sus, jos, stanga, dreapta), butoanele avand roulul de a semnaliza apasarea unui buton. Dupa fiecare apasare se va trimite un cod pe care programul realizat in Processing il va interpreta rezultatul fiind desenarea pe ecran a unei linii: fie orizontala fie verticala.



     Cele doua butoane fac exact ceea ce scrie sub ele : unul sterge tot ce se afla pe ecran iar celalalt sterge ultima linie desenata. Probabil ar fi fost mult mai interesant daca desenul s-ar fi realizat cu doua potentiometre. Am incercat si aceasta varianta insa exista o problema cu calibrarea si cu cat de repede se invarte potentiometrul. O alta idee ar fi utilizarea encoderelor unui mouse cu bila dar timpul si mouse-ul pe care nu-l am nu mi-au permis un test. Nu voi comenta codul deoarce pentru Arduino este simplu si pana la urma scopul acestui blog este experienta cu microcontrollere sau cu electronica in general si nu programele scrise in Java (cu scrisul carora incerc cu greu sa ma descurc).

Cod Arduino:


 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
int led_array[4]={24,26,28,30};
int b_array[4]={2,3,4,5};
String com[4]={"a","b","c","d"};
int i;

void setup(){

 Serial.begin(9600);
 for(i=0;i<2;i++){
  pinMode(led_array[i],OUTPUT);
  pinMode(b_array[i],INPUT);
 }
}

void loop(){
 for(int i=0;i<4;i++){
  if(digitalRead(b_array[i])){
   digitalWrite(led_array[i]);
   while(digitalRead(b_array[i])){
    Serial.write(com[i]);
    delay(250);//SE MODIFICA DELAY PT VITEZA 
                                           //MAI MARE DE DESEN
   }
  }
 }
}

Cod Processing program principal:

  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
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
/////SIMPLE DRAWING WITH ARDUINO//////
/////PETRESCU CRISTIAN///////////////
/////hobbyelectro.blogspot.com//////
/////JAN. 2014/////////////////////


import processing.serial.*;
color normal= color(0,255,0);
color pushed =color(255,0,0);
boolean ready;
boolean append;
boolean sort=true;
int xwindow=600;
int ywindow=600;
button reset = new button(50,560,60,20,"RESET");
button undo = new button(490,560,60,20,"UNDO");
pot ho =new pot(xwindow/2,ywindow/2);
color black = color(0);
color back =color(200);
IntList h_line;
String inString;
Serial arduino;

////////////DRAW MARKER///////////////////
void draw_marker(int x1,int y1){
  stroke(black);
  line(x1,y1,x1+3,y1+3);
  line(x1,y1,x1-3,y1+3);
}
////////////ADD VALUES TO LIST////////////
void append(int x,int y){
  h_line.append(x);
  h_line.append(y);
}
/////////////SETUP//////////////////////
void setup(){
  arduino = new Serial(this, Serial.list()[0], 9600);
  arduino.buffer(1);
  size(xwindow,ywindow);
  background(back);
  draw_marker(ho.newX,ho.newY);
  h_line=new IntList();
  h_line.append(xwindow/2);
  h_line.append(ywindow/2);
}
//////////////////DRAW///////////////////////////
void draw(){
  background(back);
  fill(normal);
  rect(reset.xpos,reset.ypos,reset.len,reset.wid);
  rect(undo.xpos,undo.ypos,undo.len,undo.wid);
  fill(0, 102, 153);
  text(reset.caption,reset.cX,reset.cY);
  text(undo.caption,undo.cX,undo.cY); 
  int k =h_line.size();
  draw_marker(h_line.get(k-2),h_line.get(k-1));
  if(ready){
    for(int i=0;i<k-2;i=i+2){
      line(h_line.get(i),h_line.get(i+1),h_line.get(i+2),h_line.get(i+3));
    }
  }
  sort=true;
}
/////SERIAL EVENT/////////////////////
void serialEvent(Serial arduino) { 
  inString = arduino.readString();
  if(sort){
    sort=false;
    if(inString.equals("l")&&ho.newX>0){
      ho.refresh(ho.newX-5,ho.newY);
      append(ho.newX,ho.newY);
    }
    if(inString.equals("r")&&ho.newX<600){
      ho.refresh(ho.newX+5,ho.newY);
      append(ho.newX,ho.newY);
    }
    if(inString.equals("u")&&ho.newY>0){
      ho.refresh(ho.newX,ho.newY-5);
      append(ho.newX,ho.newY);
    }
    if(inString.equals("d")&&ho.newY<550){
      ho.refresh(ho.newX,ho.newY+5);
      append(ho.newX,ho.newY);
    }
    ready=true;    
    }
 }
/////////////CLICK MOUSE///////////////////////////////
void mouseClicked(){
  if((mouseX<(reset.xpos+reset.len)&&mouseX>reset.xpos)&&
    (mouseY<(reset.ypos+reset.wid)&&mouseY>reset.ypos)){
      h_line.clear();
      h_line.append(xwindow/2);
      h_line.append(ywindow/2);
      ho.newX=xwindow/2;
      ho.newY=ywindow/2;
   }
   if((mouseX<(undo.xpos+undo.len)&&mouseX>undo.xpos)&&
    (mouseY<(undo.ypos+reset.wid)&&mouseY>undo.ypos)){
      int k=h_line.size();
      if(k>=4){
        h_line.remove(k-1);
        h_line.remove(k-2);
        ho.newX=h_line.get(k-4);
        ho.newY=h_line.get(k-3);
      }  
   }
}

    Cod Processing clasa "pot":


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class pot{
  public int newX;
  public int newY;
  public pot(int ox, int oy){
    this.newX=ox;
    this.newY=oy;
  }
  void refresh(int rx, int ry){
    this.newX=rx;
    this.newY=ry;
  }
}

    Cod Processing clasa "button":

 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
class button{
  int xpos,ypos,len,wid, cX,cY;
  String caption;
  //color normal= color(0,255,0);
  //color pushed color(255,0,0);
  button(int x, int y, int l, int w, String text){
    this.xpos=x;
    this.ypos=y;
    this.len=l;
    this.wid=w;
    this.caption=text;
    this.cX=x;
    this.cY=captionY();
  }
  int centerX(){
    int x=this.xpos+(this.len/2);
    return x;
  }
  int centerY(){
    int y=this.ypos+(this.wid/2);
    return y;
  }
  int captionX(){
    int cX=this.xpos;
    return cX;
  }
  int captionY(){
    int cY=this.ypos+this.wid+15;
    return cY;
  }

   Cei care doresc pot descarca codul de aici.
   Succes! Si pentru cei napastuiti (ca mine) BAFTA LA EXAMENE !!!

sâmbătă, 18 ianuarie 2014

INTERFATA GRAFICA PC - ARDUINO

2 comentarii | Read more...

     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!


sâmbătă, 11 ianuarie 2014

ARDUINO SI COMENZI PRIN INTERFATA SERIALA

0 comentarii | Read more...

     Pot declara oficial: Arduino m-a prins. Nu voi face apologia avantajelor sau dezavantajelor acestei platforme dar tinand cont de pret si de simpliatate este prea tentanta sa nu fie bagata in seama.

Ok. Ieri m-am tot gandit cum as putea trimite comenzi placutei prin interfata seriala: ceva de genul sa aprind sau sa sting niste leduri utilizand doar comenzi gen consola (sechele de pe vremea MS DOS-ului). Dupa putina bataie de cap am gasit solutia. De fapt am facut doua programe : unul in care se comanda fiecare bit independent iar altul in care se trimite prin interfata seriala o secventa de bytes iar Arduino stinge si aprinde ledurile conform acelei secvente.

     In postul de azi voi prezenta primul program urmand ca intr-un post ulterior sa vorbesc si despre cea de-a doua varianta. Sa incepem:  

    Cand se citeste ceva de la portul serial intotdeauna se primeste informatia bit cu bit pana cand a fost atins un byte (adica au fost transmisi 8 biti). Daca nu exista alte constrangeri Arduino va stoca aceasta informatie intr-o variabila de tip char (de fapt este un byte care ia valori in domeniul codului ASCII 0-127). Cand am vorbit de constarngeri am incercat sa zic faptul ca se pot trimite mai multe caractere insa tinand cont de particularitatile transmisiei seriale, pentru a putea utiliza aceste date este nevoie ca ele sa fie salvate intr-un vector (array). Arduino dispune de o functie care face fix acest lucru " Serial.readBytes(arg1, arg2) ". Primul argument reprezinta un array in care se stocheaza datele primite prin portul serial iar cel de-al doilea argument reprezinta numarul de bytes care vor fi cititi. De exemplu:
Sa zicem ca avem definit un vector denumit " buffer[7]". Functia descrisa mai sus va lua primul argument arg1= buffer (de fapt este un pointer catre vectorul buffer) si daca dorim sa citim doar primle 3 caractere trimise arg2 va fi egal cu 3: Serial.readBytes(buffer, 3). 
Daca se trimite  secventa : "arduino" continutul vectorului buffer va fi:
  • buffer[0]='a'
  • buffer[1]='r'
  • buffer[2]='d'
Acum: pentru a putea face ceva cu aceste caractere este necesar sa ne legam de valorile lor din codul ASCII. Valoarea ASCII pentru 'a' este 97, pentru 'r' este  114 iar pentru 'd' este 100. Acum ca avem codurile putem manipula datele asa cum vrem.

Destul cu teoria. Sa vedem acum cum lucreaza programul. Utilizand un Arduino Mega 2560 se leaga la 8 pini ai acestuia (24,26,28,30,32,34,36,38) cate un led. Se trimite prin interfata seriala (personal utilizez programul Terminal ce poate fi descarcat de aici) numarul ledului urmat de starea dorita de exemplu: daca dorim sa aprindem ledul numarul 1 se scrie "11" iar daca dorim sa il stingem se scrie "10". 
     Codul este urmatorul:


     
     Ok. Acum sa vedem si ceva screenshot-uri:




     Acesta este programul Terminal in care s-a introdus comanda de aprindere a ledului numarul 1.

COMANDA 11

Acesta este efectul : ledul 1 este aprins. Apoi se trimit succesiv comenzile "21", "10" cu urmatoarele rezultate:

COMANDA 21

COMANDA 10


     Cam asta ar fi. In postul urmator voi arata cum se poate trimite o secventa de bytes in urma careia se pot aprinde ledurile in modul dorit de utilizator.

vineri, 10 ianuarie 2014

EDITOR ARDUINO

0 comentarii | Read more...

     De sarbatori am primit cadou o placuta Arduino Mega 2560 - simfonie de pini si de optiuni. Desi nu prea sunt un mare fan al acestei platforme de dezvoltare am zis sa ii dau o sansa si credeti-ma chiar nu am fost dezamagit . Entuziasmul mi-a scazut brusc cand am (re)vazut IDE-ul. Aceeasi interfata super minimalista... ce sa zic aproape spartana. Chestia care ma enerva la culme era aceea ca nu poti deschide mai multe proiecte intr-o singura instanta. Asa ca am inceput sa sap.
    Stiam inca de la primele mele experiente cu Arduino ca exista undeva o optiune de a folosi un editor extern, insa pe atunci nu gasisem o optiune viabila. Acum insa exista. Sa nu uit:

TOATE INFORMATIILE PREZENTATE IN ACEST POST SUNT PRELUATE DE PE FORUMUL ARDUINO, VARIANTA ORIGINALA O GASITI AICI .

     In esenta se utilizeaza o versiune portabila a editorului de cod Notepad++ careia i se aduc la cunostinta comenzile pentru Arduino.

     Cum se realizeaza?

1.Download versiune portabila Notepad ++ de aici :
2.Se deazarhiveaza intr-un locatie convenabila (fiind o versiune portabila nu necesita instalare).
3.Se deschide editorul si se fac urmatoarele modificari:

  • Click Settings -> Style Configurator


  • Alegeti o tema (mie personal mi-a placut "Zenburn"):


  • Click pe "C++", click pe "Instruction Word" si in "User defined keywords" dati paste la urmatorul text asa cum se vede in  imagine:




  • Click acum pe "Type Word " si paste in  "User defined keywords" a urmatorului text ca in imagine:





  • Ultimul pas este de a adauga la extensia "ino" in caseta de text "User ext. :"
     Acum ca am facut modificarile in editor suntem gata sa il folosim pentru a scrie cod. Algoritmul este urmatorul.
  1. Creati in Arduino IDE un proiect nou deschideti unul existent si in File/Preferences bifati utilizarea unui editor extern. Ecranul in care se scrie codul se va face gri, facand imposibila editarea sau scrierea codului . 
  2. Deschideti fisierul creat sau existent cu editorul Notepad++. 
  3. Dupa ce ati terminat de scris sau editat codul va reintoarceti in mediul de programare Arduino unde dupa caz verificati sau uploadati codul. Veti observa ca in fereastra gri a fost adaugat tot codul pe care l-ati scris in Notepad++.
  4. Spor la treaba si succes.
   Aceasta metoda de editare si scriere are avantajul ca suporta intr-o oarecare masura auto code completition si chiar daca pentru fiecare proiect trebuie deschisa cate o instanta noua a Arduino IDE nu va mai fi necesara comutarea de la una la alta decat in momentul compilarii.

Iata si o poza cu editorul in actiune:  



Totalul afișărilor de pagină

Despre

Blog cu si despre electronica !