Encoder rotativo e regolazione PWM

Salve a tutti sono nuovo di questo Forum e di Arduino Uno (ce l'ho da meno di una settimana) ma frequento la classe quinta elettronica di un Istituto Tecnico quindi so qualcosa sia di programmazione che di elettronica. Il mio progetto consiste nel regolare la velocità di un motore a 12V, controllato in PWM, con un Encoder Rotativo. Ho guardato alcuni esempi On-line, ma fino ad ora nessuno mi è stato d'aiuto. Ringrazio anticipatamente per l'aiuto.

Riporto il link per l'encoder che utilizzo

http://www.sparkfun.com/datasheets/Components/TW-700198.pdf

Riccardo

Ciao morobot, benvenuto, la cosa che vuoi fare è possibile in modo abbastanza semplice. Ho guardato la doc dell'encoder e lo trovo pessima, comunque il terminale C va a GND, A e B vanno collegati ad ingressi digitali. La gestione la puoi fare in poolling http://it.wikipedia.org/wiki/Polling_%28informatica%29, oppure usando gli interrupt. Dovrai gestire l'incremento/decremento di una variabile in base al verso in cui ruoti l'encoder, ovviamente la variabile non deve andare in negativo o superare il valore prestabilito.

Dopo aver preso confidenza con l'encoder passi a realizzare il comando in pwm e ti renderai conto che il PWM lo gestisci con una variabile che va da 0 a 255.

Poi passi ad integrare le due cose insieme.

Ho guardato alcuni esempi On-line, ma fino ad ora nessuno mi è stato d'aiuto.

Quali esempi hai guardato?

Ciao

Ciao, grazie per la risposta. L’esempio che ho trovato è questo, ma non ne ho capito molto e non mi funziona.

/* Rotary encoder read example */
#define ENC_A 14
#define ENC_B 15
#define ENC_PORT PINC
 
void setup()
{
  /* Setup encoder pins as inputs */
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);
  Serial.begin (115200);
  Serial.println("Start");
}
 
void loop()
{
 static uint8_t counter = 0;      //this variable will be changed by encoder input
 int8_t tmpdata;
 /**/
  tmpdata = read_encoder();
  if( tmpdata ) {
    Serial.print("Counter value: ");
    Serial.println(counter, DEC);
    counter += tmpdata;
  }
}
 
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
  static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t old_AB = 0;
  /**/
  old_AB <<= 2;                   //remember previous state
  old_AB |= ( ENC_PORT & 0x03 );  //add current state
  return ( enc_states[( old_AB & 0x0f )]);
}

Per la modulazione PWM, ho capito come funziona. Ora vorrei capire come posso pilotare un motore 12V DC con questo segnale.

Ciao

Ciao, ho dato una guardata al codice e devo dire che anche io non l'ho compreso all'istante, però dovrebbe funzionare, dovrebbe perchè non lo posso testare. Comunque quel codice è poco didattico e necessità di una spiegazione perchè un principiante lo possa capire.

A te alla fine ti serve la variabile "counter" la quale viene incrementata o decrementato in base al senso di rotazione dell'encoder. Tu però dici che non funziona, allora potrebbe essere che hai sbagliato a collegare l'encoder ad arduino.

Il codice dice che A e B devono essere collegati rispettivamente ai pin 14 e 15 che corrispondo ai digital pin 8 e 9 di Arduino. Ricontrolla e poi dammi più info, su cosa accade di preciso. Nota che viene inviato il valore della variabile counter tramite seriale quindi aprendo il monitor seriale di Arduino IDE dovresti vedere la scritta "Counter value: 'il valore di counter'.

Se trovi l'inghippo dovrai risolvere il problema legato al superamento del valore minimo/massimo accettato dal PWM.

Ciao.

morobot: Riporto il link per l'encoder che utilizzo

http://www.sparkfun.com/datasheets/Components/TW-700198.pdf

Riccardo

Ciao Riccardo Quel encoder é pensato come dispositivo di input per un umano non come sensore di posizione o velociá di rotazione per un motore. Regge solo 30000 giri ("Rotational life: 30,000 cycles") che un motore fa in 5 minuti. Ciao Uwe

Quel encoder é pensato come dispositivo di input per un umano non come sensore di posizione o velociá di rotazione per un motore. Regge solo 30000 giri ("Rotational life: 30,000 cycles") che un motore fa in 5 minuti. Ciao Uwe

Io però ho capito che non volesse collegarlo meccanicamente al motore, ma che volesse usarlo per variare il PWM manualmente. Se però lo deve collegare all'albero deve scegliere un Encoder ottico, da acquistare ho da autocostruire.

Ciao.

MauroTec: Io però ho capito che non volesse collegarlo meccanicamente al motore, ma che volesse usarlo per variare il PWM manualmente. Se però lo deve collegare all'albero deve scegliere un Encoder ottico, da acquistare ho da autocostruire. Ciao.

È una possibile e molto probabile interpretazione. Ciao Uwe

Ciao quello che voglio fare è regolare manualmente la velocità di rotazione di un motore tramite un encoder.

Ho riprovato il programma e, come per la prima volta, non funziona e non riesco a capire dove sbaglio. Nel frattempo però ho trovato un'altro esempio, che funziona, ma doveri includere il contatore e non ho idea da dove iniziare.

// This is just a code snippet, provided in case it helps you.
// My setup: This encoder has pin C (middle pin of the three on one side) and 
// one of the pair on the other side connected to ground.  The other pins are 
// connected as follows to my Arduino Mega:
//      'A': digital pin 22
//      'B': digital pin 24
//      'press': digital pin 26
// In "real" code, you'd want a state machine to keep track of the rotation,
// and only take note of the "forward" or "back" when the encoder is reporting
// 0 again.

// Digital pin definitions
enum enDigitalPins
{
  // Rotary encoder input lines
  dpInEncoderA=22,
  dpInEncoderB=24,
  dpInEncoderPress=26,
};


static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);
  pinMode(dpInEncoderB, INPUT);
  digitalWrite(dpInEncoderB, HIGH);
  pinMode(dpInEncoderPress, INPUT);
  digitalWrite(dpInEncoderPress, HIGH);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}


void ReadEncoder()
{
  int Position, Press;
  int isForward = 0;
  
  _ResetPins();
  Serial.println("Reading the encoder... press a key to abort.");
  _lowlevel_ReadEncoder(Position, Press);
  while (!Serial.available())
  {
    int Position2, Press2;
    do
    {
      _lowlevel_ReadEncoder(Position2, Press2);
    } while ((Position2 == Position) && (Press2 == Press));
    if (Position2 != Position)
    {
      // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
      // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
      // turning the device the other way.  Remember: this is Gray code, not
      // binary.
      int isFwd = ((Position == 0) && (Position2 == 1)) ||
                  ((Position == 1) && (Position2 == 3)) ||
                  ((Position == 3) && (Position2 == 2)) ||
                  ((Position == 2) && (Position2 == 0));
      Serial.println(isFwd ? "FWD" : "BWD");
    }
    if (Press2 != Press)
    {
      Serial.println(Press ? "Press" : "Release");
    }
    Position = Position2;
    Press = Press2;
  }
}


void setup()
{
  // configure the pins
  _ResetPins();

  // init serial communication
  Serial.begin(115200); 
  Serial.println("Ready to begin");
}


void loop()
{
  ReadEncoder();
}

Ciao

Ciao
dopo settimane di prove e riprove sono finalmente giunto a un codice definitivo che funziona.
Eccolo qua:

#define encoderPinA 2
#define encoderPinB 3

int encoderCounter = 0;

void setup() {

pinMode(encoderPinA, INPUT);
digitalWrite(encoderPinA, HIGH); // turn on pullup resistor
pinMode(encoderPinB, INPUT);
digitalWrite(encoderPinB, HIGH); // turn on pullup resistor
pinMode(6, OUTPUT);

attachInterrupt(0, doEncoder, CHANGE); // encoder pin on interrupt 0 - pin 2
Serial.begin(9600);
}

void loop(){
  
  int p=encoderCounter*0.39215686;
  Serial.println(p);  //Stampa la percentuale del duty cicle dell'onda
  Serial.println(encoderCounter);  //Stampa il valore in uscita PWM (0-255)

  analogWrite(6,encoderCounter);
  
}

void doEncoder() {

if (digitalRead(encoderPinA) == digitalRead(encoderPinB)) {
encoderCounter++;
} else {
encoderCounter--;
}

}

int p=encoderCounter*0.39215686;

Non capisco perche lo moltiplichi per quella costante, ne devi fare di giri per arrivare avere p = 255.

Cosa accade se giri l’encoder quando “encoderCounter” supera 255 (ritorna ad 1) o quando a zero sottrai 1 (va a 255), se questo comportamento non è voluto, puoi introdurre delle if alla fine di doEncoder(), ma devi togliere la moltiplicazione *0.39…
Tipo:
if (econderCounter > 255) encoderCounter = 255;
if (encoderCounter < 0 ) encoderCounter = 0;

Ciao.

Ciao la moltiplicazione per 0,39215686 serve per calcolare la percentuale del duty cicle dell'onda triangolare (è 100/255). Ho aggiunto le righe di programma per evitare che vada sotto il minimo o sopra il massimo.