Small Aircraft Temperature Control

I'm working on a climate control system to put in an experimental aircraft.

The aircraft interior is heated and cooled via air inlets that can be controlled with servos and butterfly valves.

Let's call them:

heatservo
coolservo

The heatservo controls air coming off a heat source on the engine.
The coolservo takes cold vent air from outside the aircraft.

It was pretty easy to open and close servos based on whether the temp was < or > the set temp, but I'm trying to figure out how to build a curve that can control how open the butterfly valves are based on the temperature spread.

So for example:

10-60 degrees warmer than settemp open the coolservo 180
5-9.99 degrees warmer open the coolservo 90
3-4.99 degrees warmer open the coolservo 25
1-2.99 degrees warmer open the coolservo 10
0-.99 degrees warmer open the coolservo 5

10-60 degrees colder open the heatservo 180
etc
etc

This is what I tried but it wasn't working.

if ((settemp >= cabintemp+10) && (settemp<= cabintemp+50)) {
heatservoval = 180; // degrees my servo opens
heatservo.write(heatservoval);
coolservoval = 0; // coolservo stays cosed
coolservo.write(coolservoval);
}
if ((settemp >= cabintemp+5) && (settemp<= cabintemp+9.99)) {
heatservoval = 90; // heat servo closes some since the temp spread is less
heatservo.write(heatservoval);
coolservoval = 0;
coolservo.write(coolservoval);
}
if ((settemp >= cabintemp+1) && (settemp<= cabintemp+4.99)) {
heatservoval = 10; // heat servo closes more since the temp spread is getting smaller
heatservo.write(heatservoval);
coolservoval = 0;
coolservo.write(coolservoval);
}
else {
heatservoval = 0;
heatservo.write(heatservoval);
coolservoval = 0;
coolservo.write(coolservoval);
}

I also thought something like this would be more elegant.

heatservoval = ((settemp - cabintemp) * 5);
heatservo.write(heatservoval);

Any ideas would be much appreciated. I've only been working with Arduino for a couple of days now.

Thanks!

Don't bother. Use a table look-up to access the values for what you need.

Please post a complete, compilable sketch, and don't forget to put it in code tags for proper forum display.

A graph of the curve you want with a readable scale would help. Any spreadsheet program can make one with ease.

Thanks for the fast feedback. I'm new to this forum and Arduino. Will look into a lookup table?

And will figure out how to post a sketch properly.

Thanks!

The alternative is a polynomial expression. If your values fall close to one, you can derive it and use a simple math expression to produce the value.

/*
 LiquidCrystal Library - display() and noDisplay()

 The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/LiquidCrystalDisplay

DHT11 Sensor Code

* REQUIRES the following Arduino libraries:
* DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
* Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

*/


// This section is for the servo
#include <Servo.h> // servo library

Servo heatservo;  // create servo object to control a servo
Servo coolservo;  // create servo object to control a servo


// This section grabs the value off a potentiometer as a way to set the value settemp
int potpin = A0;  // analog pin used to connect the potentiometer
int tempval;    // variable to read the value from the analog pin

  
// This section is for the temp sensor
#include <DHT.h> // temp sensor libraries
#define DHTPIN 7     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);

// This section gets the LCD up and running
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
#include <LiquidCrystal.h> // lcd display library
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int ledPin = 13;       // pin that the LED is attached to


void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.begin(16, 2); 
  pinMode(ledPin, OUTPUT);
  heatservo.attach(9);  // attaches the servo on pin 9 to the servo object
  coolservo.attach(10); // attaches the servo on pin 10 to the servo object
}

void loop() {
  // Wait a few seconds between measurements.
  delay(3000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  
  float h = dht.readHumidity();
  
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  
  float settemp = 0;
  float heatservoval = 0;
  float coolservoval = 0;
  float mode = 1;
  
  tempval = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  tempval = map(tempval, 0, 1023, 60, 90);     // scale it for use with the servo (value between 60 and 90)
  settemp = tempval;

  heatservoval = ((settemp - f) * 10);
  heatservo.write(heatservoval);

  Serial.print(F("Temperature: "));
  Serial.print(f);
  Serial.println(F("F "));
  Serial.print(F("Set Temperature: "));
  Serial.print(settemp);
  Serial.println("F");
  // Serial.print(t); // this is celcius if needed
  // Serial.print(F("C ")); // this is celcius if needed
  // Serial.print(F("Humidity: "));
  // Serial.print(h);
  // Serial.println("%");
  Serial.print("Heat Servo: ");
  Serial.println(heatservoval);
  Serial.print("Cool Servo: ");
  Serial.println(coolservoval);
  Serial.println("--------------");
  
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  lcd.print(f);
  lcd.print("F  ");
  lcd.print(mode);
  lcd.setCursor(0, 1);
  // lcd.print("Humi: ");
  // lcd.print(h);
  // lcd.print("%");
  lcd.print("Set Temp: ");
  lcd.print(settemp);
  lcd.print("F");
  }

I was trying to figure out if else statements in this go...

/*
 LiquidCrystal Library - display() and noDisplay()

 The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/LiquidCrystalDisplay

DHT11 Sensor Code

* REQUIRES the following Arduino libraries:
* DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
* Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

*/


// This section is for the servo
#include <Servo.h> // servo library

Servo heatservo;  // create servo object to control a servo
Servo coolservo;  // create servo object to control a servo


// This section grabs the value off a potentiometer as a way to set the value settemp
int potpin = A0;  // analog pin used to connect the potentiometer
int tempval;    // variable to read the value from the analog pin

  
// This section is for the temp sensor
#include <DHT.h> // temp sensor libraries
#define DHTPIN 7     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);

// This section gets the LCD up and running
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
#include <LiquidCrystal.h> // lcd display library
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int ledPin = 13;       // pin that the LED is attached to


void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.begin(16, 2); 
  pinMode(ledPin, OUTPUT);
  heatservo.attach(9);  // attaches the servo on pin 9 to the servo object
  coolservo.attach(10); // attaches the servo on pin 10 to the servo object
}

void loop() {
  // Wait a few seconds between measurements.
  delay(3000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  
  float h = dht.readHumidity();
  
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  
  float settemp = 0;
  float heatservoval = 0;
  float coolservoval = 0;
  float mode = 1;
  
  tempval = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  tempval = map(tempval, 0, 1023, 60, 90);     // scale it for use with the servo (value between 60 and 90)
  settemp = tempval;



  if ((settemp >= f+10) && (settemp<= f+50)) {
    heatservoval = 180;
    heatservo.write(heatservoval);
    coolservoval = 0;
    coolservo.write(coolservoval);
    mode = (1);
  }
  if ((settemp >= f+5) && (settemp<= f+9.99)) {
    heatservoval = 90;
    heatservo.write(heatservoval);
    coolservoval = 0;
    coolservo.write(coolservoval);
    mode = (1);
  }
else {
    heatservoval = 0;
    heatservo.write(heatservoval);
    coolservoval = 0;
    coolservo.write(coolservoval);
    mode = (0);
  }

  Serial.print(F("Temperature: "));
  Serial.print(f);
  Serial.println(F("F "));
  Serial.print(F("Set Temperature: "));
  Serial.print(settemp);
  Serial.println("F");
  // Serial.print(t); // this is celcius if needed
  // Serial.print(F("C ")); // this is celcius if needed
  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.println("%");
  Serial.print("Heat Servo: ");
  Serial.println(heatservoval);
  Serial.print("Cool Servo: ");
  Serial.println(coolservoval);
  Serial.println("--------------");
  
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  lcd.print(f);
  lcd.print("F  ");
  lcd.print(mode);
  lcd.setCursor(0, 1);
  // lcd.print("Humi: ");
  // lcd.print(h);
  // lcd.print("%");
  lcd.print("Set Temp: ");
  lcd.print(settemp);
  lcd.print("F");
  }

So I guess your poly is just y=10x in that code. Because

heatservoval = ((settemp - f) * 10);

If you have an offset then it is just a linear equation y=mx + b

If you want help with this, the starting point is for you to produce a mathematical description of the desired translation.

Then, code advice can be targeted to the actual requirement.

You are actually defining two things:

  1. a transfer function to translate temperatures into a "comfort" scale
  2. partitioning that scale into fixed servo settings

You can actually combine those in the code, as you already do by partitioning by temperature, but to design that properly it is best to do a mental evaluation of the above two factors first.

If you need to produce ranges, you take the output of whatever mapping you used y=f(x) and do a nested elimination like:

if y>9
{
 do thing 9
}
else if y>8
{
do thing 8
}
else if y>7
{
do thing 7
...

This completely eliminates the complex test expressions like you have there.

The array driven version of that, would truncate the output y, and use it as an array index into (for above example) {9, 8, 7,...}. But actually there are many approaches and combinations thereof.

1 Like

Thanks aarg! That did the trick! Probably not as elegant as some sort of curve but it works and I can manually add more resolution and mess with the degrees of open and close in each temp range! I just wasn't using the else if properly.

if ((settemp >= f+20) && (settemp<= f+100)) {
    heatservoval = 180;
    heatservo.write(heatservoval);
}
 else if ((settemp >= f+10) && (settemp<= f+19.99)) {
    heatservoval = 90;
    heatservo.write(heatservoval);{
    }
 } 
 else if ((settemp >= f+5) && (settemp<= f+9.99)) {
    heatservoval = 20;
    heatservo.write(heatservoval);{
  }
 }
 else if ((settemp >= f+1) && (settemp<= f+4.99)) {
    heatservoval = 10;
    heatservo.write(heatservoval);{
  }
 }

Your welcome. It's a standard design pattern. Which is nicely supported in C.

So something like:

void loop()
{
  float tempError = getTemperature() - DesiredTemperature;

  // A difference of 10 or more degrees (temperature) leads 
  // to a valve angle of 180 degrees (angle)
  int valveAngle = constrain(tempError * 18, -180, +180);

  if (valveAngle < 0)
  {
     // Calling for cooling
     coolservo.write(-valveAngle);
     heatservo.write(0);
  }
  else
  {
     // Calling for heating
     coolservo.write(0);
     heatservo.write(valveAngle);
  }
}
1 Like

Thanks to everyone who has contributed to my little project so far! I have a prototype up and running and am encouraged by initial results.

Here's the thinking on hardware.

  • Arduino Mega
  • 1 servo controls front heat
  • 1 servo controls rear heat
  • 1 servo controls outside vent air to front pass
  • 1 servo controls outside vent air to rear pass
  • 2 temp sensors. One for front and back respectively
  • Nextion 7 inch capacitive touch screen interface
  • I'm also thinking about adding a sensor for barometric pressure / altitude, a G sensor, and a CO sensor. I understand calibrating a CO sensor can be tricky. If it's a huge ordeal, I can purchase a commercial unit for aviation that will tie into the avionics system and generate an audible alert in my headset.
  • System will be powered by the ships power which is 12v with a dedicated circuit breaker.

Here are my modes of operation.

Auto Mode
Logic board opens and closes heat and cool butterflies depending on the desired set temp. Passengers can still open manual panel vents or rear side vents and system will try to compensate by adding more heat.

Vent Mode (I'm gonna puke and need fresh air)
Front and back passengers can set a desired temp and the % flow of vent air and the logic board adds heat to try and maintain a set temp. This lets you open the panel vents and side vents as well as fully opening the overhead vents and the system will add heat to try and reach a target. This is a max airflow mode.

Manual Mode
Passengers can open and close heat and cold servos manually and see the current temp displayed for front and back.

Off
Closes all servo controlled butterflies.

Some questions about hardware.

Would you start with 12v servos, or use 5v servos powered by a step down converter. I've seen some beefy RC servos.

If a step down, what power supply would you recommend to go from 12v to 5v to supply clean power to the servos, Arduino and touch screen?

Should I power the Arduino and screen with their own power supply and the servos with separate unit?

What temp sensor would you all recommend for the two cabin measurement locations? Need something relatively durable and easy to use.

How would you harden the system to prevent damage from current spikes, voltage drops, etc.

Thinking I need to use some sort of shield that I can solder all of my connections on once finalized or is there a more Industrial strength board I should use once this is all configured?

What are the chances an Arduino, and or the Nextion screen could introduce enough electrical noise that it might interfere with my radios?

Thanks for any thoughts in advance!

Thinking? Whoa! You're way past that! You should be prototyping and testing.






That's better. :slight_smile:

I got about 100 hours of continuous operation out of those plastic geared servos. I have 3 metal geared servos that have been running 24/7 for 3+ years.

Was thinking about something like this for servos. Higher quality. Metal and higher torque. Seems like they would last a lifetime.

Going in an aircraft so spending a little more on good hardware is not an issue.

Link to Amazon servo

https://www.servocity.com/

Think vibration wearing the components!