sehr schön, danke, das hat jetzt weitergeholfen. 8-)
Den regler jetzt auf Encoderwerte zu tunen, ist ntl eine Lebensaufgabe.
Gibt es eine Tabelle mit Erfahrungswerten für Encoder, Reg.-Time ca 10ms?
mit PID 2,5,1 schwankt er sehr langsam um den Zielwert (100),
mit höheren PID Werten ist er schneller, aber zittert mächtig.
//***********************************************************************************
// PID controller
// Reading motor encoder[0] to control PWM motor [0]
// ver 1.007
//************************************************************************************
#include <PID_v1.h>
//Define Variables we'll be connecting to
double PID0setpoint, PID0input, PID0output;
//Specify the links and initial tuning parameters
// PID myPID(&PIDInput, &PIDOutput, &PIDSetpoint,2,5,1, DIRECT);
PID PID0(&PID0input, &PID0output, &PID0setpoint,20,5,3, DIRECT);
#define PID_REGTIME_MS 10
//*************************************************************
#define sensortouch(pinHIGH) !digitalRead(pinHIGH)
#define startpin 12
#define MAXMOTORS 2
#define OUT_RUNSTATE_IDLE 0
#define OUT_RUNSTATE_ACTIVE 1
// set motor pins
// motor 0
#define pinmenc0A 2 // encA yellow
#define pinmenc0B 3 // encB blue
#define pinmot0d1 4 // dir1
#define pinmot0d2 5 // dir2
#define pinmot0pwm 6 // enable
// motor 1
#define pinmenc1A 7 // encA yellow
#define pinmenc1B 8 // encB blue
#define pinmot1d1 9 // dir1
#define pinmot1d2 10 // dir2
#define pinmot1pwm 11 // enable
//************************************************************************************
// Encoder functions courtesy of / entnommen aus: http: //www.meinDUINO.de //
//
// Globale Variablen zur Auswertung in der Interrupt-Service-Routine (ISR)
//************************************************************************************
volatile int8_t altAB[MAXMOTORS] = {0,0};
volatile long motenc[MAXMOTORS] = {0,0},
oldenc[MAXMOTORS] = {0,0};
// Die beiden Schritt-Tabellen für 1/1, 1/2 oder 1/4-Auflösung/resolution
// 1/1 Auflösung/resolution
//int8_t schrittTab[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
// 1/2 Auflösung/resolution
int8_t schrittTab[16] = {0, 0,0,0,1,0,0,-1, 0,0,0,1,0,0,-1,0};
// 1/4 Auflösung/resolution
//int8_t schrittTab[16] = {0,0,0,0,0,0,0,-1,0,0,0,0,0,1,0,0};
//*************************************************************
// Interrupt Service Routine: wenn Interrupt ausgelöst wird
//*************************************************************
ISR(TIMER1_COMPA_vect) {
altAB[0] <<= 2;
altAB[0] &= B00001100;
altAB[0] |= (digitalRead(pinmenc0A) << 1) | digitalRead(pinmenc0B);
motenc[0] += schrittTab[altAB[0]]; //
altAB[1] <<= 2;
altAB[1] &= B00001100;
altAB[1] |= (digitalRead(pinmenc1A) << 1) | digitalRead(pinmenc1B);
motenc[1] += schrittTab[altAB[1]]; //
}
//************************************************************************************
byte pinmotdir[MAXMOTORS][2]={ {pinmot0d1, pinmot0d2},
{pinmot1d1, pinmot1d2} };
int pinmotpwm[MAXMOTORS]={pinmot0pwm, pinmot1pwm};
//************************************************************************************
inline void motoron(byte motnr, int power) {
if(power>0) {
digitalWrite( pinmotdir[motnr][0],HIGH);
digitalWrite( pinmotdir[motnr][1],LOW);
}
else
if(power<0) {
digitalWrite( pinmotdir[motnr][0],LOW);
digitalWrite( pinmotdir[motnr][1],HIGH);
}
else
if(power==0) {
digitalWrite( pinmotdir[motnr][0],LOW);
digitalWrite( pinmotdir[motnr][1],LOW);
}
power = abs(power);
if(power>254) power=254;
analogWrite(pinmotpwm[motnr],power);
}
//------------------------------------------------------------------------------------
inline void motorbrake(byte motnr) { // to do list !!!
motoron(motnr, 0);
}
//------------------------------------------------------------------------------------
inline void motorcoast(int motnr) {
motoron( motnr, 0);
}
#define motoroff motorcoast
//************************************************************************************
void setup()
{
pinMode(startpin,INPUT_PULLUP); // btn to start
pinMode(pinmot0d1,OUTPUT); // dir1
pinMode(pinmot0d2,OUTPUT); // dir2
pinMode(pinmenc0A,INPUT_PULLUP); // encA
pinMode(pinmenc0B,INPUT_PULLUP); // encB
pinMode(pinmot0pwm,OUTPUT); // enable
pinMode(pinmot1d1,OUTPUT); // dir1
pinMode(pinmot1d2,OUTPUT); // dir2
pinMode(pinmenc1A,INPUT_PULLUP); // encA
pinMode(pinmenc1B,INPUT_PULLUP); // encB
pinMode(pinmot1pwm,OUTPUT); // enable
// time interrupt for encoder readings
noInterrupts(); // Jetzt keine Interrupts / disable
TIMSK1 |= (1<<OCIE1A); // Timer 1 PIDOutput Compare A Match Interrupt Enable
TCCR1A = 0; // "Normaler" Modus
// WGM12: CTC-Modus einschalten (Clear Timer on Compare match)
// Stimmen OCR1A und Timer überein, wird der Interrupt ausgelöst
// Bit CS12 und CS10 setzen
// => Prescaler=1024:
// TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);
// => Prescaler=8:
TCCR1B = (1<<WGM12) | (1<<CS11);
// Frequenz = 16000000 / 1024 / 15 = rd. 1042Hz = 1kHz
// Frequenz = 16,000,000 / 8 / 64 = rd. 31 kHz
// Frequenz = 16,000,000 / 8 / 512 = rd. 4 kHz
OCR1A =511;
interrupts(); // Interrupts wieder erlauben / enable
//initialize the variables we're linked to
PID0input = motenc[0];
PID0setpoint = 100;
//turn the PID on
PID0.SetMode(AUTOMATIC);
PID0.SetOutputLimits(-255, 255);
PID0.SetSampleTime(PID_REGTIME_MS);
Serial.begin(115200);
}
//************************************************************************************
void loop()
{
PID0input = motenc[0];
PID0.Compute();
motoron(0, PID0output);
Serial.println(motenc[0]);
}
Nur mit sehr kurzen Reg.-Time von ca 2ms ist er halbwegs schnell und zuckt nicht und schwingt nicht. Derart kurze Regzeiten will ich aber vermeiden.
Erfahrungswerte wären also gut.