5.11.13

Stripboard PID Arduino Shield, Part 2: Firmware

Install the code base for the stripboard Arduino PID shield and get started using it as a standalone temperature controller.



DIY PID Controller Firmware



The Arduino firmware is a variant of the original osPID code, written by Brett Beauregard and revamped by Benjamin K. Stuhl. The code has been adapted to reflect the new hardware and extended and updated in all sorts of ways. 


Uploading The Firmware


Download the firmware by cloning the Github repository and load osPID_Firmware.ino into the Arduino IDE. The firmware can then be compiled and uploaded in the usual way.

The new code only just fits in 32 kB so you might need to switch to a shorter bootloader like optiboot to fit it on an Arduino Uno. The various versions of the Arduino IDE may compile the code to different lengths. Just in case this is a problem, there is a version of the code precompiled for the Atmega328P that can be uploaded directly with avrdude.

Please note that the shield was tested on an Arduino Uno R3. Reports using other Arduino boards would very much appreciated. The shield should work just fine on the Arduino Mega but there may be some firmware glitches, so please let us know! The firmware will need to be shortened by several kB to fit on an Arduino Leonardo, which has longer bootloader: see the compilation options below for some suggestions. Feel free to fork the firmware on Github and share your versions with the OSH community.


Main Menu


On start up the PID controller shows a banner with the controller name and version number.

The next thing that you see is a scrollable list of menus, starting with Dashboard, Tuning, Config and the name of the current Profile. The dashboard is displays the set value and measured temperature and is what you usually want in view when the apparatus is running. The configuration menu sets the options that allow flexible use of the controller.



Dashboard Menu


Clicking OK to enter the dashboard menu displays the set value Sv and input reading Pv (for "process value"), just as you would typically see on the panel of a normal PID controller. Scrolling down shows the output duty cycle Out expressed as a percentage, and a setting that toggles between Manual Control and PID Control of the output.



The set value can be edited by pressing OK. The prompt will change from ">" to "→" indicating that the value is being edited. The value can be altered one digit at a time, as indicated by the cursor, by pressing Up and Down. Press OK to edit the next digit or Return to edit the previous digit. To finish editing press OK or Return until the cursor is back to ">".

The set value can be swapped between 4 different temperatures by pressing and holding OK until you see a 2x2 menu of 4 items, Sv1 (the default) through Sv4. These are initially preset to different values but after selection each can be edited as above.

Scrolling down to the input value Pv you will see the prompt "|" which indicates that the value cannot be edited.

The output value O can be manually set between 0 and 100%, provided that the final menu item is set to Manual Control. Manual control can be used, for example, to boil wort when the power percentage sets the vigor of the boil. PID Control is the other option, and is useful when you want to reach and hold a specified temperature (the set value).

The Alarm sets limits for the input temperature. When the bounds are exceeded an loud chirp sounds intermittently and the prompt flashes "!" to alert the user. The alarm menu has four settings: Alarm Enabled / Disabled, low temperature limit Min, upper temperature limit Max, and Auto / Manual Reset. Under Auto Reset, the alarm will automatically turn off when the temperature falls back within the specified temperature limits. If Manual Reset is selected, the alarm must be turned off either manually by navigating to set point in the dashboard menu and pressing OK. (It can also be reset by a command over a serial link: serial communication with the controller is covered in the next post).

Clicking Return sends you back from the dashboard to the main menu.



Tuning Menu


The first three menu options are P, I, and D and set the proportional, integral, and derivative gains, respectively. Tuning a PID controller manually requires some skill and can be time consuming. A relatively easy method to auto tune the settings initially until the performance seems reasonable, and tweak the settings from there.



The next item selects between Direct Action and Reverse Action, and governs the sign of the gain. Reverse action is useful when heating, direct action when cooling.

The final item on the main menu turns on auto tuning (as indicated by a flashing "T" cursor) or cancels the auto tuner if it is already running. By default the auto tuner uses a relay method to calculate PI tunings based on the Ziegler-Nichols rule, but other options are available. The defaults can be changed as compile options in the firmware, or by using the serial interface (see details in next post). For lag-dominated processes, a PID tuning (with non-zero derivative term) is a good choice.



Config Menu


Next, onto the Config menu. (We will deal with Profile settings in the next post.)

Sensor selects between three measurement options: Thermistor, DS18B20+, and Thermocouple. The default thermistor is a 10 KΩ NTC thermistor with 10 KΩ reference resistor. The recommended 1-wire sensor is DS18B20+, which is accurate to 0.5 °C across its range.



The next option sets the calibration value Cal, a temperature offset for the selected sensor. A different value can be applied to each of the three types of sensor. 

The next option sets the output cycle period Cyc. The default of 5 seconds is fine when a resistive heating element is being controlled by an SSR. Electromechanical relays will eventually fail after many operations, so a longer cycle period may be desired if driving a relay of this kind. Certain kinds of load do not tolerate fast switching, such as refrigerator compressors which should be set to a cycle length no shorter than 10 minutes (600 seconds).

The Power On menu switches between 3 kinds of behavior when restarting from power down. Disable resumes in manual mode. Continue carries on running the controller using the set point that was in use before power down. Resume Profile restarts the current profile from the point at which it was previously running.

The final item Reset Memory wipes the EEPROM of all stored information and restores the default settings. This is a useful option after switching between Celsius and Fahrenheit units using the compile options (see below).


Compilation Options


Further configuration options are available as compile options, intended to be chosen when setting up the controller and changed only infrequently. These options can be manually edited in ospConfig.h.

The controller name and version tag are included here, should you wish to display different values on start up. The pin assignments are also defined here, can can be changed if you have altered the hardware of the PID shield in some way.

#define UNITS_FAHRENHEIT sets the input sensor units to Fahrenheit. After changing between Fahrenheit and Celsius, the controller will reset the memory to clear the values in the old units.

#define SILENCE_BUZZER makes the PID quiet. You will still get a visual prompt of the alarm signal.

#define USE_SIMULATOR generates input values from a simple simulation model and may be useful when debugging. (Try an LED across the terminals of the 2-pin output block as a visual indication of the output duty cycle). 

#define ATMEGA_32kB_FLASH is the option to choose if you use an Arduino such as the Uno with 32 kB of flash memory. Undefining this option restores a couple of serial commands and debugging utilities, which might be handy if you are using something with more memory like an Arduino Mega.

#define STANDALONE_CONTROLLER disables the serial communication while retaining all the features of a standalone PID controller.

The default auto tune settings and thermistor values — nominal and reference resistance, etc — can also be edited the PID_Engine.h file.


Standalone PID Controller


This sous vide set up is made from an Arduino Uno with stripboard PID shield and an electric kettle plugged into a solid state relay module built previously. The Arduino is powered by a wall-mounted USB adapter.



This poached fish supper was thrown together from fillet of arctic char with lemon juice, salt, peppercorns, sliced shallot, and splash of vermouth. (The sprig of parsley was strictly for the photographs.) Sealed up in a ziploc sandwich bag, it went in the kettle for 30 minutes at 51 °C. For the record, I used a PI tuning with P = 3 and I = 0.005.


Everything you need to know about sous vide cooking you can find out from Douglas Baldwin.


Notes


Sometimes the resistor values used for the analogue buttons are not close to their specified values. If the buttons seem unreliable, try fiddling with the preset values in ospConfig.h, or swap the resistors out.


Resources


41 comments:

Tom said...

Struggling a bit to get this working. I flashed an uno with the pre-compiled celsius firmware. I have a thermo couple hooked up using the MAX31855 but the firmware always report 0.00C as the temperature (as read in the processing frontend). Keeping the wiring the same but using a custom sketch and the MAX31855 library from Adafruit I can read the temperature from the max31855 without any problems. The precompiled sketch uses A0/A1/A2 right?

This is how I init it with adafruit library:

int thermoDO = A0;
int thermoCS = A1;
int thermoCLK = A2;

Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);

Any ideas ?

Tom said...

Email me (click on name "Tom" in tagline to post)

Anonymous said...

Great project!
I tried to upload to a nano board but even with optiboot bootloader it won't fit (compiles to 33,718 using arduino ide 1.0.5)

I don't have an avr programmer and can't figure out how to burn the compiled version with a second nano (like I did to install optiboot)

Any pointers or do I have to order an UnoR3 ?

