luni, 25 noiembrie 2013

un..gamepad cu Arduino Uno

Incontinuare la articolul precedent mi-am pus intrebarea :
Cum se poate face cel mai simplu gamepad cu Arduino ?
Să aiba un grup de 5 butoane , cu următorul rol :
 - dacă aps pe 4 din ele,  deplaseze intr-o fereastra de pe PC o figură geometrică, (un pătrat)  pe patru direcţii: sus; jos; dreapta; stânga
-  al cincilea buton, să fie "fire" - când îl apăs, să se schimbe culoarea pătratului;  
În primul rând, trebuie să construim  gamepad-ul nostru pe breadboard. Vom folosi 4 butoane pentru direcţii (dreapta, sus, stânga, jos), și un altul pentru foc.
O să le conectãm la pinii  Arduino și masă în mod direct, fără nici o rezistenţã pullup sau pulldawn: vom activa rezistenţe pull-up interne din cadrul programului.Folosind rezitorii pullup interni, circuitul va fi mult mai simplu. El  va arãta astfel :


 După asamblarea pe bredboard și cuplarea la pinii lui Arduino Uno, mai trebuie incrcat programul .  Exemplul l-am preluat de la :
http://www.varesano.net/blog/fabio/serial-communication-arduino-and-processing-simple-examples-and-arduino-based-gamepad-int   prezentat în paragraful  Interfacing Arduino with a program running on a PC: Arduino and Processing to implement a simple gamepad and videogame"
Şi aici a fost surpriza:     la compilare, a apãrut eroarea şi confuzia!





















Am fost nevoit sã reiau la rând funcţiile din Arduino IDE, şi totul despre tipurile de date BYTE ! ca sã pricep scriptul. A trebuit sã inlocuiesc ultima instrutiune, dar … macar am priceput “ce şi cum face“  programul. 

Am tradus comentariile , am corectat ultima instrucţiune şi scriptul meu este astfel :
-------------------------------------------------------------------------------------------------------
/** game1
* Utilizeaza  rezistoarele interne pullups pentru a citi starea
* celor 5 butoane.
* Apoi , declara variabila "unsigned int state" care este de fapt
* echivalenta cu tipul Byte. Prin operatii pe bit, (bitwise)
* incarca succesiv valorile citite de pe pini pe locurile 5; 4; 3; 2; 1 din variabila state;
*  variabila state ocupa 4 digiti; ea este expediata serial   
*/

#define IN1 2  // fire
#define IN2 3  // right
#define IN3 4  // up
#define IN4 5  // left
#define IN5 6  // down

int state1 = HIGH;
int state2 = HIGH;
int state3 = HIGH;
int state4 = HIGH;
int state5 = HIGH;

void setup() {
  Serial.begin(9600);
 
  pinMode(IN1, INPUT);
  digitalWrite(IN1, HIGH); // enable pullup resitor
 
  pinMode(IN2, INPUT);
  digitalWrite(IN2, HIGH); // enable pullup resitor
 
  pinMode(IN3, INPUT);
  digitalWrite(IN3, HIGH); // enable pullup resitor
 
  pinMode(IN4, INPUT);
  digitalWrite(IN4, HIGH); // enable pullup resitor
 
  pinMode(IN5, INPUT);
  digitalWrite(IN5, HIGH); // enable pullup resitor
}

void loop() {
  delay(10); // debounces switches
 
  int val1 = digitalRead(IN1);
  int val2 = digitalRead(IN2);
  int val3 = digitalRead(IN3);
  int val4 = digitalRead(IN4);
  int val5 = digitalRead(IN5);
 
  // verific daca s-a facut vre-o modificare in "state" 
  if(state1 != val1 || state2 != val2 || state3 != val3 || state4 != val4 || state5 != val5) {
    state1 = val1;
    state2 = val2;
    state3 = val3;
    state4 = val4;
    state5 = val5;
   
    /*
   acum, creem un cuvint pe  8 biti (1 byte) ai carui 5 biti din dreapta reprezinta -
   dela dreapta la stinga-  starea butoanelor fire, right, up, left, down :
   adica 0 daca e apasat, 1 daca nu e apasat not pressed
   Ceilalti  biti nu sint utilizati.
     */
    unsigned int state = (val5 << 4) | (val4 << 3) | (val3 << 2) | (val2 << 1) | val1 ;
    Serial.write(state);
   }

}
-------------------------------------------------------------------------------------------------------------------------------------------------------

Programul de mai sus este destul de simplu. Am văzut deja totul despre logica de comunicare aici.
Singurul lucru nou este faptul că am încercat să limitez cantitatea de date care călătoresc pe firul de serie. De aceea, am setat  variabila "state" cu ajutorul unor operații la nivel de bit. Se construiește un cuvânt de 8 biți ("state"), a cărui 5 biți din dreapta sunt setaţi la 1 în cazul în care butonul asociat nu este apăsat,  sau la 0, dacă este apăsat.
Fiecare bit este inserat pe un loc specificat in byte. Ceilalţi 3 biti rãmin neutilizaţi. astfel , se va expedia serial un singur byte.
Jocul video din Processing
Mai sus, am creat un program care este capabil sã trimitã datele  noastre de stare trimise de  gamepad pe firul serial la PC-ului.
 Acum avem nevoie de ceva pe partea de PC, care va citi aceste date și care va reacționa conform cu valorile situate în variabila “state”.Vom crea un program simplu care deplaseazã un pătrat pe o fereastră.
Folosind butoanele de pe gamepad vom deplasa caseta de pe ecran.
Când apăsați butonul foc, caseta se va schimba culoarea casetei.
Scriptul l-am copiat de la adresa specificată in link-ul de mai sus.
Atentie : şi partea asta de program am modificat-o pentru cã instrucţiunea din scriptul original care cautã  portul serial al lui Arduino, pentru ca  pe PC-ul meu nu a funcţionat.
Linia urmãtoare
             myPort = new Serial(this, "/dev/ttyUSB5", 9600);
a trebuit sã o inlocuiesc cu setul de instrucţiuni:
String portName = Serial.list()[portIndex];
println(" Connecting to -> " + Serial.list()[portIndex]);
myPort = new Serial(this, portName, 9600)
Scriptul corectat, editat in Processing 2.0 şi care merge , este acesta :

-------------------------------------------------------------------------------------------------------------
// game1 = Processing
 import processing.serial.*;
Serial myPort;  // Create object from Serial class
short portIndex = 1; // select the com port, 0 is the first port

int state = 31;
int fire = 1;
int right = 1;
int up = 1;
int left = 1;
int down = 1;

int x = 275;
int y = 275;
int c = 0;

void setup()
{
  size(600, 600);
String portName = Serial.list()[portIndex];
println(" Connecting to -> " + Serial.list()[portIndex]);
myPort = new Serial(this, portName, 9600);

}

void draw() {
  if(myPort.available() > 0) {
    state = myPort.read();
    println(state);
  println(binary(state));  //sa vedem efectul
    println(state);
    fire = state & 1;
    right = (state & 2) >> 1;
    up = (state & 4) >> 2;
    left = (state & 8) >> 3;
    down = (state & 16) >> 4;
   
    print(fire);
    print(right);
    print(up);
    print(left);
    println(down);
  }
   
  c = (fire == 0) ? 250 : 0;
 
  if(right == 0 && left == 1) {
    x = x + 2;
  }
  if(up == 0 && down == 1) {
    y = y - 2;
  }
  if(left == 0 && right == 1) {
    x = x - 2;
  }
  if(down == 0 && up == 1) {
    y = y + 2;
  }
 
  background(255, 255, 150);
  fill(c);
  rect(x, y, 50, 50);
}

Intrebarea retoricã ar fi : de ce  unii mai publicã , daca scripurile lor nu sint corectate, şi funcţionale !
Poate mai sânt şi începatori , chiar şi copii de 14 – 18 ani, care vor sã lucreze , şi sã reuşeascã ! 

duminică, 6 octombrie 2013


Arduino si Processing – comunicare seriala

 Pe net , se gãsete literaturã suficientã, tutoriale şi exemple privind comunicarea serialã intre placa duino şi PC. Una din variantele cele mai accesibile de abordat este Processing 2.0. O sa postez câteva din încercãrile mele , care au funcţionat, fãrã prea multe referiţe teoretice .Doar strictul nrcesar pentru cine vrea sã încerce. 
