- SF800 Solar Speicher Tutorial         
Ergebnis 1 bis 10 von 45

Thema: pthread-Task als Methode einer C++ Klasse?

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    HaWe
    Gast
    hallo,
    2 Dinge sind mir mit der Struktur noch unklar:
    warum muss am Anfang immer eine Null stehen

    Code:
    struct PID pids[] = { 
      {0, "Task A", 0.015, 0.2, 0.7 },
      {0, "Task B", 0.3, 0.5, 0.80 }
    };
    und 2., ist es erlaubt, die Struktur statt mit einem String auch mit einem char (0, 1, 2, 3, ...) zu definieren und aufzurufen oder muss es unbedingt ein String sein?

    Code:
    struct PID pids[] = { 
      {0, 0, 0.015, 0.2, 0.7 },
      {0, 1, 0.3, 0.5, 0.80 }
    };

  2. #2
    HaWe
    Gast
    @botty:
    je mehr ich drüber nachdenke, wird mir allerdings klar, dass ich gar nicht recht verstehe, wofür diese Struktur

    https://www.roboternetz.de/community...l=1#post631429
    Code:
    struct PID pids[] = { 
      {0, "Task A", 0.015, 0.2, 0.7 },
      {0, "Task B", 0.3, 0.5, 0.80 }
    };
    überhaupt da ist:

    Das "setten" der Kp, Ki, Kd (kurz: P, I, D) soll ja nicht im Aufruf der PID-Funktion stehen.
    Die PID Funktion wird nur mit der Motornummer und dem RotationTarget aufgerufen plus einem pwm-Wert für die max. Rotationsgeschwindigkeit


    Code:
    void RotatePIDtoTarget (char port, long Target, float RotatSpeed); // approach absolute target once
    void RotatePIDdegrees  (char port, long Target, float RotatSpeed); // turn relative degrees
    void RotatePIDcontinue (char port, long Target, float RotatSpeed); // approach target continuously
    void StopPIDcontrol    (char port);                                // stop PID
    Das Setten der PID-Konstanten geschieht automatisch bei der Initialisiering und kann dann auf Wunsch auch optional durch extra Funktionen geschehen:

    // first Initialization:
    void PIDinit(); // P=0.4, I=0.4, D=10.0
    //
    // b) simple customized PID setting:
    void SetPIDparam(char port, float P,float I,float D);
    //
    // c) extended customized parameter setting:
    void SetPIDparamEx(char port, float P,float I,float D, float prec,int rtime, float damp);

    wozu also deine
    Code:
    struct PID pids[]
    Geändert von HaWe (24.09.2016 um 08:28 Uhr)

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    19.05.2015
    Beiträge
    69
    Hallo HaWe,
    sorry das ich mich jetzt erst melde aber bei dem schönen Wetter konnte mich am WE nichts vor den Bildschirm locken.

    Zu Deinen Fragen:

    Meine "struct pid" sollte nur ein Auszug aus Deiner "struct PIDstruct" sein. Worauf es mir ankommt ist, dass du diese um zwei Felder erweiterst:
    einmal um ein Element pthread_t und
    zweitens, um ein Element worüber du deine Motoren identifizieren kannst.

    Dadurch kannst du deinen Code wesentlich verkürzen, schau mal deine
    Code:
    safecall void StopPIDcontrol (char port) {
    
      if (port==OUT_A) {
    
        if (PID_A.runstate!=0) { // stop PID task if already running
          stop task_PID_A;
          PlayTone(TONE_C7,100);
          Off(OUT_A);
          Wait(50);
          PID_A.cont=false;
          PID_A.runstate=0;
          Wait(1);
          return;
        }
    
      }
      else
      if (port==OUT_B) {
    
        if (PID_B.runstate!=0) { // stop PID task if already running
          stop task_PID_B;
          PlayTone(TONE_C7,100);
          Off(OUT_B);
          Wait(50);
          PID_B.cont=false;
          PID_B.runstate=0;
          Wait(1);
          return;
        }
    
      }
      else
      if (port==OUT_C) {
    
        if (PID_C.runstate!=0) { // stop PID task if already running
          stop task_PID_C;
          PlayTone(TONE_C7,100);
          Off(OUT_C);
          Wait(50);
          PID_C.cont=false;
          PID_C.runstate=0;
          Wait(1);
          return;
        }
    
      }
    
    
    }
    an.

    Da steht dreimal quasi das Gleiche.
    Wenn du jetzt deine Struktur erweiterst und statt dem Port einen Zeiger auf die Variable übergibst, läßt sich der Code um 2/3 kürzen.
    Code:
    struct PIDstruct {
      /* Erweiterung */
      pthread_t tid;
      unsigned short motor_id;
    
                     // custom target values
      long  target;                  // set target
      int   tarpwm;                  // motor target speed
                     // custom regulation parameters
      float P;                       // P: basic propotional to error
      float I;                       // I: integral: avoid perish
      float D;                       // D: derivative: avoid oscillating
      float precis;                  // error precision to target
      int   regtime;                 // PID loop time
      float damp;                    // damp the integral memory
      char  cont;                    // target: continue or hit once
                     // internal control variables
      char  runstate;                // monitors runstate
      int   outp;                    // PID control output value
      int   maxout;                  // max output (max motor pwr)
      long  read;                    // current sensor reading
      float err;                     // current error
      float integr;                  // integral of errors
      float speed;                   // current speed
    
    
    } ;
    
    void StopPIDcontrol (struct PIDstruct *pid) {
    
      if (pid->tid) { // stop PID task if already running
        pid_stop(pid, 1); // siehe botties zweites Beispiel
        Off(pid->motor_id);
        pid->cont=false;
        pid->runstate=0;
        return;
      }
    
    }
    Wenn du jetzt eine Variable PID_A definierst, würde der Aufruf so aussehen:
    Code:
    struct PIDstruct PID_A;
    
    void eine_stop_funktion(void) {
      StopPIDcontrol( &PID_A );
    }
    Du wählst somit nicht mehr über eine port/switch Kombination deinen PID Controler aus, sondern beim Aufruf der Funktionen über den Zeiger auf die Variable, welche alle Daten für einen Controler enthält.
    D.h. bei allen Funktionen ersetzt du "char port" durch "struct PIDstruct* pid" und dereferenzierst die Elemente der Struktur nicht mehr über den "." Operator sondern über den "->" Operator.

    Auch bei der Erezugung der Threads können wir jetzt den Zeiger auf die Variable als Parameter in die Thread-Funktion hineingeben, denn die Signatur dieser Funktion lautet:
    Code:
    void *(*function)(void *arg);
    Zwar ist arg vom Typ "void *" nur da wir immer nur Zeiger vom Typ "struct PIDcontrol *" hineingeben können wir am Anfang der Routine diesen Zeiger sicher auf den richtigen Typ casten:
    Code:
    void *pid_calc(void *arg) {
      float aspeed, damp, PWMpwr, readold, errorold, tprop;
      long  readstart, cmax, cmin;                         // for monitoring
      long  starttime, runtime, clock, dtime;              // timer
      char  regloop;
    
      /* das ist ein ziemlich sicherer cast */
      struct PIDcontrol *pid = (struct PIDcontrol *) arg;
    
      pid->runstate = 0x10;                               // reg state: RAMPUP
      pid->read      = (MotorRotationCount(pid->motor_id));        // get current encoder reading
      pid->err        = pid->target - pid->read;          // error to target
    
      readstart      = pid->read;
    
    /* ... */
    
    }
    so brauchst du auch diese Routine nur einmal, denn bei der Thread Erzeugung übergibst du den Zeiger auf die Variable z.B.:
    Code:
    pthread_create(&PID_A.tid, 0, pid_calc, &PID_A);
    ich hoffe das es jetzt klarer ist, warum ich Zeiger verwenden würde?


    Noch ein Wort zu den Variablen für die einzelnen PID Controler, du definierst die so:
    Code:
    struct PIDcontrol PID_A;
    struct PIDcontrol PID_B;
    struct PIDcontrol PID_C;
    bei sowas sehe ich sofort eine Aufzählung und wenn ich dann auch noch Operationen über diese machen muss, wie z.B. ein warten auf das Beenden eines Threads, dann ordne ich sowas in einem Array an:
    Code:
    enum motoren {
      MOT_SCHULTER = 0,
      MOT_ELLE,
      MOT_HAND,
      MOT_MAX
    };
    
    struct PIDcontrol pids [MOT_MAX];
    
    /* Verwendung */
    
    void ein_stop(void) {
       StopPIDcontrol( &pids[MOT_SCHULTER );
    }
    
    void mehrere_stops(void) {
      int idx;
    
      for(idx = MOT_SCHULTER; idx < MOT_MAX; idx++)
        StopPIDcontrol( &pids[idx] );
    }
    find ich bequemer, ist aber Geschmackssache.

    Gruss

    botty

  4. #4
    HaWe
    Gast
    vielen Dank, dass ich mehere Einzelfunktionen einsparen will ist kar, das war ja meine Absicht, dennoch sehe ich jetzt schon ein wenig klarer.
    Dennoch ist das mit den doppelten Pointern un dem "casting" schon seeehr kompliziert...
    Außerdem ist mir nicht klar, wie jetzt genau die Verknüpfung erfolgen muss von der aufrufenden simplen API Funktion bis hin zum Task:

    der vereinfachende Wrapper
    Code:
    inline void RotatePIDtoTarget(char port, long Target, float RotatSpeed) {
       RotatePID(port, Target, RotatSpeed, false);
       Wait(1);
    }
    ruft auf die ein wenig komplexere Interface-Funktion inkl. dem Target-Haltemodus:
    Code:
    RotatePID(port, Target, RotatSpeed, false);

    und hier wird nach Setzen der PID Laufzeit-Variablen der PID Task gestartet:
    Code:
    safecall void RotatePID(char port, long Target, float RotatSpeed, char cont) {
      if (port==OUT_A) {
    
        //...
        //...
    
        PID_A.runstate=1;                // set runstate: PID active
    
        // custom init PID_A
        PID_A.target =Target;                   // assign target
        PID_A.tarpwm =RotatSpeed;               // assign rotation speed
        PID_A.cont=cont;                        // cont vs. hit once
    
        // Reset PID control defaults
        PID_A.outp    =0;                // PID control output value
        PID_A.maxout  =100;              // absolute max possible output (max pwr)
        PID_A.read    =0;                // current reading
        PID_A.err     =0;                // current error
        PID_A.integr  =0;                // integral of errors
        PID_A.speed   =0;                // current speed
    
    
        start task_PID_A;
      }
    
      else
      if (port==OUT_B) {
      //...
    statt der if-Schleifen für jeden Motor käme jetzt dein expliziter PID-Aufruf mit Motornummer als Parameter -
    wie würde es aber denn heißen müssen, wenn ich den PID pthread task innerhalb deiner neuen Struktur starten will?
    Geändert von HaWe (26.09.2016 um 17:44 Uhr)

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    19.05.2015
    Beiträge
    69
    Na ja,
    zuerst must du die PIDinit ergänzen:
    Code:
    void PIDinit(void)  {
    
      PID_A.tid = 0;
      PID_A.motor_id = OUT_A;
      
      // für alle Variablen und dann natürlich die anderen Elemente der Struktur.
    
    }
    Die Signaturen deiner High-Level Funktionen ändern sich nur im ersten Element, die anderen Parameter kannst du 1:1 übernehmen z.B.:
    Code:
    inline void RotatePIDtoTarget(struct PIDstruct *pid, long Target, float RotatSpeed) {
       RotatePID(pid, Target, RotatSpeed, false);
    }
    wobei du festlegen musst ob evtl. Fehlercodes wieder hochgereicht werden? Hier spar ich mir das mal.

    Deine zentrale RotatePID sähe dann so aus:
    Code:
    void RotatePID(struct PIDstruct *pid, long Target, float RotatSpeed, char cont) {
      // Nullzeiger?
      if( ! PID ) {
        fprintf(stderr, "RotatePID Null Zeiger!\n");
        return;
      }
    
      // Laeuft der PID in einem Thread bereits?
      if( pid->tid != 0 ) {
        fprintf(stderr, "RotatePID - PID schon gestartet!\n");
        return;
      }
    
      // Koennte weg
      PID_A.runstate=1;                // set runstate: PID active
    
      // custom init PID
      pid->target =Target;                   // assign target
      pid->tarpwm =RotatSpeed;               // assign rotation speed
      pid->cont=cont;                        // cont vs. hit once
    
      // Reset PID control defaults
      pid->outp    =0;                // PID control output value
      pid->maxout  =100;              // absolute max possible output (max pwr)
      pid->read    =0;                // current reading
      pid->err     =0;                // current error
      pid->integr  =0;                // integral of errors
      pid->speed   =0;                // current speed
    
      // Thread starten
      if(pthread_create(&pid->tid, 0, pid_calc, pid)) {
        perror("RotatePID");
        pid->tid = 0;
        return;
      }
    }
    Stoppen ginge dann so
    Code:
    void StopPIDcontrol (struct PIDstruct *pid, int cancel) {
    
      if (pid->tid) { // stop PID task if already running
        Off(pid->motor_id);
    
        if(cancel)
           pthread_cancel(pid->tid);
    
        pthread_join(pid->tid, 0);
        pid->tid = 0; // wichtig!
    
        pid->cont=false;
        pid->runstate=0;
      }
    }
    Die verwendung sähe dann etwa so aus:
    Code:
    struct PIDstruct PID_A;
    
    int main(int argc, char** argv) {
      PIDinit();
    
      // Wartend
      RotatePIDtoTarget(&PID_A, 25, 0.4); // Sinvolle Werte kennst du besser als ich ;)
      StopPIDcontrol(&PID_A, 0);
    
      // Abbrechend
      RotatePIDtoTarget(&PID_A, 35, 0.3);
    
      sleep(2);
    
      StopPIDcontrol(&PID_A, 1);
    
      return 0;
    }
    Ich habe diesen Code nicht durchkompiliert, hoffe aber das er trotzdem deine Fragen klärt.
    Noch ein Wort zur pid_calc Funktion: In ihr solltest du alle paar Schritte, insbesondere in Schleifen, pthread_testcancel() aufrufen, damit ein cancel auch wirklich stattfinden kann.

    Gruss

    botty

  6. #6
    HaWe
    Gast
    hallo botty,
    ganz herzlichen Dank für deine viele Mühe und deine ausführlichen Codebeispiele. Leider verstehe ich im Moment doch noch gar nichts über die ganzen neuen kryptischen Funktionen, Aufrufe und Konstruktionen, insb. noch nicht einmal, warum ich -> statt . verwenden muss.

    Tatsächlich möchte ich allerdings im Aufruf auch nur eine Motornummer übergeben (0,1,2,3 oder per
    #define OUT_A 0
    #define OUT_B 1
    etc.
    und keine PID-Struktur.
    Der Sinn ist, dass meine neue C Syntax an NXC-API Befehle angelehnt sein soll, denn das Ziel ist es auch, Lego Roboter für bisherige Lego NXT und NXC Nutzer mit einer Raspi API zu programmieren und zu betreiben, was bisher nicht möglich ist bei dem völlig fehlkonstruierten neuen Lego EV3-SoC: also quasi als Konkurrenz-Gegenentwurf . Ich habe auch schon mit so einem Gegenprojekt angefangen, PID wäre der nächste Schritt hierfür: http://www.mindstormsforum.de/viewtopic.php?f=78&t=8851
    NXC (bzw. Vorgänger NQC) ist den Lego Nutzern seit fast 20 Jahren bekannt, und hier werden ebenfalls Motor Steuerbefehle verwendet wie
    motorcommand ( motorNr, rotationDegrees, pwm)

    Ich bin für deine neuen Konstrukte aber einfach noch zusehr auf dem absoluten C Anfängerlevel, als dass ich das jetzt wirklich umsetzen könnte. Ich fürchte im Moment, dass meine 3 -10 Einzel Tasks wie bei NXC doch die einzige Möglichkeit sind, das ganze PID Projekt auf dem Raspi für mich zu verwirklichen.

    Vlt könntest du mir aber doch quasi als minimal kleinst-möglichen Lernschritt erklären, warum ich hier oft -> statt . verwenden muss?
    Bei Arduino und auch sonst nutzt man doch auch den . z.B.
    Serial.print()
    Serial.available()
    Wire.begin()

    Und Variablenwerte in Strukturen meine ich auch schon mit Punkt gesehen zu haben

    mystruc.fvar=1.234;

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    19.05.2015
    Beiträge
    69
    Wenn du mit Zeigern arbeitest musst du dir im Klaren darüber sein, dass es immer zwei Speicherbereiche zu unterscheiden gibt. Der eine ist der Speicherbereich in dem die eigentlichen Daten stehen, die andere Speicherzelle ist der Zeiger, dessen Wert die Adresse des anderen enthält.
    Wenn du jetzt eine Variable von einem einfachen Basistypen wie int, char oder double etc. hast und über den Zeiger den Wert ändern willst, muss der Compiler unterscheiden können ob du den Wert des Zeigers oder den Wert auf den den er zeigt ändern möchtest.
    Code:
    int aval = 5;
    
    int main(void) {
      int *ptr;
    
      ptr = &aval;
    
      printf("Der Wert an der Adresse %p ist %d\n", ptr, *ptr);
    
      *ptr = 7;
    
      printf("Der Wert an der Adresse %p ist %d\n", ptr, *ptr);
    
      return 0;
    }
    Für einfache Typen ist das schlicht. "ptr = &aval" weisst dem Zeiger die Adresse von aval zu, während " *ptr = 7 " den Zeiger dereferenziert und in den Speicher dieser Adresse den Wert 7 hineinschreibt. Zwei gänzlich unterschiedliche Dinge.

    Bei Strukturen kommt jetzt hinzu, dass der Compiler Offsets für die Elemente der Struktur berechnen muss, damit er den korrekten Speicherbereich liesst bzw. beschreibt.
    Bei einer Variablen weiss der Compiler zum Übersetzungszeitpunkt wo der Start der Variablen ist und kann diese Offsets absolut oder relativ berechnen.
    Code:
    #include <stdio.h>
    
    struct vec2d {
      double x, y;
    };
    
    struct vec2d ein_vec;
    
    int main(void) {
      ein_vec.x = 3.0;
      ein_vec.y = 7.0;
    
      printf("Adressen von ein_vec=%p, ein_vec.x=%p, ein_vec.y%p\n", &ein_vec, &ein_vec.x, &ein_vec.y);
    
      return 0;
    
    }
    Verwende ich einen Zeiger auf eine Variable einer Struktur, dann kennt der Compiler diesen Startpunkt nicht und ich brauche einen Mechanismus ihm diesen mitteilen zu können. Der "->" sagt also aus: in der Zeigervariable findest du die Startadresse, nimm die und berechne von da an. Während bei Variablen der Compiler die Verantwortung für den Start hat, habe ich als Programmierer die Verantwortung bei Zeigern den richtigen Startpunkt dem Compiler mitzuteilen.

    Code:
    #include <stdio.h>
    
    struct vec2d {
      double x, y;
    };
    
    struct vec2d ein_vec;
    
    int main(void) {
      struct vec2d *vptr;
    
      vptr = &ein_vec;
    
      vptr->x = 3.0;
      vptr->y = 7.0;
    
      printf("Adressen von vptr=%p, ein_vec=%p\n", vptr, &ein_vec);
    
      /* Fehler gibt SEGFAULT */
      vptr = 0;
      vptr->x = 3.0;
      vptr->y = 7.0;
    
      return 0;
    
    }
    An die Adresse 0x00000000 darf man nichts schreiben.

    Falls dir die Erklärungen nicht so ganz einleuchten, solltest du dann vielleicht doch nochmal in ein gutes C-Buch reinschauen und dort die Erklärungen über Zeiger durchgehen. Mir fehlt im Erklären die Übung. Nichts desto trotzt sind Zeiger ein wichtiges und mächtiges Werkzeug in der C-Programmierung.

    Warum ich die überhaupt benutzen wollte hatte einen bestimmten Grund:
    Bei Threads muss man immer aufpassen, dass man sich keine Wettbewerbsbedingungen einfängt, sprich ein Thread in Daten eines anderen hineinschreibt. Obwohl ich erstmal globale Variablen als Speicherort gewählt hatte, werden die einzelnen PIDs dadurch isoliert, dass in den Threads immer nur auf eine Variable über den zugehörigen Zeiger zugegriffen wird (das wäre selbst so, wenn ich alle in einem Feld anordnen würde.). Diese Zeiger liegen auf dem Thread lokalem Stack, sind nach Aussen nicht sichtbar.
    Das war die Idee.

    Gruss
    botty
    Geändert von botty (27.09.2016 um 15:12 Uhr)

  8. #8
    HaWe
    Gast
    @botty:
    habe mir jetzt die letzten Tage deinen Vorschlag noch ein paar mal genauer angesehen und überdacht, etwas herumprobiert und die bereits in meiner "LegoPi" bestehende Raspi- Motorstuktur durch die PID-Parameter aufgebohrt:
    Code:
    //*************************************************************
    // motor API
    //*************************************************************
    
    #define  MAXMOTORS          10    // maximum number of motors
    #define  MAXMOTORSLOCAL      2    // maximum number of local motors
    #define  MAXPWMRANGE       255    // maximum software-pwm range (0-255)
    
    // motor control structure
    
    typedef struct  {   
                    // electrical motor pins
          uint8_t   pind1, pind2, pinpwm;    // dir + pwm L293 H-Bridge type
          uint8_t   pinQa, pinQb;            // rotary enc pins Qa,Qb
         
                    // pwm and encoder values
          int16_t   dirpwm;     
          int32_t   motenc, oldenc;          // rotary encoder values
          
                    // PID    
          pthread_t tid;
          int16_t   motorID;      
                    // PID custom target values
          int32_t   target;                  // set target
          int16_t   tarpwm;                  // motor target speed
                    // PID custom regulation parameters
          double    P;                       // P: basic propotional to error
          double    I;                       // I: integral: avoid perish
          double    D;                       // D: derivative: avoid oscillating
          double    precis;                  // error precision to target
          int16_t   regtime;                 // PID loop time
          double    damp;                    // damp the integral memory
          int8_t    cont;                    // target: continue or hit once
                    // PID internal control variables
          int16_t   runstate;                // monitors runstate
          int16_t   outp;                    // PID control output value
          int16_t   maxout;                  // max output (max motor pwr)
          int32_t   read;                    // current sensor reading
          double    err;                     // current error
          double    integr;                  // integral of errors
          double    speed;                   // current speed
         
    } tEncMotor;
    
    
    tEncMotor motor[MAXMOTORS];
    3 Fragen dazu:
    1) da ich jetzt alles statisch in einem Array deklariert habe: käme man jetzt überwiegend ohne die Pointerpfeile -> aus ?
    2) da jede einzelne Motorstruktur über den Platz im Array definiert ist (motor[0] für motorID=0) : braucht man dann noch die Strukturvariable motorID?
    3) kann man eine zusätzliche Variable im pthread-Aufruf übergeben, indem man die Motornummer mit übergibt?
    bisher läuft mein pthread Aufruf immer per
    pthread_create(&threadID, NULL, threadname, NULL);
    wofür man die 2 NULLs braucht, ist mir z.B. auch noch unklar, vlt kann man die ein oder andere verwenden - und würde das die Sache einfacher machen?

    - - - Aktualisiert - - -

    ps,

    der API Aufruf
    RotatePID(port, Target, RotatSpeed, false);

    würde dann die folgende Funktion aufrufen, die wieder nach Setten der Variablen einen pthread task starten müsste..... (????) :

    Code:
     void RotatePID(char port, long Target, float RotatSpeed, char cont) {
        motor[port].runstate=1;                // set runstate: PID active
        // custom init PID [port]    
        motor[port].target =Target;                   // assign target
        motor[port].tarpwm =RotatSpeed;               // assign rotation speed
        motor[port].cont=cont;                        // cont vs. hit once
        // Reset PID control defaults
        motor[port].outp    =0;                // PID control output value
        motor[port].maxout  =100;              // absolute max possible output (max pwr)
        motor[port].read    =0;                // current reading
        motor[port].err     =0;                // current error
        motor[port].integr  =0;                // integral of errors
        motor[port].speed   =0;                // current speed
    
        // <<<<<<  
        // nur wie wäre das hier dann richtig zu implementieren ????
        // threadname ist ja für jeden Motor immer ein anderer ????  
        // wäre hierfür eine tEncMotor Hilfsvariable  char[12]  tEncMotor.thrnamebuf hilfreich ???? 
        // ("PIDthread00"... "PIDthread99", könnte man beim Initialisieren setten  ????) 
        // aber schreiben will ich ja für alle nur 1x ein einziges PID-Funktionstask-Muster ????
        // >>>>>>
    
        pthread_create(& motor[port].tid, NULL??,  motor[port].thrnamebuf, NULL??); 
    
    
    
    }
    Geändert von HaWe (28.09.2016 um 17:26 Uhr)

Ähnliche Themen

  1. Abgeleitete Klasse = konkrete Klasse?
    Von vixo im Forum Software, Algorithmen und KI
    Antworten: 4
    Letzter Beitrag: 15.09.2016, 16:02
  2. Antworten: 4
    Letzter Beitrag: 02.04.2016, 14:23
  3. Task motionControl() mit der M32
    Von inka im Forum Robby RP6
    Antworten: 8
    Letzter Beitrag: 10.04.2013, 06:40
  4. Gegen-EMK-Methode
    Von MatlStg im Forum Motoren
    Antworten: 7
    Letzter Beitrag: 11.02.2008, 17:07
  5. Was ist die besser Methode? (ADC auswerten)
    Von quantum im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 28.01.2007, 12:57

Berechtigungen

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

fchao-Sinus-Wechselrichter AliExpress