Pages: 1 2 [3]   Go Down
Author Topic: Processing Front-End for the PID Library  (Read 16009 times)
0 Members and 1 Guest are viewing this topic.
Cumming, GA
Offline Offline
Edison Member
*
Karma: 20
Posts: 1661
Ultimate DIY: Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Please consider keeping PID Library an active project.  I personally love it.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

in all honesty I threw that in there to do what you are doing, but it's been a while since I've used it.  since then there's been a new version of processing, a new windows OS, and a few tweaks to the code.

the not-closing-cleanly thing is something I just plain missed.
Brett
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice.good working in graphics  
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 10
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey Everyone,

I'm desperately trying to get this front-end to work, but I keep getting the following error when I try to run it in the Processing program:

Note that release 1.0, libraries must be installed in a folder named 'libraries' inside the 'sketchbook' folder.

My "sketchbook" is defined as being in "My Documents/Processing" per the Preferences in Processing.  I created a "libraries" folder there and placed the "controlP5" folder in it.  I've also made "libraries" folders all over the place trying to get this to work.  Any idea what I could be doing wrong?

Thanks,
Patrick
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 200
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Brett,

thanks for developing this Processing interface.  I hope to trial some PID ideas soon & I'm sure I'll use your interface.

+1
Logged

Cumming, GA
Offline Offline
Edison Member
*
Karma: 20
Posts: 1661
Ultimate DIY: Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It really helps!
Logged

Argentina
Offline Offline
Full Member
***
Karma: 0
Posts: 188
Sé feliz
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, we started looking for the PID library for our robots. Did not adopted it yet, but we worked a little bit on it. We used the v06, not the FixedPoint version, which we saw later, smiley-sad.

I don't know if this may be useful, but here is the code with the small changes. Basically, added the "const" when we think it's needed, converted the getters to inlines, and with a default param in the constructor, eliminated the second constructor and the ConstructorCommon().  The only change in the interface is that the Bias is now the last param in the constructor, due to the C++ requirement that the default arguments must be the last ones).

So we compiled the three examples, and them are a bit reduced now, and the inline members must be a little faster:

- PIDSample:       5790 bytes ->  5708 bytes
- PIDSample2:       5730 bytes ->  5648 bytes
- PIDSample3:       5948 bytes -> 5826 bytes

I know it's not a lot of less bytes, but it's not only smaller, but also a little more robust (due to the const).

Here is the .h, and the cpp will be in the next post, to make this shorter:
Code:
class PID
{
  public:

  #define AUTO      1
  #define MANUAL      0
  #define LIBRARY_VERSION      0.6

  //commonly used functions **************************************************************************
    PID(double*, double*, double*,        // * constructor.  links the PID to the Input, Output, and
        const double, const double, const double,
        //This is truly NULL in C++ (see http://www2.research.att.com/~bs/bs_faq2.html#null):
        double *FFBias = 0);          //   Setpoint.  Initial tuning parameters are also set here

    void SetMode(const int Mode);               // * sets PID to either Manual (0) or Auto (non-0)

    void Compute();                       // * performs the PID calculation.  it should be
                                          //   called every time loop() cycles. ON/OFF and
                                          //   calculation frequency can be set using SetMode
                                          //   SetSampleTime respectively

    void SetInputLimits(const double, const double);  //Tells the PID what 0-100% are for the Input

    void SetOutputLimits(const double, const double); //Tells the PID what 0-100% are for the Output


  //available but not commonly used functions ********************************************************
    void SetTunings(const double, const double,       // * While most users will set the tunings once in the
                    const double);              //   constructor, this function gives the user the option
                                          //   of changing tunings during runtime for Adaptive control

    void SetSampleTime(const int);           // * sets the frequency, in Milliseconds, with which
                                          //   the PID calculation is performed.  default is 1000

    void Reset();                         // * reinitializes controller internals.  automatically
                                          //   called on a manual to auto transition

    /*****************************************************************************
     * STATUS SECTION
     * These functions allow the outside world to query the status of the PID
     *****************************************************************************/

    bool JustCalculated()
    {
        return justCalced;
    }
    int GetMode() const
    {
        if(inAuto)
            return 1;
        else
            return 0;
    }

    inline double GetINMin() const
    {
        return inMin;
    }
    inline double GetINMax() const
    {
        return inMin + inSpan;
    }
    inline double GetOUTMin() const
    {
        return outMin;
    }
    inline double GetOUTMax() const
    {
        return outMin+outSpan;
    }
    inline int GetSampleTime() const
    {
        return tSample;
    }
    inline double GetP_Param() const
    {
        return P_Param;
    }
    inline double GetI_Param() const
    {
        return I_Param;
    }
    inline double GetD_Param() const
    {
        return D_Param;
    }
  private:

   //scaled, tweaked parameters we'll actually be using
    double kc;                    // * (P)roportional Tuning Parameter
    double taur;                  // * (I)ntegral Tuning Parameter
    double taud;                  // * (D)erivative Tuning Parameter

   //nice, pretty parameters we'll give back to the user if they ask what the tunings are
    double P_Param;
    double I_Param;
    double D_Param;

    double *myInput;              // * Pointers to the Input, Output, and Setpoint variables
    double *myOutput;             //   This creates a hard link between the variables and the
    double *mySetpoint;           //   PID, freeing the user from having to constantly tell us
                                  //   what these values are.  with pointers we'll just know.

    double *myBias;               // * Pointer to the External FeedForward bias, only used
                                  //   if the advanced constructor is used
    unsigned long nextCompTime;    // * Helps us figure out when the PID Calculation needs to
                                  //   be performed next
                                  //   to determine when to compute next
    unsigned long tSample;       // * the frequency, in milliseconds, with which we want the
                                  //   the PID calculation to occur.
    bool inAuto;                  // * Flag letting us know if we are in Automatic or not

    double lastOutput;            // * remembering the last output is used to prevent
                                  //   reset windup.
    double lastInput;             // * we need to remember the last Input Value so we can compute
                                  //   the derivative required for the D term
    double accError;              // * the (I)ntegral term is based on the sum of error over
                                  //   time.  this variable keeps track of that
    double bias;                  // * the base output from which the PID operates


    double inMin, inSpan;         // * input and output limits, and spans.  used convert
    double outMin, outSpan;       //   real world numbers into percent span, with which
                                  //   the PID algorithm is more comfortable.

    bool justCalced;              // * flag gets set for one cycle after the pid calculates
};

Regards,
Julián
http://robotgroup.com.ar
Logged

Argentina
Offline Offline
Full Member
***
Karma: 0
Posts: 188
Sé feliz
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

and here is the .cpp (we deleted he function description headers because we could not paste the complete cpp here otherwise -is there an text size limite?-):

Code:
PID::PID(double *Input, double *Output, double *Setpoint,
         const double Kc, const double TauI, const double TauD,
         double *FFBias)
{
    SetInputLimits(0, 1023);            //default the limits to the
    SetOutputLimits(0, 255);            //full ranges of the I/O

    tSample = 1000;                  //default Controller Sample Time is 1 second

    SetTunings(Kc, TauI, TauD);
    nextCompTime = millis();

    inAuto = false;
    myOutput = Output;
    myInput = Input;
    mySetpoint = Setpoint;
    myBias = FFBias;

    Reset();
}

void PID::SetInputLimits(const double INMin, const double INMax)
{
      //after verifying that mins are smaller than maxes, set the values
      if(INMin >= INMax) return;

      //rescale the working variables to reflect the changes
      lastInput = (lastInput) * (INMax - INMin) / (inSpan);
      accError *= (INMax - INMin) / (inSpan);

      //make sure the working variables are
      //within the new limits
      if (lastInput > 1) lastInput = 1;
      else if (lastInput < 0) lastInput = 0;


    inMin = INMin;
      inSpan = INMax - INMin;
}

void PID::SetOutputLimits(const double OUTMin, const double OUTMax)
{
      //after verifying that mins are smaller than maxes, set the values
      if(OUTMin >= OUTMax) return;

      //rescale the working variables to reflect the changes
      lastOutput = (lastOutput) * (OUTMax - OUTMin) / (outSpan);

      //make sure the working variables are
      //within the new limits
      if (lastOutput > 1) lastOutput = 1;
      else if (lastOutput < 0) lastOutput = 0;

      outMin = OUTMin;
      outSpan = OUTMax - OUTMin;
}

void PID::SetTunings(const double Kc, const double TauI, const double TauD)
{
      //verify that the tunings make sense
      if (Kc == 0.0 || TauI < 0.0 || TauD < 0.0) return;

      //we're going to do some funky things to the input numbers so all
      //our math works out, but we want to store the numbers intact
      //so we can return them to the user when asked.
      P_Param = Kc;
      I_Param = TauI;
      D_Param = TauD;

      //convert Reset Time into Reset Rate, and compensate for Calculation frequency
      double tSampleInSec = ((double)tSample / 1000.0);
      double tempTauR;
      if (TauI == 0.0)
            tempTauR = 0.0;
      else
            tempTauR = (1.0 / TauI) * tSampleInSec;

      if (inAuto)
      {      //if we're in auto, and we just change the tunings, the integral term
            //will become very, very, confused (trust me.) to achieve "bumpless
            // transfer" we need to rescale the accumulated error.
            if(tempTauR != 0.0) //(avoid divide by 0)
                  accError *= (kc * taur)/(Kc * tempTauR);
            else
                  accError = 0.0;
      }

      kc = Kc;
      taur = tempTauR;
      taud = TauD / tSampleInSec;
}

void PID::Reset()
{
    //Is myBias a NULL pointer?
      if(myBias != 0) //you can ask only if (myBias), but that's more error prone and less clear.
        bias = (*myBias - outMin) / outSpan;
      else
        bias = (*myOutput - outMin) / outSpan;

    lastOutput = bias;
      lastInput = (*myInput - inMin) / inSpan;

      // - clear any error in the integral
      accError = 0;

}

void PID::SetMode(const int Mode)
{
      if (Mode!=0 && !inAuto)
      {      //we were in manual, and we just got set to auto.
            //reset the controller internals
            Reset();
      }
      inAuto = (Mode!=0);
}

void PID::SetSampleTime(const int NewSampleTime)
{
      if (NewSampleTime > 0)
      {
            //convert the time-based tunings to reflect this change
            taur *= ((double)NewSampleTime)/((double) tSample);
            accError *= ((double) tSample)/((double)NewSampleTime);
            taud *= ((double)NewSampleTime)/((double) tSample);
            tSample = (unsigned long)NewSampleTime;
      }
}

void PID::Compute()
{
      justCalced=false;
      if (!inAuto) return; //if we're in manual just leave;

      unsigned long now = millis();

      //millis() wraps around to 0 at some point.  depending on the version of the
      //Arduino Program you are using, it could be in 9 hours or 50 days.
      //this is not currently addressed by this algorithm.


      //...Perform PID Computations if it's time...
      if (now>=nextCompTime)
      {
            //pull in the input and setpoint, and scale them into percent span
            double scaledInput = (*myInput - inMin) / inSpan;
            if (scaledInput>1.0) scaledInput = 1.0;
            else if (scaledInput<0.0) scaledInput = 0.0;

            double scaledSP = (*mySetpoint - inMin) / inSpan;
            if (scaledSP>1.0) scaledSP = 1;
            else if (scaledSP<0.0) scaledSP = 0;

            //compute the error
            double err = scaledSP - scaledInput;

            // check and see if the output is pegged at a limit and only
            // integrate if it is not. (this is to prevent reset-windup)
            if (!(lastOutput >= 1 && err>0) && !(lastOutput <= 0 && err<0))
                  accError = accError + err;

            // compute the current slope of the input signal
            double dMeas = (scaledInput - lastInput);  // we'll assume that dTime (the denominator) is 1 second.
                                             // if it isn't, the taud term will have been adjusted
                                             // in "SetTunings" to compensate

            //if we're using an external bias (i.e. the user used the
            //overloaded constructor,) then pull that in now
            if (myBias != 0) //Is myBias a NULL pointer?
                  bias = (*myBias - outMin) / outSpan;

            // perform the PID calculation.
            double output = bias + kc * (err + taur * accError - taud * dMeas);

            //make sure the computed output is within output constraints
            if (output < 0.0) output = 0.0;
            else if (output > 1.0) output = 1.0;

            lastOutput = output;            // remember this output for the windup
                                    // check next time
            lastInput = scaledInput;      // remember the Input for the derivative
                                    // calculation next time

            //scale the output from percent span back out to a real world number
                *myOutput = ((output * outSpan) + outMin);

            nextCompTime += tSample;                        // determine the next time the computation
            if(nextCompTime < now) nextCompTime = now + tSample;      // should be performed

            justCalced=true;  //set the flag that will tell the outside world that the output was just computed
      }
}

This should use a little less RAM too (but very very little)

Regards,
Julián
http://robotgroup.com.ar
Logged

Argentina
Offline Offline
Full Member
***
Karma: 0
Posts: 188
Sé feliz
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry, I should post the previous two posts to the http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226431507 , is there any way to move them?
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Binary solo!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Great work!
Logged

Pages: 1 2 [3]   Go Up
Jump to: