0

I've recently built my Arduino Incubator, which consists of a DHT22 sensor, an LCD Keypad Shield, some fans, resistors, e.t.c.

I uploaded the sketch, and everything seemed fine. However, when I try to select the temperature and humidity I want, it won't let me change anything, and it says "Temperature: NanC, Humidity: Nan%".

What am I doing wrong? I didn't write the code myself. I copied it from a guy who made his incubator and wrote his code himself. He has the incubator project on github.

As you can see in the pictures he posted, everything appears to be working fine. What would be the problem? I don't have a lot of Arduino knowledge, although I am OK with reading and tinkering with code.

The display below, shows NaN when I try to select my own temperature/humidity. When I see the current temperature/humidity, it works fine. The sensor works with no problems at all, though I didn't connect a pullup resistor. I am going to try adding one. However, to me it seems like the problem isn't that. I get NaN errors when trying to select my own value. The buzzer beeps, the servo turns and the fan works fine. As said above, DHT sensor works and sends the values.

The error I get when trying to set the temperature. Same error in humidity selection.

Useful Links:

The code (Github)

The schematic (Github)

The whole incubator project (Github)

Update - 7/1/2019 Thanks to Jot, everything works fine now! He corrected my code, and he adviced me to reset the values in the EEPROM. I would have given up the project, unless he had helped me. I have now fully finished the build, even though I plan to add some features in the future.

I want to add:

  • A backup power source (lead acid battery)
  • Bigger ventilation holes
  • Design improvements
  • The ability to control everything using the serial monitor, so I can connect to the Arduino via Internet (Using an MFP Storage Server which I have)
  • A larger box for more eggs
  • A system which turns the eggs automatically
  • A pump which pumps water to the sponge automatically as well

However, nothing could be done without Jot's help. Again, thanks a lot to Jot for his help, and the efforts he put in order to help me. I really appreciate that, since I have not any kind of Arduino knowledge (I'm 14 years old), and I found his advices and comments very very useful.

I have now put 5 eggs inside the incubator, and it is right now working. I am counting backwards from today, and in about 21 days I am going to have chickens!

Here are some pictures of the machine for those who are interested (or just curious!):

The incubator working, with the screen turned on: [9]

The "egg hatching" room: (Inside, there is a wet sponge, all the devices and of course, 5 eggs!) enter image description here

  • 2
    i think that nan means not a number ..... comment out this line H = dht.readHumidity(); and add H = 0.5; ..... what do you get on the display then? – jsotola Jan 2 at 22:10
  • 2
    Please, Post all the code that you are using to. – leoc7 Jan 2 at 22:11
  • The code, is given in the link above. However, here is the link: github.com/quantenschaum/egg-incubator/blob/master/…. I only made a few changes at the beginning, so the lcd screen shows both date and time. Actually, I dodn't think this affects the error, as it has nothing to do with that. In addition to the above, I imported the code to the Arduino (before changing anything), and it seemed like the problem existed. – Lefteris the builder Jan 3 at 0:01
  • @jsotola thanks for the reply! However, it seems like the H = dht.readHumidity(); is already included. Take a look at that: if (!key) { // beep(2000, 50); T = dht.readTemperature() + T_OFFSET; H = dht.readHumidity(); if ((isnan(T) || T < 10 || T > 60) || (Hcontrol && (isnan(H) || H < 5 || H > 95))) { heater(0); lcd.clear(); lcd.print("SENSOR ERROR!"); It seems like it includes those, and also sets off an alarm if a nan value is displayed. When I add H = 0.5;, it beeps and reboots as the code says. My problem is when I select t/h. – Lefteris the builder Jan 3 at 9:03
  • @jsotola Also, the screen says "SENSOR ERROR", and that is something that the code says. As you can see in the previous code, if a nan value is displayed, then it sets off the alarm. For more information you can also see the whole code at the link included. Something to mention, is that I only have trouble selecting values e.g. temperature or humidity. I see the current temperature and humidity displayed with not problems. However, when I go to the selection menu, all the setpoints are NaN values. – Lefteris the builder Jan 3 at 9:09
1

Hi Lefteris the builder,
StackExchange is about questions and answers.
Arduino is about learning and fast prototyping.

For guidance with your project, the forum at http://forum.arduino.cc/ is more appropriate.

I suppose that a number of us have read the code that you use. We really do read code.
That code is not bad, but there are a few weak spots in that code:

  • Not enough comments to explain what is going on.
  • Many conditions with flags. That is okay, but the flags are sometimes a boolean and sometimes a byte, and there is no explanation what the flag is used for.
  • Many checks for isnan(). Does that indicate that a floating point "nan" problem might pop up at any time in the sketch?
  • Most of the code is in the loop(). I don't mind that, but others prefer to put large blocks of code in functions.

It seems that your hardware is working okay.

It is hard to confirm that the code for the Holt-Winters algoritme is working.

All this together is too confusing for us at the moment.


I have changed my answer, the hardware seems to be working.


Below is the changed sketch to test it without extra hardware.
I use the serial monitor. The sadw keys (followed by enter) are the cursor keys and the space bar (followed by enter) is select.

#include <avr/wdt.h>
// #include <Servo.h>
// #include <LiquidCrystal.h>
// #include <DHT.h>
#include <EEPROM.h>

// stty -F /dev/ttyACM0 115200 cs8 cread clocal -hupcl time 30 && tee incubator.log </dev/ttyACM0

#define WDT_TIMEOUT WDTO_8S // if defined, enable hardware watchdog
#define DHTPIN 3 // data pin of the DHT T/H sensor
#define T_OFFSET 0.9 // temperature sensor offset
#define FAN_PIN 2 // fan tacho signal pin
#define FAN_THRES 500 // fan alarm threshold
#define BEEPER A2 // pin where beeper is attached
#define BRIGHTNESS 10 // display brightness pin
#define HEATER A1 // heater MOSFET pin
#define DELAY 2000 // loop delay in ms
#define TS_ADDR 0 // temperature set point EEPROM address
#define HS_ADDR 4 // humidity set point EEPROM address
#define HC_ADDR 8 // humiditiy control mode EEPROM address
#define TI_RESET 1 // integral reset threshold, set integral to 0 when T error greater than this
#define HI_RESET 5 // integral reset threshold, set integral to 0 when H error greater than this
#define ALARM_T 2 // temperature alarm threshold, alert if T error greater than this
#define ALARM_H 8 // humidity alarm threshold, alert if H error greater than this
#define H_AUTO_THRES 3 // disable vent control in auto mode if H error < this
#define H_AUTO_COUNT 200 // disable for n cycles
#define HWAT 0.25 // holt winters parameters for temperature smoothing
#define HWBT 0.2
#define HWAH 0.7 // holt winters parameters for humidity smoothing
#define HWBH 0.5
#define A 0.005 // long average parameter
#define VENTCLOSED 80 // consider vent closed if under this angle
#define VENTOPENMS  480000L // open vent if closed longer
#define VENTRESETMS 600000L // reset vent after this time (>VENTOPENMS!)

// Servo vent;
// DHT dht(DHTPIN, DHT22);
// LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define RIGHT 16
#define UP 8
#define DOWN 4
#define LEFT 2
#define SELECT 1
#define NO_KEY 0

// added define to show messages on serial monitor.
#define lcd Serial

byte getKey() {
//  int key = analogRead(0);
//  if (key < 50) {
//    return RIGHT;
//  } else if (key < 150) {
//    return UP;
//  } else if (key < 300) {
//    return DOWN;
//  } else if (key < 500) {
//    return LEFT;
//  } else if (key < 800) {
//    return SELECT;
//  } else {
//    return NO_KEY;
//  }
  if (Serial.available() > 0) {
    int inChar = Serial.read();
    switch (inChar)
    {
      case 'w': return UP;
      case 'a': return LEFT;
      case 's': return DOWN;
      case 'd': return RIGHT;
      case ' ': return SELECT;
    }
  } else {
    return NO_KEY;
  }
}

void eeread(int address, int length, void* p) {
  byte* b = (byte*)p;
  for (int i = 0; i < length; i++) {
    *b++ = EEPROM.read(address + i);
  }
}

void eewrite(int address, int length, void* p) {
  byte* b = (byte*)p;
  for (int i = 0; i < length; i++) {
    EEPROM.write(address + i, *b++);
  }
}

void write_byte(int address, byte &value) {
  eewrite(address, sizeof(value), &value);
}

byte read_byte(int address) {
  byte value;
  eeread(address, sizeof(value), &value);
  return value;
}

void write_int(int address, int &value) {
  eewrite(address, sizeof(value), &value);
}

int read_int(int address) {
  int value;
  eeread(address, sizeof(value), &value);
  return value;
}

void write_float(int address, float &value) {
  eewrite(address, sizeof(value), &value);
}

float read_float(int address) {
  float value;
  eeread(address, sizeof(value), &value);
  return value;
}

void heater(boolean on) {
//  digitalWrite(HEATER, !on ? LOW : HIGH);
}

boolean heater() {
//  return digitalRead(HEATER) == HIGH;
  return true;
}

volatile int fancount;

void count() {
  ++fancount;
}

void beep(unsigned long f, unsigned long l) {
//  pinMode(BEEPER, OUTPUT);
  byte v = 0;
  f = 500000 / f;
  l = (1000 * l) / f;
  for (int i = 0; i < l; ++i) {
//    digitalWrite(BEEPER, v = !v);
//    delayMicroseconds(f);
  }
//  pinMode(BEEPER, INPUT);
}

float Ts, Hs; // set points
byte Hcontrol; // H control mode
byte Ts_changed, Hs_changed; // setpoint changed flags
float ET, dETdt, IETdt; // prop/diff/integ terms for T
float EH, dEHdt, IEHdt; // prop/diff/integ terms for H
float T, Tavg = NAN, Tvar, Tstd;
float H, Havg = NAN, Hvar, Hstd;
float Hpower, Hduty; // heater current power, average duty cycle
unsigned long t0, Hon, talarm, tventclosed;
byte displayMode;
byte key, bri = 255, alarm;
boolean ventclosed;
int fanrpm;

void setup() {
#if defined(WDT_TIMEOUT)
//  wdt_enable(WDT_TIMEOUT);
#endif
  Serial.begin(9600);
  Serial.println("Egg Incubator");
  Serial.println("Use wsad and space is select");

//  pinMode(HEATER, OUTPUT);
//  heater(0);
//  pinMode(BRIGHTNESS, OUTPUT);
//  analogWrite(BRIGHTNESS, bri = 255);
//  lcd.begin(16, 2);
//  lcd.noCursor();
  lcd.print("Incubator 0.7");
//  lcd.setCursor(0, 1);
  Serial.println();
  lcd.print(__DATE__);
//  dht.begin();
//  vent.setMinimumPulse(800);
//  vent.setMaximumPulse(2600);
//  vent.attach(11);
  //  write_float(TS_ADDR, Ts=37.8);  write_float(HS_ADDR, Hs=55);
  Ts = read_float(TS_ADDR);
  Hs = read_float(HS_ADDR);
  Hcontrol = read_byte(HC_ADDR);
//  pinMode(FAN_PIN, INPUT_PULLUP);
//  attachInterrupt(0, count, FALLING);
//  sei();
//  beep(800, 100);
//  beep(1000, 100);
//  beep(1200, 100);
//  beep(1600, 100);
}

void loop() {
  unsigned long t1 = millis();
  int dt = t1 - t0;

  if (!key) {
    key = getKey();
  }

  if (key) {
//    analogWrite(BRIGHTNESS, bri = 255);
  }

  if (t1 - Hon > Hpower * DELAY) {
//    heater(0);
  }

  if (Hcontrol && Hcontrol < H_AUTO_COUNT) {
//    vent.refresh();
  }

  if (alarm && !(alarm & 8)) {
//    beep(1000, 50);
//    beep(1414, 50);
  }

  if (dt > DELAY || key) {

    if (!key) {
      //    beep(2000, 50);
//      T = dht.readTemperature() + T_OFFSET;
      T = 30.0 + T_OFFSET;             // set to fixed value !
//      H = dht.readHumidity();
      H = 60.0;                        // set to fixed value !

      if ((isnan(T) || T < 10 || T > 60) || (Hcontrol && (isnan(H) || H < 5 || H > 95))) {
//        heater(0);
//        lcd.clear();
        lcd.print("SENSOR ERROR!");
//        lcd.setCursor(0, 1);
        Serial.println();
        lcd.print("T=");
        lcd.print(T);
        lcd.print("C H=");
        lcd.print(H, 1);
        lcd.print("%");
        beep(2000, 1000);
        return;
      }

      float dts = dt * 1e-3;

      if (dt > DELAY) {
        fanrpm = fancount * 60 / dts;
        fancount = 0;
      }

      if (fanrpm < FAN_THRES) {
        alarm |= 4;
      } else {
        alarm &= ~4;
      }

      // temperature Holt-Winters smoothing
      float E0 = ET;
      ET = HWAT * (T - Ts) + (1 - HWAT) * (ET + dETdt * dts); // smoothed T error (deviation from set point)
      dETdt = HWBT * (ET - E0) / dts + (1 - HWBT) * dETdt; // smoothed derivative
      IETdt += ET * dts; // integral of error
      if (abs(ET) > TI_RESET) // reset integral on big deviation
        IETdt = 0;
      float pidT = 1.1765 * (ET + 0.010526 * IETdt + 23.75 * dETdt); // PID value, adjust coefficients to tune
      Hpower = fanrpm > FAN_THRES ? max(0, min(1, -pidT)) : 0;
      heater(Hpower > 0.1);
      Hon = millis();

      if (abs(ET) > ALARM_T) {
        alarm |= 1;
//        vent.write(ET < 0 ? 0 : 180);
        if (Hcontrol > 1) {
          Hcontrol = 2;
        }
      } else {
        alarm &= ~1;
      }

      // humidity Holt-Winters smoothing
      E0 = EH;
      EH = HWAH * (H - Hs) + (1 - HWAH) * (EH + dEHdt * dts); // smoothed H error (deviation from set point)
      dEHdt = HWBH * (EH - E0) / dts + (1 - HWBH) * dEHdt; // smoothed derivative
      IEHdt += EH * dts; // integral of error
      if (abs(EH) > HI_RESET) // reset integral on big deviation
        IEHdt = 0;
      float pidH = 0.1176 * (EH + 0.09091 * IEHdt + 2.75 * dEHdt); // PID value, adjust coefficients to tune
//      vent.write(pidH * 180);

      if (Hcontrol && abs(EH) > ALARM_H) {
        alarm |= 2;
      } else {
        alarm &= ~2;
      }

      boolean ventclosed0 = ventclosed;
//      ventclosed = vent.read() < VENTCLOSED;  
      ventclosed = VENTCLOSED;         

      if (ventclosed && ventclosed != ventclosed0) {
        tventclosed = millis();
      }

      boolean openvent = ventclosed && millis() - tventclosed > VENTOPENMS;
      if (openvent) {
//        vent.write(180);
        if (millis() - tventclosed > VENTRESETMS) {
          tventclosed = millis();
        }
      }

      if (Hcontrol > 1) {
        if (abs(EH) > H_AUTO_THRES || openvent) {
          Hcontrol = 2;
        } else {
          if (Hcontrol < H_AUTO_COUNT) {
            ++Hcontrol;
          } else {
            IEHdt = 0;
          }
        }
      }

      // long term averages
      Tavg = A * T + (1 - A) * (isnan(Tavg) ? T : Tavg);
      Tvar = A * pow(T - Tavg, 2) + (1 - A) * (isnan(Tvar) ? 0 : Tvar);
      Tstd = sqrt(Tvar);

      Havg = A * H + (1 - A) * (isnan(Havg) ? H : Havg);
      Hvar = A * pow(H - Havg, 2) + (1 - A) * (isnan(Hvar) ? 0 : Hvar);
      Hstd = sqrt(Hvar);

      Hduty = A * Hpower + (1 - A) * Hduty;

      if (Ts_changed) {
        if (Ts_changed-- == 1)
          write_float(TS_ADDR, Ts);
      }

      if (Hs_changed) {
        if (Hs_changed-- == 1)
          write_float(HS_ADDR, Hs);
      }
    }

    if (key & SELECT) {
      displayMode = ++displayMode % 8;
    }

//    lcd.clear();
    Serial.println();
    lcd.print("T=");
    lcd.print(Ts + ET);
    lcd.print("C H=");
    lcd.print(Hs + EH, 1);
    lcd.print("%");

//    lcd.setCursor(0, 1);
    Serial.println();

    float uptime;
    char unit;
    switch (displayMode) {
      case 0: // raw values
        lcd.print("T=");
        lcd.print(T);
        lcd.print("C H=");
        lcd.print(H, 1);
        lcd.print("%");
        break;
      case 1: // temperature setpoint
        if (key & (UP | DOWN | LEFT | RIGHT)) {
          Ts = max(20, min(50, Ts + (key & (UP | RIGHT) ? +1 : -1) * (key & (UP | DOWN) ? 0.1 : 1)));
          Ts_changed = 10;
        }
        lcd.print("Ts=");
        lcd.print(Ts);
        lcd.print("C");
        break;
      case 2: // humidity setpoint
        if (key & (UP | DOWN)) {
          Hs = max(10, min(90, Hs + (key & UP ? +1 : -1)));
          Hs_changed = 10;
        }
        if (key & RIGHT) {
          if (Hcontrol < 2) {
            Hcontrol = ++Hcontrol;
          } else {
            Hcontrol = 0;
          }
          IEHdt = 0;
          write_byte(HC_ADDR, Hcontrol);
        }
        lcd.print("Hs=");
        lcd.print(Hs);
        lcd.print("% ");
        lcd.print(Hcontrol == 1 ? "on" : (Hcontrol > 1 ? "auto" : "off"));
        break;
      case 3: // average temperatur
        lcd.print("Ta=");
        lcd.print(Tavg);
        lcd.print("C (");
        lcd.print(Tstd);
        lcd.print(")");
        break;
      case 4: // average humidity
        lcd.print("Ha=");
        lcd.print(Havg);
        lcd.print("% (");
        lcd.print(Hstd);
        lcd.print(")");
        break;
      case 5: // heater duty cycle
        lcd.print("Hd=");
        lcd.print(Hduty);
        lcd.print(" Hp=");
        lcd.print(Hpower);
        break;
      case 6: // air vent
        lcd.print("V=");
//        lcd.print(vent.read() / 180.0);
        lcd.print(" F=");
        lcd.print(fanrpm);
        break;
      case 7: // average humidity
        uptime = t1 * 1e-3;
        unit = 's';
        if (uptime > 60) {
          uptime /= 60;
          unit = 'm';
          if (uptime > 60) {
            uptime /= 60;
            unit = 'h';
            if (uptime > 24) {
              uptime /= 24;
              unit = 'd';
            }
          }
        }
        lcd.print("Up=");
        lcd.print(uptime, 1);
        lcd.print(unit);
        break;
      default:;
    }

    Serial.println();

    if (alarm & 7) {
      if (!talarm) {
        talarm = millis();
      }
      // sound on persistent alarm and fan failure
      if (millis() - talarm > 300000L || alarm & 4) {
        alarm &= ~8;
      }
//      analogWrite(BRIGHTNESS, bri = 255);
//      lcd.setCursor(0, 0);
      if (alarm & 1)
        lcd.print("T ");
      if (alarm & 2)
        lcd.print("H ");
      if (alarm & 4)
        lcd.print("F ");
      lcd.print("ALARM!          ");
      if (!(alarm & 8) && key) {
        alarm |= 8; // alarm acknowledged
        talarm = millis();
      }
      if (!(alarm & 8)) {
//        lcd.setCursor(0, 1);
        Serial.println();

        lcd.print("T=");
        lcd.print(T);
        lcd.print("C H=");
        lcd.print(H, 1);
        lcd.print("%");
      }
    } else {
      alarm = 0;
      talarm = 0;
    }

    if (key) {
      delay((key & SELECT) ? 500 : 200);
    }

    if (bri) {
//      analogWrite(BRIGHTNESS, --bri);
    }
    key = 0;
    t0 = t1;
  }

#if defined(WDT_TIMEOUT)
  wdt_reset();
#endif
}

@Lefteristhebuilder, you have selected that sketch, but the sketch might not handle problems very well.

Anyone can write code for Arduino and put it online.
At least at Github it is possible that others can write an issue (as you did). The project at Github has 9 stars and the creator showed the project at the Arduino "Project Hub". That is all good, but I'm not very happy with the code itself.

  • Hi! First of all... I didn't write the code myself! I copied from a guy who did the same thing and it worked for him. The display above, shows NaN when I try to select my own temperature/humidity. When I see the current temperature/humidity, it works fine. The sensor works no problems at all, though I didn't connect a pullup resistor. I am going to try adding one. However, to me it seems like the problem isn't that. I get NaN errors when trying to select my own value. Buzzer, servo and fan work fine. Buzzer, fan and servo work fine. As said above, DHT sensor works and sends the values. – Lefteris the builder Jan 3 at 11:49
  • @Lefteristhebuilder please update your question with this extra information. Also add a link to your issue at github to your question. Add to question which DHT library you use. Did you really use a SoftwareServo library? – Jot Jan 3 at 15:38
  • @Lefteristhebuilder I'm running a simulation of the code. I don't get the "nan" numbers when adjusting the values with up and down. The way the menu works in the sketch is hard to understand. If I had to solve this for myself, I would print a lot of variables to the serial monitor and probably end up rewriting the whole sketch. – Jot Jan 3 at 16:19
  • thanks for your reply! What kind of simulation did you do? Can I do that as well? I don't know whether the code is hard to understand or not, since as mentioned above, I have not any kind of experience with coding. Unfortunately I can't write the sketch, I haven't done any similar thing before and if you asked me to create just a blink sketch, I would struggle a lot, or I would just copy something posted online. What are the available options? I spent a lot of money for this project and I don't want to throw it away.... Hope you kindly understand. I used DHT.h and SoftwareServo.h. – Lefteris the builder Jan 3 at 22:38
  • @Lefteristhebuilder I have added the changed sketch to my answer. There are many libraries with "DHT.h" and no one uses the SoftwareServo anymore because that became the normal Arduino Servo library. – Jot Jan 4 at 8:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.