come posso migliorare lettura encoder

Ciao
Sono alle prese con una applicazione che prevede la lettura di un encoder allegato tipo CWZ6C, ho un segnale quadrato controllato con oscilloscopio, devo migliorare la forma del segnale in uscita dal fotoaccoppiatore 4N32 che è pessimo, allego l'immagine del segnale e lo schema completo che sto utilizzando. Il tutto serve a controllare un motore stepper, potrebbe essere il motore a creare i disturbi?

Avete qualche suggerimento?

Stefano

tappeto_1.pdf (15.5 KB)

Omron_Rotary_Encoder_E6B2_Sept2012.pdf (109 KB)

encoder.pdf (856 KB)

potresti provare con un optocopia a trigger di shmit tipo una H11L1 che è anche abbastmza veloce.

oppure una 6N137 per velocità ancora maggior ma senza il trigger.

ma l'optoisolatore ti serve realmente??

ciao
l'encoder può essere alimentato anche a 5v ma nell'applicazione le altre tensioni sono a 12v, era per avere una sola tensione, cerco quello che mi hai indicato.
Grazie
Stefano

se la velocità è il problema (quindi devi usare opo veloci) ricorda che ci son integrati come il7414 che son trigger di shmit che puoi interporre tra opto ed arduino, nel caso servisse!

Il tuo encoder è con uscite open collector, questo significa che puoi avere 2 tensioni distinte come alimentazione encoder=12VDC e livello di uscita=5VDC, leva il fotoaccoppiatore e metti una resistenza da 1Kohm tra uscita A e +5VDC, e un'altra resistenza tra uscita B e +5VDC , usa un cavo schermato, se l'encoder dista da arduino al massimo 2-3 metri non avrai problemi

ciao
si vede che ci capisco veramente poco, ho seguito schemi trovati in rete, l'uso del fotoaccopiatore mi piaceva per proteggere l'arduino da problemi a monte.
@matinix il 7414 lo conosco e la velocità non è un problema
@icio ma c'e una tensione minima di 2v, ho provato con lo schema ma non funziona il conteggio degli impulsi

Vi descrivo l'applicazione:
devo fare ruotare un tamburo di un certo angolo, da un lato ho un motore stepper collegato al tamburo con una puleggia, dall'altro questo encoder da 360 impulsi/giro, un arduino è collegato all'encoder per usare la funzione interrupt, mentre un altro arduino è collegato attraverso un driver al motore. Questo è lo sketch.

/*
per trapianto_stepper_test_31
 gestisce il segnale dell'encoder
 utilizzo di un encoder NPN
 scheda 7/10
 */
#define encoder_PinA 2
#define motor_Pin 12
#define motor_led 13

volatile long angolo;
long angolo_1;
long angolo_k;

byte fila;
long k;
long i;

void setup()
{
  Serial.begin(9600);

  pinMode(encoder_PinA, INPUT_PULLUP);  
  attachInterrupt(0, canaleA, RISING); //encoder al pin 2
  angolo = 0;
  angolo_1 = 0;
  angolo_k = 100;
  fila = 1;
  k = 1;
  i = 1;

  /*  Serial.print("k");
   Serial.print('\t');
   Serial.println("angolo");*/
  pinMode(motor_Pin, OUTPUT);
  pinMode(motor_led, OUTPUT);

  digitalWrite(motor_Pin, LOW);
  digitalWrite(motor_led, HIGH);
  delay(1000);
  //Serial.println("Pronto");
}

void loop()
{
  while(k == i)
  {
    i++;
    angolo_1 = angolo_k * k;

    switch(fila)
    {
    case 1:
      digitalWrite(motor_Pin, LOW);
      digitalWrite(motor_led, LOW);
      //Serial.println(digitalRead(motor_Pin));
      fila = 2;
      break;

    case 2:
      digitalWrite(motor_Pin, HIGH);
      digitalWrite(motor_led, HIGH);
      fila = 1;
      // Serial.println(digitalRead(motor_Pin));
      break;
    }
    Serial.println(k);
    Serial.println(angolo); 
    Serial.println(angolo_1);
  }

  if(angolo == angolo_1)
  {
    k++;
  }
}

void canaleA()
{
  angolo++;
}

Stefano

ciao
ho migliorato, l'uscita dell'opto verso arduino, mettendo una R2 10k e una R3 tra base e gnd da 1M, adesso ho un problema con lo sketch che, dopo un certo numero di conteggi si ferma, ultriore osservazione è che questo numero è variabile, come al solito chiedo suggerimenti

grazie
Stefano

/*
 gestisce il segnale dell'encoder
 utilizzo di un encoder NPN
 scheda 7/10
 */
#define encoder_PinA 2
#define motor_Pin 12
#define motor_led 13

volatile long angolo;
long angolo_1;
long angolo_k;

byte fila;
long k;
long i;

void setup()
{
  Serial.begin(9600);

  pinMode(encoder_PinA, INPUT_PULLUP);  
  attachInterrupt(0, canaleA, RISING); //encoder al pin 2
  angolo = 0;
  angolo_1 = 0;
  angolo_k = 70;
  fila = 1;
  k = 1;
  i = 1;
  
  pinMode(motor_Pin, OUTPUT);
  pinMode(motor_led, OUTPUT);

  digitalWrite(motor_Pin, LOW);
  digitalWrite(motor_led, HIGH);
  delay(1000);
  //Serial.println("Pronto");
}

void loop()
{
  while(k == i)
  {
    i++;
    angolo_1 = angolo_k * k;
  
    switch(fila)
    {
    case 1:
      digitalWrite(motor_Pin, HIGH);
      digitalWrite(motor_led, HIGH);
      //Serial.println(digitalRead(motor_Pin));
      fila = 2;
      break;

    case 2:
      digitalWrite(motor_Pin, LOW);
      digitalWrite(motor_led, LOW);
      fila = 1;
      // Serial.println(digitalRead(motor_Pin));
      break;
    }
//    Serial.println(k);
//Serial.println(angolo); 
//    Serial.println(angolo_1);
  }

  if(angolo == angolo_1)
  {
    k++;
  }
}

void canaleA()
{
  angolo++;
}

tappeto_1.pdf (15.9 KB)

Ho capito bene cosa significa open collector, ho collegato arduino+encoder ma stavolta è il driver dello stepper a dare problemi, in qualche modo interferisce con la scheda

Stefano

comè alimentato il driver per lo stepper? non è che magari va a rompere le scatole all'alimentazione "generale"?

@martinix
allego lo schema spero sia comprensibile

tappeto.pdf (18.8 KB)

msd752 Motion Control Products _ Stepper Drivers _ MSD542 Microstepping Driver.pdf (2.03 MB)

l'univca cosa che capisco è che ci son 3 alimentazioni (+5vcc, +12Vcc, +24vcc) ma nessuna informazione su chi le da, come son legate tra loro da dove provvengono ecc ecc ecc.
in più hai fatto una stima (almeno) della corrente necessaria a tenere in piedi tutto??

ciao, grazie per il supporto

dalla rete 220v
+24v alimentatore collegato al V+ del driver
GND alimentatore collegato al GND del driver

dalla rete 220v
+9v alimentatore per il primo e secondo arduino

pull+ del driver collegato al +5v del secondo arduino
pull- del driver collegato al pin 12 del secondo arduino

+5v del primo arduino collegato al V+ dell'encoder e a una estremità di una resistenza da 10k
pin 2 collegato all'altra estremità della resistenza da 10k e al segnale dell'encoder
GND collegato al GND dell'encoder

quello che non capisco è perchè il secondo arduino collegato all'encoder funziona solo con il driver non alimentato

oggi ho acquistato dei cavi schermati vediamo se la cosa migliora

Stefano

resistenza di pullup encoder da 1k non da 10k

quindi due alimentatori distinti per +12Vcc e +24vcc le masse son in comune? o le ai lasciate "separate"?

EDIT:
si può avere anche un foto panoramica del tutto ben fatta? magari si nota qualche cosa!

ciao
@martinix come sospettavi c'erano problemi di alimentazione con l'alimentatore (il solito cinese) di arduino, le masse sono tutte in comune con lo schermo dei cavi a massa solo da un lato

il tutto è migliorato ma ancora non funziona allego l'onda dell'encoder e l'onda al pin 12 e qualche foto, nello sketch,

/*
per trapianto_stepper_test_31
 gestisce il segnale dell'encoder
 utilizzo di un encoder NPN
 scheda 7/10
 */
#define encoder_PinA 2
#define motor_Pin 12
#define motor_led 13

volatile long angolo;
long angolo_k;

byte fila;
long k;
long i;

void setup()
{
  Serial.begin(9600);

  pinMode(encoder_PinA, INPUT);  
  attachInterrupt(0, canaleA, RISING); //encoder al pin 2
  
  angolo = 0;
  angolo_k = 100;
  
  fila = 1;
  k = 1;
  i = 1;

  pinMode(motor_Pin, OUTPUT);
  pinMode(motor_led, OUTPUT);

  digitalWrite(motor_Pin, LOW);
  digitalWrite(motor_led, LOW);
  delay(1000);
  //Serial.println("Pronto");
}

void loop()
{
  while(k == i)
  {
    i++;

    switch(fila)
    {
    case 1:
      digitalWrite(motor_Pin, HIGH);
      digitalWrite(motor_led, HIGH);
      //Serial.println(digitalRead(motor_Pin));
      fila = 2;
      break;

    case 2:
      digitalWrite(motor_Pin, LOW);
      digitalWrite(motor_led, LOW);
      fila = 1;
      // Serial.println(digitalRead(motor_Pin));
      break;
    }
    //Serial.print(k);
    //Serial.print('\t');
    //Serial.println(i);
    //Serial.println(angolo); 
    //    Serial.println(angolo_1);
  }
}

void canaleA()
{
  angolo++;
  
    if(angolo == angolo_k * k)
  {
    k++;
  }
}

viene continuamente eseguito mentre dovrebbe essere eseguito ogni qualvolta

angolo == angolo_k * k

grazie
Stefano

pin_12.oxps (776 KB)

encoder.pdf (121 KB)

ciao
le prove continuano, ma senza risultato ho fatto una modifica allo sketch che legge l'encoder ma senza risultato, allora ho provato contando il numero di passi dello stepper ma il posizionamento non è regolare forse perde passi, ma ne la coppia resistente e la velocità di rotazione non sono elevate, 0.2 kg*cm e 1 giro/sec.
Capisco che arduino abbia dei limiti, ma l'applicazione non mi sembra esasperata, considerando il fatto che il conteggio degli impulsi dell'encoder a tavolino funziona bene. La presenza dello stepper nei paraggi crea problemi.

Stefano

a questo punto (se non ci son altre idee) bisognerebbe analizzare un pò tutti i segnali con le nuove modifiche, oltre che i segnali del encoder, anche quelli di uscita di arduino e le alimentazioni, per vedere se entrano disturbi o altro!

ciao
dopo diverse prove e consigli, la situazione è migliorata, resta da risolvere il non trascurabile dettaglio dell'errato posizionamento, cerco di recuperare un opto più veloce come consigliato

Stefano

tappeto.pdf (19.7 KB)

ciao
ho risolto in parte il problema del posizionamento dello stepper, eliminando l'encoder e contando i passi del motore, pero' adesso si presenta uno strano comportamento, che provo a descrivere:
quando il motore si arresta a grazie a un sensore collegato al pin 3 e monitorato dall'interrupt in modalità FALLING, talvolta succede che dopo l'arresto il motore trascorso l'intervallo stabilito ruoti di qualche passo per arrestarsi e riprendere a muoversi regolarmente dopo il medesimo tempo, in pratica succede questo
STOP-MOTO-STOP-MOTO fino al prossimo stop
mentre dovrebbe fare questo
STOP-MOTO fino al prossimo stop

Credo che il comportamento sia anche corretto, perchè dipende da dove l'interrupt riprende il programma, ho quindi provato a mettere un goto dentro l'interrupt per rimandare il programma all'inizio, ma il compilatore non lo accetta

lo sketch che uso:

/* 
 by Nick Gammon per debounce
 */
const byte switchPin = 11;
byte oldSwitchState = HIGH;  // assume switch open because of pull-up resistor
const unsigned long debounceTime = 5;  // milliseconds
unsigned long switchPressTime;  // when the switch last changed state
byte switchState;

#define led_pin         13
#define sensor_stop_pin 3
#define motorPin        12// digital pin per il driver dello stepper


int ritardo, ritardo_1;
volatile byte k;
byte pin;

void setup()
{
  pinMode (led_pin, OUTPUT);

  pinMode (switchPin, INPUT_PULLUP);

  pinMode(sensor_stop_pin, INPUT_PULLUP);
  attachInterrupt(1, sensor_stop, FALLING); //sensore induttivo collegato al pin 2

  pinMode(motorPin,OUTPUT);// set the digital pin as output

  ritardo = 3500;// pauses for microseconds us
  ritardo_1 = 5000;// pauses for milliseconds ms
  
    Serial.begin(9600);
}

void loop()
{ 
  // see if switch is open or closed
  switchState = digitalRead (switchPin);

  // has it changed since last time?
  if (switchState != oldSwitchState)
  {
    // debounce
    if (millis () - switchPressTime >= debounceTime)
    {
      switchPressTime = millis ();  // when we closed the switch 
      oldSwitchState =  switchState;  // remember for next time 
      if (switchState == LOW)
      {
        Serial.println ("Switch closed.");
        digitalWrite(led_pin, HIGH);
      }  // end if switchState is LOW
      else
      {
        Serial.println ("Switch opened.");
        digitalWrite(led_pin, LOW);
      }  // end if switchState is HIGH
    }  // end if debounce time up
  }  // end of state change

  if(k == 0)
  {
    k = 1;
    delay(ritardo_1);
  }
/*
  //sezione motore  
   while(k == 1 && switchState == LOW)
   {
   digitalWrite(motorPin, LOW);   // sets the pin on
   delayMicroseconds(ritardo);// pauses for microseconds
   digitalWrite(motorPin, HIGH);    // sets the pin off
   delayMicroseconds(ritardo);// pauses for microseconds
   switchState = digitalRead(switchPin);
  // Serial.println('a');
   }
*/

  motore();
  
}//fine loop

void sensor_stop()
{
  k = 0;
}


void motore()
{
  if(k == 1 && switchState == LOW)
  {
    digitalWrite(motorPin, LOW);   // sets the pin on
    delayMicroseconds(ritardo);// pauses for microseconds
    digitalWrite(motorPin, HIGH);    // sets the pin off
    delayMicroseconds(ritardo);// pauses for microseconds
  }
}

ciao
ho risolto scrivendo la funzione sotto interrupt in questo modo:

void sensor_stop()
{
  if(digitalRead(sensor_stop_pin) == LOW)
  {
    k = 0;
  }
  else
  {
    k = 1;
  }
}

qualcuno mi può spiegare come mai con un segnale che va da LOW ad HIGH del sensore, talvolta l'interrupt richiama ancora la funzione associata, i segnali controllati con oscilloscopio sono puliti.