PID motor control

Hello,

I'm trying to implement a PID motor control. The setpoint is set over the serial monitor. When i set the desired speed (setpoint) the serial monitor is displaying the readings from the analog input.

PID library im using Arduino Playground - PIDLibrary

The problem is that when I enter the desired value, nothing happens, the motor doesn't start.

#include <PID_v1.h>
int incomingByte = 0;   // for incoming serial data
char buffer[4];         // buffer
int pInput;                //  input from serial monitor
int motorPin = 9;
int analogPin = 0;
int value = 0;
int pValue = 0;  // storing the mapped value

double Setpoint, Input, Output; 

PID myPID(&Input, &Output, &Setpoint,1,0.05,0.25, DIRECT); 

void setup() {
        Serial.begin(9600);
        pinMode(9, OUTPUT);
        Input = map (value,0,1023,0,255);
        Setpoint = pInput;
   
        myPID.SetMode(AUTOMATIC); // Turn ON PID     
}

void loop() {

            
                incomingByte = Serial.readBytes(buffer,4);
                
                pInput = atoi(buffer);
                
                value = analogRead (analogPin);
                pValue = map (value,0,1023,0,255);
                Serial.println (pValue);
                delay(1000);

                Input = map (value,0,1023,0,255);
                myPID.Compute();
                analogWrite (9,Output);
                       
                
}

Can you run the motor without the PID control? What values are you getting for output? What does your circuit look like?

wildbill:
Can you run the motor without the PID control? What values are you getting for output? What does your circuit look like?

Yes, the motor runs fine without the PID.

The circuit looks like the one on the image without the push button. I have a second DC motor connected to the first one and it functions as a generator, they are not electricaly connected. The generator is my feedback so my output is 0.

Hi ManFish

In loop(), I can't see where you assign the entered value to Setpoint?

And have you checked that the entered value is being read correctly? Maybe add some debug print statements ...

pInput = atoi(buffer);
Serial.print("pInput = ");
Serial.println(pInput);

Regards

Ray

Hackscribble:
Hi ManFish

In loop(), I can't see where you assign the entered value to Setpoint?

Correct, i missed that one. I added the Setpoint = pInput in loop() and now it seems to work, sort of...

Hackscribble:
And have you checked that the entered value is being read correctly? Maybe add some debug print statements ...

pInput = atoi(buffer);

Serial.print("pInput = ");
Serial.println(pInput);




Regards

Ray

I added the print statements and the values are being read correctly. The new problem is that the motor is running and stoping, pulsating for the lack of a better word and if I enter a different value it ignores it.

Here is the output from the serial monitor when i enter 050:

pInput = 0
0
pInput = 0
0
pInput = 0
0
pInput = 50
0
pInput = 50
194
pInput = 50
0
pInput = 50
238
pInput = 50
0
pInput = 50
231
pInput = 50
0
pInput = 50
235
pInput = 50
0

Each time round loop(), you are calling the readBytes() function. If you have not typed in a new value, this will return 0 (after a timeout period) to indicate no characters received. So I think your Setpoint is being reset to 0 each time.

Try changing the first part of your loop() to be ...

    if (Serial.available()) 
    {                
        incomingByte = Serial.readBytes(buffer,4);
        pInput = atoi(buffer);
    }
    Serial.print("pInput = ");
    Serial.println(pInput);

    value = analogRead (analogPin);
    // rest of existing code

This will only update pInput if you have typed a new value and, therefore, there is something in the serial input buffer.

Hackscribble:
Each time round loop(), you are calling the readBytes() function. If you have not typed in a new value, this will return 0 (after a timeout period) to indicate no characters received. So I think your Setpoint is being reset to 0 each time.

Try changing the first part of your loop() to be ...

    if (Serial.available()) 

{               
        incomingByte = Serial.readBytes(buffer,4);
        pInput = atoi(buffer);
    }
    Serial.print("pInput = ");
    Serial.println(pInput);

value = analogRead (analogPin);
    // rest of existing code




This will only update pInput if you have typed a new value and, therefore, there is something in the serial input buffer.

I did as you've suggested but i'm not sure if it's working. I tried entering 000 to stop the motor but it doesn't stop.

With the changed code, if you enter just one number to start the motor and then you don't enter any more numbers, are you still getting this problem?

The new problem is that the motor is running and stoping, pulsating for the lack of a better word and if I enter a different value it ignores it.

Hackscribble:
With the changed code, if you enter just one number to start the motor and then you don't enter any more numbers, are you still getting this problem?

The new problem is that the motor is running and stoping, pulsating for the lack of a better word and if I enter a different value it ignores it.

Yes, it's still pulsating. Could it be that i'm using the wrong MOSFET (IRF520) ?

Could be that the PID needs tuning. I am not an expert in PIDs but I believe that the parameters need to be adjusted to get the right balance between achieving the setpoint sufficiently quickly, while not going into oscillation.

There have been several PID-related threads recently on this forum. They included references to other websites with different approaches to tuning. Might be worth looking at them.

I suggest you post a schematic of the complete system, including the feedback loop connection back to the Arduino. And maybe change the thread title to include something about "problem with pulsating motor". It might catch the eye of a PID specialist.

Sorry I can't help more.

Ray

Hackscribble:
Could be that the PID needs tuning. I am not an expert in PIDs but I believe that the parameters need to be adjusted to get the right balance between achieving the setpoint sufficiently quickly, while not going into oscillation.

There have been several PID-related threads recently on this forum. They included references to other websites with different approaches to tuning. Might be worth looking at them.

I suggest you post a schematic of the complete system, including the feedback loop connection back to the Arduino. And maybe change the thread title to include something about "problem with pulsating motor". It might catch the eye of a PID specialist.

Sorry I can't help more.

Ray

I'll do that. You've been very helpfull, thank you.

May be the question is stupid: ¿where is the feedback?.

Regards.

vffgaston:
May be the question is stupid: ¿where is the feedback?.

Regards.

It seems that the problem was bad tuning. I'll add the full schematic as soon as i get some time and make some progress.

The pulsating motor problem was caused by the delay(1000) in the code. The motor is working fine now.

The new problem is that the PID is not working at all. The feedback on the serial monitor is too fast so I assume I should do some kind of main loop timing control ? If this is the case how could i achieve that ?

the schematic of the project Imgur: The magic of the Internet

code so far:

#include <PID_v1.h>
int pInput;                //  input from serial monitor
int motorPin = 9;
int analogPin = 0;
int value = 0;
int pValue = 0;  // storing the mapped value

double Setpoint, Input, Output; 

PID myPID(&Input, &Output, &Setpoint,1,0.05,0.25, DIRECT); 

void setup() {
        Serial.begin(9600);
        pinMode(9, OUTPUT);
         
        myPID.SetMode(AUTOMATIC); // Turn ON PID     
}

void loop() {

            if(Serial.available() > 0){
                pInput = Serial.parseInt();
                pInput = constrain(pInput,0,255);
            }
                
                value = analogRead (analogPin);
                Input = map (value,0,1023,0,255);
                Setpoint = pInput;
                              
                myPID.Compute();
                analogWrite (9,Output);
                       
                
}

In my experience, is better not to use the library, instead write your own PID function. Read this article

http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

it helps you to understand how the PID works. You don't need to implement all the steps, just do it until your project works well.

By the way, the guy from the article (Brett Beauregard) is the same guy that developed the PID library.

Gilgamesh90:
In my experience, is better not to use the library, instead write your own PID function. Read this article

http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

it helps you to understand how the PID works. You don't need to implement all the steps, just do it until your project works well.

By the way, the guy from the article (Brett Beauregard) is the same guy that developed the PID library.

I was hoping the PID library would help me finish my project faster. I'm obviously doing something wrong and would like to know what. Implementing from scratch is still an option even though im short on time (the main reason im trying to use the library).

Well, since you're controlling speed, it shouldn't be any problem, if you apply yourself, you should develop your own code in a day or less.