Git Product home page Git Product logo

arduino-pid-autotune-library's Introduction

/**********************************************************************************************
 * Arduino PID AutoTune Library - Version 0.0.1
 * by Brett Beauregard <[email protected]> brettbeauregard.com
 *
 * This Library is ported from the AutotunerPID Toolkit by William Spinelli
 * (http://www.mathworks.com/matlabcentral/fileexchange/4652) 
 * Copyright (c) 2004
 *
 * This Library is licensed under the BSD License:
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are 
 * met:
 * 
 *     * Redistributions of source code must retain the above copyright 
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright 
 *       notice, this list of conditions and the following disclaimer in 
 *       the documentation and/or other materials provided with the distribution
 *       
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 **********************************************************************************************/
 
 Note:  I'd really hoped to have this more polished before release, but with the
		osPID coming out I felt that this needed to be out there NOW.  if you 
		encounter any issues please contact me, or post to the diy-pid-control
		google group.
 

arduino-pid-autotune-library's People

Contributors

br3ttb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arduino-pid-autotune-library's Issues

Reverse type of controller

This two lines of code are made for DIRECT type of pid controller. What if user wants reverse type? Output will never step in other direction. We have to swap +'s and -'s.

    //oscillate the output base on the input's relation to the setpoint

    if(refVal>setpoint+noiseBand) *output = outputStart-oStep;
    else if (refVal<setpoint-noiseBand) *output = outputStart+oStep;

To this:

    //oscillate the output base on the input's relation to the setpoint

    if(refVal>setpoint+noiseBand) *output = outputStart+oStep;
    else if (refVal<setpoint-noiseBand) *output = outputStart-oStep;

getting wrong gains for dc motor pid

Hi,
I'm using the autotune PID library for finding the gains of the dc motors of my differential drive. I am using a teensy 3.2 microcontroller, a sabertooth 2x12 motor driver, HC-05 Bluetooth module, two dc motors, and two external rotary/incremental encoders having 360ppr. I was unable to find any example to use the autotune library except for the library example so I used it as a reference and made the changes to suit my code. Here it is

#include <PID_v1.h>
#include <PID_AutoTune_v0.h>
#include <SoftwareSerial.h>
#include <SabertoothSimplified.h> //library for sabertooth motordriver

SoftwareSerial SWSerial1(0,2);
SabertoothSimplified ST1(SWSerial1);

int pinA1 = 11;
int pinB1 = 12;
int pinA2 = 7;
int pinB2 = 8;
int count1 = 0, count2 = 0; // encoder counts
int prevCount1=0, prevCount2 = 0; // last count
unsigned long prevTime1=0,prevTime2=0,prevTime3=0,prevTime4=0,prevTime5=0;
double reqRPM1 = 150,reqRPM2 = 150,reqTheta = 0 ; // required RPM
double actRPM1 =0,actRPM2= 0,motorInput2=0; // actual RPM
byte ATuneModeRemember=2;
double kp=0.43793,ki=0.06332,kd=0.75718; // parameters obtained from autotuner
double aTuneStep=45, aTuneNoise=10, aTuneStartValue=55;
unsigned int aTuneLookBack=1;
unsigned long modelTime, serialTime;
double kpmodel=1.5, taup=100, theta[50];
double outputStart=5;
boolean tuning = false; //changed to false after tuning

PID myPID(&actRPM2, &motorInput2, &reqRPM2,kp,ki,kd, DIRECT);
PID_ATune aTune(&actRPM2, &motorInput2);

boolean useSimulation = true;
//set to false to connect to the real world

void Check2() // interrupt function to get encoder readings
{
if(digitalRead(pinB2) == digitalRead(pinA2))
count2--;
else
count2++;
}

void setup()
{
myPID.SetMode(AUTOMATIC);
aTune.SetControlType(1);
ST1.motor(1,0); // running only one motor for now
delay(1000);

// if(tuning) //commented this code otherwise the autotuner was not starting
// {
// tuning=false;
// changeAutoTune(); //this functions sets output to atuneStartValue and was not letting
//autotuner to start, had to comment this for it to run
// tuning=true;
// }

serialTime = 0;
if(useSimulation)
{
for(byte i=0;i<50;i++)
{
theta[i]=outputStart;
}
modelTime = 0;
}
//encoder pins
pinMode(pinA2,INPUT);
pinMode(pinB2,INPUT);
//interrupt
attachInterrupt(digitalPinToInterrupt(pinA2),Check2,RISING);
//keeping track of time from start
prevTime1 = micros();
prevTime4 = micros();
prevTime5 = micros();

Serial.begin(9600);
SWSerial1.begin(9600);//serial for sabertooth motor driver
}

void loop()
{
unsigned long now = micros();
ST1.motor(1,0); // running only one motor

if((micros()-prevTime1)>10000) // run every 10 ms
{
if(tuning)
{
byte val = (aTune.Runtime());
if (val!=0)
{
tuning = false;
}
if(!tuning)
{ //we're done, set the tuning parameters
kp = aTune.GetKp();
ki = aTune.GetKi();
kd = aTune.GetKd();
myPID.SetTunings(kp,ki,kd);
AutoTuneHelper(false);
}
}
else {
myPID.Compute();
}

if(useSimulation)
{
theta[30]=motorInput2;
if(now>=modelTime)
{
modelTime +=100;
actRPM2 = getRPM2(); // instead of DoModel() in order to update input value I placed my
// code to update input in this portion
ST1.motor(2 ,motorInput2); // sending values to motor
}
}

if(micros()>serialTime)
{
SerialReceive();
SerialSend();
serialTime+=500;
}
prevTime1 = micros();
}
}

int getRPM2() // calculating RPM
{
long pps2 = long(count2 - prevCount2);
float ppr2 = 360;
prevTime4 = micros() - prevTime5;
double tt = prevTime4 / 6000.0 ;
double actRPM2 = ((pps2*10000.0)/(tt*ppr2));
prevTime5 = micros();
// SWSerial2.print(" rpm2= " );
// SWSerial2.println(actRPM2);
prevCount2 = count2;
return actRPM2;
}

void changeAutoTune()
{
if(!tuning)
{
//Set the output to the desired starting frequency.
//removed one line of code that sets the output to aTuneStartValue
aTune.SetNoiseBand(aTuneNoise);
aTune.SetOutputStep(aTuneStep);
aTune.SetLookbackSec((int)aTuneLookBack);
AutoTuneHelper(true);
tuning = true;
}
else
{ //cancel autotune
aTune.Cancel();
tuning = false;
AutoTuneHelper(false);
Serial.print("Adad222");
}
}

void AutoTuneHelper(boolean start)
{
if(start)
ATuneModeRemember = myPID.GetMode();
else
myPID.SetMode(ATuneModeRemember);
}

void SerialSend()
{
Serial.print("setpoint: ");Serial.print(reqRPM2); Serial.print(" ");
Serial.print("input: ");Serial.print(actRPM2); Serial.print(" ");
Serial.print("output: ");Serial.print(motorInput2); Serial.print(" ");
if(tuning){
Serial.println("tuning mode");
} else {
Serial.print("kp: ");Serial.print(myPID.GetKp(),5);Serial.print(" ");
Serial.print("ki: ");Serial.print(myPID.GetKi(),5);Serial.print(" ");
Serial.print("kd: ");Serial.print(myPID.GetKd(),5);Serial.println();
}
}

void SerialReceive()
{
if(Serial.available())
{
char b = Serial.read();
Serial.flush();
if((b=='1' && !tuning) || (b!='1' && tuning))changeAutoTune();
}
}

Even after I commented the changeAutoTune and AutoTuneHelper the autotuner was taking forever to end. So I looked at the library .cpp file and tweaked with LookBackSec, Noise, and some other values, getting no success. Finally, when I reduced the value of nLookBack in RunTime function to a value lower than 9 (worked good till 5 for me) the tuner came to an end after oscillating for a while. But the problem is the values that I am getting are too high that it makes the pid unstable.

Kp both for PonE and PonM?

I have a doubt that others may have too. The PID library got an update for choosing Kp applied on actual error (Proportional on Error, PonE) or Kp applied on deltaInput (Proportional on Measurement).
Does the Autotune PID library calculated Kp is useful for both or only PonE? Thanks!

How can a library work?

We need to strive for setpoint. And in the code at the start of tuning, this is what input was like that - it will be instead of setpoint.
And all the time it will float near input.

int PID_ATune::Runtime()
{
justevaled=false;
if(peakCount>9 && running)
{
running = false;
FinishUp();
return 1;
}
unsigned long now = millis();

if((now-lastTime)<sampleTime) return false;
lastTime = now;
double refVal = *input; --------------------------------------------------------------?
justevaled=true;
if(!running)    ------------------------------------------------ first start
{ //initialize working variables the first time around
	peakType = 0;
	peakCount=0;
	justchanged=false;
	absMax=refVal;
	absMin=refVal;
	setpoint = refVal; ----------------------------------first start setpoint = input ?
	running = true;
	outputStart = *output;
	*output = outputStart+oStep;
}
else
{
	if(refVal>absMax)absMax=refVal;
	if(refVal<absMin)absMin=refVal;
}

if(refVal>setpoint+noiseBand) *output = outputStart-oStep; -------------------? input and input ?
else if (refVal<setpoint-noiseBand) *output = outputStart+oStep; ----------- ? input and input ?

"corrected" output float near input? or maybe near setpoint ???????????

Ziegler Nichols 2nd Method - Isn't it for Series Algorithm? (PID library uses ISA form)

Hi Guys,

Isn't Ziegler-Nichols 2nd Method (Frequency Response Method or Oscillation Method or Ku/Pu Method etc) for Series PID Algorithm?
image
From https://www.pidtuning.net/pid-algorithm.php

image

From Autotuning of PID Controllers A Relay Feedback Approach_, 2nd edition, Cheng-Ching Yu (2007), page 30?

Bret's PID library uses ISA (Ideal) PID Algorithm, right?

So, shouldn't we transform Kp, Ki, Kd from Series to Parallel form?

image
from http://www.acsysteme.com/en/serial-or-parallel-pid

Or from ISA slides:
image

from ISA Effective Use of PID Controllers 3-7-2013, https://pt.slideshare.net/sarodp/isa-effective-use-of-pid-controllers-372013
@br3ttb

Thanks!

Minimum value for nLookBack

SetLookbackSec(2) will give nLookBack=8 but with nLookBack<9 Runtime() will always return 0 and never call a peak.

Autotune should be a method for class PID

It seems desirable to me to have the entire PID object passed to the auto tune function rather than the individual variables. Probably not possible since I don't see a way to do this that would not break existing programs.

Swapped constants used for Ki calculation

I think you accidently swapped the 1.2 and 0.48 in the Ki calculation:

double PID_ATune::GetKi()
{
return controlType==1? 1.2*Ku / Pu : 0.48 * Ku / Pu; // Ki = Kc/Ti
}

Should be like this for Ziegler & Nichols (closed loop):

double PID_ATune::GetKi()
{
return controlType==1? 0.48 * Ku / Pu : 1.2 * Ku / Pu; // Ki = Kc/Ti
}

/Thanks

Runtime() boolean rather than int

Runtime() returns 0 or 1 currently. I suppose int might be preferable if there are plans to extend the range of return codes to include other values. If not then it might be tidier to call it boolean.

Install Troubles

Hello!

I'm having a hard time even getting this library to install. It's not showing up in the Library Manager so I came here to install the .zip and that's not working out either. It always just says that:

"Specified folder/zip file does not contain a valid library"

What can I even attempt do with that? I know that my IDE is installing .zip files fine otherwise--I just installed via .zip for the Adafruit Motor Shield V2 Library and it's working just fine.

Tuning plot doesn't seems like Bret's Blog Example

Hi Guys,

This is what what the graph Setpoint (S), Input (I) (both left axis), and Output (O - right axis) looks like.

image

for Lookback =10 Step =30 Noise = 2.0, it gets Ku=152 Pu=2699

kp: | 91,67 |
ki: | 0,68 |
kd: | 3085,77

It doesn't looks like Bret's example on his blog:

image

Obs: time is in seconds (horizontal axis)

But with the obtained parameters (kp, ki, kd) I can get the input to be 31.95 - 32.05 (setpoint 32), so it seems fine.

But I wonder why we don't see the output as HIGH ad LOW pulses, neither the input as clear peaks.

SampleTime of data is 0,96 seconds, +-0,024 seconds.
It's tuned after 1178 seconds; as you can see, the perfomance is fine.

Thanks!

===================

Sorry, my mistake, there was a PID.comput() being run while tuning. Closed issue.

possible lastInputs overrun

Question: Wont the following code run off the end of the lastInputs Array?

nLookBack could potentially be 100, in which case 'i' starts at 99, the end of the array, only for lastInputs[100] to eventually be updated. I would think the array should be declared of size 101 to fix this, yes?

for(int8_t i=nLookBack-1;i>=0;i--)
{
double val = lastInputs[i];
if(isMax) isMax = refVal>val;
if(isMin) isMin = refVal<val;
lastInputs[i+1] = lastInputs[i];
}

Output limits

PID_ATune::Runtime() does not check that outputStart-oStep is greater than or equal to the minimum possible value for *output, nor that outputStart+oStep is less than or equal to the maximum possible value for *output.

Where these boundaries are exceeded it is likely that Ku is overestimated because the actual changes in *output are less than +/- oStep.

use sampleTime from PID

Wouldn't it make sense to have sampleTime in the auto tuner as some multiple (>=1) of the sampleTime used in the PID.

Simulated input equation - Where does it come from?

Hello, from where does the simulated input equation comes from?

input = (kpmodel / taup) (theta[0]-outputStart) + input(1-1/taup) + ((float)random(-10,10))/100;

What kind of dynamics? How was it linearized?

Thanks!!!

"LIBRARY_VERSION" Warning

Library version clash with supporting script PID_v1

In file included from eThrottleV2.ino:3:0:
C:\Program Files (x86)\Arduino\libraries\PID_AutoTune_v0/PID_AutoTune_v0.h:3:0: warning: "LIBRARY_VERSION" redefined [enabled by default]

define LIBRARY_VERSION 0.0.1

^
In file included from eThrottleV2.ino:2:0:
C:\Program Files (x86)\Arduino\libraries\br3ttb-Arduino-PID-Library-d46dded/PID_v1.h:3:0: note: this is the location of the previous definition

define LIBRARY_VERSION 1.1.1

^

peak-to-peak amplitude for relay is 2*oStep

In the formula for the ultimate gain Ku, oStep is used as the measure of amplitude for the relay which is half the peak-to-peak amplitude. The amplitude of the induced oscillation is measured by ( absMax - absMin ) i.e. the peak-to-peak amplitude. This would appear to underestimate Ku by a factor of 2.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.