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)); }
Recent Comments