rims-arduino-library  v3.1.1
Recirculation infusion mash system library for Arduino
Public Member Functions | Protected Member Functions | Friends | List of all members
Rims Class Reference

Recirculation infusion mash system (RIMS) library for Arduino. More...

#include <Rims.h>

Inheritance diagram for Rims:
RimsIdent RimsTuner

Public Member Functions

 Rims (UIRims *uiRims, byte analogPinPV, byte ssrPin, double *currentTemp, double *ssrControl, double *settedTemp)
 Constructor. More...
 
void setTempProbe (byte probeType, float probeCoefs[], float res1)
 Set temperature probe (RTD, thermistor or custom) parameters. More...
 
void setPinLED (byte pinLED)
 Set pin for heater LED indicator. More...
 
void setFlowSensor (byte pinFlow, float flowFactor, float lowBound=DEFAULTFLOWLOWBOUND, float upBound=DEFAULTFLOWUPBOUND, float criticalFlow=DEFAULTFLOWLOWBOUND)
 Set pin for flow sensor and parameters. More...
 
void setHeaterPowerDetect (char pinHeaterVolt)
 Set pin to detect if there is voltage applied on heater. More...
 
void setTuningPID (float Kp, float Ki, float Kd, float tauFilter, int mashWaterQty=-1)
 Set tuning for PID object. More...
 
void setMemCSPin (byte csPin)
 Set pin for flash memory chip select. More...
 
void checkMemAccessMode ()
 Check if enterring in USB memory access mode. More...
 
void run ()
 Start and run Rims instance. More...
 
float getTempPV ()
 Get temperature from temperature probe (RTD, thermistor or custom). More...
 
float getFlow ()
 Get flow from hall-effect flow sensor. More...
 
bool getHeaterVoltage ()
 Check if heater is powered or not. More...
 
void stopHeating (bool state)
 Stop heater no matter what PID output. More...
 

Protected Member Functions

virtual void _initialize ()
 Initialize a Rims instance before starting temperature regulation. More...
 
void _initSession ()
 Init all attributes and I/O for starting a brew session.
 
void _endSession ()
 Attributes treatments for ending a brew session.
 
virtual void _iterate ()
 Main method called for temperature regulation and other actions at each iteration. More...
 
void _refreshTimer ()
 Refresh time related values. More...
 
void _refreshDisplay ()
 Refresh display used by UIRims instance.
 
void _refreshSSR ()
 Refresh solid state relay. SSR will be refreshed in function of _controlValPtr (duty-cycle in percentage) and SSRWINDOWSIZE (mSec) values.
 
void _serialPrintBrewData ()
 Print current data points values to the Serial logger. Serial port (UART) need to be initialized in the main sketch with Serial.begin()
 
unsigned int _memCountSessions ()
 Count how many brew sessions were saved in flash mem. More...
 
unsigned long _memCountSessionData ()
 Count how many data point were taken. More...
 
void _memInitSP ()
 Initialize flash memory. More...
 
void _memAddBrewData ()
 Add data point to the flash memory. More...
 
void _memDumpBrewData ()
 Dump brew session data on USB serial port.
 
void _memFreeSpace ()
 Show free memory on flash mem via USB serial port.
 
void _memClearAll ()
 Clear all memory via USB serial port.
 

Friends

class RimsIdent
 
class RimsTuner
 

Detailed Description

Recirculation infusion mash system (RIMS) library for Arduino.

Note
If WITH_W25QFLASH is defined, methods related to W25QFlash memory is added in the class.
Author
Francis Gagnon
Examples:
rimsBasic.ino, rimsFlow.ino, and rimsMem.ino.

Constructor & Destructor Documentation

◆ Rims()

Rims::Rims ( UIRims uiRims,
byte  analogPinPV,
byte  ssrPin,
double *  currentTemp,
double *  ssrControl,
double *  settedTemp 
)

Constructor.

Parameters
uiRims: UIRims*. Pointer to UIRims instance
analogPinPV: byte. Analog pin to temperature probe
ssrPin: byte. Pin to control heater's solid state relay.
currentTemp: double*. Pointer to a double that will be used for current temperature
ssrControl: double*. Pointer to a double that will use to control SSR duty-cycle
settedTemp: double*. Pointer to a double that will be use to store setted temperature

Member Function Documentation

◆ _initialize()

void Rims::_initialize ( )
protectedvirtual

Initialize a Rims instance before starting temperature regulation.

Initialization procedure :

  1. Ask Temperature set point
  2. Ask Timer time
  3. Ask Mash water qty (if setted)
  4. Show pump switching warning
  5. Show heater switching warning

Reimplemented in RimsTuner, and RimsIdent.

◆ _iterate()

void Rims::_iterate ( )
protectedvirtual

Main method called for temperature regulation and other actions at each iteration.

At each PID calculation (at each SAMPLETIME mSec), datas is sent over Serial communication (and flash mem, if applicable) for logging purpose.

Reimplemented in RimsTuner, and RimsIdent.

◆ _memAddBrewData()

void Rims::_memAddBrewData ( )
protected

Add data point to the flash memory.

Five values is added at _memNextAddr, 20 bytes in total. Temperature setpoint (float : 4 bytes) is saved only once, at the beginning of the brew sessions in Rims::_memInitSP(). For exemple, for the first data (starting at ADDRBREWDATA or 0x002000) of the first brew session, the memory map would be :

Address Data Size
0x002000 sp 4 bytes
0x002004 time 4 bytes
0x002008 cv 4 bytes
0x00200C pv 4 bytes
0x002010 flow 4 bytes
0x002014 timerRemaining 4 bytes

◆ _memCountSessionData()

unsigned long Rims::_memCountSessionData ( )
protected

Count how many data point were taken.

When brew data is added in the memory, a sector is filled with "0" to remember how many data were taken. This sector is at the address ADDRDATACOUNT or 0x001000 (second sector).

If 12 brew data were taken since de beginning (or 12 seconds were ellapsed), the memory map would be like this :

Address Data
0x001000 b00000000
0x001001 b11110000
0x001002 b11111111
0x001003 b11111111
... ...
0x001FFF b11111111

I used this method because of a limitation of the flash memory. I could not use normal counting because freshly erased bits can be cleared (set to "0") but cannot be set to "1" without full sector erase.

◆ _memCountSessions()

unsigned int Rims::_memCountSessions ( )
protected

Count how many brew sessions were saved in flash mem.

Max is 4096 brew sessions. When a new brew session is started, the starting address of the datablock is saved in the brew sessions table, starting at ADDRSESSIONTABLE or 0x000000. For exemple, if 2 brew sessions were done of 2 seconds each (so 4+20+20=44 bytes each), the memory map of the brew sessions table would be :

Address Data Size
0x000000 0x00002000 4 bytes
0x000004 0x0000202C 4 bytes
0x000008 0xFFFFFFFF 4 bytes
0x00000C 0xFFFFFFFF 4 bytes
... ... ...
0x000FFF 0xFFFFFFFF 4 bytes

◆ _memInitSP()

void Rims::_memInitSP ( )
protected

Initialize flash memory.

Verify where to store the new datas and add current temperature setpoint at the beginning of the datablock.

◆ _refreshTimer()

void Rims::_refreshTimer ( )
protected

Refresh time related values.

If error on temperature >= MAXTEMPVAR, timer will not count down. Error on current temperature should not be greater than MAXTEMPVAR to count down. If current temperature setpoint is NAN , current temperature is ignored in the countdown. If timer setted time is >= NOTIMELIMIT, timer will never elapsed and the remaining time will be equal to the running time.

◆ checkMemAccessMode()

void Rims::checkMemAccessMode ( )

Check if enterring in USB memory access mode.

