PieterP:
I'm interested to know what makes you think that control theory is pseudoscience?
You must be a lot more careful with your use of language. I did not say that "control theory" is pseudoscience.
...R
PieterP:
I'm interested to know what makes you think that control theory is pseudoscience?
You must be a lot more careful with your use of language. I did not say that "control theory" is pseudoscience.
...R
Could you explain what you did mean?
Robin2:
You must be a lot more careful with your use of language. I did not say that "control theory" is pseudoscience....R
PID is a part of control theory and neither PID nor control theory in general are pseudosciences - if they were, then my classical controls professor wouldn't have been able to teach us controls classes in college
Trust me, I've taken several systems/controls classes in college: it is an art, but there is a helluva bit of hard science and math involved. But that's just it - if you don't have the foundational background, it makes understanding the high level explanations of PID extremely difficult.
To get back on track with OP's question, I tried to understand what's going on, but the sketch is rather unreadable for me - could use better use of whitespace, better naming conventions (instead of just appending 'a' to every variable, etc), and could add more comments to explain what is going on. I also do not see "val_ouput" anywhere in your sketch.
PieterP:
Could you explain what you did mean?
I can't think of anything other than to repeat what I said in Reply #14
"As far as I can see most of what is written about PID is just pseudo-science"
And the evidence I have in favour of that is the good performance from my simple motor control code which uses the same calculations as the PID library but with a huge range of sampling interval.
If this business is as scientific as people make out then they would be able to produce a pair of experiments to demonstrate how it works in one case and not in another despite the best efforts to get the other case to work. We can all demonstrate the effect of gravity, or the splitting of light with prism.
...R
Robin2:
If this business is as scientific as people make out then they would be able to produce a pair of experiments to demonstrate how it works in one case and not in another despite the best efforts to get the other case to work. We can all demonstrate the effect of gravity, or the splitting of light with prism....R
You should take a read here. I've started to read it and I think you should too. It explains how the theory on controls (and, by extension, PID) actually works in the discrete-time domain. This is all of the science you call "pseudo-science"
The pseudo-science is the things written about it. Like astrology is written about planets and constellations.
Statements like "just set d to zero and turn it up until it is unstable" are not very scientific.
Power_Broker:
You should take a read here.
I'm afraid to. If I were to understand what is theoretically wrong with my program it might stop working
...R
Robin2:
I'm afraid to. If I were to understand what is theoretically wrong with my program it might stop working...R
I know that feeling myself all too well, lol
That would be a Schroedingbug. As soon as you look inside the box, it stops working.
Hi,
I would like two know if I can improve my program to have perfectly the same speed on two motors for a long time.(one hour at least)
Because, I have two same motor+encoder but after a couple of minutes, one of them have one half round in more.
Maybe i have got problem declaring constant in the setup with the attachinterrupt. Should i replace const byte by volatile byte or something else?
My program with the monitor detect the two speed are both same.
//The sample code for driving one way motor encoder
#include <PID_v1.h>
//MOTOR GAUCHE pin D 3,7,9,8,5
const byte encoder0pinA = 3;//A pin -> the interrupt pin 1
const byte encoder0pinB = 7;//B pin -> the digital pin 4
byte encoder0PinALast; // volatile byte encoder0PinALast
double latestDurationCount,duration,abs_duration;//the number of the pulses
boolean Direction;//the rotation direction
boolean result;
double val_output;//Power supplied to the motor PWM value.
double Setpoint;
double Kp=1, Ki=10, Kd=0.01; // 0.6 ; 5 ; 0
PID myPID(&abs_duration, &val_output, &Setpoint, Kp, Ki, Kd, DIRECT);
//**************************************************
//MOTOR DROIT pin C 2,4,11,10,6
const byte encoder0pinAa = 2;//A pin -> the interrupt pin 1
const byte encoder0pinBa = 4;//B pin -> the digital pin 7
byte encoder0PinALasta;
double latestDurationCounta,durationa,abs_durationa;//the number of the pulses
boolean Directiona;//the rotation direction
boolean resulta;
double val_outputa;//Power supplied to the motor PWM value.
double Setpointa;
//double Kp=0.6, Ki=5, Kd=0; // 0.6 ; 5 ; 0
PID myPIDa(&abs_durationa, &val_outputa, &Setpointa, Kp, Ki, Kd, DIRECT);
//***************************************************
// PORT POUR KIT L298N 2nd (Bleu clair) supllied with 6 V
// MOTEUR GAUCHE avec myPID
//Ports de commande du moteur D supplied with 6 volt.(8,9,5,3,7,
int motorPinD1 = 9; //13 pin to set H BRIDGE of L298N
int motorPinD2 = 8; //12 pin to set H BRIDGE of L298N
const int enablePinD= 5; //11 // Commande de vitesse moteur, to Output ENA pour L298 the second
// MOTEUR C Droit avec myPIDa 10,11,6,2,4
//Ports de commande du moteur C supplied with 6 volt.
int motorPinC1 = 10; // pin to set H BRIDGE of L298N
int motorPinC2 = 11; //12 pin to set H BRIDGE of L298N
const int enablePinC= 6; //11 // Commande de vitesse moteur, to Output ENA pour L298 the second
void setup()
{
Serial.begin(19200);//Initialize the serial port
// Configuration des ports en mode "sortie" C
pinMode(motorPinC1, OUTPUT); //L298N Control port settings direction of motor C (originaly L298P)
pinMode(motorPinC2, OUTPUT); //L298N Control port settings direction of motor C
pinMode(enablePinC, OUTPUT); // powerRate to control speed of motor C
// Configuration des ports en mode "sortie" D moteur GAUCHE
pinMode(motorPinD1, OUTPUT);
pinMode(motorPinD2, OUTPUT);
pinMode(enablePinD, OUTPUT);
//Originaly to Set the output value of the PID // (read between 42 and 43 pulses when setpoint=30 val outpout=47)
Setpoint; // MOTEUR GAUCHE
myPID.SetMode(AUTOMATIC);//PID is set to automatic mode
myPID.SetSampleTime(5);//Set PID sampling frequency is 100ms
EncoderInit();//Initialize the module
advance();
//REGLAGE PID MOTEUR DROIT (pinc)
Setpointa;
myPIDa.SetMode(AUTOMATIC);//PID is set to automatic mode
myPIDa.SetSampleTime(5);//Set PID sampling frequency is 100ms
EncoderInita();//Initialize the module
advancea();
}
void loop()
{
//MOTOR GAUCHE less fast when latestDurationCount = duration; or myPID at top of void loop?
noInterrupts();
latestDurationCount = duration;
interrupts();
abs_duration = abs(latestDurationCount);
Setpoint= 40;
result=myPID.Compute();//PID conversion is complete and returns 1
advance();
if(result)
{
Serial.print("LD"); Serial.print(latestDurationCount);
Serial.print("D : "); Serial.print(duration); Serial.print(duration); Serial.print(duration);
duration = 0; //Count clear, wait for the next count
//Serial.print("Setpoint"); Serial.println(Setpoint);
Serial.print("V"); Serial.println(val_output);// volt to MOTOR= real speed
}
// *******************************************
// SETTING MOTEUR DROIT PIDa avec PIN C
noInterrupts();
latestDurationCounta = durationa;
interrupts();
abs_durationa = abs(latestDurationCounta);
Setpointa=40; //
resulta=myPIDa.Compute();//PID conversion is complete and returns 1
advancea();
if(resulta)
{
//val_outputa124.95 latestDurationCounta100.00Plusea: 194.00
//with 19200 bauds Setpointa20.00 val_outputa73.10 latestDurationCounta20.00Plusea: 39.00
Serial.print("LDa"); Serial.print(latestDurationCounta);
Serial.print("Da: "); Serial.print(durationa);Serial.print(durationa);Serial.print(durationa);
durationa = 0; //Count clear, wait for the next count
//Serial.print("Setpointa"); Serial.println(Setpointa);
Serial.print("Va"); Serial.println(val_outputa);// volt to MOTOR= real speed
}
}
void EncoderInit()
{
Direction = true;//default -> Forward
pinMode(encoder0pinB,INPUT);
attachInterrupt(1, wheelSpeed, CHANGE);
}
void wheelSpeed()
{
byte Lstate = digitalRead(encoder0pinA);
if((encoder0PinALast == LOW) && Lstate==HIGH)
{
byte val = digitalRead(encoder0pinB);
if(val == LOW && Direction)
{
Direction = false; //Reverse
}
else if(val == HIGH && !Direction)
{
Direction = true; //Forward
}
}
encoder0PinALast = Lstate; // volatile byte encoder0PinALast ??
if(!Direction) duration++;
else duration--;
}
void advance()//Motor Forward
{
digitalWrite(motorPinD1,HIGH);
digitalWrite(motorPinD2,LOW);
analogWrite(enablePinD,val_output);
}
void back()//Motor reverse
{
digitalWrite(motorPinD1,LOW);
digitalWrite(motorPinD2,HIGH);
analogWrite(enablePinD,val_output);
}
void Stop()//Motor stops
{
digitalWrite(enablePinD, LOW);
}
void EncoderInita()
{
Directiona = true;//default -> Forward
pinMode(encoder0pinBa,INPUT);
attachInterrupt(0, wheelSpeeda, CHANGE);
}
void wheelSpeeda()
{
byte Lstatea = digitalRead(encoder0pinAa);
if((encoder0PinALasta == LOW) && Lstatea==HIGH)
{
byte vala = digitalRead(encoder0pinBa);
if(vala == LOW && Directiona)
{
Directiona = false; //Reverse
}
else if(vala == HIGH && !Directiona)
{
Directiona = true; //Forward
}
}
encoder0PinALasta = Lstatea;
if(!Directiona) durationa++;
else durationa--;
}
void advancea()//Motor Forward
{
digitalWrite(motorPinC1,HIGH);
digitalWrite(motorPinC2,LOW);
analogWrite(enablePinC,val_outputa);
}
void backa()//Motor reverse
{
digitalWrite(motorPinC1,LOW);
digitalWrite(motorPinC2,HIGH);
analogWrite(enablePinC,val_outputa);
}
void Stopa()//Motor stops
{
digitalWrite(enablePinC, LOW);
}
Huh, sounds a lot like your post here
double latestDurationCount,duration,abs_duration;//the number of the pulses
I can't imagine the relationship between variables with duration in the name and number of pulses.
Setpoint; // MOTEUR GAUCHE
If that comment translates to "stupid code", I agree. If not, explain just what you think this useless statement is accomplishing.
Setpointa;
More uselessness.
Threads merged.
PaulS:
double latestDurationCount,duration,abs_duration;//the number of the pulses
I can't imagine the relationship between variables with duration in the name and number of pulses.
Setpoint; // MOTEUR GAUCHE
If that comment translates to "stupid code", I agree. If not, explain just what you think this useless statement is accomplishing.
Setpointa;
More uselessness.
duration is to know the number of pulse which should be the same as Setpoint, but actually it is not a good measurement method, that's why someone tall me to add this to have the latest duration
noInterrupts();
latestDurationCount = duration;
interrupts();
abs_duration = abs(latestDurationCount);
I added Setpoint and Setpointa in the setup just to make understand (for me) which Setpoint is on LEFT or RIGHT MOTOR. It's standard label in PID, I should call it Setspeed, maybe.
No, my threads are not merged. But I have seen someone who program PID by "masking the other input in order they don't affect the Arduino"
Like that
void counter()
{
byte state=PIND;
state|=B11101011; // mask to look only changing on 2 et 4
// Modifier le MASK B01111011 par BXXXXXXXX mettre des 0 là où sont les pins utilisés par l'encodeur
if( state!=laststate)
{
(((state&(1<<ENCODEURA))>>ENCODEURA)^((state&(1<<ENCODEURB))>>ENCODEURB))?count--:count++;
laststate=state;
}
}
Is it useful?
bvking:
I would like two know if I can improve my program to have perfectly the same speed on two motors for a long time.(one hour at least)
For a system like that I would control the speed of one motor directly and make the other motor match the first motor, rather than trying to control it separately at the same speed.
If you want very close co-ordination you may need to account for the accumulated difference between the motors and adjust to bring that back to zero also.
Or just make a physical connection between the motors?
Using a pair of stepper motors would be much easier if the requirement is for a slow speed within the scope of a stepper motor.
...R