1.Date de la Arduino la Processing :
- am încãrcat în Arduino Uno sketch-ul “serialAut”:
............................................................................................................ 
/* serialAut – trimite secvental la ‘serialIn’ din Processing  expresia “Hello World!”
Pe portul serial Com3 – in cazul meu */

 void setup()
{
// initialize serial communications at a 9600 baud rate
Serial.begin(9600);
}
void loop()
{
// trimite  'Hello, world!'  la portul serial
Serial.println("Hello, world!");
      //asteaptã  100 millisecunde
delay(100);
}
........................................................................................................................ 
Dupa încãrcarea pe Arduino şi verificarea în Serial Monitor , programul Arduino
1.0  poate fi oprit. Afişarea stringulu transmis se face în Processing 
Programul din Processing care peia datele serial de la Com3 trimise de Arduino:
……………………………………………………………………………………………………..
//serialIn.pde
import processing.serial.*;
//merge !
Serial myPort;   // Creazã un obiect din clasa Serial
String val;         // reţine datele primate de la portul seria
  // aflat în lista Serial.list()[0].  In  Windows, la mine se      //deschid COM1 şi COM3. In Processing primul port deschis //apare cu (0) iar al doilea cu (1)
void setup(){
String portName = Serial.list()[1]; //schimb  0 la 1
//sau portul pe care lucreazã Arduino !
myPort = new Serial(this, portName, 9600);
}
void draw(){
  if ( myPort.available() > 0)  {  // daca au intrat date pe port,
       val = myPort.readStringUntil('\n');   
     // le citeşte şi le preia în  variabila val
  }
println(val);      //print it out in the console
}
………………………………………………………………….
Datele preluate (Hello World) sînt afişate în partea de
jos a interfeţei Processing.
2.Date transmise de la Processing la Arduino
In acest exemplu, sketch-ul “ardIn” primeşte caracterul 1 trimis din Processing de la  “outPro”. Dacã facem click  (sau ţine apasat  butonul stânga mouse) în mini displayul afişat de Processing la rulare, ledul de la pin 13 se aprinde.



3.Comunicare bilaterala (partea 1)  “Shaking Hands”
 Până acum am arătat că Arduino și Processing pot comunica serial atunci când unul “vorbește” și celălalt  “ascultã”. Putem face un link care permite datelor să circule în ambele sensuri, astfel încât Arduino și Processing sa trimita  și sa primeasca date?
 În biz acest lucru este denumit “Shaking Hands” (strângere de mână) , deoarece ambele părți trebuie să fie de acord atunci când  trimit și primesc  date.
Pe aceasta paginã și următoarea, vom combina cele două exemple  anterioare, în așa fel încât Processing poate primi  "Bună ziua, lume!" de la Arduino și poate trimite un 1 înapoi la Arduino pentru a comuta un LED.
Desigur, acest lucru înseamnă, de asemenea, că Arduino trebuie să fie capabil să trimită "Bună ziua, lume!" în timp ce asculta pe portul serial  pentru a primi  un 1 de la Processing. !
Să începem cu partea Arduino a lucrurilor. Pentru ca acest lucru să ruleze fără probleme, ambele părți trebuie să știe ce să asculte și ce trebuie sã trimitã  cealaltă parte, ce așteaptă să audă.
 De asemenea, dorim să reducem la minimum traficul de pe portul serial așa ca sã putem obține mai multe răspunsuri în timp util.
Avem nevoie de o variabilă pentru datele noastre de intrare și o variabilă pentru pinul LED pe care  dorim sa îl  aprindem. In Arduino se încarca scriptul   arduWR.ino:
………………………………………………………………………………………….
/*  arduWR   */
char val;                                          //retine data receptionata de la portul serial
int ledPin = 13;                                // seteaza    pin-ul 13 pentru pentru led  
boolean ledState = LOW;                             // retine starea LED-ului si o initializeaza LOW
void setup()
{
  pinMode(ledPin, OUTPUT);             // seteaza  pinul  ca  OUTPUT
                                                      //initializeaza comunicarea seriala la 9600 baud
  Serial.begin(9600);
  establishContact();  // trimite un byte pentru a stabli contactul atit timp cit  recetorul raspunde
}
void loop()
{
  if (Serial.available() > 0) {    // daca datele sint disponibile pt a fi citite
   val = Serial.read();            //  citeste si le preia in variabila  val
   if(val == '1')                      //daca a fost  trimis ‘1’
    {
       ledState = !ledState;     // comuta starea anterioara a LED-ului: dca a fost stins il aprinde, si invers
       digitalWrite(ledPin, ledState);
    }
    delay(100);                
  }
    else {
    Serial.println("Hello, world!");         //altfel daca nu este ‘1’ trimite inapoi sirul hello world
    delay(50);
    }
}
void establishContact() {
  while (Serial.available() <= 0) {
  Serial.println("A");   // trimite caracterul   A
  delay(300);
  }
}
………………………………………………………………………………………………………..
 In Processing , se editeaza / deschide scriptul “procWR
…………………………………………………………………..
//procWR
 import processing.serial.*; //import the Serial library
 Serial myPort;  //the Serial port object
 String val;   // deoarece facem “serial handshaking”,
// este nevoie sa verificam ce auzim de la microcontroller
boolean firstContact = false;
void setup() {
  size(200, 200);       //make our canvas 200 x 200 pixels big
                               //  initialize your serial port and set the baud rate to 9600
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.bufferUntil('\n');
}
void draw() { //  putem pstra metoda draw goala
                   // pentru că toate programul nostru se petrece în serialEvent (vezi mai jos)}
void serialEvent( Serial myPort) {
// preia data sosita intr-un String
// '\n' este delimitatorul   final, care indica sfirsitul pachetului de date care a fost primit  complet
val = myPort.readStringUntil('\n');
// verificam daca datele noastre nu sint nule , inainte de a continua
if (val != null) {
                  //eliminam  spațiile goale și caracterele de formatare (cum ar fi retur de car)
  val = trim(val);
 println(val);
      // ne uitam dupa șirul  "A"  noastre pentru “start the handshake”
       //daca sirul ‘a’ este prezent, golim  the buffer-ul , si trimitem o cerere de date ( request for data)
  if (firstContact == false) {
    if (val.equals("A")) {
      myPort.clear();
      firstContact = true;
      myPort.write("A");
      println("contact");
    }
  }
  else { // daca am stability udeja un contact, pastram achizitia si preluam datele si le analizam
    println(val);
    if (mousePressed == true)
    {                           //if we clicked in the window
      myPort.write('1');        //send a 1
      println("1");
    }

                              // when you've parsed the data you have, ask for more:
    myPort.write("A");
    }
  }
}
…………………………………………………………………………………………..
Cu board-ul Arduino cuplat la portul serial ( si avind montat LED-ul cu resistor la pin13), se ruleazã “procWR” cu Processing 2 .
 La rularea programului , la click-uri consecutive  în miniDisplay-ul deschis din Processing, LED-ul se aprinde şi se stinge.
Atentie : dacã portul serial este scris corect în Processing, totul merge din prima încercare !
Porturile în Processing sunt numerotate cu 0; 1; 2; 3. Eu am pus 1 pentru cã am douã porturi active : Com1 şi COM3. La mine în PC, portul  COM3 este al doilea port serial si se deschide când cuplez boardul Arduino   



miercuri, 14 august 2013

ATtiny 2313 cu senzor IR

 Printre alte preocupãri, mi-am propus sã vãd cum mai pot utiliza ATtiny 2313. De data asta, am utilizat un senzor digital  infraroşu pentru distanţã (sharp 2-12 cm), la pinul 2 şi un LED roşu la pinul 13.  Am folosit un sketch simplu, pe care l-am incãrcat cu ArduinoUno  


De fapt, am vrut sã vãd şi câtã memorie ocupã in  ATtiny 2313. Si pentru cã bloggerul Google nu mã  lasã  sã  pun fimuletul (nu tiu de ce  !) , am pus doar o imagine :


 Sic - atunci când trece maşina , se aprinde LED-ul !