Must be called at the end of the setup() function of the main sketch. If KEYSELECT is pressed, entering in USB memory access mode. In this mode, you can dump brew session data on the serial port and erase the entire memory. A basic menu interface is implemanted via serial communication.

The menu is :

  1. dump brew session data
  2. calculate free space
  3. clear all memory
  4. exit

Serial port (UART) need to be initialized in the main sketch with Serial.begin() to used memory access mode.

◆ getFlow()

float Rims::getFlow ( )

Get flow from hall-effect flow sensor.

Returns
float. Flow measurement in L/min

◆ getHeaterVoltage()

bool Rims::getHeaterVoltage ( )

Check if heater is powered or not.

If pinHeaterVolt is -1 (default value), always return true.

Returns
boolean. Heater power state

◆ getTempPV()

float Rims::getTempPV ( )

Get temperature from temperature probe (RTD, thermistor or custom).

First, probe is read and connection checkup is performed. Then, the measured sensor value is pre-filtered with a 1st order low-pass filter. Finally, the filtered value is converted to a temperature. If the probe is not connected, heating is stopped until reconnection.

  1. If _probeType == PROBE_RTD : Temperature sensor resistance is calculated from the filtered voltage and cubic-fit equation is applied here. If voltage is too small or too large (under 0.8V and over 4.2 V) it means that the RTD is not connected. Both extreme values is verified because of the nonlinear behavior of the INA126 outside the output swing limits of the 2 opAmps.
  2. If _probeType == PROBE_THERM : Temperature sensor resistance is calculated from the filtered voltage and Steinhart-hart equation will be applied here. If voltage is maximal (i.e. ~=5V) it means that the thermistor is not connected.
  3. If _probeType == PROBE_CUSTOM : Insert additional code in specified sections.
Returns
float. Temperature measurement in deg C

◆ run()

void Rims::run ( )

Start and run Rims instance.

Should be called in the loop() function of your sketchbook

◆ setFlowSensor()

void Rims::setFlowSensor ( byte  pinFlow,
float  flowFactor,
float  lowBound = DEFAULTFLOWLOWBOUND,
float  upBound = DEFAULTFLOWUPBOUND,
float  criticalFlow = DEFAULTFLOWLOWBOUND 
)

Set pin for flow sensor and parameters.

Make sure that the pin used for the flow sensor supports interrupts. For exemple, on an Arduino UNO, pin 3 is associated to interrupt #1. For more info : http://tinyurl.com/jwy4zgu.

Pull-up resistor is automatically enabled on the selected pin since it's needed for most hall-effect sensor.

Parameters
pinFlow: byte. Pin number (supporting interrupts) connected to the flow sensor.
flowFactor: float. Factor used to calculate flow from the input frequency, i.e. :

\[ freq[Hz] = flowFactor * flow[L/min] \]

lowBound: float. Lower bound used for accepted flow rate.
upBound: float. Upper bound used for accepted flow rate
criticalFlow: float. If flow < criticalFlow , heater is turn off. Set at -1 to ignore flow mesurement on heater actions.

◆ setHeaterPowerDetect()

void Rims::setHeaterPowerDetect ( char  pinHeaterVolt)

Set pin to detect if there is voltage applied on heater.

If no voltage is detect on the heater, a speaker alarm is trigerred.

Warning
Do not apply 120V or 240V directly on arduino pins !!!

It can be easily and cheaply made with a +5V DC power supply in parallel with the SSR and heater. It is recommended to add a 10Kohm or so resistor in series with the power supply.

power_circuit.png
Voltage detection circuit

I use it to detect if my breaker is tripped or if I shut it off manually with an external switch. If the PID is informed that the heater is shut off, it will run smoother when the heater will be re-powered. This feature is really not mandatory.

Parameters
pinHeaterVolt: byte. 5V power supply pin.

◆ setMemCSPin()

void Rims::setMemCSPin ( byte  csPin)

Set pin for flash memory chip select.

WITH_W25QFLASH must be defined in Rims.h to used flash memory functions. Code was built on Windbond W25Q80BV SPI flash memory. (possible alternative : W25Q80DV)

MOSI, MISO and CLK are fixed pins on all Arduino. For ex, it's 11, 12, 13 for MOSI, MISO and CLK respectivly on Arduino UNO. For more information : http://tinyurl.com/6byntug.

Warning
Winbond W25Q80BV works in 3.3V and most arduino works in 5V. If it's your case, do not directly connect Arduino MOSI, MISO, CLK and CS on the memory pins.

If you have to convert 5V signal to 3.3V signal, here's a simple and cheap circuit that works well.

mem_circuit.png
Voltage convert flash memory
Parameters
csPin: byte. pin used for flash memory chip select.

◆ setPinLED()

void Rims::setPinLED ( byte  pinLED)

Set pin for heater LED indicator.

Parameters
pinLED: byte

◆ setTempProbe()

void Rims::setTempProbe ( byte  probeType,
float  probeCoefs[],
float  res1 
)

Set temperature probe (RTD, thermistor or custom) parameters.

If custom temperature probe is desired, insert your code in Rims::getTempPV

rtd_circuit.png
RTD instrument amplifier circuit with a PT-100 RTD
Warning
To use this RTD amplifier, be sure that your rtd is a PT-100 with the 3-wires connection (yellow connected to the probe braid shield only)
thermistor_circuit.png
Thermistor voltage divider circuit
Parameters
probeType: byte. Either PROBE_RTD, PROBE_THERM or PROBE_CUSTOM
probeCoefs: float[4].
  1. If probeType is PROBE_RTD : It's the cubic fit coefficients of the RTD probe in order of increasing power, i.e. :

    \[ T[deg C]=C_{0} + C_{1}R_T + C_{2}R_T^2 + C_{3}R_T^3 \]

    for more information : http://tinyurl.com/zklerv8
  2. If probeType is PROBE_THERM : Steinhart-hart equation coefficients in order of increasing power, i.e. :

    \[ \frac{1}{T[kelvin]}=C_{0}+C_{1}\ln(R_T)+C_{2}\ln(R_T)^2+C_{3}\ln(R_T)^3 \]

    for more information : http://tinyurl.com/359coj2
  3. If probeType is PROBE_CUSTOM : It's an array of any 4 float. It can be an array of 4 zeros if unused.
res1: float. Res1 [ohm] value in circuits above.

◆ setTuningPID()

void Rims::setTuningPID ( float  Kp,
float  Ki,
float  Kd,
float  tauFilter,
int  mashWaterQty = -1 
)

Set tuning for PID object.

Algorithm is in parallel form, i.e. :

\[ G_{c}(s) = K_{p}+\frac{K_{i}}{s}+\frac{K_{d}s}{\tau s+1} \]

where \(\tau=\mathrm{tauFilter[sec]}\). It can be set to the same value as a PID output filter. In practice, a good value of derivative filter is :

\[ \tau = \frac{K_{d}}{10} \]

For more information about PID the algorithm : http://tinyurl.com/nrvavus

For anti-windup, integration static saturation was replaced by integration clamping. Basically, it stop integration at a smarter time than "if limit is reached at the output of the integrator". More precisely, it stop integration if limit is reached at the ouput of the PID AND if the temperature error and and the PID output have the same sign.

pid.png
Full PID block diagram
clamping.png
Integration clamping diagram
Parameters
Kp: float. Propotionnal gain
Ki: float. Integral gain.
Kd: float. Derivative gain.
tauFilter: float. Derivative filter time constant in sec.
mashWaterQty: int (default=-1). If multiple regulators is needed, set this parameter to mash water volume in liter. This mash water volume will be associated to this PID. Total of 4 regulators is allowed (with different mash water volume).

◆ stopHeating()

void Rims::stopHeating ( bool  state)

Stop heater no matter what PID output.

Parameters
state: boolean. If true, heater is shut off. Else, heater is turned on.

The documentation for this class was generated from the following files: