PID to mechanical valve to regulate/shunt watertemp in a boiler

In sweden we use hot water to keep us warm!
We mix water from the boiler and return water pipes. All heating elements are waterfilled
In sweden we call this a shuntvalve which is exactly what it is, only that we shunt water instead of electrical current.
To buy a shunt regulator in Sweden is very expensive like 500 usd or more
So i wish to build my own shuntvalve regulator using ds18b20 for indoor/outdoor temp and and a servo or stepper motor to control the angle on the mechanichal shunt, thus mixing return waterfeed with the very hot water in the boiler.
this is very complex, and i wanted to pick your brains to point me in the right direction.
i have seen similar PID to rotational, but in these cases the motor is used to balance a robot, and in my case i wish to have a stable water temperature. none of these are written in ide
anyone can help me find a similar sollution?

The hardest part would appear to be the mechanical control of the shunt value- I image it would require significant torque to move and require some kind of adapter to your motor system. You will also need some kind of limit detector so you dont try to force the shunt valve past the fully open or fully closed positions.

This thread appears to be relevant DS18B20 One Wire Servo Temperature Gauge - Project Guidance - Arduino Forum there's also lots of projects if you search "arduino ds18b20 thermostat"

As a starting point I suggest you write a sketch that reads the temperature.

Next write a sketch to move your motor up and down and make it obey the limits.

Once you have those two building blocks then you can combine them to make your control system.

thanks. Thats exactly what i have done, so those building blocks are up and running.
But to write a logic funktion that would keep the outtgoing temperature constant is very hard.
the parameters are
boiler/furnace temp whick goes from 52 degrees celsius to 62 degrees (it's an incinerator)
return watertemp from heating/flooring elements goes from 20-47 degrees
these are mixed via the mechanical shuntvalve.
I have a cheap regulator already but it will go into selfocillating when i try to use it, so now it's running in constant temp mode giving me a temperature set on a potentiometer. this means i have to fiddle with it constantly according to weather.
I need to let outdoor temperature control the valve so that indoor floorheating is constant and not as today going from cold to too hot.
the only way to do this is to have PID or PD contol over the servo or stepper motor. But it's 30 years since i studied this and my enginnering skills are long forgotten.
So it all boils down to a sketch where someone lets temperature control a valve via PID.
This should be close to having a robot be balanced via motor rotation angle; only that a gyro steers the motorangle/rpm and not a temperature sensor.
but i cannot find such a sketch written in ide for the Arduino.
Today i have a number of PID controllers that control pumps startup of incinerator but they run i on/off mode and so on, but i simply dont know how to make them control a valve.
they have ssr outs. PID controllers with 0-5v outputs are very expensive compared to Arduino.
the first idea i had was to buy a PID with 0 to 5 v output and have that control a servo via a 0 to 5v servo driver then i could compensate the output from the pid controller via the arduino by adding voltage to that curcuit.
doing all of this i an Arduino would be cheaper though and i would have 100 % controll over both soft and hardware

below is a sketch made of 3 others ds18b20 to servoangle alter to lm35 analoge tempsensor and a i2c lcd so i can se what's happening It's working and maybe this could work without implementing PID or PD regulation.
the floorheating is very slow

//#include <OneWire.h>
//#include <DallasTemperature.h>

// Data wire is plugged into pin 2 on the Arduino
//#define ONE_WIRE_BUS 2
//OneWire oneWire(ONE_WIRE_BUS);
//DallasTemperature sensors(&oneWire);
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

Servo myservo; // create servo object to control a servo
int pos; // variable to store the servo position
const byte factor = 3; // keep temp below 180/3 = 60 degr. C or change factor to 2 or 1

void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
Serial.begin(9600);
lcd.backlight();
//Serial.println("Dallas Temperature IC Control Library Demo");
//sensors.begin();
//sensors.requestTemperatures(); // Send the command to get temperatures

float temperature;
// read the input on analog pin 0:
float sensorValue = analogRead(A0);
// print out the value you read:
float powervoltage = 5; //define the power supply voltage.
temperature = (sensorValue / 1023) * powervoltage * 100; // tempsens =temperature

int tempSens = temperature; //sensors.getTempCByIndex(0);
for (pos = 0; pos < tempSens * factor; pos ++) // guess you want servo to move from 0 to 'temp' at startup mulitply factor for bette view in this example
{
myservo.write(pos);
delay(20);
}
}

void loop()
{
// sensors.requestTemperatures(); // Send the command to get temperatures
float temperature;
// read the input on analog pin 0:
float sensorValue = analogRead(A0);
// print out the value you read:
float powervoltage = 5; //define the power supply voltage.
temperature = (sensorValue / 1023) * powervoltage * 100; // tempsens =temperature
int tempSens = temperature;//sensors.getTempCByIndex(0);

delay(200);
Serial.print(tempSens);
lcd.init(); // initialize the lcd

lcd.setCursor(0, 0); //tecken 0 rad 0
lcd.print("temp is :");

lcd.setCursor(14, 0); // börja skriv på tecken 11, rad 0 obs 0-15 rader!
lcd.println(tempSens, 1); // antal decimaler

myservo.write(tempSens * factor ); // tell servo to go to the current temperature plus the difference between the current and old temperature
delay(1150);
}

There are more than a few issues that you have to be aware of.

first, ball valves are horrible for throttling. they are not designed for anything but on/off use.
globe valves are a little better and you may be able to use a guillotine valve.

you can have the best, most sophisticated control algorithm and most sensitive sensors, but if your final element is not capable of controlling in the ranges needed, then you are wasting time and effort.

second, when you throttle one line to reduce flow, you increase pressure across the valve. that will increase flow. it becomes faster through the smaller opening and volume may be reduced, but not in a linear fashion.

from the description, I assume you have a circulator pump. this would circulate the water from the boiler into the space.
then, you either re-circulate the water in the space, or send some through the boiler.

a true throttling valve is based on pressure drop and in most cases, water valves are full port and do not have much restriction until nearly fully closed.

I would offer that if you added a second, parallel valve, that was of a very small port, you would have much better low flow (temperature) control.

I would also offer that if you could find a flow meter, you could use that and then calculate BTU or some such and use that either as feedback or as the controlling value.

look at V-notch valves for more information about what flow characteristics can be available for valves.

I used to say that a great mechanic can get an average job done with poor tools
an average mechanic will get an average job with average tools
and a poor mechanic will have a poor job with perfect tools.

get a great performing valve or use simple valves in an array and most of your problems will be solved.

Mcudnic:
boiler/furnace temp whick goes from 52 degrees celsius to 62 degrees (it's an incinerator)
return watertemp from heating/flooring elements goes from 20-47 degrees
these are mixed via the mechanical shuntvalve.
I have a cheap regulator

I would offer that a flow diagram might help us to figure out what you are doing.
also, I would suspect you have a thermal mass in the floor, so if you sent in temperature that was much too high, but for a short period, the effect would not be noticed.
as I understand, you have a water loop in the floor. this is recirculated. and when needed, you add heat.
if you stop the circulation, then the temperature of the return will be a slug of cold water, this should be ignored in any control. if you do shut off the circulator, then just turn it on and allow for 2 or 3 full circulations to occur and ramp up the heat input.
the only valid temperature sensing would be from the average water flow, and not a slug of cold or hot water.
you should be able to determine the loop time by running the recirculation and then opening the hot water side an inject heat. then time how long it takes until your return water shows a rise in heat. do not expect much, but any rise would indicate one loop of flow was complete.
I would think that you could add some small amount and plot the temperature rise to help indicate the effects of heating.

its a 3 way shunt valve.
I have a circulation pump Yes.
The valve is on top of the furnace or boiler and mixes the boiler water with the returning cold water from an array of heating elements. the valve is design exactly for this purpose and are commonly used in sweden to mix the water without restricting the return feed wich could damage the pump and make the flow digital and impossible to regulate.
It's a fully operational system which came with the house but since then i have radically altered the control system, so an array of digital temp regulators are controlling the entire furnace from electrical heating cartridge to the incinerator unit. This part is working perfectly because i bult the systems myself with cheap pid controller and ssr relays
To buy a new furnace with shunt system would cost 15000 usd.
the shunt controller itself costs around 800 usd but will not really suit the furnace.
We (Swedes) never measure the flow on existing systems, but they are controlled via the output temperature, and outdoor temperature.
The system is very slow due to the heating is hose imbedded in concrete floor, and that's why the cheap controller i have now doesnt work. it was build for heating element on the wall which are much faster and this causes the systyem to selfocillate
So i aim to use only 2 ds18b20: one outoors and one on outgoing pipe on the 3 way shunt valve.
Here is the result of the sketch i patched up the get the ideas going /Markus

If you have an issue with oscillating readings then your system has too much gain or insufficient damping.

Your system has lots of thermal mass so you need to control it slowly to avoid the oscillations. The outgoing water temp to achieve a comfortable subfloor temperature is going to vary depending on external factors so I suspect you need to measure the temperature of the underfloor slab (since thats what really matters)

First you need to define the set point - your desired temperature - say 21 degrees.

Then you need to define the dead-band- thats the amount the actual temperature can get away from the set point before you need to do anything about it. Lets call it 1 degree (you probably cant notice the difference between 20.5 degrees and 21.5 degrees in your sub-floor).

From this you get 2 temperatures: too_hot (above 21.5) and too_cold (below 20.5).

Then the control logic is pretty easy (in theory at least)

loop() {

  current_t=read_temperature();
  t_diff=current_t-last_t;

  if (current_t>too_hot) {
     if (t_diff>=0) {
       // close valve a little bit (make water cooler)
     }
  }

  if (current_t<too_cold) {
     if (t_diff<=0) {
       // open valve a little bit (make water hotter)
     }
  }

  last_t=current_t;
  // wait a while
}

The complicated bit is deciding what "a little bit" and "wait a while" is in your situation. I'd suggest you take readings no more than every 10 to 30 minutes to ensure you get a real signal and not just measurement noise.

If you find the above logic still doesnt perform well you can then modify it to open or close the valve proportionally depending on the values of current_t and t_diff rather than a fixed amount.

I am a little confused about what you are trying to control.

if you are trying to have a fixed discharge temperature and modulate the mixing valve (shunt valve) then your control should be slow and rely more on integral than P. D us not needed as much on temperature due to the very slow changes.

With control of your discharge temperature, you then change the setpoint of discharge, based on the OA temperature.

what comes to mind is that your discharge sensor is located in a place that allows for proper mixing of the two streams.

thanks dave-in-nj. You are correct, i read someplace that PD regulation is used on slow system, but it should be the integrating part thats most important. I have solved many issues with destillating alcohol in my younger days (as a school project)
I did that by PD control and with a programmable 7step pid regulator. Guess that's why it stuck in my mind , only that it was a very fast and slow system depending on with stage the burner was in. I still have that controller but only ssr output without pwm control.
I have seen this on newer controllers.
but with serial coms and software this would be a very, very expensive, way to control the shunt whereas a arduino would give me an endlessly expandble platform to build a better system, for no money at all.
Or how would you convert the ssr output to an angle on the shunt. (the manual is a 120 pages book)
it's been 26 years since i graduated my engineering education. The laplace formulas and Nyquist diagams are long gone , and i havent worked in this field for 24 years.
luckily the Arduino does not go that deep, so i can cut an paste the sketches and simply modify P, I D to suit my needs. If it doesnt work i can make a farmers degree sollution. Ignorent people often come up with genius sollution becase they work without prejudice.
i hope this will become a completed project that contributes to Arduino users

I agree with what rw950431 has offered, but would add

DWTSP = 50 // discharge water temperature setpoint
OAT = 0 // outside air temperature.

// after your do your readings

deltaT = (DWTSP - current_temp);
deltaT_integral + detlaT;

if deltaTintegral > 100
// send small step output to increase amount of heat
deltaT_integral = 0 ;

if deltaT_integral < -100
// send small step output to decrease amount of heat
deltaT_integral = 0 ;

I see that you are currently running your scan about 1,370 seconds based on delays.
if you are off by 10 degrees, then this will result in a small step change in about 7 seconds.

if you are off by 5 degrees, then 14 seconds, this may be way too fast. but changes should be very small on the motor.

ideally, you will be off by less than 1 degree and it will take a long time before any change is called.

you could substitute 100 for the value of a pot.
then use a pot to change the threshold for the point where a change occurs. it could be much-much higher in value.

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

to allow for the OAT, you have one value of the discharge water temperature set point
and want to change that to allow for the outside air temperature OAT

if this is a flat line, from say 0°C to -50°C

and you wanted to alter your DWT by 10 degrees over that range. you would need to alter the DWTSP by whattever value you wanted to use.

Here in the States, I lower the house temp based on the OA temp. if it gets a lot colder outside, I allow it it get colder inside.
I only change by a few degrees, about 5 degrees at maximum. that means we could have a change of 30°F outside and I would change 3°F inside.

you would need to scale the OAT and then adjust your RWTSP by some amount.

Mcudnic:
... i can make a farmers degree solution. Ignorant people often come up with genius solution because they work without prejudice.
i hope this will become a completed project that contributes to Arduino users

I find that many people think a pump and a valve work the exact same way a resistor divider does. to about 20 decimal places and at the speed of light.
Unfortunately, when you move a motor, that moves a linkage, that moves a valve, you get a change.
when you reverse, you may have to move 10 steps before you see a change. for the beginner, they just use float and not int so they can get more 'accuracy' and I just shake my head.
in this area, valves and actuators, the problem is the hysteresis at the final element.
I would offer that time would be well spent to send a step change to the motor and see what change occurred in the output.
If your motor and valve cannot resolve 1°C, then you must use that Farmers alternative and be happy that you are close enough.
send the smallest change you can and see if the motor can move. Characterize the valve/motor combination.
once you know what input is required to make a change, you have most of your problem solved.

thanks guys! i think i have all i need now.
the extremely ugly sketch which i slammed toghter in this thread operates the servo with 1 degree.The shunt, if i use float then the servo goes smoothly without visusal steps, but one degree should be enough.
the existing shunt motor moves more than 1 degree for sure, maybe 2-3 degrees.
I operates on outgoing feed temp and 1 room sensor. but it is a programmed one and cannot be altered.
it was never good even before so i maxed it out and use constant temperature instead.

I think i will use a servo because i wouldif i was to take away the potentiometer i not need a switch or rotary encoder to know what angle the valve or servo has, it is also strong enough to move the valve.
It's a sketch for ds18b20 that i changed to lm35 without erasing the original program, and then i wanted i2c lcd as well so i could see what happed. there is a clip on youtube also.
Im an rc enthusiast buggy freak so i have plenty of servos lying around already
I will wait for the ds18b20 i ordered and get them upp and running. then i will make a multichannel setup.
i only have one LM35 and no ntc's at home. Only type k and pt100 thermocouples

Today the outside temperature is -12 degrees celsius that's 10.4 Farenheit.
so we have much bigger temperture fluctuations than most Americans will have i think?
last week it was +12 degrees celsius :slight_smile:

Yes karma i see your point. But i know a lot of guys from school that have done amazing things without anything else than determinatation.
One guy was a farmer sons and worked as a car mechanic.
Today he runs a company that designs the rotors on windpower plants.
I have a lot of education behind me which helps me alot.
Machine Engineer, Machinist degree on boats, i worked as a electroinics repairman for 18 years. I'm also a goldsmith. so i have more than one leg to stand on.
But i have not worked as an engineer for 26 year nor with PID and microcontrollers for 26 years. So i have a lot of catching up to do when it comes to programming IDE which was unknown to me until my arduino showed up.
i have resonable knowledge to set them up.
My last programming was pascal and before that Basic on a commodore 64! or ABC800
But i know that determination will overcome what lacks in knowledge.

so now the shuntvalve is up and running w/o pid sofar. Seems to work fine with Proportional only.
it's basically a ds18b to servo angle sketch that i have modified to suit my needs. a strong servo is mounted on top of the old shunt motor so there is a backup if the servo should fail. i will take pics and get back when the outdoor sensor is implemented. Right now it run with constant temperature. The arduino is i the boilerroom and i have a usb cable to monitor the outgoing watertemp. it's is amazingly accurate and the biggest deviation is +-0,3 degress celsius which is ten times better than the old shuntvalve regulator. I will take som pics and put on youtube, so you can see. of course i will implement pid later. but for now i will start with the oteher blocks and pice them together one by one.

here's the sketch and pardon me for not being so perfectly designed but still working/ MGU

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
#include <LiquidCrystal_I2C.h> // Markus G
#include <Wire.h> //because of i2clcd1602
#include <Servo.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); //implemented by Markus
Servo myservo; // create servo object to control a servo
float pos; // variable to store the servo position // bytt int mot float mgu
const byte factor = 1 ; // keep temp below 180/3 = 60 degr. C or change factor to 2 or 1 yhis is the proprtional feedback i will make this a float variable to fine tune it if necessary/ MGU

void setup() /****** SETUP: RUNS ONCE ******/

{
{
//------- Initialize the Temperature measurement library--------------
sensors.begin();
// set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)

//---------------- Initialize the lcd ------------------
lcd.init(); // initialize the lcd
lcd.clear(); // Reset the display
lcd.backlight(); //Backlight ON if under program control

}//--(end setup )---

myservo.attach(9); // attaches the servo on pin 9 to the servo object
Serial.begin(9600);
lcd.init(); // initialize the lcd
Serial.println("Dallas Temperature IC Control Library Demo");// mgu
sensors.begin();
sensors.requestTemperatures(); // Send the command to get temperatures
float tempSens = sensors.getTempCByIndex(0); //int

for (pos = 120; pos < tempSens * factor; pos ++) // guess you want servo to move from 0 to 'temp' at startup mulitply factor for bette view in this example (120 is close to 33 degrees c on on outgoing watertemp /MGU
{
myservo.write(pos);
delay(200);
}
}

void loop()
/-----( Declare User-written Functions )-----/

{
// Print our characters on the LCD
// NOTE: Line number and character number start at 0 not 1
sensors.requestTemperatures(); // Send the command to get temperatures

float tempSens = sensors.getTempCByIndex(0);

delay(200);
lcd.setCursor(0, 0); //tecken 0 rad 0
lcd.print("t:");
lcd.setCursor(3, 0); // börja skriv på tecken 11, rad 0 obs 0-15 rader!
Serial.print(tempSens);
Serial.print(" ");
lcd.println(tempSens); // MGU
lcd.setCursor(3, 1); //Start at character 0 on line 1
myservo.write(147- tempSens * factor ); // tell servo to go to the current temperature plus the difference between the current and old temperature the nummer 147 lets me set the temp setpoint and is also a servo reverse function
delay(10000);
lcd.println(147-tempSens * factor ); // i will clean up the code here later
Serial.println(147-tempSens*factor);// this lets me monitor the Gizmo on my PC aswell as in the boiler room
delay(150);
}

I made a similar heating system management with Arduino Mega 2560
The valve and actuator as here -CELSIS UAB - Šildymas . Santechnika . Vonios kambario įranga. Vedinimas
When temperature rises, very slowly responsive sensor, so that the iron pipe is heated in about 10-15 seconds.
My actuator rotates 180 degrees within 1.5 minutes. I made the menu, and can determine how much time will work and what will be actuator pause.
An example of the algorithm.

  1. If the temperature rises, actuator operates for 5 seconds.
  2. 10 seconds. pause
  3. Checks or suspended rise in temperature.
    2 years acting controller - GitHub - SauleVire/KKK_valdiklis_v2: Kieto kuro katilo valdiklis
    actuator - KKK_valdiklis_v2/PVoztuvas2.ino at master · SauleVire/KKK_valdiklis_v2 · GitHub
    P.S. Sorry, all Lithuanian language ...