leggere impulsi dal radiocomando x modellismo con arduino???

ciao a tutti,sempre da principiante e modellista rc di aerei...sono gia molto intenzionato a comprarmi arduino 2009.....ho ancora alcune domande da porvi x essere sicuro di passar ad arduino senza pentirmene.......ricordo che ho gia avuto esperienze con mikrobasic e mikroc.....ho imparato molte cose ma molte cose faccio fatica a capirle...x questo che sto cercando un linguaggio piu semplice.

io vorrei tramite gli stic o interuttori del mio radiocomando mx22......poter azionare ,durante il volo di un aereomodello,luci o carelli di atteraggio e altre diavolerie....

è possibile con arduino leggere gli impulsi che arrivano dalla radio?
guardando il ricevitore rc
so che arriva un segnale pwm o ttl dalla radio che normalmente controllano i servocomandi......l impulso è da 50Herz e l impulso positivo dura da 1ms a 2ms e in base a questo il servo si posiziona come io voglio......

ma io vorrei ad esempio a 1,5ms far azionare un transistor che chiude il circuito x accendere dei led.......e a 2ms far azionare un altro transistor x azionare un cicalino che mi servirebbe quando un aereo cade nell erba alta.......TUTTO CIO è POSSIBILE CON ARDUINO??

allora il segnale dalla radio è un PPM
un impulso (che porta tutti i canali) dura circa 20millisec, e il segnale alto va da un minimo di 800microsec a un massimo di 2600.
con arduino puoi leggere sia il segnale "sorgente", ovvero il segnale che contiene tutti i canali, oppure un singolo canale alla volta.

purtroppo data la durata "effimera" del segnale, bisogna per forza usare gli interrupt. Arduino mette a disposizione 2 interrupt facili da usare, ma in realtà ogni pin può essere controllato.

il codice che uso io:
InputPin.cpp

/*
Let You read digital pin 2,4,5,6
modified FROM BIRONPILOT V59, tnx to ciskje
*/
#include "InputPin.h"

#define MASKPCINT0 (1<<2)
#define MASKPCINT1 (1<<4)
#define MASKPCINT2 (1<<5)
#define MASKPCINT3 (1<<6)

InputPin::InputPin(){
  pinMode(2, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  // interrupt on pin change FROM PCINT16 to PCINT23
  PCICR |= (1 << PCIE2);

  PCMSK2 = (1 << PCINT18) | // digital pin2
  (1 << PCINT20) | // digital pin4
  (1 << PCINT21) | // digital pin5
  (1 << PCINT22); // digital pin6
}

//putted here because interrupt dosn't want it in .h
unsigned long _startIn[4];
unsigned long _rawIn[4];
unsigned long _time;
byte _oldbit=0, _newbit, _changed;
volatile boolean _hasChanged=false;

ISR(PCINT2_vect) {
  _time=micros();
  
  _newbit=PIND;
  _changed=_newbit^_oldbit;
  
  if (_changed&MASKPCINT0){//if digital PIN2 has changed

    if (_newbit&MASKPCINT0) { //if PIN2 now is high
      _startIn[0]=_time;
    }else{
      _rawIn[0]=_time-_startIn[0];
    }
    _hasChanged=true;
  }

  if (_changed&MASKPCINT1){//if digital PIN4 has changed
    if (_newbit&MASKPCINT1) 
      _startIn[1]=_time;
    else 
      _rawIn[1]=_time-_startIn[1];
    _hasChanged=true;
  }
  
  if (_changed&MASKPCINT2){//if digital PIN5 has changed
    if (_newbit&MASKPCINT2) 
      _startIn[2]=_time;
    else 
      _rawIn[2]=_time-_startIn[2];
    _hasChanged=true;
  }

  if (_changed&MASKPCINT3){//if digital PIN6 has changed
    if (_newbit&MASKPCINT3) 
      _startIn[3]=_time;
    else 
      _rawIn[3]=_time-_startIn[3];
    _hasChanged=true;
  }
  _oldbit=_newbit;
}

bool InputPin::getAndSetFalseHasChanged(){
  bool temp = _hasChanged;
  _hasChanged = false;
  return temp;
}

int InputPin::getDuration(int i){
  return _rawIn[i];
}

inputPin.h

#ifndef InputPin_h
#define InputPin_h


#include "WProgram.h"

class InputPin{
  
  public:
    InputPin();
    bool getAndSetFalseHasChanged(); // send the initilization handshake
    int getDuration(int); //return the raw duration of high signal, input: channel
  private:
};
#endif

MAMMA MIA che programmone.....spero che quando inizierò a studiarmi il linguaggio di arduino....possa sembrarmi tutto un po piu facile.
comunque sono contento che si possa fare
grazie mille

ciao dai un occhio anche a:
Il codice è davvero semplice, è pensato apposta per far capire il concetto.
Spero ti sia utile:

il codice che hai postato non va benissimo, servono 5 letture per avere un dato buono (in realtà ne basterebbero 2: la prima serve solo per essere sicuri di partire la lettura nel momento in cui il segnale diventa high, la seconda legge il valore reale)
in oltre tutti i segnali che arrivano mentre esegui il resto del codice vengono persi.

Sicuramente è un inizio :slight_smile:

@elicottero78: il codice usa delle funzioni a basso livello che non trovi nel codice arduino, ma nel manuale del microcontrollore, ovvero l'atmega. Da qui deriva la compatibilità solo con atmega <= 328
Il codice è scritto in c++, perché in questo modo è più comoda la portabilità sfruttando il vantaggio delle classi, detto anche paradigma ad oggetti.
per usare la classe è sufficiente copiare i due file nella cartella del tuo progetto, poi per usarla:

#include "InputPin.h"
InputPin lettura;
void loop(){
int valore = lettura.getDuration(pinDaLeggere);
}

Ciao Lesto! Ma l'hai scritto tu?? Interessante!!
In poche parole per provarlo devo includere i due file nell'intestazione?
Ma l'hai scritto tu? Complimenti

Il mio tutorial è orientato a chi una cosa del genere non è in grado di leggerla, per permettergli di capire il concetto e iniziare a giocare :P, mi rendo conto che è abbastanza becero come metodo!! Se guardi il codice utilizzo una semplice media di 5 valori e si mi perdo un sacco di comunicazioni durante il loop!! Hai visto il video?? :stuck_out_tongue:

Ciao Lesto! Ma l'hai scritto tu?? Interessante!!
In poche parole per provarlo devo includere i due file nell'intestazione?
Ma l'hai scritto tu? Complimenti

no, il codice di partenza è di ciskje (vedi commenti), io l'ho riadattato per i altri pin e sotto forma di classe, anche se ormai credi che del codice originale rimanga poco :slight_smile:
il file da includere è solo il .h!!
ah piccolo errore: il file InputPin.c in realtà è InputPin.cpp, altrimenti mi sa che cerca di compilarlo secondo il C ed ovviamente da errore :), ora modifico il post :slight_smile:

Il mio tutorial è orientato a chi una cosa del genere non è in grado di leggerla, per permettergli di capire il concetto e iniziare a giocare smiley-razz, mi rendo conto che è abbastanza becero come metodo!! Se guardi il codice utilizzo una semplice media di 5 valori e si mi perdo un sacco di comunicazioni durante il loop!! Hai visto il video?? smiley-razz

comunque sembra funzionare in modo abbastanza "liscio", perché il tuo loop() è veloce e l'input non è "critico".
Io il codice lo uso su un quadricottero(che deve ancora prendere il volo :drooling_face:), e quindi il loop deve essere il più veloce possibile perché deve gestire l'orientamento (DCM), i PID, i sensori...

Ottimo lesto! :slight_smile:
ho dato un'occhiata veloce al codice... funziona solo con CHANGE o anche con gli altri trigger?

grazie mille,ho capito che questo arduino puo fare molte cose....non mi rimane altro che comprarlo e sperimentare ....x ora grazie a tutti,ciao

funziona solo con CHANGE, visto che la lunghezza dell'impulso va da quando si alza il segnale a quando si abbassa.
Visto però che il segnale è a frequenza fissa, conoscendola a priori si potrebbe usare solo l'interrupt di quando si passa a LOW(il segnale inizia sempre HIGH), e ricavare la lunghezza del segnale HIGH, la prima lettura potrebbe essere sballata ma poi si dimezza il numero di chiamate dell'interrupt, quindi stimiamo 50% di uso CPU?

Salve, prima di aprire un'altra discussione provo a porre la domanda qui, allora:

Possiedo un vecchio elicottero che gestisco tramite una scheda Arduino che sto ovviamente programmando piano piano, ora mi trovo con un problema che aimè non son preparato ad affrontare, che sarebbe: la gestione del quarzo RX di un radiocomando...

Come lo collego alla scheda arduino? ho due soli pin del quarzo(un 35.100) ma il radiocomando è a 4 canali....
Devo collegare un pin a massa, l'altro 5v o in un pin di ingresso Analogico, ad esempio A0??
Non voglio bruciare il quarzo o la scheda, ma non trovo nulla sui collegamenti di un quarzo per interfacciarlo alla scheda potendo quindi leggere gli impulsi ricevuti dal Radiocomando...

Mi scuso per la domanda probabilmente stupida o niubba ma sto imparando ora a gestire elettronica e informatica in "simbiosi" ed ho parecchia ruggine su troppi argomenti elettronici ...
Grazie infinite!!!

Andrea_infoBG:
ma non trovo nulla sui collegamenti di un quarzo per interfacciarlo alla scheda potendo quindi leggere gli impulsi ricevuti dal Radiocomando...

Non trovi nulla per il semplice motivo che non puoi collegare un quarzo su due pin generici di Arduino.
Il quarzo è un elemento risonante utilizzato per realizzare un oscillatore molto stabile e preciso, non è un ricevitore per radiocomando.

Ah caspita chiedo scusa... Ero convinto si potesse fare, ma a questo punto mi viene da chiedere: come posso fare a leggere gli impulsi inviati dal radiocomando in 35.100 con arduino per pilotare l'elicottero?

Andrea_infoBG:
Ah caspita chiedo scusa... Ero convinto si potesse fare, ma a questo punto mi viene da chiedere: come posso fare a leggere gli impulsi inviati dal radiocomando in 35.100 con arduino per pilotare l'elicottero?

Non ho ben capito cosa vuoi fare ?
Il tuo elicottero dovrebbe già avere un ricevente, a cui sono collegati i servo, pertanto con Arduino cosa vorresti farci ?
Sopratutto di che elicottero parliamo ? Se è uno di quei "giocattoli" di piccole dimensioni anche pochi grammi di peso in più va a finire che non ce la fa a sollevarsi.

l'elicottero in questione è un walkera w5 birotore, in poche parole la scheda ricevente è bruciata. comunque la mia idea è di pilotarlo tramite arduino, con l'aggiunta di qualche sensore(sonar, fotoresistenza, una microcamera ecc...) tutto questo l'ho già scritto e funziona(per i test ho utilizzato dei cavi abbastanza 'lunghi' con dei pulsanti e potenziometri(ho limitato la potenza dei motori in modo che non potesse decollare o giocare strani scherzi mentre provavo le funzioni dei sensori, ma il peso della scheda e dei sensori nelle prove non mi è sembrato un problema... male che vada modifico trasmissione e motori), e fin qui tutto bene....

Ora il problema è che per pilotarlo speravo di riutilizzare il radiocomando originale(che funziona con quarzi a 35 Mhz ed ha 4 canali), evitando di aggiungere il modulo a 433Mhz low cost, ma non so come si faccia e sopratutto non so se si possono leggere gli impulsi del radiocomando da una scheda arduino....

lesto:
allora il segnale dalla radio è un PPM
un impulso (che porta tutti i canali) dura circa 20millisec, e il segnale alto va da un minimo di 800microsec a un massimo di 2600.
con arduino puoi leggere sia il segnale "sorgente", ovvero il segnale che contiene tutti i canali, oppure un singolo canale alla volta.

purtroppo data la durata "effimera" del segnale, bisogna per forza usare gli interrupt. Arduino mette a disposizione 2 interrupt facili da usare, ma in realtà ogni pin può essere controllato.

il codice che uso io:
InputPin.cpp

/*

Let You read digital pin 2,4,5,6
modified FROM BIRONPILOT V59, tnx to ciskje
*/
#include "InputPin.h"

#define MASKPCINT0 (1<<2)
#define MASKPCINT1 (1<<4)
#define MASKPCINT2 (1<<5)
#define MASKPCINT3 (1<<6)

InputPin::InputPin(){
 pinMode(2, INPUT);
 pinMode(4, INPUT);
 pinMode(5, INPUT);
 pinMode(6, INPUT);
 // interrupt on pin change FROM PCINT16 to PCINT23
 PCICR |= (1 << PCIE2);

PCMSK2 = (1 << PCINT18) | // digital pin2
 (1 << PCINT20) | // digital pin4
 (1 << PCINT21) | // digital pin5
 (1 << PCINT22); // digital pin6
}

//putted here because interrupt dosn't want it in .h
unsigned long _startIn[4];
unsigned long _rawIn[4];
unsigned long _time;
byte _oldbit=0, _newbit, _changed;
volatile boolean _hasChanged=false;

ISR(PCINT2_vect) {
 _time=micros();
 
 _newbit=PIND;
 _changed=_newbit^_oldbit;
 
 if (_changed&MASKPCINT0){//if digital PIN2 has changed

if (_newbit&MASKPCINT0) { //if PIN2 now is high
     _startIn[0]=_time;
   }else{
     _rawIn[0]=_time-_startIn[0];
   }
   _hasChanged=true;
 }

if (_changed&MASKPCINT1){//if digital PIN4 has changed
   if (_newbit&MASKPCINT1)
     _startIn[1]=_time;
   else
     _rawIn[1]=_time-_startIn[1];
   _hasChanged=true;
 }
 
 if (_changed&MASKPCINT2){//if digital PIN5 has changed
   if (_newbit&MASKPCINT2)
     _startIn[2]=_time;
   else
     _rawIn[2]=_time-_startIn[2];
   _hasChanged=true;
 }

if (_changed&MASKPCINT3){//if digital PIN6 has changed
   if (_newbit&MASKPCINT3)
     _startIn[3]=_time;
   else
     _rawIn[3]=_time-_startIn[3];
   _hasChanged=true;
 }
 _oldbit=_newbit;
}

bool InputPin::getAndSetFalseHasChanged(){
 bool temp = _hasChanged;
 _hasChanged = false;
 return temp;
}

int InputPin::getDuration(int i){
 return _rawIn[i];
}




inputPin.h


#ifndef InputPin_h
#define InputPin_h

#include "WProgram.h"

class InputPin{
 
 public:
   InputPin();
   bool getAndSetFalseHasChanged(); // send the initilization handshake
   int getDuration(int); //return the raw duration of high signal, input: channel
 private:
};
#endif

Ciao Lesto,
è passato un po di tempo dal tuo post,
volevo sapere se hai perfezionato il tuo codice, e se è possibile aumentare il numero di canali in ingresso, portandolo fino ad 8.
Ho preso un Pro Trinket che monta un ATmega328 con 18 GPIO, 28K of flash, and 2K of RAM.
Appena mi arriverà proverò subito il tuo codice...
Se hai altre informazioni utilissime ti ringrazio.
Ciao

@elettrone: essendo il tuo primo post, ti chiederei di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione) e di leggere con attenzione il REGOLAMENTO ... Grazie.

Guglielmo