24V Drehgeber Arduino

Hallo zusammen,

ich habe einen 24V Drehgeber hier liegen (Hengstler RI58-O/500EK.42KH), dieser arbeitet mit 24V und gibt ein Rechtecksignal A und B 90° versetzt aus, wenn ich das Datenblatt richtig verstanden habe..

Wie gehe ich da am besten vor? Ich habe das jetzt einfach testweise mal per Spannungsteiler mit 2 Widerständen an einen Arduino gehangen und seinen Code genommen: https://www.gammon.com.au/forum/?id=11130 der wurde ja oft empfohlen.
Nun habe ich wenn ich nur A anschließe, dass der immer weiter zählt, aber sobald ich drehe deutlich schneller. Wenn ich B auch verbinde, zählt er nur wenn ich auch drehe, sowohl negativ als auch positiv aber sehr durcheinander (mit Sprüngen, plötzlich zählt er andersrum, etc.)

Liegt das daran, dass die Schaltung nicht entprellt ist, oder weil die Signale zu viele sind für den Arduino mit 500 Pulsen / Umdrehung?

Kann mir jemand vielleicht einen Tipp oder Lösung geben wie ich am beste vorgehe? Zunächst möchte ich mir damit ein Längenmessgerät basteln, also ein Messrad zum ablängen von Kabeln o.ä. Mit viel viel Zeit wollte ich daraus einen kleinen Schneidautomat bauen, aber da muss ich erstmal schauen. Geplant wäre erstmal Arduino, Display und ein verlässliches Messrad womit ich dann erstmal weiter rumtüftel. Auf der Codeseite schreibt er etwas von Kondensatoren, aber die sind ja sicher nicht allgemeingültig für alle Drehgeberarten?
Ich wäre in den nächsten Tagen nochmal in der Nähe eines Elektronikshops, dann könnte ich benötigte Teile zum testen kaufen :slight_smile:

Datenblätter:

https://www.hengstler.de/gfx/file/shop/encoder/RI58/Datenblatt_RI58-O_de(2).pdf
https://www.hengstler.de/gfx/file/shop/encoder/RI58/2522479_Installation_Instruction_RI58.pdf

Merci :slight_smile:

Höchstwahrscheinlich hast Du die Masseleitung zwischen Arduino und Geber vergessen.

Zeige doch mal Dein Schaltbild.

Schaltbild versuche ich heute Abend zu erstellen, aber:

  • Arduino Nano, Power über USB aktuell
  • Drehgeber an 24V Netzteil

Drehgeber:
Pin 10 Weiß - GND
Pin 12 Braun - VCC
Pin 5 Grau - A
Pin 8 Grün - B

Spannungsteiler:
GND von Drehgeber <> 5,6k Ohm <> Leitung zu Arduino D2 <> 1,5k Ohm <> Pin 5 Drehgeber (A)
GND von Drehgeber <> 5,6k Ohm <> Leitung zu Arduino D5 <> 1,5k Ohm <> Pin 8 Drehgeber (B)

Ja, keine extra Masseverbindung zwischen Arduino und Drehgeber-Masse, die werde ich dann heute Abend noch anklemmen, vielleicht wars das ja dann :slight_smile:

Sollte eigentlich nicht prellen da der Drehgeber optisch abgetastet wird.
Wenn Du nur ein signal auswerten willst mußt du den anderen Arduinoeingang auf Masse oder +5V legen und nicht einfach unbeschaltet lassen.

Grüße Uwe

Okay, ich werde das heute abend dann so nochmal mit Masseleitung versuchen.

Ist ein solcher spannungsteiler aus 2 Widerständen denn ausreichend für den dauerhaften Betrieb oder sollte ich lieber etwas anderes verwenden?

Leider sagt der Hersteller 10-30v VCC, wäre lieber auf 5V gegangen dafür aber dann wird wohl kein Signal rauskommen aber der Drehgeber war nunmal da.

Ich habe aber doch richtig verstanden das 500 Striche bedeutet, dass eine Umdrehung 500 Impulse sein sollten, oder? Dann könnte ich mir schonmal Gedanken um ein Messrad machen welches mir genug Genauigkeit bietet.

JumpY:
Spannungsteiler:
GND von Drehgeber <> 5,6k Ohm <> Leitung zu Arduino D2 <> 1,5k Ohm <> Pin 5 Drehgeber (A)
GND von Drehgeber <> 5,6k Ohm <> Leitung zu Arduino D5 <> 1,5k Ohm <> Pin 8 Drehgeber (B)

Ja, keine extra Masseverbindung zwischen Arduino und Drehgeber-Masse, die werde ich dann heute Abend noch anklemmen, vielleicht wars das ja dann :slight_smile:

Die Masseleitung muss sein.

Ich werde aus deiner Beschreibung des Spannungsteilers nicht schlau. Mich dünkt, du hast ihn falsch herum angeschlossen, so dass 19V (24V-5V) am Arduino ankommen, wenn du denn GND verbunden hättest.

Hallo

Die Drehgeber von dem Hersteller sind sehr gut da prellt sicher nichts

Ja die 500 sind die impulse einer Spur bei einer Umdrehung

Ich denke auch du hast den Teiler falsch herum

Spannungsteiler
Die Teilspannungen verhalten sich wie die Einzelwiderstände

Also 24 ist die Gesamtspannung

5 die eine Teilspannungen = kleinerer Widerstsnd
19 die andere Teilspannungen = größere Widerstsnd

Wenn du nur die Position benötigst kann du mit einem Kanal zahlen und den zweiten nur für die Richtung benutzen.
A positive Flanke soll zählen
Wenn die Flanke erkannt wird und B ist H dann vorwärts
Wenn die Flanke erkannt wird und B ist L dann rückwärts

Hi

Kann der Treiber des Drehgeber Strom auch aufnehmen? (5V ca. 10kΩ)
Dann kannst Du folgendes versuchen:

  • Arduino-Pins auf INPUT_PULLUP
  • Zwischen Arduino-Pins und Drehgeber-Signale jeweils eine Diode, Anode (Plus-Seite) zum Arduino

Wenn das Signal +24V ist, sperrt die Diode und der Arduino sieht Seine 5V (vom PullUp).
Wenn das Signal GND ist, leitet die Diode und der Pin wird auf GND gezogen, Strom wird durch den PullUP begrenzt.

Netter Nebeneffekt: Bei einem 3,3V-Arduino sieht Dieser halt 3,3V und GND

MfG

PS: Nicht auf meinem Mist gewachsen, irgendwo auf mc.net aufgeschnappt

Der Spannungsteiler war schon richtig, vielleicht habe ich das falsch aufgeschrieben, habs mit der konstanten Spannungsquelle getestet, kommen 5V raus.

Ich habe jetzt eine Masseleitung vom Netzteil mit auf den Arduino gelegt, die Messung ist trotzdem irgendwie seltsam.
Ich weiß nicht wie ich das jetzt am besten zeige wo das Problem liegt..

Wenn ich ganz langsam im Uhrzeigersinn 360° drehe, zählt der Code ~1000 Counts, drehe ich deutlich schneller, verschluckt der Arduino Counts (teilweise kommen dann nur 500 raus), vermutlich ist das Signal dann zu schnell für den Arduino, oder? Das gleiche auch gegen den Uhrzeigersinn, da scheint also noch was nicht zu stimmen.. Angeschlossen sind beide Signale also A und B aktuell, oder gibt es vielleicht einen besseren Code dafür um das zu testen?

Mir wäre wichtig das beide Drehrichtungen richtig abgerechnet werden, falls ich beim Messvorgang mal ein Stück zurück muss.

Dieses Modell ist für 10 bis 30V Versorgungsspannung. Es gibt Modelle dieses Encoders für 5V Versorgung.
Grüße Uwe

Das ist mir bekannt, deshalb ja der Spannungsteiler, oder passts nicht?

Hallo,

wenn das pollen nicht zu langsam ist, kannste das gern einen "fremden" Praxistest unterziehen. Wäre mal interessant zu wissen.
Pins ins Zeile 144 ändern und losgehts :slight_smile:

/*
 *  https://forum.arduino.cc/index.php?topic=583310.0
 */

using Register = volatile byte *;

// UNO, Nano, Pro Mini usw.
#if defined(__AVR_ATmega328P__) | defined(__AVR_ATmega328__) | defined(__AVR_ATmega168P__) | defined(__AVR_ATmega168__)
  constexpr byte pinMaske[]     = {0b1, 0b10, 0b100, 0b1000, 0b10000, 0b100000, 0b1000000, 0b10000000, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b100000, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b100000,};
  constexpr Register portList[] = {&PORTD, &PORTD, &PORTD, &PORTD, &PORTD, &PORTD, &PORTD, &PORTD, &PORTB, &PORTB, &PORTB, &PORTB, &PORTB, &PORTB, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC,};
  constexpr Register ddrList[]  = {&DDRD, &DDRD, &DDRD, &DDRD, &DDRD, &DDRD, &DDRD, &DDRD, &DDRB, &DDRB, &DDRB, &DDRB, &DDRB, &DDRB, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC,};
  constexpr Register pinList[]  = {&PIND, &PIND, &PIND, &PIND, &PIND, &PIND, &PIND, &PIND, &PINB, &PINB, &PINB, &PINB, &PINB, &PINB, &PINC, &PINC, &PINC, &PINC, &PINC, &PINC,};
//    #endif

// Mega
#elif defined(__AVR_ATmega2560__) | defined(__AVR_ATmega1280__)
  constexpr byte pinMaske[]     = {0b1, 0b10, 0b10000, 0b100000, 0b100000, 0b1000, 0b1000, 0b10000, 0b100000, 0b1000000, 0b10000, 0b100000, 0b1000000, 0b10000000, 0b10, 0b1, 0b10, 0b1, 0b1000, 0b100, 0b10, 0b1, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b100000, 0b1000000, 0b10000000, 0b10000000, 0b1000000, 0b100000, 0b10000, 0b1000, 0b100, 0b10, 0b1, 0b10000000, 0b100, 0b10, 0b1, 0b10000000, 0b1000000, 0b100000, 0b10000, 0b1000, 0b100, 0b10, 0b1, 0b1000, 0b100, 0b10, 0b1, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b100000, 0b1000000, 0b10000000, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b100000, 0b1000000, 0b10000000,};
  constexpr Register portList[] = {&PORTE, &PORTE, &PORTE, &PORTE, &PORTG, &PORTE, &PORTH, &PORTH, &PORTH, &PORTH, &PORTB, &PORTB, &PORTB, &PORTB, &PORTJ, &PORTJ, &PORTH, &PORTH, &PORTD, &PORTD, &PORTD, &PORTD, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTA, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC, &PORTD, &PORTG, &PORTG, &PORTG, &PORTL, &PORTL, &PORTL, &PORTL, &PORTL, &PORTL, &PORTL, &PORTL, &PORTB, &PORTB, &PORTB, &PORTB, &PORTF, &PORTF, &PORTF, &PORTF, &PORTF, &PORTF, &PORTF, &PORTF, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK,};
  constexpr Register ddrList[]  = {&DDRE, &DDRE, &DDRE, &DDRE, &DDRG, &DDRE, &DDRH, &DDRH, &DDRH, &DDRH, &DDRB, &DDRB, &DDRB, &DDRB, &DDRJ, &DDRJ, &DDRH, &DDRH, &DDRD, &DDRD, &DDRD, &DDRD, &DDRA, &DDRA, &DDRA, &DDRA, &DDRA, &DDRA, &DDRA, &DDRA, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC, &DDRD, &DDRG, &DDRG, &DDRG, &DDRL, &DDRL, &DDRL, &DDRL, &DDRL, &DDRL, &DDRL, &DDRL, &DDRB, &DDRB, &DDRB, &DDRB, &DDRF, &DDRF, &DDRF, &DDRF, &DDRF, &DDRF, &DDRF, &DDRF, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK,};
  constexpr Register pinList[]  = {&PINE, &PINE, &PINE, &PINE, &PING, &PINE, &PINH, &PINH, &PINH, &PINH, &PINB, &PINB, &PINB, &PINB, &PINJ, &PINJ, &PINH, &PINH, &PIND, &PIND, &PIND, &PIND, &PINA, &PINA, &PINA, &PINA, &PINA, &PINA, &PINA, &PINA, &PINC, &PINC, &PINC, &PINC, &PINC, &PINC, &PINC, &PINC, &PIND, &PING, &PING, &PING, &PINL, &PINL, &PINL, &PINL, &PINL, &PINL, &PINL, &PINL, &PINB, &PINB, &PINB, &PINB, &PINF, &PINF, &PINF, &PINF, &PINF, &PINF, &PINF, &PINF, &PINK, &PINK, &PINK, &PINK, &PINK, &PINK, &PINK, &PINK,};
//    #endif

#else
  #error "This AVR type is currently not yet supported."
#endif

constexpr Register getOutPort(const byte pin) {
  return portList[pin];
};

constexpr Register getDdrPort(const byte pin) {
  return ddrList[pin];
};

constexpr Register getInPort(const byte pin) {
  return pinList[pin];
};

constexpr byte getMaske(const byte pin) {
  return pinMaske[pin];
};

template <byte pin_a, byte pin_b, byte raster = 0, int _min = 0, int _max = 0>
class GrayEncoder               // Klassenname "GrayEncoder"
{
  protected:                    // private wird zu protected, nur intern zugängliche Elemente ...
    int relMin;
    int relMax;
    byte shift;                 // Zählkorrektur wegen Steps pro Rastung
    volatile long rel_counter;  // relativer Zähler, veränderbar
    volatile long abs_counter;  // absoluter Zähler, nicht veränderbar
    int direction;              // Richtungsanzeige  +1 / -1
    int enc_delta;
    int last;
    byte phase_a;               // erste Phase
    byte phase_b;               // zweite Phase
    long abs_old;
    
    int getPhases() {
      int n = 0;                      // new
      
      phase_a = bool(*getInPort(pin_a)  &  getMaske(pin_a));
      phase_b = bool(*getInPort(pin_b)  &  getMaske(pin_b));

      if ( phase_a ) n = 3;
      if ( phase_b ) n ^= 1;          // convert gray to binary
      return n;
    }
    
    void update_RelativCounter () {
      long new_abs = abs_counter >> shift;          // halbiert, geviertelt oder ... Steps pro Rastung
      
      if ( new_abs != abs_old) {
        if (new_abs > abs_old) {
          rel_counter++;
        }
        else {
          rel_counter--;
        }
        
        abs_old = new_abs;
      
        if (rel_counter < relMin) {
          rel_counter = relMax;
        }
        else if (rel_counter > relMax) {
          rel_counter = relMin;
        }
      }
    }
    
  public:              // von außen zugängliche Elemente ...    
    GrayEncoder ():
      // Initialisierungsliste
      relMin(_min),
      relMax(_max),
      shift(raster/2),
      rel_counter(_min),   // Zähler
      abs_counter(0),   // Zähler
      direction(0),     // Richtungsanzeige  +1 / -1     
      abs_old(0)
    { }
    
    void init()
    {
      *getDdrPort(pin_a) &= ~getMaske(pin_a);
      *getOutPort(pin_a) |=  getMaske(pin_a);
      
      *getDdrPort(pin_b) &= ~getMaske(pin_b);
      *getOutPort(pin_b) |=  getMaske(pin_b);
      
      last = getPhases();   // power on state
      enc_delta = 0;
    }

    void encode()
    {
      int n = getPhases();
      int diff = last - n;
      
      if ( diff & 1 )  {                        // bit 0 = value (1)
        last = n;                               // store new as next last
        enc_delta = (diff & 2) - 1;             // bit 1 = direction (+/-), Zähler
        abs_counter += (long) enc_delta;
        direction = enc_delta;                  // Richtungsanzeige (+1 / -1)
      }
      update_RelativCounter();
    }

    int getDirection()  {return direction; }      // Richtungsabfrage
    
    long getRelCounter()  {return rel_counter; }  // relativen Zählwert abfragen, ist schon angepasst
                  
    long getAbsCounter()  {return abs_counter >> shift; } // absoluten Zählwert abfragen
                                                          
    int getA()  { return phase_a; }
    
    int getB()  { return phase_a; }
        
};

// ---------------------------------------------------------------------------------------

GrayEncoder <40, 41, 0> Hengstler; // Pins Phase A,B / Raster

int Hengstler_Direction;
int Hengstler_AbsCounter;


void setup() {
  Serial.begin(250000);
  
  Hengstler.init();
}

void loop() {

  update_Encoder();

  serieller_Monitor(); 
}


// ****** Funktionen ******

void update_Encoder ()
{
  
  Hengstler.encode();
  Hengstler_Direction  = Hengstler.getDirection();
  Hengstler_AbsCounter = Hengstler.getAbsCounter();
}

/*
void Ausgabe()
{
  static long Enc1_old_abs = 0;
 
  if (Hengstler_AbsCounter != Enc1_old_abs) {
    serieller_Monitor();
    Enc1_old_abs = Hengstler_AbsCounter;
  }
}
*/

void serieller_Monitor ()
{  
  const unsigned int INTERVAL = 999;
  static unsigned long last_ms = 0;

  if (millis() - last_ms < INTERVAL) return; // Zeit noch nicht erreicht, Funktion abbrechen

  last_ms += INTERVAL;
  
  Ueberschriftszeile();

  Serial.print(Hengstler_Direction);   Serial.print('\t');
  Serial.print(Hengstler_AbsCounter);    
  Serial.println();
}


void Ueberschriftszeile ()
{
  static int counter = 33;

  counter++;

  if (counter < 30) return; // Zeilen noch nicht erreicht, Funktion abbrechen

  counter = 0;
  Serial.print(F("DIR"));  Serial.print('\t');
  Serial.print(F("abs"));    
  Serial.println();
}

Arduino: 1.6.1 (Windows 8.1), Platine: "Arduino Uno"

sketch_dec06a.ino:6:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:6:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:7:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:7:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:8:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:8:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:9:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:9:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:5:7: error: expected nested-name-specifier before 'Register'

sketch_dec06a.ino:5:7: error: 'Register' has not been declared

sketch_dec06a.ino:5:16: error: expected ';' before '=' token

sketch_dec06a.ino:5:16: error: expected unqualified-id before '=' token

sketch_dec06a.ino:9:3: error: 'constexpr' does not name a type

sketch_dec06a.ino:9:3: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:10:3: error: 'constexpr' does not name a type

sketch_dec06a.ino:10:3: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:11:3: error: 'constexpr' does not name a type

sketch_dec06a.ino:11:3: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:12:3: error: 'constexpr' does not name a type

sketch_dec06a.ino:12:3: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:27:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:27:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:31:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:31:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:35:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:35:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino:39:1: error: 'constexpr' does not name a type

sketch_dec06a.ino:39:1: note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11

sketch_dec06a.ino: In member function 'int GrayEncoder<pin_a, pin_b, raster, _min, _max>::getPhases()':

sketch_dec06a.ino:62:38: error: there are no arguments to 'getInPort' that depend on a template parameter, so a declaration of 'getInPort' must be available [-fpermissive]

sketch_dec06a.ino:62:38: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)

sketch_dec06a.ino:62:58: error: there are no arguments to 'getMaske' that depend on a template parameter, so a declaration of 'getMaske' must be available [-fpermissive]

sketch_dec06a.ino:63:38: error: there are no arguments to 'getInPort' that depend on a template parameter, so a declaration of 'getInPort' must be available [-fpermissive]

sketch_dec06a.ino:63:58: error: there are no arguments to 'getMaske' that depend on a template parameter, so a declaration of 'getMaske' must be available [-fpermissive]

sketch_dec06a.ino: In member function 'void GrayEncoder<pin_a, pin_b, raster, _min, _max>::init()':

sketch_dec06a.ino:106:24: error: there are no arguments to 'getDdrPort' that depend on a template parameter, so a declaration of 'getDdrPort' must be available [-fpermissive]

sketch_dec06a.ino:106:44: error: there are no arguments to 'getMaske' that depend on a template parameter, so a declaration of 'getMaske' must be available [-fpermissive]

sketch_dec06a.ino:107:24: error: there are no arguments to 'getOutPort' that depend on a template parameter, so a declaration of 'getOutPort' must be available [-fpermissive]

sketch_dec06a.ino:107:44: error: there are no arguments to 'getMaske' that depend on a template parameter, so a declaration of 'getMaske' must be available [-fpermissive]

sketch_dec06a.ino:109:24: error: there are no arguments to 'getDdrPort' that depend on a template parameter, so a declaration of 'getDdrPort' must be available [-fpermissive]

sketch_dec06a.ino:109:44: error: there are no arguments to 'getMaske' that depend on a template parameter, so a declaration of 'getMaske' must be available [-fpermissive]

sketch_dec06a.ino:110:24: error: there are no arguments to 'getOutPort' that depend on a template parameter, so a declaration of 'getOutPort' must be available [-fpermissive]

sketch_dec06a.ino:110:44: error: there are no arguments to 'getMaske' that depend on a template parameter, so a declaration of 'getMaske' must be available [-fpermissive]

sketch_dec06a.ino: In instantiation of 'void GrayEncoder<pin_a, pin_b, raster, _min, _max>::init() [with unsigned char pin_a = 2u; unsigned char pin_b = 5u; unsigned char raster = 0u; int _min = 0; int _max = 0]':

sketch_dec06a.ino:153:18: required from here

sketch_dec06a.ino:106:44: error: 'getMaske' was not declared in this scope

sketch_dec06a.ino:106:24: error: 'getDdrPort' was not declared in this scope

sketch_dec06a.ino:107:44: error: 'getMaske' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]

sketch_dec06a.ino:106:44: note: 'getMaske' declared here, later in the translation unit

sketch_dec06a.ino:107:24: error: 'getOutPort' was not declared in this scope

sketch_dec06a.ino:109:44: error: 'getMaske' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]

sketch_dec06a.ino:106:44: note: 'getMaske' declared here, later in the translation unit

sketch_dec06a.ino:109:24: error: 'getDdrPort' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]

sketch_dec06a.ino:106:24: note: 'getDdrPort' declared here, later in the translation unit

sketch_dec06a.ino:110:44: error: 'getMaske' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]

sketch_dec06a.ino:106:44: note: 'getMaske' declared here, later in the translation unit

sketch_dec06a.ino:110:24: error: 'getOutPort' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]

sketch_dec06a.ino:107:24: note: 'getOutPort' declared here, later in the translation unit

Fehler beim Kompilieren.

Dieser Report hätte mehr Informationen mit
"Ausführliche Ausgabe während der Kompilierung"
aktiviert in Datei > Einstellungen

Hallo,

ich habe leider keinen Encoder, hab aber mal was rumgespielt. Der Skatch verwendet Tone() zum testen. must Du dann rausnehmen.

Funktion

Spur A wird zur Ermittlung der Position (Counter) benutzt und zur Ermittlung der Geschwindigkeit ( Frequenz).
Spur B wird für die Richtung benutzt, ist ja wegen der Phanseverschiebung von 90 grad möglich.

aktualisiert werden die Messwerte alle 100ms

Gemessen hab ich mit tone bis zu 10KHz läuft stabil. Natürlich macht das Ding nicht viel, aber Dein Messrad ja auch nicht wirklich.

Heinz

int A = 2;// Spur A
int B = 3;// Spur B

long count;
unsigned long altzeit;// Anzeige Speicher 
unsigned long altmicros, t;//Frequenzmessung 

bool a, b;
bool reverse;//Rückwärts
float frequenz;// Geschwindigkeit 

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  //pinMode(A, INPUT);
  pinMode(B, INPUT);

  attachInterrupt(digitalPinToInterrupt(A), isr, RISING);// nur Pos Flanke
}

void loop() {
  // put your main code here, to run repeatedly:
  tone(5, 100); // Testfrequenz Brücke erforderlich von Pin5 auf Pin2 

  if ( millis() - altzeit >= 100) { // Anzeige Zyklus 
    altzeit = millis();
    if ( t > 0) {
      frequenz = 1000000.0 / t;
    }
    else {
      frequenz = 0;
    }

    // Anzeige 
    if (reverse) frequenz = frequenz * -1;
    Serial.print(count); Serial.print("\t"); Serial.println(frequenz);
  }

}
void isr() { // Interrupt Routine 

  t = micros() - altmicros;
  altmicros = micros();
 // a = digitalRead(A);
  b = digitalRead(B);
  if (b) {
    count++;
    reverse = false;
  }
  if (!b) {
    count--;
    reverse = true;
  }

}

Hallo,

für meinen Sketch wird deine IDE zu alt sein, es kennt das Schlüsselwort constexpr nicht.
Unabhängig vom Sketch solltest du deine IDE aktualisieren.

Hallo zusammen, ich habe meiner IDE ein Update verpasst und beide Codes mal versucht, es funktionieren beide identisch "genau".

Ich habe verschiedene Versuche gemacht: Schnell Vor/Zurück, wechselnde Geschwindigkeit, mal richtig Gas gegeben. Dabei optisch an einer Markierung vorbeigepeilt, stimmt bis auf 2-3 Ticks immer genau. (Kann am Ablesen liegen)

Das Script von Rentner zählt genau 500 Striche, das von Doc_Arduino 2000 pro Umdrehung. Wie kann das sein, ist da noch ein Parameter falsch gesetzt? (Zählt der alle Flanken sowohl steigend als auch fallend und dann von A und B, oder wodurch kommt das?)

Theoretisch ist das ja vollkommen egal, da das nur ein relativer Wert ist, 2000 gaukelt natürlich eine höhere Genauigkeit vor.

So nun weiter im Projekt:
Ich wollte einfach mal eure Meinung hören, vielleicht hat jemand eine ganz andere verrückte Idee die viel besser ist.

Zunächst wird das eine reine Messmaschine, weil meine Zeit gerade enorm begrenzt ist, ich die Maschine für meine aktuelle Arbeit aber sehr gerne verwenden will. Geplant war jetzt ein definiertes Messrad, z.B. mit einem 50mm Durchmesser. Das würde ja bedeuten, dass ich einen Umfang von 157.08mm habe und somit jeder Strich einer Differenz von 0,314mm entspricht. Das ganze lasse ich mir auf einem kleinen Zeilendisplay anzeigen (mit eurem Code) und evtl. biete ich noch die Möglichkeit einer festen Längeneingabe mit Summer. Dafür müsste ich dann noch ein paar Buttons haben womit ich die Länge einstellen kann und ist diese erreicht ertönt der Summer. (Natürlich etwas tricky, weil ich ja möglichst genau messen will, da muss man am Ende ja sehr langsam ziehen, aber das teste ich noch)

Also die Maschine wird aufjedenfall zunächst handbetätigt sein. Mir schweben da insgesamt 2 Räder vor, das eine ist das Messrad, welches von oben mit einem Druck auf das andere Rad drückt, dazwischen liegt das Kabel. (Irgend ein Federmechanismus) So hätte ich immer einen Druck auf dem Kabel und das ganze dann möglichst Schlupffrei, was die wirkliche Herausforderung ist. Zieht man ruckartig, wird das Messrad sicher Aussetzer haben.
Die andere Möglichkeit wäre nur ein Rad welches ebenfalls per Feder oder vielleicht manueller Klemmung das Kabel auf eine Schiene drückt. Ob das besser ist wage ich aber noch zu bezweifeln. Das Messrad muss dann vermutlich noch irgendwie mit Gummi bespannt sein, weiß ich noch nicht wie ich das umsetzen kann. Zunächst versuche ich irgendwelche Haushaltssachen zu entfremden um das einfach mal zu testen ob das überhaupt so aufgehen könnte.

Für später: Geplant ist das ganze zu automatisieren. Dazu dachte ich an Transportrolle und an eine Messrolle. Die Transportrolle wird durch einen Schrittmotor (ist das das richtige dafür??) angetrieben und wartet läuft solange bis das Maß erreicht ist und wird dann gestoppt. Dabei wäre ein sehr genauer Stop natürlich wichtig, vielleicht eine Art Bremse dafür, oder zumindest die Geschwindigkeit die letzten cm sehr stark reduzieren? Zusätzlich eine Schneidvorrichtung (normale Kabelschere irgendwie mit einem Hebel und Motor versehen), oder eine richtige Schneidbacke, wie ich die am besten antreibe weiß ich auch noch nicht.

Falls jemand Ideen hat, gerne her damit. Mir steht leider kein riesen Maschinenpark und Material zur Verfügung, aber das könnte ich noch irgendwie besorgen. Zumindest wäre eine Drehbank vorhanden für Messräder der "finalen" Ausführung. Ansonsten ist handwerkliches Geschick vorhanden :slight_smile:

Vielen Dank
JumpY

Hallo,

Der Unterschied liegt am Einlese- und Auswerteprinzip. Mein Code wertet jede Pegeländerung von A/B aus. Was bedeutet der Drehgeber hat eine echte Auflösung von 2000 Counts hat. Warum der mit 500 angegeben ist weiß ich nicht.

Kannste ändern mit dem 3. Parameter bzw. anpassen wie du es benötigst.

GrayEncoder <40, 41, 4> Hengstler; // Pins Phase A,B / Raster

Der große Unterschied ist das meiner pollt und der vom Rentner die Pegel per Interrupt erfasst.

Danke für den Test.

Zum Messrad. Klingt erstmal soweit vernünftigt. Die Feder muss straff sein und das Messrad muss Grip haben und sich sehr leicht drehen können. Dann kann es auch schnellere Bewegungen mitgehen.

So eine Konstruktion entspricht schon ähnlich meiner Vorstellung: Automatic Cable Cutting Machine - Hackster.io ; Das ist zwar vom Antrieb und messen etwas anders gelöst, aber mit den 2 Rädern etc.

Wenn ich die Funktionsweise von Polling und Interrupts noch richtig weiß, sollte man doch wenn möglich immer Interrupts nehmen oder? Da kann das Signal jederzeit abgefangen werden, beim Polling wird ja zyklisch (wenn auch sehr sehr enge Zyklen) geprüft ob gerade ein Signal ansteht oder eben nicht, richtig? Bei der Anwendung scheint es noch zu funktionieren, ja.

Das Messrad gibt aber eigentlich wirklich nur die 500 Striche aus. Kann es sein, dass dein Script die steigende A und fallende A so wie steigende B und fallende B Flanke mitzählt und somit auf den Faktor 4 kommt? Also jede Pegeländerung und nicht nur die Highflanke z.B.?

Ich schaue mal das ich in den nächsten Tagen etwas auf die Beine stellen kann, dann werde ich nochmals berichten :slight_smile:

Hallo,

ob Interrupt sinnvoll ist oder nicht lässt sich so pauschal nicht sagen. Aussagen wie "generell sind Interrupts gut" oder "generell sind Interrupts schlecht" sind demzufolge nicht sinnvoll. Es kommt drauf an wie schnell sich das Rad maximal dreht, also wieviel Zeit zwischen den Impulsen Minimum ist und was das Programm noch alles machen soll außer den Encoder behandeln. Wo die Prioritäten liegen. Viele Leute neigen zu schnell "da nehm ich einfach einen Interrupt". Auf dem Uno hat man eh nur 2 "richtige" Interrupteingänge. Die mit eigenem Interrupt Vector und Flankenerkennung. Daneben sind fast alle "normal" Pin Change Interrupt detect fähig. Etwas salopp ausgedrückt.

Wechsel mal beim Code vom Rentner die ISR Option von RISING auf CHANGE. Wenn das immer noch klappt und auch sollte, kann man später auch alle anderen Interruptfähigen Pins verwenden. Lässt mehr Auswahl und man ist nicht auf Pin 2 und 3 begrenzt.

Mein Code wertet keine Flanken aus sondern jede Pegeländerungen auf A und B. Es werden nur die Signale an den Pins gepollt eingelesen. Was gerade anliegt. Der Kern Encoder Code ist auch nicht von mir. Ich habe den von Peter Dannegger bei mir nur eingebaut. Drehgeber – Mikrocontroller.net Das drum herum wurde dann noch mit dem Forum hier optimiert.
Mein Code kann auch keine Pulse künstlich erfinden. Er kann nur das zählen was auch da ist. Wenn man nur eine Spur zählt und die andere Spur nur zur Richtungsauswertung nutzt, dann verschenkt man Auflösung. Ob das Sinn macht oder nicht sei erstmal dahingestellt. Warum Hengstler von 2000 möglichen nur 500 angibt weiß ich auch nicht. Ich kann nur sagen das 2000 die maximal mögliche Auflösung von dem Teil ist. Es verbietet dir jedoch niemand nur 1/4 zu nutzen. Mir ist das egal. :slight_smile:

Hallo,
Doc Arduino hat ja bereits alles gesagt.

ob mein code mit der Auswertung für beide Flanken (CHANGE) der A Spur funktioniert weiss ich nicht, denke abe ehr nicht da das erkennen vor vor zurück nicht funktionieren wird.

ich kenne das nur so das bei Encodern die Strichzahl bzw Impulse pro Umdrehung angegeben wird. Der Begriff Strichzahl macht es eigendlich kar. Früher und auch heute noch werden Glasscheiben verwendet die mit Strichen eingefärbt oder geätzt sind. Eine Lichtschranke kann dann durch sehen oder eben nicht. damit gibt die Lichtschranke dann z.B 500 Impulse ab. Eine zweite , etwas versetzt ist für die B Spur zuständig. Elektrisch kann man nun natürlich die Flanken beider Spuren auswerten damit ist die Auflösung 4mal besser.

Zu deinem Messrädern , zwei Räder find ich gut und das zweite kann dann auch gut das Antriebsrad sein wie abgebildet. Du must nur dafür sorgen das das Kabel nicht seitlich herausläuft. Dazu kann ja ein Rad etwas hohl sein. Tendeziell würde ich ehr das Messrad etwas grösser machen wie von Dir vorgesehen, dann dreht es sich leichter. Wenn Du 0,5-1mm Auflösung hast reicht das doch. Industrielle Messräder haben meist einen Umfang von 500mm . Die Lager von dem Encoder sehen zwar ganz stabil aus aber ich wurde das Messrad separat lagern. Denke daran die Lagerung des Messrades dann so auszulegen das das Lager die Federkraft zum Andrücken aufnehmen kann. Zwischen Messrad und Encoder gehört dann eine flex Kupplung.

Den Link zu der Maschine hab ich mir angesehen, wenn das die gewünschte Grössenordnung ist halte ich die Lösung für gut. Fall alles etwas grösser sein soll noch ein paar Gedanken.

Ob ein Schrittmotor das Richtige ist glaube ich ehr nicht. ich würde einen "normalen" Motor nehmen. Wo kommt Dein Kabel letztlich her, von einen Trommel ? Kabel ist schwer. Du wirst hohe Dremmomente benötigen um die Trommel in Bewedung zu versetzen. Ein GetiebeMotor wird nötig sein. Einen GSMotor kannst du einfach langsam starten , beliebig lange laufen lassen, und vor Erreichen der Schnittstelle langsam abbremsen und langsam bis zur Position weiter laufen lassen. Wenn es sich um grössere Antriebsleistung handelt, wirklich grosse Trommel, wirst du eventuell einen DS Getriebe Motor mit Frequenzumrichter verwenden.

Die Schere wir sicher eine Herausforderung werden. Wie abgebildet klappt das sicher mit den Hebeln für kleinere Querschnitte gut. Welche Kabel willlst Du denn verwenden. Vorstellen kann ich mir eventuell auch noch eine Konstruktion mit einem Knie und Spindel und einem Motor. Ab 4X25mm2 wird es eine Herausforderung werden :slight_smile: