- LiFePO4 Speicher Test         
Ergebnis 1 bis 10 von 10

Thema: Raspi mit C/C++: Encoder per pigpio und callback auslesen?

  1. #1
    HaWe
    Gast

    Raspi mit C/C++: Encoder per pigpio und callback auslesen?

    Anzeige

    LiFePo4 Akku selber bauen - Video
    hallo,
    ich komme nicht weiter:

    ich will 2 Rotationsencoder auslesen, dazu bräuchte ich eigentlich einen Timer-IRQ mit 100µs Frequenz.
    Das gibt es aber nicht auf dem Raspi.
    Andere Versuche sind gescheitert, da zu langsam:

    http://www.mindstormsforum.de/viewto...tart=15#p68001

    wie richte ich jetzt für meine 2 Encoder eine Callback-Funktion mit Pinchange-Interrupts ein, wie sie von "Joan" vorgeschlagen werden?
    Mir ist der Code ein einziges Rätsel:

    https://github.com/joan2937/pigpio/t...ROTARY_ENCODER
    bzw.
    https://github.com/joan2937/pigpio/t...ROTARY_ENCODER


    meine Pinbelegung ist diese:

    Code:
    // motor 0
    #define pigpio0A   23  // enc 0 A
    #define pigpio0B   24  // enc 0 B
    
    // motor 1
    #define pigpio1A   25  // enc 1 A
    #define pigpio1B   4   // enc 1 B
    und meine 2 Encoderwerte werden in diesem Array gespeichert:

    Code:
    volatile static long motenc[2];

    wer kann "Joan's" Code darauf anpassen helfen?

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    707
    Hallo,

    siehe Datei "test_rotary_encoder.cpp".

    Du brauchst wohl zwei Instanzen der Klasse und zwei Callbackfunktionen, etwa so
    Code:
    void callback1(int way)
    {
       static int pos = 0;
    
       pos += way;
    
       std::cout << "pos1=" << pos << std::endl;
    }
    
    void callback2(int way)
    {
       static int pos = 0;
    
       pos += way;
    
       std::cout << "pos2=" << pos << std::endl;
    }
    
    int main(int argc, char *argv[])
    {
       if (gpioInitialise() < 0) return 1;
    
       re_decoder dec1(23, 24, callback1);
       re_decoder dec2(25, 4, callback2);
    
      // ...

  3. #3
    HaWe
    Gast
    ach soooo - das mit den 2 Instanzen war mir bsolut nicht klar!

    Danke, das probiere ich sofort mal aus!

    was bedeutet dieser Teil...?
    Code:
    Pi_Renc_t * renc;
    
    
    sleep(3000);
    dec.re_cancel();
    in


    Code:
    int main(int argc, char *argv[])
    
       Pi_Renc_t * renc;
    
       if (gpioInitialise() < 0) return 1;
    
       renc = Pi_Renc(7, 8, callback);
    
       sleep(300);
    
       Pi_Renc_cancel(renc);
    
       gpioTerminate();
    
    }
    - - - Aktualisiert - - -

    und am Anfang was ist das: (ich nehme den C code, nicht cpp)

    Pi_Renc_t * renc;

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    707
    Eigentlich ist das schlechtes C++, guter Stil wäre es, das in einem Destruktor zu machen. (Google mal nach RAII)

    Im Konstruktor von re_decoder registriert er _pulseEx irgendwo in der Library
    Code:
    gpioSetAlertFuncEx(gpioA, _pulseEx, this);
    wobei in _pulseEx
    Code:
     mySelf->_pulse(gpio, level, tick);
    aufgerufen wird und dort der Callback auftaucht, z.B.
    Code:
    if (levB) (mycallback)(1);
    D.h innerhalb des Librarycodes wird irgendwo der Callback aufgerufen, wahrscheinlich bei jeder Änderung des Pins.

    Am Ende des Programms muss der Callback wieder abgeschaltet werden, das macht er in re_cancel()
    Code:
    gpioSetAlertFuncEx(mygpioA, 0, this);
    dort übergibt er einen Nullzeiger als neuen Callback.

  5. #5
    HaWe
    Gast
    ich kriegs nicht hin.

    gefühlte 50 Seiten Error Meldungen.


    Ich brauche echt jemanden, der mir den kompletten (!) C++ Code schreibt, für 2 unabhängige Rotationencoder.

    - - - Aktualisiert - - -

    Code:
    // encoder test
    // pigpio, pinchange IRQs
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <math.h>
    #include <fcntl.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <stdint.h>
    #include <errno.h>
    #include <pthread.h>
    #include <termios.h>
    #include <iostream>
    #include <pigpio.h>
    
    #include "VG/openvg.h"
    #include "VG/vgu.h"
    #include "fontinfo.h"
    #include "shapes.h"
    
    
    
    
    #define  byte  uint8_t;
    
    #define  MAXMOTORS           2 // max number of encoder motors at Arduino Uno=2 // Due=6 // Mega=8
    
    
    // motor 0
    
    
    #define pigpio0A   23
    #define pigpio0B   24
    
    #define pigpio0d1  11
    #define pigpio0d2  14
    #define pigpio0pwm 15
    
    
    // motor 1
    
    
    #define pigpio1A   25
    #define pigpio1B   4
    
    #define pigpio1d1  28
    #define pigpio1d2  29
    #define pigpio1pwm 30
    
    
    volatile long   motenc[MAXMOTORS],
                    oldenc[MAXMOTORS] ;
                   
    
    
                                   
    /*************************************************************
    * Interrupt Handler Routine
    *************************************************************/
    
    typedef void (*re_decoderCB_t)(int);
    class re_decoder
    {
       int mygpioA, mygpioB, levA, levB, lastGpio;
       re_decoderCB_t mycallback;
       void _pulse(int gpio, int level, uint32_t tick);
       /* Need a static callback to link with C. */
       static void _pulseEx(int gpio, int level, uint32_t tick, void *user);
       
       public:
       re_decoder(int gpioA, int gpioB, re_decoderCB_t callback);
       /*
       This function establishes a rotary encoder on gpioA and gpioB.
       When the encoder is turned the callback function is called.
       */
       void re_cancel(void);
       /*
       This function releases the resources used by the decoder.
       */
    };
    
    
    
    
    void re_decoder::_pulse(int gpio, int level, uint32_t tick)
    {
       if (gpio == mygpioA) levA = level; else levB = level;
    
       if (gpio != lastGpio) /* debounce */
       {
          lastGpio = gpio;
    
          if ((gpio == mygpioA) && (level == 1))
          {
             if (levB) (mycallback)(1);
          }
          else if ((gpio == mygpioB) && (level == 1))
          {
             if (levA) (mycallback)(-1);
          }
       }
    }
    
    void re_decoder::_pulseEx(int gpio, int level, uint32_t tick, void *user)
    {
       /*
          Need a static callback to link with C.
       */
    
       re_decoder *mySelf = (re_decoder *) user;
    
       mySelf->_pulse(gpio, level, tick); /* Call the instance callback. */
    }
    
    re_decoder::re_decoder(int gpioA, int gpioB, re_decoderCB_t callback)
    {
       mygpioA = gpioA;
       mygpioB = gpioB;
    
       mycallback = callback;
    
       levA=0;
       levB=0;
    
       lastGpio = -1;
    
       gpioSetMode(gpioA, PI_INPUT);
       gpioSetMode(gpioB, PI_INPUT);
    
       /* pull up is needed as encoder common is grounded */
    
       gpioSetPullUpDown(gpioA, PI_PUD_UP);
       gpioSetPullUpDown(gpioB, PI_PUD_UP);
    
       /* monitor encoder level changes */
    
       gpioSetAlertFuncEx(gpioA, _pulseEx, this);
       gpioSetAlertFuncEx(gpioB, _pulseEx, this);
    }
    
    
    
    void re_decoder::re_cancel(void)
    {
       gpioSetAlertFuncEx(mygpioA, 0, this);
       gpioSetAlertFuncEx(mygpioB, 0, this);
    }
    
    
    
    
    
    
    
    
    void setup() {
      int i;   
       
      // motor pin settings
      // setup for L293D motor driver
      // pullup resistors:
      // wiringPi: pullUpDnControl (butpin, PUD_UP);
      // pigpio:  gpioSetPullUpDown(butpin, PI_PUD_UP);
     
     
      // motor 0
         gpioSetMode(pigpio0A, PI_INPUT);                 // 4 enc0A    yellow
         gpioSetPullUpDown(pigpio0A, PI_PUD_UP);   
         gpioSetMode(pigpio0B, PI_INPUT);                 // 5 enc0B    blue
         gpioSetPullUpDown(pigpio0B, PI_PUD_UP);
         
         gpioSetMode(pigpio0d1, PI_OUTPUT);        // dir0-1   
         gpioSetMode(pigpio0d2, PI_OUTPUT);        // dir0-2   
         gpioSetMode(pigpio0pwm, PI_OUTPUT);       // enable0
           
      // motor 1
         gpioSetMode(pigpio1A, PI_INPUT);                 // 6 enc1A    yellow
         gpioSetPullUpDown(pigpio1A, PI_PUD_UP);   
         gpioSetMode(pigpio1B, PI_INPUT);                 // 7 enc1B    blue
         gpioSetPullUpDown(pigpio1B, PI_PUD_UP);
         
         gpioSetMode(pigpio1d1, PI_OUTPUT);        // dir1-1   
         gpioSetMode(pigpio1d2, PI_OUTPUT);        // dir1-2
         gpioSetMode(pigpio1pwm, PI_OUTPUT);       // enable1   
    
         for( i=0; i< MAXMOTORS; ++i) motenc[i] = 0;     
     
    }
    
    
    
     
       
       
       
    void callback0(int way){
       static int pos = 0;
       pos += way;
       std::cout << "pos=" << pos << std::endl;
    }
    
    
    void callback1(int way){
       static int pos = 0;
       pos += way;
       std::cout << "pos=" << pos << std::endl;
    }
    
    
    
    int main(int argc, char *argv[])
    {
       if (gpioInitialise() < 0) return 1;
    
       setup();
    
       re_decoder dec0(pigpio0A, pigpio0B, callback0);
       re_decoder dec1(pigpio1A, pigpio1B, callback1);
       
    
    
       sleep(3000);
    
       dec0.re_cancel();
       dec1.re_cancel();
    
       gpioTerminate();
       
       
    }

    g++ -Wall -I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -o "enc0005" "enc0005.c" -lshapes -L/opt/vc/lib -lOpenVG -lEGL -pthread -lrt -lwiringPi (im Verzeichnis: /home/pi/programs/test/encoder)
    Kompilierung fehlgeschlagen.
    /tmp/ccHKEpu6.o: In function `re_decoder::re_decoder(int, int, void (*)(int))':
    enc0005.c:(.text+0x1ac): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x1bc): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x1cc): undefined reference to `gpioSetPullUpDown'
    enc0005.c:(.text+0x1dc): undefined reference to `gpioSetPullUpDown'
    enc0005.c:(.text+0x1f0): undefined reference to `gpioSetAlertFuncEx'
    enc0005.c:(.text+0x204): undefined reference to `gpioSetAlertFuncEx'
    /tmp/ccHKEpu6.o: In function `re_decoder::re_cancel()':
    enc0005.c:(.text+0x240): undefined reference to `gpioSetAlertFuncEx'
    enc0005.c:(.text+0x258): undefined reference to `gpioSetAlertFuncEx'
    /tmp/ccHKEpu6.o: In function `setup()':
    enc0005.c:(.text+0x278): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x284): undefined reference to `gpioSetPullUpDown'
    enc0005.c:(.text+0x290): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x29c): undefined reference to `gpioSetPullUpDown'
    enc0005.c:(.text+0x2a8): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x2b4): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x2c0): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x2cc): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x2d8): undefined reference to `gpioSetPullUpDown'
    enc0005.c:(.text+0x2e4): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x2f0): undefined reference to `gpioSetPullUpDown'
    enc0005.c:(.text+0x2fc): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x308): undefined reference to `gpioSetMode'
    enc0005.c:(.text+0x314): undefined reference to `gpioSetMode'
    /tmp/ccHKEpu6.o: In function `main':
    enc0005.c:(.text+0x454): undefined reference to `gpioInitialise'
    enc0005.c:(.text+0x4c8): undefined reference to `gpioTerminate'
    collect2: error: ld returned 1 exit status

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    707
    Sieht so aus, als ob da ein include fehlt, wahrscheinlich
    Code:
    #include <pigpio.h>
    Außerdem sehe ich da ein
    Code:
    -lwiringPi
    wo sicher ein
    Code:
    -lpigpio
    hingehört.

    Ansonsten kenne ich mit pigpio nicht aus, Linux GPIOs stehen auf meiner Prioritätenliste weit unten.

  7. #7
    HaWe
    Gast
    ja, stimmt, aber ich glaube, das war jetzt der Tropfen, der das Fass zum Überlaufen gebracht hat.
    Ich hasse diese tonnenweisen -l und -I Parameter für compile, make und build,
    dann dieser unglaublich langsame Bildschirmaufbau beim Raspi-Onboard-Programmieren,
    dann dass es keine Windows-IDE mit Crosscompiler gibt wie bei der Arduino IDE,
    dann die unglaublich - viel zu - wenigen Pins für IO, ADC, DAC, UART, I2C,
    keine Interrupts auf Hardware-level,
    und zu allem Überfluss noch nicht mal 2 pins mit PWM vorhanden.

    Ich lass es bleiben mit dem Raspi, es bringt nichts außer Ärger und Frust.


    Da kann ja ein Uno schon mehr.

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    18.05.2007
    Ort
    Berlin
    Alter
    53
    Beiträge
    765
    Da gebe ich Dir Recht. C zu kompilieren ist nicht immer nur GCC aufzurufen. Ich mag das auch nicht sonderlich, klappt aber bei meinen kleinen Projekten. Wo es auf Echtzeit ankommt, nutze ich immer einen AVR als 'Co-Prozessor'. Der kann Drehencoder, WS2812B LEDs und Interrupts problemlos. Die Kommunikation ist dann per UART zum Raspi. Der Raspi selbst ist für das Netzwerk und die Anbindung an USB-Hardware zuständig. Dafür sind die AVRs einfach zu lahm / ressourcenarm. Der große Vorteil ist, dass man den AVR bequem übers Netzwerk per Raspi flashen kann.
    Wenn das Herz involviert ist, steht die Logik außen vor! \/

  9. #9
    HaWe
    Gast
    update:
    hatte es dann doch hingekriegt, dass es wenigstens läuft (B+).
    A-Bär: wenn man normal schnell dreht (3 U/s), dann werden pro 360° nur 300 encoder ticks gelesen, also werden jede Menge übersehen und daher verschluckt.
    Wenn man es nicht über Pinchange implementiert, sondern als Extra-pthread-Task im 100µs-Takt, klappt es noch schlechter (beim Arduino klappen sogar 8 Motoren im 200µs-Timer-IRQ-Takt!)

    wenn man sehr langsam dreht (1U pro 2 sec), dann liest er korrekt alle 360 ticks.
    Der Raspi ist also tatsächlich nicht in der Lage, schnelle Pin-Lese-Vorgänge durchzuführen.

    neu:

    Ich habe jetzt einen Raspi 2B Quadcore und werde es nochmals testen -
    diesmal aber nicht per pinchange-Interrupt, denn da ändert sich ja nichts, sondern wieder als pthread-Task im 100µs-Takt und mit pthread-priority von 90%.
    Ich habe nämlich festgestellt, dass das Betriebssystem und Posix die Tasks sehr geschickt auf die cpu-Kerne verteilen, daher habe ich die Hoffnung, dass einer der cores bevorzugt nur mit diesem 90% prio-Task beschäftigt sein wird, um wenigstens halbwegs ein taktgenaues Arbeiten zu ermöglichen (ohne wieder von user space tasks ausgebremst zu werden).

    Ich werde berichten!

  10. #10
    HaWe
    Gast
    update:

    mit Raspi 2B klappt es! Keine Zähl-Ausfälle mehr, selbst bei recht schnellen Umdrehungen, getestet mit Lego-Encodermotoren
    (Auflösung: 1/2, d.h. 360 ticks/360°. Drehgeschwindigkeit 5 U/sec.).


    Es wird über einen High Priority pthread Task ein Timer-Interrupt im 100µs Takt simuliert, und der Pi Quadcore hat jetzt die Performance, dies auch im Linux User Space sicher durchzuhalten - die Simulation verwendet dazu bisher insgesamt 4 Tasks mit unterschiedlicher Priorität:

    Klicke auf die Grafik für eine größere Ansicht

Name:	Raspi_Enc_C++_200453.jpg
Hits:	11
Größe:	99,7 KB
ID:	31315

    Hier der Code :

    share and enjoy!


    Code:
    // encoder test
    // wiringPi,   
    // Encoder Timer High Priority Thread
    // ver 0007
    
    // protected under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
    // http://creativecommons.org/licenses/by-nc-sa/3.0/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <math.h>
    #include <fcntl.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <stdint.h>
    #include <errno.h>
    #include <pthread.h>
    #include <termios.h>
    
    #include "VG/openvg.h"
    #include "VG/vgu.h"
    #include "fontinfo.h"
    #include "shapes.h"
    
    #include <wiringPi.h>
    #include <wiringSerial.h>
    
    
    #define  byte  uint8_t;
    
    #define  MAXMOTORS    2   // max number of encoder motors
    
    typedef struct {
          uint8_t    pd1, pd2, pwm;
          uint8_t    pqa, pqb;
          int32_t    motenc, oldenc;
    
    }  tpimotor ;
    
    tpimotor  motor[MAXMOTORS];
    
                                   
    /*************************************************************
    * Encoder Handler Routine
    *************************************************************/
    
    volatile int8_t ISRab[MAXMOTORS];
    
    // 1/2 resolution
    int8_t enctab[16] = {0, 0,0,0,1,0,0,-1, 0,0,0,1,0,0,-1,0};
    
    void updateEncoders() {   
      int i;    
      for( i=0; i<MAXMOTORS; ++i ) {   
        ISRab [ i] <<= 2;
        ISRab [ i] &=  0b00001100;
        ISRab [ i] |= (digitalRead( motor[ i].pqa ) << 1) | digitalRead(  motor[ i].pqb );
        motor[ i].motenc += enctab[ ISRab[ i] ];   
      }     
    
    }
    
    
                                 
    
    void* thread3Go(void *)   // encoder high priority thread
    {
       while(1) {
         updateEncoders();
         usleep(100);
       }         
       return NULL;
    }
    
    void* thread2Go(void *)
    {
       while(1) {
          delay(10);
       }         
       return NULL;
    }
    
    void* thread1Go(void *)   // low priority display thread
    {
       char  sbuf[128];
       while(1) {   
         delay(100);
       }         
       return NULL;
    }
    
    void* thread0Go(void *)
    {
       char  sbuf[128];
       while(1) {
        sprintf(sbuf, " 0=%6ld    1=%6ld \n ",  motor[0].motenc, motor[1].motenc );
         printf(sbuf);
         delay(100);
       }         
       return NULL;
    }
    
    
    
    
    void setup() {
      int i;   
       
      // motor pins, wiringPi numbering (in parenthesis: BCM numbering)
    
         motor[0].pinQa = 5;   // (BCM 24) change for rotation direction
         motor[0].pinQb = 4;   // (BCM 23) change for rotation direction
         motor[0].pind1 =24;   // (BCM 19)
         motor[0].pind2 =25;   // (BCM 26)
         motor[0].pinpwm= 1;   // (BCM 18) hardware pwm
         
         motor[1].pinQa = 0;   // (BCM 17) change for rotation direction
         motor[1].pinQb = 2;   // (BCM 27) change for rotation direction
         motor[1].pind1 =21;   // (BCM 5)
         motor[1].pind2 =22;   // (BCM 6)
         motor[1].pinpwm=23;   // (BCM 13) hardware pwm   
    
         
         for( i=0; i< MAXMOTORS; ++i)  {       
            pinMode(motor[i].pqa, INPUT);        // encA   
            pinMode(motor[i].pqb, INPUT);        // encB   
            pinMode(motor[i].pd1, OUTPUT);       // dir-1   
            pinMode(motor[i].pd2, OUTPUT);       // dir-2   
            pinMode(motor[i].pwm ,OUTPUT);       // pwm
           
            motor[i].motenc = 0;
            motor[i].oldenc = 0;
            ISRab[i] = 0;
       }
    }
    
    
    
    
    
    int main() {
        char  sbuf[128];
        pthread_t thread0, thread1, thread2, thread3;
       
        wiringPiSetup();   
        if(wiringPiSetup() == -1) return 1;   
       
        setup();
       
        struct sched_param param;
       
       
        pthread_create(&thread0, NULL, thread0Go, NULL);
        param.sched_priority = 10;
        pthread_setschedparam(thread0, SCHED_RR, &param);
       
        pthread_create(&thread1, NULL, thread1Go, NULL);
        param.sched_priority = 25;
        pthread_setschedparam(thread1, SCHED_RR, &param);
       
        pthread_create(&thread2, NULL, thread2Go, NULL);
        param.sched_priority = 50;
        pthread_setschedparam(thread2, SCHED_RR, &param);
       
        pthread_create(&thread3, NULL, thread3Go, NULL);
        param.sched_priority = 90;
        pthread_setschedparam(thread3, SCHED_RR, &param);
       
       
        pthread_join(thread0, NULL);
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
        pthread_join(thread3, NULL);
       
        exit(0);
       
    }
    Code:
    # build:
     g++ -Wall -I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -o "%e" "%f" -pthread -lshapes -L/opt/vc/lib -lOpenVG -lEGL -lrt -lwiringPi -lpigpio
    Geändert von HaWe (20.02.2016 um 13:18 Uhr) Grund: code update

Ähnliche Themen

  1. Raspi GPP C++ WiringPi: Rotationsencoder auslesen
    Von HaWe im Forum Raspberry Pi
    Antworten: 1
    Letzter Beitrag: 18.10.2015, 10:29
  2. [C, C++] GPIO lib: pigpio oder WiringPi?
    Von HaWe im Forum Raspberry Pi
    Antworten: 0
    Letzter Beitrag: 15.10.2015, 18:19
  3. [ERLEDIGT] Raspi Club?
    Von pofoklempner im Forum Raspberry Pi
    Antworten: 16
    Letzter Beitrag: 09.07.2015, 07:20
  4. wie funktioniert encoder(LEFT) und encoder(RIGHT)
    Von natalie im Forum Sonstige Roboter- und artverwandte Modelle
    Antworten: 2
    Letzter Beitrag: 22.11.2005, 22:45
  5. Encoder (IGR) auslesen??
    Von focobot im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 26.09.2004, 16:22

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress