strange behavior

Hi all,
recently I tried an external library for PID controllers but I can’t get it work.
of course I already asked developers but to me it seem to be some compilation issue.
this is a simple code they give as example:

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Input = analogRead(0);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output);
}

and it compile without errors but nothing will be sent out from pin 3.
I managed it to work only removing Setmode and activating it into constructor.
I also find that it is not possible to have this PID object and Serial used in the same code.

developer told me that he uses same version I do Arduino_0022 but I’m not sure about compiler and libraries.
I’m actually using Gentoo Linux and avr-gcc -h return this

Using built-in specs.
COLLECT_GCC=/usr/x86_64-pc-linux-gnu/avr/gcc-bin/4.5.3/avr-gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/avr/4.5.3/lto-wrapper
Target: avr
Configured with: /var/tmp/portage/cross-avr/gcc-4.5.3-r1/work/gcc-4.5.3/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/avr/gcc-bin/4.5.3 --includedir=/usr/lib/gcc/avr/4.5.3/include --datadir=/usr/share/gcc-data/avr/4.5.3 --mandir=/usr/share/gcc-data/avr/4.5.3/man --infodir=/usr/share/gcc-data/avr/4.5.3/info --with-gxx-include-dir=/usr/lib/gcc/avr/4.5.3/include/g++-v4 --host=x86_64-pc-linux-gnu --target=avr --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --without-ppl --without-cloog --disable-lto --enable-nls --without-included-gettext --with-system-zlib --disable-werror --enable-secureplt --disable-multilib --disable-libmudflap --disable-libssp --disable-libgomp --with-python-dir=/share/gcc-data/avr/4.5.3/python --enable-checking=release --disable-libgcj --enable-languages=c,c++ --enable-shared --disable-threads --disable-bootstrap --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo 4.5.3-r1 p1.0, pie-0.4.5'
Thread model: single
gcc version 4.5.3 (Gentoo 4.5.3-r1 p1.0, pie-0.4.5)

anyone have hints?

Hi s_michele,

where did you get the library?

F.

Hi fsuperga, sorry for delay. this is a link I downloaded library. http://www.arduino.cc/playground/Code/PIDLibrary

I don't see any pin modes being set. Don't you need to do that?

Have you tried logging the values you're reading from the input pin and writing to the output pin? Do these values correspond to what you're supplying to the input and measuring at the output?

Yes I tried to just print input values and to inspect output and they work. for pin mode I know that using analogWrite there is no need to set pin in output mode (it should be automatic) and analogRead never required mode setting.
strange thing is that even Serial port stop working if I try to decleare a pid object. It seems to me some kind of compilation issue.

strange thing is that even Serial port stop working if I try to decleare a pid object. It seems to me some kind of compilation issue.

If you can't compile, how do you know that the serial port stops working?

but I can compile. it does not work when I load it, but it atually compile always and without any error or strange messages

and it compile without errors but nothing will be sent out from pin 3. I managed it to work only removing Setmode and activating it into constructor. I also find that it is not possible to have this PID object and Serial used in the same code.

My hope is that somewhere there is a way to have some report to understand what is going on

but I can compile.

Then it can't possibly be a compilation issue.

PaulS
I know I can be really messy when explaining my tough so let’s start again.
with code I posted I can compile but my board seems dead
removing these lines (I modified constructor to make it useless)

//turn the PID on
  myPID.SetMode(AUTOMATIC);

it still compile and I can see my board work.
I didn’t make any other change to library but I tried to use some other function of PID object and it always stop working.
I also try to use serial communication to inspect what’s going on but if I use Serial object board stop working and nothing will be sent to serial monitor.

when I say that board seems dead it means that my arduino uno board did not produce any output signal (nor analog nor digital) even if it is done on the first line of setup procedure.

my idea was that it is an issue related to compilation process.
what do you think it can be?

I modified constructor to make it useless

Why? How? Perhaps you removed something necessary.

I got it to work as per the example in the original post, depending on how you define “work”. The LED flashed as I turned a pot I put on A0.

I also try to use serial communication to inspect what’s going on but if I use Serial object board stop working and nothing will be sent to serial monitor.

I didn’t find that, adding serial messages helped. This is the code with debugging prints:

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>
#include <Streaming.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Input = analogRead(0);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-128, 127);
  
  Serial.begin (115200);
  Serial << "Starting ..." << endl;
}

void loop()
{
  Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output + 128);
  
  Serial << "Input: " << Input << " Setpoint: " << Setpoint <<  " Output: " << Output << endl;
  delay (500);

}

I had an LED (and resistor) on pin D3. I had a pot wiper on A0, and the other ends of the pot on +5V and Gnd.

I added this line:

  myPID.SetOutputLimits(-128, 127);

Otherwise I don’t see how it could “throttle back” when required. However maybe I just don’t understand PIDs.

However this is the strange part …

With the pot carefully adjusted to give around 100 this was the debugging output:

Input: 92.00 Setpoint: 100.00 Output: 2.00
Input: 92.00 Setpoint: 100.00 Output: -104.00
Input: 78.00 Setpoint: 100.00 Output: 75.00
Input: 78.00 Setpoint: 100.00 Output: -54.00
Input: 79.00 Setpoint: 100.00 Output: -55.50
Input: 80.00 Setpoint: 100.00 Output: -47.50
Input: 80.00 Setpoint: 100.00 Output: -27.50
Input: 80.00 Setpoint: 100.00 Output: -17.50
Input: 82.00 Setpoint: 100.00 Output: -32.50
Input: 81.00 Setpoint: 100.00 Output: 9.00
Input: 81.00 Setpoint: 100.00 Output: 8.50
Input: 81.00 Setpoint: 100.00 Output: 18.00
Input: 81.00 Setpoint: 100.00 Output: 27.50
Input: 81.00 Setpoint: 100.00 Output: 37.00
Input: 81.00 Setpoint: 100.00 Output: 46.50
Input: 81.00 Setpoint: 100.00 Output: 56.00
Input: 80.00 Setpoint: 100.00 Output: 78.00
Input: 81.00 Setpoint: 100.00 Output: 65.50
Input: 95.00 Setpoint: 100.00 Output: -90.00
Input: 95.00 Setpoint: 100.00 Output: 52.50
Input: 96.00 Setpoint: 100.00 Output: 42.50
Input: 97.00 Setpoint: 100.00 Output: 42.00
Input: 97.00 Setpoint: 100.00 Output: 53.50
Input: 100.00 Setpoint: 100.00 Output: 17.50
Input: 102.00 Setpoint: 100.00 Output: 22.50
Input: 100.00 Setpoint: 100.00 Output: 66.50
Input: 101.00 Setpoint: 100.00 Output: 34.00
Input: 102.00 Setpoint: 100.00 Output: 31.00
Input: 102.00 Setpoint: 100.00 Output: 40.00
Input: 101.00 Setpoint: 100.00 Output: 51.50
Input: 102.00 Setpoint: 100.00 Output: 28.50
Input: 101.00 Setpoint: 100.00 Output: 50.00
Input: 101.00 Setpoint: 100.00 Output: 39.50
Input: 100.00 Setpoint: 100.00 Output: 51.50
Input: 101.00 Setpoint: 100.00 Output: 29.00
Input: 101.00 Setpoint: 100.00 Output: 38.50
Input: 100.00 Setpoint: 100.00 Output: 50.50
Input: 101.00 Setpoint: 100.00 Output: 28.00
Input: 100.00 Setpoint: 100.00 Output: 50.00
Input: 100.00 Setpoint: 100.00 Output: 40.00
Input: 100.00 Setpoint: 100.00 Output: 40.00
Input: 101.00 Setpoint: 100.00 Output: 27.50
Input: 101.00 Setpoint: 100.00 Output: 37.00
Input: 101.00 Setpoint: 100.00 Output: 36.50
Input: 100.00 Setpoint: 100.00 Output: 48.50
Input: 101.00 Setpoint: 100.00 Output: 26.00
Input: 100.00 Setpoint: 100.00 Output: 48.00
Input: 100.00 Setpoint: 100.00 Output: 38.00
Input: 101.00 Setpoint: 100.00 Output: 25.50
Input: 101.00 Setpoint: 100.00 Output: 35.00
Input: 100.00 Setpoint: 100.00 Output: 47.00
Input: 100.00 Setpoint: 100.00 Output: 37.00
Input: 100.00 Setpoint: 100.00 Output: 37.00
Input: 100.00 Setpoint: 100.00 Output: 37.00
Input: 101.00 Setpoint: 100.00 Output: 24.50
Input: 101.00 Setpoint: 100.00 Output: 34.00
Input: 100.00 Setpoint: 100.00 Output: 46.00
Input: 100.00 Setpoint: 100.00 Output: 36.00

I confess I don’t understand why the output varies all over the place when the input is practically the same (or is exactly the same) as the set point.

Eventually (quite a while later) it settled down to outputting -128:

Input: 100.00 Setpoint: 100.00 Output: -107.00
Input: 100.00 Setpoint: 100.00 Output: -117.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -120.00
Input: 100.00 Setpoint: 100.00 Output: -108.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -108.50
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -109.00
Input: 100.00 Setpoint: 100.00 Output: -119.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -122.00
Input: 101.00 Setpoint: 100.00 Output: -122.50
Input: 101.00 Setpoint: 100.00 Output: -123.00
Input: 101.00 Setpoint: 100.00 Output: -123.50
Input: 101.00 Setpoint: 100.00 Output: -124.00
Input: 101.00 Setpoint: 100.00 Output: -124.50
Input: 101.00 Setpoint: 100.00 Output: -125.00
Input: 101.00 Setpoint: 100.00 Output: -125.50
Input: 100.00 Setpoint: 100.00 Output: -113.50
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -126.50
Input: 100.00 Setpoint: 100.00 Output: -114.50
Input: 100.00 Setpoint: 100.00 Output: -124.50
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -127.50
Input: 100.00 Setpoint: 100.00 Output: -115.50
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -116.00
Input: 100.00 Setpoint: 100.00 Output: -126.00
Input: 100.00 Setpoint: 100.00 Output: -126.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -116.50
Input: 100.00 Setpoint: 100.00 Output: -126.50
Input: 100.00 Setpoint: 100.00 Output: -126.50
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 100.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 100.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 100.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00
Input: 100.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -128.00
Input: 101.00 Setpoint: 100.00 Output: -128.00
Input: 100.00 Setpoint: 100.00 Output: -118.00

Maybe the parameters aren’t right, but I wouldn’t want this controlling my car.

Nick, your setup sounds very strange to me. to work with PID you need some kind of closed loop and it seems you don't have it. this open loop configuration can explain your data because you have I coefficient not to 0 so even if your wipe is stable as PID is integrating error it will result in variable output. regarding output range it depends only on how you physically control your system, for example if you want to use internal PWM it will use only values from 0 to 255 and every value outside this range will be trimmed.

regarding change I made this is the code:

PID::PID(double* Input, double* Output, double* Setpoint,
        double Kp, double Ki, double Kd, int ControllerDirection)
{
    PID::SetOutputLimits(0, 255);               //default output limit corresponds to 
                                                //the arduino pwm limits

    SampleTime = 250;                         //default Controller Sample Time is 0.1 seconds

    PID::SetControllerDirection(ControllerDirection);
    PID::SetTunings(Kp, Ki, Kd);

    lastTime = millis()-SampleTime;               
    inAuto = true;  //originally set to false
    myOutput = Output;
    myInput = Input;
    mySetpoint = Setpoint;

}

I only change init value of a variable and I'm sure it can be done

s_michele: Nick, your setup sounds very strange to me.

What do you mean "my setup"? I just used the example code that came with the library. It said to have analog input on pin A0, which I did with a pot. Now I suppose the output doesn't physically connect back to the input, but I am trying to simulate what would happen, for example, if the input was reading the speed of my car (or robot) and the output was the accelerator.

Now if the set point is 100, and it reads back 100, wouldn't you expect the correction to be zero? Changing the initialization of the PID back to the original in the example:

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

I still get something like this:

Input: 101.00 Setpoint: 100.00 Output: 159.00
Input: 101.00 Setpoint: 100.00 Output: 178.50
Input: 100.00 Setpoint: 100.00 Output: 190.50
Input: 101.00 Setpoint: 100.00 Output: 168.00
Input: 101.00 Setpoint: 100.00 Output: 177.50
Input: 101.00 Setpoint: 100.00 Output: 177.00
Input: 100.00 Setpoint: 100.00 Output: 189.00
Input: 101.00 Setpoint: 100.00 Output: 166.50
Input: 100.00 Setpoint: 100.00 Output: 188.50
Input: 101.00 Setpoint: 100.00 Output: 166.00
Input: 100.00 Setpoint: 100.00 Output: 188.00
Input: 100.00 Setpoint: 100.00 Output: 178.00
Input: 100.00 Setpoint: 100.00 Output: 178.00
Input: 101.00 Setpoint: 100.00 Output: 165.50
Input: 101.00 Setpoint: 100.00 Output: 175.00
Input: 100.00 Setpoint: 100.00 Output: 187.00
Input: 100.00 Setpoint: 100.00 Output: 177.00
Input: 101.00 Setpoint: 100.00 Output: 164.50
Input: 100.00 Setpoint: 100.00 Output: 186.50
Input: 100.00 Setpoint: 100.00 Output: 176.50
Input: 101.00 Setpoint: 100.00 Output: 164.00
Input: 101.00 Setpoint: 100.00 Output: 173.50
Input: 100.00 Setpoint: 100.00 Output: 185.50
Input: 101.00 Setpoint: 100.00 Output: 163.00
Input: 99.00 Setpoint: 100.00 Output: 197.50
Input: 101.00 Setpoint: 100.00 Output: 153.00
Input: 101.00 Setpoint: 100.00 Output: 172.50
Input: 99.00 Setpoint: 100.00 Output: 197.00
Input: 100.00 Setpoint: 100.00 Output: 165.00
Input: 100.00 Setpoint: 100.00 Output: 175.00
Input: 100.00 Setpoint: 100.00 Output: 175.00
Input: 101.00 Setpoint: 100.00 Output: 162.50
Input: 100.00 Setpoint: 100.00 Output: 184.50
Input: 99.00 Setpoint: 100.00 Output: 187.00
Input: 100.00 Setpoint: 100.00 Output: 165.00

I would have thought that at least for all the lines which read input 100, setpoint 100, the output should be zero. That is, the current position is correct (although what is the current position?).

I suppose I see what you mean ... if you don't "close the loop" the algorithm can't work out what "accelerator pressure" is needed to reach the set speed, and is thrashing around trying to find it.


Anyway, back to your earlier posts:

I didn't make any other change to library but I tried to use some other function of PID object and it always stop working.

I don't know what you mean, then, by "it always stop working". Stops working in what way?

I also try to use serial communication to inspect what's going on but if I use Serial object board stop working and nothing will be sent to serial monitor.

And I demonstrated above that you can indeed use Serial debugging.

PID::PID(double* Input, double* Output, double* Setpoint,
        double Kp, double Ki, double Kd, int ControllerDirection)
{
    PID::SetOutputLimits(0, 255);               //default output limit corresponds to 
                                                //the arduino pwm limits

    SampleTime = 250; //default Controller Sample Time is 0.1 seconds

    PID::SetControllerDirection(ControllerDirection);     PID::SetTunings(Kp, Ki, Kd);

You, or whoever wrote the code, don't need to use PID:: in the middle of the constructor like that. It's confusing. Inside a method references to things like SetControllerDirection refer to the PID class anyway, you don't need to qualify them. In other words, do this:

PID::PID(double* Input, double* Output, double* Setpoint,
        double Kp, double Ki, double Kd, int ControllerDirection)
{
    SetOutputLimits(0, 255);              //default output limit corresponds to 
                                    //the arduino pwm limits

    SampleTime = 250;                         //default Controller Sample Time is 0.1 seconds

    SetControllerDirection(ControllerDirection);
    SetTunings(Kp, Ki, Kd);

[quote author=Nick Gammon link=topic=80707.msg617669#msg617669 date=1323287996]

It said to have analog input on pin A0, which I did with a pot. Now I suppose the output doesn't physically connect back to the input, but I am trying to simulate what would happen, for example, if the input was reading the speed of my car (or robot) and the output was the accelerator.

[/quote]

A PID controller is a dynamic system with 'state' and 'inertia'. If you set it up with the input and output isolated (so that it's control output isn't actually driving the input) then I'd expect it to diverge as it tried harder and harder to affect the input. If you set the initial conditions up exactly then it may be possible to get it to remain steady with the input exactly matching the target value, but it'd be unstable in the sense that any tiny deviation in the input would cause the PID algorithm to try harder and harder to correct it, until it hit the stops.