Go Down

Topic: sensori per ostacoli (Read 12006 times) previous topic - next topic

xelendilx

Vanno bene questi secondo voi?

http://cgi.ebay.it/8x-L-516-INFRARED-EMITTING-DIODE-IR-Emitter-/170422999871?pt=LH_DefaultDomain_212&hash=item27ae009b3f#ht_840wt_905

lesto

eccomiii!!!!
finalmente ho avuto la voglia di scrivere la classe.... come al solito NON è testata, perché non ho i pezzi... se mi fate un po' di debug mi fate un favore, che la mettiamo nel playground

ERER.cpp
Code: [Select]

#import "ERER.h"

/*
 ERER.cpp - Library for ERER sensors.
 (use 2 infrared LEDs to build a distance sensor)
 Rewritten by Mauro Mombelli 03/04/2011
 Based on code of Giovanni Blu Mitolo, March 11, 2011.
 Released with Creative Commons Attribution licence  
*/

volatile byte _oldbit;
byte _changed, _newbit;
volatile boolean _hasChanged=false;
volatile long rawDistance=0;
volatile byte BCDreceiverN, BCDreceiverP, BCDemitterP;
volatile byte MASKreceiverN, MASKemitterP, MASKreceiverP;
volatile boolean emitterStatus;
unsigned long _time;
unsigned long _startIn[2];
unsigned long _rawIn[2];

ERER::ERER(byte PCINTemitterP, byte PCINTreceiverP, byte PCINTreceiverN){

 //set emitterP pin mode
 BCDemitterP = getBCDpin(PCINTemitterP); //find BCD (see PortManipulation)
 MASKemitterP = (1<< (PCINTemitterP - (8*BCDemitterP) ) ); //find MASK for esy port manipulation
 //set as OUTPUT and HIGH
 switch (BCDemitterP){
   case 0:
     DDRB |= MASKemitterP;
     PORTB |= MASKemitterP;
     break;
   case 1:
     DDRC |= MASKemitterP;
     PORTC |= MASKemitterP;
     break;
   case 2:
     DDRD |= MASKemitterP;
     PORTD |= MASKemitterP;
     break;
 }
 emitterStatus=true;
 
 //set receiverP pin mode
 BCDreceiverP = getBCDpin(PCINTreceiverP); //find BCD (see PortManipulation)
 MASKreceiverP = (1<< (PCINTreceiverP - (8*BCDreceiverP) ) ); //find MASK for esy port manipulation
 //set as OUTPUT and LOW
 switch (BCDreceiverP){
   case 0:
     DDRB |= MASKreceiverP;
     PORTB &= ~MASKemitterP;
     break;
   case 1:
     DDRC |= MASKreceiverP;
     PORTC &= ~MASKemitterP;
     break;
   case 2:
     DDRD |= MASKreceiverP;
     PORTD &= ~MASKemitterP;
     break;
 }
 
 //set PCINTreceiverN as INPUT AND attach Interrupt
 /*
 remember:
 PORTB maps to Arduino digital pins 8 to 13 (PCIE0) form PCINT0 to PCINT7
 PORTC maps to Arduino analog pins 0 to 5 (PCIE1) form PCINT8 to PCINT14
 PORTD maps to Arduino digital pins 0 to 7 (PCIE2) form PCINT16 to PCINT23
 */
 BCDreceiverN = getBCDpin(PCINTreceiverN);
 MASKreceiverN = (1<< (PCINTreceiverN - (8*BCDreceiverN) ) ); //find MASK for esy port manipulation
 
 switch (BCDreceiverN){
   case 0:
     PORTB &= ~MASKreceiverN;//set as INPUT
     PCICR |= (1 << PCIE0); //INTERRUPT ON PCIE0 CHANGE ACTIVATED
     PCMSK0 |= MASKreceiverN; //UMASKING INTERRUPT FOR PIN
     _oldbit = PINB;//To understand witch pin has changed
     break;
   case 1:
     PORTC &= ~MASKreceiverN;//set as INPUT
     PCICR |= (1 << PCIE1); //INTERRUPT ON PCIE0 CHANGE ACTIVATED
     PCMSK1 |= MASKreceiverN; //UMASKING INTERRUPT FOR PIN
     _oldbit = PINC;//To understand witch pin has changed
     break;
   case 2:
     PORTD &= ~MASKreceiverN;//set as INPUT
     PCICR |= (1 << PCIE2); //INTERRUPT ON PCIE0 CHANGE ACTIVATED
     PCMSK2 |= MASKreceiverN; //UMASKING INTERRUPT FOR PIN
     _oldbit = PIND;//To understand witch pin has changed
     break;
 }
 
 //charge ReceiverN using internal pull-up
 setStatus(BCDreceiverN, MASKreceiverN, true);
 //stop charge ReceiverP
 setStatus(BCDreceiverN, MASKreceiverN, false);
}

long ERER::getRawDistance(){
 return rawDistance;
}

byte ERER::getBCDpin(byte PCINTpin){
 if (PCINTpin>=0 && PCINTpin<=7){
   return 0;
 }
 
 if (PCINTpin>=8 && PCINTpin<=14){
   return 1;
 }
 
 if (PCINTpin>=16 && PCINTpin<=23){
   return 2;
 }
 return 3;  
}

void ERER::setStatus(byte BCD, byte MASK, boolean state){
 if (state){
   switch (BCD){
     case 0:
     PORTB |= MASK;
     break;
   case 1:
     PORTC |= MASK;
     break;
   case 2:
     PORTD |= MASK;
     break;
   }
 }else{
   switch (BCD){
     case 0:
     PORTB &= ~MASK;
     break;
   case 1:
     PORTC &= ~MASK;
     break;
   case 2:
     PORTD &= ~MASK;
     break;
   }
 }
}

ISR(PCINT2_vect) {
 if (BCDreceiverN == 2){
   _newbit=PIND;
   _changed=_newbit^_oldbit;
 
   if (_changed & MASKreceiverN){//if PCINTreceiverN has changed
     _time=micros();
     _hasChanged=true;
     
     if (_newbit & MASKreceiverN) { //if PCINTreceiverN now is high
       _startIn[emitterStatus]=_time;
     }else{
       _rawIn[emitterStatus]=_time-_startIn[emitterStatus];
     
       if (!emitterStatus){ //if we read with emitter HIGH and then LOW we have a distace
         rawDistance = _rawIn[0]-_rawIn[1]; //because dark read teorically is lower than light read
       }
     
       //start a new reading changing emitter status
       emitterStatus!=emitterStatus;
       if (emitterStatus){
         switch (BCDemitterP){
           case 0:
             PORTB |= MASKemitterP;
             break;
           case 1:
             PORTC |= MASKemitterP;
             break;
           case 2:
             PORTD |= MASKemitterP;
             break;
         }
       }else{
         switch (BCDemitterP){
           case 0:
             PORTB &= ~MASKemitterP;
             break;
           case 1:
             PORTC &= ~MASKemitterP;
             break;
           case 2:
             PORTD &= ~MASKemitterP;
             break;
         }
       }
   
       //charge ReceiverN using internal pull-up
       PORTD |= MASKreceiverN; //we alreadi know it's PORTD becuse we are in this interrupt :-)
       
       //stop charge ReceiverN
       PORTD &= ~MASKreceiverN;
     }
   }
 
   _oldbit=_newbit;
 }
}

ISR(PCINT1_vect) {
 if (BCDreceiverN == 1){
   _newbit=PINC;
   _changed=_newbit^_oldbit;
 
   if (_changed & MASKreceiverN){//if PCINTreceiverN has changed
     _time=micros();
     _hasChanged=true;
     
     if (_newbit & MASKreceiverN) { //if PCINTreceiverN now is high
       _startIn[emitterStatus]=_time;
     }else{
       _rawIn[emitterStatus]=_time-_startIn[emitterStatus];
     
       if (!emitterStatus){ //if we read with emitter HIGH and then LOW we have a distace
         rawDistance = _rawIn[0]-_rawIn[1]; //because dark read teorically is lower than light read
       }
     
       //start a new reading changing emitter status
       emitterStatus!=emitterStatus;
       if (emitterStatus){
         switch (BCDemitterP){
           case 0:
             PORTB |= MASKemitterP;
             break;
           case 1:
             PORTC |= MASKemitterP;
             break;
           case 2:
             PORTD |= MASKemitterP;
             break;
         }
       }else{
         switch (BCDemitterP){
           case 0:
             PORTB &= ~MASKemitterP;
             break;
           case 1:
             PORTC &= ~MASKemitterP;
             break;
           case 2:
             PORTD &= ~MASKemitterP;
             break;
         }
       }
   
       //charge ReceiverN using internal pull-up
       PORTC |= MASKreceiverN; //we alreadi know it's PORTC becuse we are in this interrupt :-)
       
       //stop charge ReceiverN
       PORTC &= ~MASKreceiverN;
     }
   }
 
   _oldbit=_newbit;
 }
}

ISR(PCINT0_vect) {
 if (BCDreceiverN == 0){
   _newbit=PINB;
   _changed=_newbit^_oldbit;
 
   if (_changed & MASKreceiverN){//if PCINTreceiverN has changed
     _time=micros();
     _hasChanged=true;
     
     if (_newbit & MASKreceiverN) { //if PCINTreceiverN now is high
       _startIn[emitterStatus]=_time;
     }else{
       _rawIn[emitterStatus]=_time-_startIn[emitterStatus];
     
       if (!emitterStatus){ //if we read with emitter HIGH and then LOW we have a distace
         rawDistance = _rawIn[0]-_rawIn[1]; //because dark read teorically is lower than light read
       }
     
       //start a new reading changing emitter status
       emitterStatus!=emitterStatus;
       if (emitterStatus){
         switch (BCDemitterP){
           case 0:
             PORTB |= MASKemitterP;
             break;
           case 1:
             PORTC |= MASKemitterP;
             break;
           case 2:
             PORTD |= MASKemitterP;
             break;
         }
       }else{
         switch (BCDemitterP){
           case 0:
             PORTB &= ~MASKemitterP;
             break;
           case 1:
             PORTC &= ~MASKemitterP;
             break;
           case 2:
             PORTD &= ~MASKemitterP;
             break;
         }
       }
   
       //charge ReceiverN using internal pull-up
       PORTB |= MASKreceiverN; //we alreadi know it's PORTB becuse we are in this interrupt :-)
       
       //stop charge ReceiverN
       PORTB &= ~MASKreceiverN;
     }
   }
 
   _oldbit=_newbit;
 }
}

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

lesto

#152
Apr 04, 2011, 01:28 am Last Edit: Apr 04, 2011, 01:33 am by lesto Reason: 1
ERER.h
Code: [Select]

#ifndef ERER_h
#define ERER_h

#include "WProgram.h"

class ERER {
 public:
   ERER(byte, byte, byte);
   long getRawDistance();
 private:
   byte getBCDpin(byte);
   void setStatus(byte, byte, boolean);
 };

#endif


attenzione ERER non vuole in input i PIN ma il loro valore PCINT (vedere http://arduino.cc/en/Hacking/PinMapping168)
questo permette di usare sia pin digitali che analogici


ESEMPIO DI UTILIZZO:
con irEmitter digital pin 13 = pcint5
irReceiverN digital 2 = PCINT18
irReceiverP digital 5 = PCINT21

Code: [Select]

#inlcude "ERER.h"

ERER lettore = ERER(5, 21, 18);

void setup(){
//non c'è nulla da fare
}

void loop(){
Serial.println( lettore.getRawDistance() );
}


scusate il doppio post ma ho superato il limite di caratteri per post (9500)

EDIT: TODO: funzione di reset e piccolo watch-dog che la richiama. In teoria dovrebbe bastare
Code: [Select]
//charge ReceiverN using internal pull-up
  setStatus(BCDreceiverN, MASKreceiverN, true);
  //stop charge ReceiverP
  setStatus(BCDreceiverN, MASKreceiverN, false);
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

jumpjack

Scusa, mi fai capire bene come posso usare questi sorgenti? La "classe" sarebbe una libreria? Come la installo?

lesto

le classi sono programmazione ad oggetti, sono più una struttura che una libreria, poiché contengono sia funzioni che variabili, e vengono usate come una variabile.
Le "installi" come una normale libreria, e le usi come una normale libreria (il file .cpp anche se non menzionato mai viene poi autocaricato)
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

cavde

ottimo lavoro! appena posso la provo...
Se gommo tiene,io vince gara! Se gommo non tiene,io come bomba dentro montagna

xelendilx


Vanno bene questi secondo voi?

http://cgi.ebay.it/8x-L-516-INFRARED-EMITTING-DIODE-IR-Emitter-/170422999871?pt=LH_DefaultDomain_212&hash=item27ae009b3f#ht_840wt_905

Qualcuno ci darebbe un occhio per piacere? :D

lesto


ottimo lavoro! appena posso la provo...


sarà difficile che funzioni al primo colpo, anche se ad occhio non ci sono errori, salteranno sicuramente fuoi...
Fammi sapere!
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

cavde

il fatto è che ho rotto uno dei led IR che avevo (non chiedermi come XD) e devo andare in negozio a prenderne un paio...
Se gommo tiene,io vince gara! Se gommo non tiene,io come bomba dentro montagna

gbm

Ciao Lesto ma sei un grande l'hai scritta???  :smiley-mr-green: :smiley-mr-green:
La provo subito!! Non sai che piacere!!

Ti farebbe piacere mostrarla su Gioblu.com??
Piu' che altro quasi tutti gli utenti che hanno costruito un robot hanno usato il sistema ERER e tornerebbe PIU CHE UTILE!!
Community robotica / programmazione Arduino
www.gioblu.com

lesto

eheheh l'altra notte avevo voglia di programmare ma i miei progetti non mi attiravano... così mi son messo su questa libreria :)

Ripeto non è ancora testata e data la sua complessità (si lavora direttamente con i registri) mi  stupirebbe assai se funzionasse al primo  colpo :)

Se la testate la finiamo per bene, i test da fare sono:
1: prova generale del funzionamento
2: prova con loop() molto cpu intensive
3: prova di più istanze della classe contemporanemente (ovviamente necessita di 2 led per ogni classe)
4: test a lunga durata: non vorrei fosse necessario creare anche un piccolo watchdog, che però può essere utile anche per evitare poche letture troppo distanti ma farne molte vicine (aumentare la frequenza a discapito  della distanza)

piccola domanda: ma visto che reciverP è sempre a LOW, non è meglio collegarlo a GND così si risparmia un PIN?

Infine una volta finita e testata la libreria volevo postarla nel reference con tanto di spiegazione di funzionamento, quindi la metto anche su gioblu.

quello che non mi torna molto è il fatto di chiamare ISR, se si creano più istanze di classe non vorrei che rompesse le balle per funzione già dichiarata...
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

xelendilx

Rispolvero questo topic per capire qual è il codice che devo usare per questi sensori XD

lesto

questa funziona bene, usa gli interrupt ma in maniera tanto semplice da poter essere un esempio per imparare ad usarli

Code: [Select]
int ricevitore = 2;
int emettitore = 9;

void setup(){
  Serial.begin(115200);
  pinMode(ricevitore, INPUT);
  pinMode(emettitore, OUTPUT);
  delay(1000);
}

unsigned long ris, lastAlto=0;
boolean statoEmettitore=true;
void loop(){
  //accende e spegne il led emettitore, e ne stampa lo stato
  if (statoEmettitore){
    statoEmettitore=false;
    Serial.print("f ");
  }
  else{
    statoEmettitore=true;
    Serial.print("t ");
  }
  digitalWrite(emettitore, statoEmettitore);

  //legge la durata del segnale HIGH sul ricevitore e la stampa a video
  ris=durataHigh();
  Serial.println( ris );
 
  if (statoEmettitore){
    lastAlto=ris;
  }else{
    if (lastAlto<ris){
      Serial.print( "distanza: " );
      Serial.println( ris-lastAlto );
    }else{
      Serial.println( "lettura incongruente" );
    }
  }
}


//FUNZIONE DI LETTURA BLOCCANTE
//per implementare un time-out basta modificare il while
//non è gestito l'overflow di micro()
unsigned long timeHigh;
volatile unsigned long timeLow;

unsigned long durataHigh(){
  timeHigh=micros();
  timeLow=0;//inizializza la lettura a un valore noto, che fungerà da "tappo" per il while
  digitalWrite(ricevitore, HIGH);//attiva pullUP, per caricare il ricevitore
  attachInterrupt(0, tempoLow, FALLING);//vogliamo intercettare quando il digitalPin2 diverrà LOW ("cade" il segnale da 1 a 0)
  digitalWrite(ricevitore, LOW);//disattiva pullUP, il ricevitore è carico

  //attende che la lettura sia completata
  while ( timeLow==0 )//finchè c'è il valore di tappo (il ricevitore è ancora HIGH)
    ;//non fare niente

  detachInterrupt(0);
  return timeLow-timeHigh;
}

//FUNZIONE DI INTERRUPT
//più minimale di così non mi viene :-)
void tempoLow(){
  timeLow=micros();
}
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie


gepponline

Mi son letto tutto il topic e vorrei capire:
Quindi la libreria non è stata realizzata alla fine?
Lesto confermi che l'ultimo codice che hai postato è quello "definitivo"?
MA soprattutto, anche se un po' OT,sono su Ubuntu e lo stavo provando, ma nel serial monitor leggo solo caratteri strani, c'e' qualche impostazione da dargli per la codifica? la versione dell'IDE è la 0022Ubuntu0.1
Grazie!

Go Up