sparkfun Weather Shield with cableing

sparkfun Weather Shield with cableing

The ideas is to translate the measurements from the sensors into movement of the servos.
The sparkfun weather shield gives us:

  • Temperature
  • Humidity
  • Ambient light
  • atmospheric pressure

I collect the data every 10 seconds and do an average between the last ten values to smooth out misreadings. Furthermore the measured values must be mapped to the angles the servo can display on the scales, so we have to calibrate this. To achieve this calibration you need to find out the min and max angle the servo has on the scale and to set the min and max value of the measurement. (see in the code below).

The hardware is describe in part 2 and the scales LaTeX code is in part 1.

And here is the code:

#include <Servo.h>
#include <math.h>
#include <Wire.h> //I2C needed for sensors
#include "MPL3115A2.h" //Pressure sensor
#include "HTU21D.h" //Humidity sensor
//---------------------------------------------
#define DEBUG false
#define warningLED 8
#define statusLED 7
#define timeBetweenMeasurements 10000
#define timeToResetMinMax 10
int runs = 0;
//---------------------------------------------
MPL3115A2 pressureSensor;
HTU21D humiditySensor;
// analog I/O pins
const byte REFERENCE_3V3 = A3;
const byte LIGHT = A1;
const byte BATT = A2;
float light_lvl = 455;
float batt_lvl = 11.8;
//---------------------------------------------
// Kind
#define Celsius 0
#define Pressure 1
#define Humidity 2
#define Light 3

// min max Values
#define minValue 0
#define maxValue 1
#define minDegree 2
#define maxDegree 3
#define oldDegree 4
#define minAlltime 5
#define maxAlltime 6
#define currentValue 7
float definition[4][8]; //Kind Value

//---------------------------------------------
#define servoCelsiusPIN 9
Servo servoCelsius;
//---------------------------------------------
float base_altitude = 531.0; //meters above normal sealevel
#define servoPressurePIN 10
Servo servoPressure;
//---------------------------------------------
#define servoHumidityPIN 5
Servo servoHumidity;
//---------------------------------------------
#define servoLightPIN 6
Servo servoLight;
//---------------------------------------------

//---------------------------------------------
// This translates our working degree space (0-180) aka left to
// the range the given servo aka right (eg. biceps from 40-175)
// make sure, we do not have values outside the working degree space too
float translate( float value, float leftMin, float leftMax, float rightMin, float rightMax) {
  value = ( value < leftMin ) ? leftMin : value;
  value = ( value > leftMax ) ? leftMax : value;
  float leftSpan = leftMax - leftMin;      // eg. 180
  float rightSpan = rightMax - rightMin;   // eg. 135
  float valueScaled = (value - leftMin) / leftSpan; // (value - 0 ) / 180
  return rightMin + (valueScaled * rightSpan);  // return = 40 + ( valueScaled * 135 )
}

//---------------------------------------------
double sealevel(double P, double A)
// Given a pressure P (Pa) taken at a specific altitude (meters),
// return the equivalent pressure (mb) at sea level.
// This produces pressure readings that can be used for weather measurements.
{
  return((P/100)/pow(1-(A/44330.0),5.255));
}

//---------------------------------------------
void displayValue(int kind)
{
  switch (kind) {
     case Celsius:
       definition[kind][currentValue] = humiditySensor.readTemperature();
       break;
     case Pressure:
       definition[kind][currentValue] = sealevel((pressureSensor.readPressure()), base_altitude);
       break;
     case Humidity:
       definition[kind][currentValue] = humiditySensor.readHumidity();
       break;
     case Light:
       definition[kind][currentValue] = get_light_level();
       break;
     default:
       break;
  }

  if ( (definition[kind][currentValue] < definition[kind][minValue]) || (definition[kind][maxValue] < definition[kind][currentValue]) )
    digitalWrite(warningLED, HIGH);
  else
    digitalWrite(warningLED, LOW);

  float newDegree = translate((definition[kind][maxAlltime]+definition[kind][minAlltime])/2.0,definition[kind][minValue],definition[kind][maxValue],definition[kind][minDegree],definition[kind][maxDegree]);
  
  if (DEBUG) Serial.print("[");
  if (DEBUG) Serial.print(definition[kind][minAlltime]);
  if (DEBUG) Serial.print("<");
  if (DEBUG) Serial.print(definition[kind][currentValue]);
  if (DEBUG) Serial.print("<");
  if (DEBUG) Serial.print(definition[kind][maxAlltime]);
  if (DEBUG) Serial.print("#");
  if (DEBUG) Serial.print((definition[kind][maxAlltime]+definition[kind][minAlltime])/2.0);
  if ( (int)newDegree != (int)definition[kind][oldDegree] ) {
    switch (kind)
    {
      case Celsius:
        servoCelsius.write((int)newDegree);
        break;
      case Pressure:
        servoPressure.write((int)newDegree);
        break;
      case Humidity:
        servoHumidity.write((int)newDegree);
        break;
      case Light:
        servoLight.write((int)newDegree);
        break;
      default:
        break;
    }
    if (DEBUG) Serial.print("=>");
  } else if (DEBUG) Serial.print ("->");  
  if (DEBUG) Serial.print((int)newDegree);
  if (DEBUG) Serial.print("]");
  definition[kind][oldDegree] = newDegree;
  definition[kind][minAlltime] = ( definition[kind][minAlltime] < definition[kind][currentValue] ) ? definition[kind][minAlltime] : definition[kind][currentValue];
  definition[kind][maxAlltime] = ( definition[kind][maxAlltime] > definition[kind][currentValue] ) ? definition[kind][maxAlltime] : definition[kind][currentValue];
}

//---------------------------------------------
void testServos()
{
  digitalWrite(warningLED, HIGH);
  servoCelsius.write(definition[Celsius][minDegree]);
  servoPressure.write(definition[Pressure][minDegree]);
  servoHumidity.write(definition[Humidity][minDegree]);
  servoLight.write(definition[Light][minDegree]);
  digitalWrite(warningLED, LOW);
  delay(100);
  digitalWrite(warningLED, HIGH);
  delay(200);
  digitalWrite(warningLED, LOW);
  delay(100);
  digitalWrite(warningLED, HIGH);
  delay(2000);
  servoCelsius.write(definition[Celsius][maxDegree]);
  servoPressure.write(definition[Pressure][maxDegree]);
  servoHumidity.write(definition[Humidity][maxDegree]);
  servoLight.write(definition[Light][maxDegree]);
  digitalWrite(warningLED, LOW);
  delay(100);
  digitalWrite(warningLED, HIGH);
  delay(1000);
  servoCelsius.write(definition[Celsius][minDegree]);
  servoPressure.write(definition[Pressure][minDegree]);
  servoHumidity.write(definition[Humidity][minDegree]);
  servoLight.write(definition[Light][minDegree]);
  delay(1000);
  digitalWrite(warningLED, LOW);
}

//Returns the voltage of the raw pin based on the 3.3V rail
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V)
//Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors:
//3.9K on the high side (R1), and 1K on the low side (R2)
float get_battery_level()
{
  float operatingVoltage = analogRead(REFERENCE_3V3);
  float rawVoltage = analogRead(BATT);
  operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V
  rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin
  rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage
  return(rawVoltage);
}

//Returns the voltage of the light sensor based on the 3.3V rail
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V)
float get_light_level()
{
  float operatingVoltage = analogRead(REFERENCE_3V3);
  float lightSensor = analogRead(LIGHT);
  operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V
  lightSensor = operatingVoltage * lightSensor;
  return(lightSensor);
}
//---------------------------------------------
void setup()
{
  if (DEBUG) Serial.begin(9600);
    
  // Define the pins
  pinMode(warningLED, OUTPUT); //Status LED Blue
  pinMode(statusLED, OUTPUT);
  pinMode(REFERENCE_3V3, INPUT);
  pinMode(LIGHT, INPUT);

  //Configure the pressure sensor
  pressureSensor.begin(); // Get sensor online
  pressureSensor.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
  pressureSensor.setOversampleRate(7); // Set Oversample to the recommended 128
  pressureSensor.enableEventFlags(); // Enable all three pressure and temp event flags 
  
  //Configure the humidity sensor
  humiditySensor.begin();
  
  // Fill the min/max array
  definition[Celsius][minValue] = -20.0;
  definition[Celsius][maxValue] = 70.0;
  definition[Celsius][minDegree] = 15.0;
  definition[Celsius][maxDegree] = 115.0;
  definition[Celsius][oldDegree] = definition[Celsius][minDegree];
  definition[Celsius][minAlltime] = definition[Celsius][maxValue];
  definition[Celsius][maxAlltime] = definition[Celsius][minValue];
  
  definition[Pressure][minValue] = 970.0;
  definition[Pressure][maxValue] = 1040.0;
  definition[Pressure][minDegree] = 10.0;
  definition[Pressure][maxDegree] = 130.0;
  definition[Pressure][oldDegree] = definition[Pressure][minDegree];
  definition[Pressure][minAlltime] = definition[Pressure][maxValue];
  definition[Pressure][maxAlltime] = definition[Pressure][minValue];
  
  definition[Humidity][minValue] = 0.0;
  definition[Humidity][maxValue] = 100.0;
  definition[Humidity][minDegree] = 20.0;
  definition[Humidity][maxDegree] = 105.0;
  definition[Humidity][oldDegree] = definition[Humidity][minDegree];
  definition[Humidity][minAlltime] = definition[Humidity][maxValue];
  definition[Humidity][maxAlltime] = definition[Humidity][minValue];
  
  definition[Light][minValue] = 0.0;
  definition[Light][maxValue] = 3.3;
  definition[Light][minDegree] = 20.0;
  definition[Light][maxDegree] = 125.0;
  definition[Light][oldDegree] = definition[Light][minDegree];
  definition[Light][minAlltime] = definition[Light][maxValue];
  definition[Light][maxAlltime] = definition[Light][minValue];
  
  // Attach the servos
  servoCelsius.attach(servoCelsiusPIN);
  servoCelsius.write(definition[Celsius][minDegree]);
  servoPressure.attach(servoPressurePIN);
  servoPressure.write(definition[Pressure][minDegree]);
  servoHumidity.attach(servoHumidityPIN);
  servoHumidity.write(definition[Humidity][minDegree]);
  servoLight.attach(servoLightPIN);
  servoLight.write(definition[Light][minDegree]);
  delay(200);

  if (DEBUG) testServos();
}

//---------------------------------------------
void loop()
{
  displayValue(Celsius);
  displayValue(Pressure);
  displayValue(Humidity);
  displayValue(Light);
  
  if (DEBUG) {
    //Calc battery level
    batt_lvl = get_battery_level();
    Serial.print("Battery Level:");Serial.print(batt_lvl, 2);Serial.println("V");
  }
  
  digitalWrite(statusLED, HIGH); 
  delay(timeBetweenMeasurements/10);
  digitalWrite(statusLED, LOW);
  
  if (0 == ( ++runs % timeToResetMinMax ) )
  {
    for (int i=0; i<4; i++)
    {
      definition[i][minAlltime] = definition[i][currentValue];
      definition[i][maxAlltime] = definition[i][currentValue];
    }
    runs = 0;
    if (DEBUG) Serial.println("--------------");
  }
  
  delay(9*(timeBetweenMeasurements/10));
}