Tom said...

I'm travelling at the moment but when I get back next week I will look into it. I might be able to compile a shorter version and upload it to the repository.

Anonymous said...

Thanks for the reply - just had a look through the code and it looks like it was a lot of work.

I have a mega I can pull from a partially completed project so will test it on that.

Anonymous said...

It won't compile when I select mega 2560 as the board (using IDE 1.0.5). It gives:

osPID_Actions.ino: In function 'void profileLoopIteration()':
osPID_Actions:113: error: 'myPID.PID::isTuning' cannot be used as a function

Probably something simple but my arduino knowledge is very limited.

Tom said...

Thanks - I'll look into it.

Anonymous said...

Any update on mega comparability?

Anonymous said...

I made a shield! But when I tried to flash an uno with the pre-compiled fahrenheit (and celsius) firmware (using AVR Studio with a Dragon for the ISP), I get an error for both files of "The specified file is not a valid Intel HEX file."

Any ideas?

Unknown said...

Figured out my pre-compiled firmware issue (others probably know the right way, but for the rest of us...)
1. go to https://raw.github.com/t0mpr1c3/osPID-Firmware/f3329ae0fe1ca31aa3a413077bcd325f996984a9/compiled/uno/fahrenheit/osPID_Firmware.cpp.hex
2. copy the whole thing (use Control-A)
3. open a new txt file and paste it in
4. save it and change the name to 'fahrenheit.cpp.hex'
5. now you can upload it

Mark said...

Hello,
Your demo is great! I was able to finally load it into the Nano, as a standalone. However I can't get it loaded to control via the front end. I'd like to connect through a bluetooth module (serial feed through). Can that be done? Additionally, does the front end let you save the graph of data?

Thank You!

Donovan said...

Hi,
Saw this a couple of days ago, looks great! small issue in that when i try to load it into a Duemilanove it complains about the sketch being too big. I have already put the optiboot bootloader on.. any ideas?

Thanks!

Tom said...

Have you tried the precompiled version?

Donovan said...

I have, and that did seem to work (havent connected lcd, buttons etc)
I would like to change some of the pins and I also only have 2*20 lcds...
Did you use something other than the Arduino IDE to compile?

Thanks!

Tom said...

Different versions of the IDE compile to different lengths, I used the most recent Linux release. An easy way to get a shorter executable is to disable the AMIGOF_PI autotune option.

Anonymous said...

disabled AMIGOF_PI and it compiled a little smaller but still too big for an optiboot nano :(

Tom said...

I'm sorry to hear that. I'll update the instructions to alert Nano and Leonardo users that the executable is too long.

Madhu Nuggehalli said...

Hello Tom,

I am trying to compile this on an Arduino Mega and I am encountering this error:

osPID_Actions.ino: In function 'void profileLoopIteration()':
osPID_Actions:113: error: 'myPID.PID::isTuning' cannot be used as a function

Is this call important? What are the effects of commenting this out?

Thanks!

Tom said...

It's just a sanity check so you can comment it out. I should probably to try fix the underlying problem at some point, though.

Madhu Nuggehalli said...

Tom,

I am trying to replace the Processing app; I am trying to port the code to the Due so that it is all on the Arduino and displaying on a 7" TFT.

I am unable to find the auto-tuning methods routines. Can you please give me a hint as to where they are located?

Thanks,
Madhu.

Tom said...

Madhu, take a look in osPID_Engine.cpp.

електроментор said...

just a small trick for everyone who want to upload precompiled hex into UNO but don't have external isp programmer you can use Xloader v1.0

http://xloader.russemotto.com/

Augustine Solis said...

Hello I have the same problem as the first poster. The thermocouple is giving a temperature reading of "err" on the lcd and reading of zero on the front end. Everything is wired correctly and I have used both precompiled hex files and a compiled "PID only" (due to size of program). Nothing has worked so far.

What was the solution to the first poster?
Does the code need to be updated for the adafruit thermocouple?

angelo said...

Hi everybody.
Did anyone was able to successfully compile and load a non-standalone, non-simulator version of the firmware on an arduino uno R3? I mean, my current windows IDE is 1.0.6. The sketch compiles to a code 33somethingKbytes big wich the compiler complains about loading onto UNO.Any help is really apreciated.
Thanks
Angelo

Augustine Solis said...

Try using the precompiled hex file with hexuploader 1.0.2. Works perfectly if you only plan to use the DS18B20+ for temperature input.

angelo said...

I agree, but what if I wanted to use a thermocouple, as Im doing indeed ?
Or if I need to use different pins for my lcd display?

Augustine Solis said...

I havent figured out the thermocouple yet. It seems there is an issue with the code. I would imagine if you used different pins for the lcd it would also have to be reflected in the code.

Unknown said...

please help,,i am getting this error when trying to upload firmware::

Arduino: 1.6.0 (Windows 7), Board: "Arduino Uno"

osPID_Engine.cpp:45:52: error: variable 'tuningRule' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
PROGMEM Tuning tuningRule[PID::NO_OVERSHOOT_PID + 1] =
^
Error compiling.

Unknown said...

ok got it working,,now how can I change it to read Fahrenheit not Celsius

Unknown said...

hi,

I have the same issue and error compiling, how did you got it working ?

Anonymous said...

I get ERROR COMPILING

osPID_Engine.cpp:45:52: error: variable 'tuningRule' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
PROGMEM Tuning tuningRule[PID::NO_OVERSHOOT_PID + 1] =
^
Same issue here, found the osPID engine.cpp,, lines involved ,just cant get it as yet any recommendations on how to do it.I am trying to do this with DS18B20+ and lcd keypad shield, looks like it will work.

Anonymous said...

The same problem with me. compile error:
\ osPID_Engine.cpp: 45: 52: error: variable 'tuningRule' must be const in order to be put into read-only section by means of '__attribute __ ((progmem))' PROGMEM Tuning tuning Rule [PID PID overshoot :: NO + 1] =
how to fix the error and whether there max6675 library for firmware.
Please help me

Unknown said...

I get ERROR COMPILING

osPID_Engine.cpp:45:52: error: variable 'tuningRule' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
PROGMEM Tuning tuningRule[PID::NO_OVERSHOOT_PID + 1] =
^

Anonymous said...

Dear all,
The same problem with me. compile error:
\ osPID_Engine.cpp: 45: 52: error: variable 'tuningRule' must be const in order to be put into read-only section by means of '__attribute __ ((progmem))' PROGMEM Tuning tuning Rule [PID PID overshoot :: NO + 1] =
how to fix the error?
Please help me.

Unknown said...

Dear all,
The same problem with me. compile error:
\ osPID_Engine.cpp: 45: 52: error: variable 'tuningRule' must be const in order to be put into read-only section by means of '__attribute __ ((progmem))' PROGMEM Tuning tuning Rule [PID PID overshoot :: NO + 1] =
how to fix the error?
Please help me.

Klink said...

I tried to compile on IDE 1.6.7 and received the same error as above. Anyone have a solution?

Anonymous said...

Different IDE version showing different error. May be this firmware compile older version or compile by other software (other than IDE).

ubergeek7 said...

is it possible to load this firmware to the actual rocketscream ospid? I am trying to get better alarm functionality and cannot figure it out in the original, yours seems to have what I want. What would I need to change to get it to work on the ospid?

Unknown said...

I have found the solution of this problem.
Put 'const' keyword before PROGMEM. Like this:
const PROGMEM Tuning tuning Rule [PID PID overshoot :: NO + 1] =
At line no. 45 of osPID_Engine.cpp, line no. 259 of osPID_Menu.ino and line no. 660 of osPID_Serial.ino, that's enough after compiling enjoy.

Anonymous said...

hi everyone! any update from the first poster problem?
i have the same prob ang im using arduino mega. The thermocouple is giving a temperature reading of "err" on the lcd.
anyone?
thanks for the help!

gray said...

Hi, i have tried to compile this using the latest arduino IDE for both UNO and Mega and get the following error;
making/OsPID_Electric_Kiln_Controller/stripboard OsPID/osPID-Firmware-stripboard 1/osPID_Firmware/ospDecimalValue.h:107:111: error: expected primary-expression before ')' token
return (*this / (ospDecimalValue){ospPow10::value}).rescale();
any help appreciated, thanks

Post a Comment