- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 10 von 16

Thema: Motor Positionsregelung mit Encoder

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    903
    Hast Du schon mal was von PID-Reglern gehört? Die sind relativ einfach in einem Controller umzusetzen.
    Das hilft allerdings bei Deinem Schrägenproblem nur bedingt , weil:

    "Ohne Abweichung keine Regelung!"

    Vielleicht wäre für das Schrägenproblem denkbar, über einen 3-Ach-Accelerometer die Schräglage zu messen und damit einen zweiten PID-Regler zuzuschalten (Die Dinger kann man kaskadieren, also das Ergebnis mehrerer Regler je nach Anwendungsfall miteinander multiplizieren oder addieren.)

    Mal ein Beispiel für eine PID-Implementierung

    PID.h
    Code:
    #ifndef INCL_PID_H
    	#define INCL_PID_H
    
        #include <avr/io.h> 
        #include <stdint.h>
    
        #define PID_SIZEOFFSET 19 // Offset in uint8_t array for data start
    
        typedef struct
        {
            uint8_t Depth;  //0
            double KP;      //1
            double KI;      //5
            double KD;      //9
            double Sum;     //13
            uint8_t Index;  //17
            double Buffer[];//18
        }PID_t;
    
    
        extern void InitPIDStruct(uint8_t arr[], uint16_t size);
        extern void PIDCalculate(PID_t* pid, double diff, double* result);
    
    
    #endif
    So ein PID-Regler benötigt drei Konstanten, die an das System anzupassen sind: KP(roportional), KI(ntegral), und KD(ifferential).
    Proportional: Je größer die aktuelle Abweichung, desto größer die Gegensteuerung
    Integral: Je "stabiler" (länger anhaltend) die Abweichung, desto größer die Gegensteuerung
    Differential: Je nach Trend (Änderung der Abweichung) ändert sich die Gegensteuerung.



    PID.c

    Code:
    #include <stdint.h>
    #include <math.h>
    #include <string.h>
    #include "PID.h"
    
    
    
    //Init array: iRead/iWrite = 0, data elements = 0, Buffer length = array length -4
    void InitPIDStruct(uint8_t arr[], uint16_t size)
    {
        memset( arr, 0, size);
        arr[0] = (size-PID_SIZEOFFSET) / sizeof(double);
    }
    
    double p, i, d;
    
    void PIDCalculate(PID_t* pid, double diff, double* result)
    {
        //Proportional
        p = diff * pid->KP;
    
        //Differential
        double previous = pid->Buffer[pid->Index];
        d = (diff - previous) * pid->KD;
    
        //Integral
        pid->Index = (pid->Index + 1) % pid->Depth; //Step up index
        double oldVal = pid->Buffer[pid->Index];
        pid->Buffer[pid->Index] = diff;
        pid->Sum -= oldVal;
        pid->Sum += diff;
        i = (pid->Sum/ pid->Depth) * pid->KI;
    
        *result = -1.0 * (p + i + d);
    }
    Um den integralen Anteil zu berechnen, verwende ich hier ein Array, dass die letzten 16 Werte hält. Allerdings berechne ich nicht die komplette Summe in jedem Durchlauf neu, sondern ziehe immer nur das älteste Element ab und füge das neu hinzugekommene Element hinzu.



    Initialisierungsbeispiel:
    Code:
    static uint8_t arrDistance[16 * sizeof(double) + PID_SIZEOFFSET];
    static PID_t* PIDDistance;
    
    void Drive_Init()
    {
        InitPIDStruct(arrDistance, sizeof(arrDistance));
        PIDDistance = (PID_t*) arrDistance;
        
        PIDDistance->KP = 0.6;
        PIDDistance->KI = 0.2;
        PIDDistance->KD = 0.4;
    }
    Vielleicht wird's hier klar, warum ich zuerst ein Array anlege und anschließend auf den Strukturtyp caste. Ich kann dadurch die Größe des Integrationspuffers in der Arraydefinition anpassen (in InitPIDStruct wird entsprechend dann das "Depth" errechnet).


    Ein Durchlauf in etwa so:
    Code:
        //calculate Distance regulation value
        static double dregDistance;
        PIDCalculate(PIDDistance, dDistance, &dregDistance);
       
        //!!! Wenn Neutral = 15000, dann hier aufaddieren
        int16_t newPWM = 15000 + (int16_t) dRegDistance;
    Eingang ist die Regeldifferenz dDistance, also Sollwert-Istwert
    Ausgang ist der Regelwert, hier als Beispiel mal die PWM.

    Die drei Konstanten kP, kI und kD einzustellen, ist allerdings eine Kunst für sich. Es gibt sowohl mathematische Ansätze als auch den reinen Probieralgorithmus, in dem zuerst kP möglichst optimal eingestellt, danach kI dazugenommen und kD als optimierendes i-Tüpfelchen zum Schluss ausgetestet wird.
    Geändert von Holomino (08.10.2016 um 10:23 Uhr)

Ähnliche Themen

  1. Antworten: 1
    Letzter Beitrag: 21.03.2012, 18:43
  2. Motor Positionsregelung
    Von Che Guevara im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 11.10.2011, 12:13
  3. Encoder für BL Motor
    Von kristof81 im Forum Motoren
    Antworten: 10
    Letzter Beitrag: 05.06.2010, 13:10
  4. Motor mit Encoder
    Von Da_Vinci13 im Forum Motoren
    Antworten: 3
    Letzter Beitrag: 19.01.2009, 19:55
  5. Antworten: 2
    Letzter Beitrag: 23.07.2007, 08:44

Berechtigungen

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

Labornetzteil AliExpress