Arduino "millis" voor P.I.D. controler die 24/7/365 aan staat

blackdog

Golden Member

Hi,

Ik ben met wat PID software bezig voor meerdere oventjes, voor mijn temperatuur sensor kalibrator niet zo van belang, ondanks dat deze ook een Arduino PID oven krijgt.
Deze zal in verhouding nooit lang genoeg aan staan voor een overflow van de millis, daar dat oventje nooit meer dan een paar uur aan zal staan.

Maar voor twee andere oventjes gebruik ik de onderstaande code die als basis wordt gebruikt voor het aansturen van de oventjes.
Dit is de P.I.D. software die je in de Arduino IDE kan vinden.
Ik heb wat extra info bovenaan de code geplaatst betreffende de info van de maker.

In de eerste regel van de setup hieronder staat dit:

c code:


void setup()
{
  windowStartTime = millis();

Houd dit nu in dat het mis gaat met de code als deze de limit berijkt van 50 dagen voor millis?
Zo ja, wat zou dan een oplossing zijn voor een meetinstrument dat 24/7/365 aan moet kunnen staan?

c code:


/********************************************************
 * PID RelayOutput Example
 * Same as basic example, except that this time, the output
 * is going to a digital pin which (we presume) is controlling
 * a relay.  the pid is designed to Output an analog value,
 * but the relay can only be On/Off.
 *
 *   to connect them together we use "time proportioning
 * control"  it's essentially a really slow version of PWM.
 * first we decide on a window size (5000mS say.) we then
 * set the pid to adjust its output between 0 and that window
 * size.  lastly, we add some logic that translates the PID
 * output into "Relay On Time" with the remainder of the
 * window being "Relay Off Time"

***************************************************************
* Arduino PID Library - Version 1.2.0
* by Brett Beauregard <br3ttb@gmail.com> brettbeauregard.com
*
* This Library is licensed under the MIT License
***************************************************************

 - For an ultra-detailed explanation of why the code is the way it is, please visit: 
   http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

 - For function documentation see:  http://playground.arduino.cc/Code/PIDLibrary

 ********************************************************/

#include <PID_v1.h>

#define PIN_INPUT 0
#define RELAY_PIN 6

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

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

int WindowSize = 5000;
unsigned long windowStartTime;

void setup()
{
  windowStartTime = millis();

  //initialize the variables we're linked to
  Setpoint = 100;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

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

void loop()
{
  Input = analogRead(PIN_INPUT);
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if (millis() - windowStartTime > WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, HIGH);
  else digitalWrite(RELAY_PIN, LOW);

}

Hartelijk dank vast,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

code:


  if (millis() - windowStartTime > WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }

Dit is in principe de juiste implementatie. Die geeft altijd het juiste resultaat, ook in geval van overflow. Kun je testen met 8-bit logica (Start en millis() allebei unsigned char:)

Stel :
Start = 254, en millis() = 254 : millis() - Start = 0
Tick
Start = 254, en millis() = 255 : millis() - Start = 1
Tick (overflow)
Start = 254, en millis() = 0 : millis() - Start = 2
Tick
Start = 254, en millis() = 1 : millis() - Start = 3
Check,
Start += 3 -> 254 + 3 = 1

Bij een unsigned long gebeurt hetzelfde me grotere getallen

Dit gaat alleen fout als WindowSize groter wordt dan 25 dagen of zo maar dat lijkt me niet van toepassing.

PS.
Als alternatief zou je denken dat het ook zo kan, maar dat gaat dus wel fout na 49.5 dagen (= 232 milli-seconden):

code:


  if (millis() >  windowStartTime + WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }

Probleem is dat windowStartTime + WindowSize al een overflow kan geven voordat millis() overflowt. En dan krijg je valse trues.

[Bericht gewijzigd door deKees op woensdag 1 juli 2020 20:16:00 (54%)

now() gebruiken van de Time library.

Het verhaal waar ik mij aan houd is dit;
https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the…

Te vinden met de termen millis() rollover.

@K7Jz

Dat is wel een dure oplossing voor een probleem dat niet bestaat! :)

blackdog

Golden Member

Hi Heren,

Dank voor de antwoorden!
Nu ben ik bezig uit te zoeken of het veel verschil gaat maken of ik de code voor de relais uitgang ga gebruiken, of de analoge uitgang.

Beide zijn PWM als ik het goed begerpen heb en als ik de analoge uitgang ga gebruiken zal ik met een opamp de twee transistoren ials stroombron moeten schakelen.
Waarbij ik mij dan weer afvraag of de 8-Bits van de PWM niet wat weinig is...

Ik denk dat ik het eens moet proberen met de analoge uitgang om te zien of dat mooi genoeg regeld. :-)
Er treed denk ik ook eeen "middeling" op door de thermische massa van het oventje, zodat je hierdoor ook een soort oversampling krijgt?

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.
EricP

mét CE

Voorop gesteld dat ik niks van Arduino weet (wel van AVRs...), zou die 8 bit best wel eens een library limitation kunnen zijn. Er is ook vast wel een 16-bit counter die het kan - 16 bit PWM.
Aan de andere kant... met 8 bit kun je al op 0.4% regelen. Je zou zelfs de PWM kunnen PWMen en gebruik maken van de thermische eigenschappen van het alu. Al weet ik niet of dat Arduino taaltje zich daarvoor leent door alle overhead die erin zit.
Het 'foefje' zou zijn dat je bijvoorbeeld elke 100mS een interrupt voorbij laat komen. Daarin kun je de PWM waarde met 1 omhoog of 1 naar beneden bijstellen indien gewenst. Daarmee heb je feitelijk je resolutie ver-tien-voudigd - vooropgesteld dat je tijdconstante van het te verwarmen object zo groot is dat die het mooi uit middelt. Als dat niet zo is, dan kun je nog naar elke 10mS interrupten gaan kijken of je daar wat mee kunt.
Methode is wat lomp, maar voor dit doel zou dat denk ik niet uit mogen maken.

benleentje

Golden Member

Mensen zijn soms net als een gelijkrichter, ze willen graag hun gelijk hebben.

@EricP Volgens mij wil Blackdog een Arduino PWM (inderdaad een 8 bit PWM met timer) vergelijke met softwarematig een relay aan/uit schakelen.

Dan heb je geen foefjes meer nodig om de PWM nauwkeuriger te maken, gewoon in de main-loop de PWM waarde aanpassen op basis van je regeling is al nauwkeuriger dan je met een relay ooit zal halen.

@Blackdog: Wellicht ten overvloede, maar je weet dat arduino niets van laagdoorlaatfiltering op de "analoge" uitgang heeft? Het is gewoon keihard digitale PWM wat eruit komt, volgens mij op 62.5kHz.

blackdog

Golden Member

Hi!

Dank weer voor de opmerkingen.

benleentje
Die link heb ik een jaar terug al eens een keer gezien, ik weet voor nu niet of de 16 bit PWM goed is toe te passen in deze PID software.
Ik denk dat ik niet aan de PWM ga zitten sleutelen, gaat mij te veel tijd kosten door gebrek aan kennis van coderen.

blurp
Als iemand over PWM begint, dat kan ik ook zelf zijn, :+ dan is dit eerste wat ik voor mijn ogen zie verschijnen: Random Noise Source...
Ik heb ergens im mijn schema archief een 2e of 3e order PWM filterje voor een Arduino uitgang.

Ik ga even wat rekenen aan het geheel, zodat ik met een dual opamp een filter en een stroombron schakeling kan maken met de twee power transistoren in mijn oventje.

Wat extra info
Ook bij dit oventje wil ik de energie die de oven krijgt toegevoerd, beperken als de oven bijna op temperatuur is.
De maximale stroom wordt 300 a 400mA bij 15V, laten we het voorlopig op 400mA houden en dat is bij 15V dan rond de 6-Watt aan vermogen die de transistoren verwerken.
Dit energie niveau is nodig om de opwarmtijd kort te houden en daarna kan de spanning op de power transistoren als b.v. 43°C is bereikt, naar zeg 6V geschakeld worden.
Dan wordt de maximale dissipatie voor die zelfde stroom van 400mA max 2-Watt, dit levert een mooier regelbereik op, ik heb dit getest met een andere PID controler.

Bij normale LAB temperaturen is de benodigde dissipatie rond de 0,8-Watt voor ongeveer 22°C temperatuur verhoging, dat is rond de 37mW/°C
Aan de hand hiervan kan ik dan bepalen vanaf welke LAB temperatuur ik wil dat de oven op temperatuur blijft, natuurlijk met wat marge.

Dus zo sPlan opstarten een een schematje fabrieken voor een stroombron schakeling met PWM filter.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Even voor de goede orde: De arduino "taal" heeft een "analogOut" maar dat is gewoon PWM op een digitale pin. Er is geen hardware voor een analoge output. Verder vermoed ik dat ze in het kader van details verbergen voor de gebruiker dat ondersteunen op pins die geen hardware PWM hebben.

Kortom, die analogout is niet PWM-loos zoals je mogelijk dacht.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
blackdog

Golden Member

Hi rew,

Ik weet niet wat jij denkt wat ik wel of niet begrijp... ;)

Maar vanaf het begin dat in met Arduino begon te prutsen, weet ik al dat er geen "analog out" op de Arduino's zit(groot gemis) en dan heb ik het over de Uno en de Nano.

Ik weet hoe men bij de Arduino probeert een analoge te simuleren, dat is dus door een PWM signaal welke je voor een mooi DC signaal goed zal moeten filteren.
In mijn hoofd had ik de 490Hz zitten voor de PWM frequentie, maar dat ik net het nog even nakijk, blijkt pin 5&6 van mijn gebruikte Arduino's een frequentie te hebben van 980Hz.

De Teensy LC die ik ook wel eens gebruik, heeft een echte DAC van 12Bit en dat kan heel handig zijn.
Deze controler verslaat alle kleinere Arduino's makkelijk, maar is natuurlijk niet tegen de Nano prijs van rond de 2,5€ opgewassen.

Misschien moet ik toch maar eens kijken of ik de Teensy LC ga gebruiken, dan heb ik voor de ADC geen extra controler nodig, hij is 3.3V handig voor mijn display en ik heb een 12Bit DAC voor het aansturen van mijn transistoren...

Nog meer om over na te denken!

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Op 2 juli 2020 10:04:37 schreef blackdog:
Nu ben ik bezig uit te zoeken of het veel verschil gaat maken of ik de code voor de relais uitgang ga gebruiken, of de analoge uitgang.

Het mooie van een goed afgeregeld PID systeem is juist dat het rekening houdt met de traagheid van je oven. Het reageert op verandering en niet alleen op het bereiken van het omslagpunt.
Dan zou je rustig een 8-bits aansturing kunnen maken en de temperatuur uitlezen met een 32-bits sensor. De output van de PID regelaar zal in de buurt van de ingestelde temperatuur heen en weer gaan springen tussen 2 8-bits waarden in de juiste tijdsverhouding. De hoeveelheid massa in de oven is dan je filter.

Ik zeg bewust "goed afgeregeld PID systeem", ik heb altijd moeite om de juiste PID parameters in te stellen bij een traag reagerend systeem.

Bedankt voor de link trouwens.

reading can seriously damage your ignorance