Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* MEAL Project (Mindful Eating through Ambient Light)
- *
- * This sketch takes input from 3 pressure sensors (FlexiForce 100 lb)
- * and uses this data to track the weight of food consumed.
- * It outputs changes in a light source in response (BlinkM RGB LEDs).
- *
- * For example:
- *
- * Plug in the device.
- * Turn on the lamp by pressing the power button. Minimum load is recorded.
- * Place a dish or individual items on the load sensing platform.
- * Press the calibrate button to register the maximum load.
- * Begin removing items from the platter.
- *
- * If the load decreases, we infer that the person is eating.
- * The light source shifts from red (a color that stimulates appetite)
- * to blue (a color that promotes relaxation),
- * signalling the eater to pause and reflect.
- *
- * FlexiForce connections to Arduino
- * Sensor pin 1 -- Analog In 0
- * Sensor pin 1 -- 2M ohm resistor -- 5V
- * Sensor pin 2 -- Gnd
- *
- * BlinkM connections to Arduino
- * PWR - -- gnd -- black -- Gnd
- * PWR + -- +5V -- red -- 5V
- * I2C d -- SDA -- green -- Analog In 4
- * I2C c -- SCK -- blue -- Analog In 5
- *
- * Note: This sketch sends to the I2C "broadcast" address of 0,
- * so all BlinkMs on the I2C bus will respond.
- *
- * by Corinna Sherman
- * December 3, 2010
- */
- #include <QueueArray.h>
- #include <Wire.h>
- #include "BlinkM_funcs.h"
- // BlinkM constants
- const int blinkmAddr = 0; // general call to all BlinkMs
- const int initialHue = 20; // yellow
- const int hueMin = 0; // red
- const int hueMax = 160; // blue
- const int brightnessMin = 0;
- const int brightnessMax = 255;
- const int saturationMin = 0;
- const int saturationMax = 255;
- // Pressure sensor constants
- const int pressureSensorCount = 3; // number of pressure sensors
- const int pressureSensorPin[pressureSensorCount] = { 0, 1, 2 }; // analog input pins for the pressure sensors
- const int pressureSensorMin = 0; // minimum value that can be produced by a pressure sensor (when load sensed is 100 lbs)
- const int pressureSensorMax = 1023; // maximum value that can be produced by a pressure sensor (when load sensed is 0)
- const int queueSize = 5; // variable to hold the size of the queue
- const int pressureChangeThreshold = 50; // variable to specify the threshold amount beyond which a change in pressure triggers a reaction
- // Input pins
- const int powerSwitchPin = 7; // digital input pin for momentary switch that controls power to circuits
- const int calibrateSwitchPin = 12; // digital input pin for momentary switch that triggers calibration mode
- // Variables
- int lampState; // variable to store ON/OFF state of lamp; set by lampOn() and lampOff()
- int powerButtonState; // variable to store state of the momentary switch that is the power button
- int calibrateButtonState; // variable to store state of the momentary switch that is the calibration button
- int calibratedMaxLoad = 0; // 0 if never calibrated, 1 if calibrated at least once
- int lastKnownHueValue = hueMin; // variable to store the last known hue of the lamp light
- // Variables related to the total pressure sensed by the system through all sensors
- int pressureMin = pressureSensorCount * pressureSensorMin; // variable to hold minimum total pressure value (set at calibration)
- int pressureMax = pressureSensorCount * pressureSensorMax; // variable to hold maximum pressure value
- int pressureAve = 0; // variable to hold the average of the summed sensor values from the last <queueSize> readings
- QueueArray <int> queue; // variable to hold the last <queueSize> summed values of sensor readings (for average smoothing purposes)
- void setup() {
- // Initialize serial communication
- Serial.begin(19200);
- Serial.println("Initializing");
- // Initialize the power switch.
- pinMode(powerSwitchPin, INPUT);
- // Initialize the calibration switch.
- pinMode(calibrateSwitchPin, INPUT);
- // Store the intial powerButtonState based on the powerpowerSwitchPin.
- powerButtonState = digitalRead(powerSwitchPin);
- // Store the initial calibrateButtonState based on the calibrate switch
- calibrateButtonState = digitalRead(calibrateSwitchPin);
- // Initialize all BlinkM modules on the I2C bus
- Serial.println("beginWithPower");
- BlinkM_beginWithPower();
- Serial.println("stopScript");
- BlinkM_stopScript(blinkmAddr); // turn off startup script
- Serial.println("lampOff");
- lampOff(); // The lamp is initially OFF.
- // Set the printer of the queue
- queue.setPrinter(Serial);
- Serial.println("Ready");
- }
- void loop() {
- // Check if the momentary switch for power is being closed,
- // and turn the lamp on or off accordingly.
- int powerSwitchState = digitalRead(powerSwitchPin);
- if (powerSwitchState != powerButtonState) { // The state has changed.
- if (powerSwitchState == HIGH) { // If switch is closed
- if (lampState == 0) { // and if lamp is OFF,
- lampOn(); // then turn lamp on.
- }
- else { // Else lamp is ON
- lampOff(); // then turn lamp off.
- }
- }
- }
- powerButtonState = powerSwitchState; // Remember the current switch state.
- // Check if the momentary switch for calibration is being closed
- // and, if it is, calibrate the sensor.
- int calibrateSwitchState = digitalRead(calibrateSwitchPin);
- if (calibrateSwitchState != calibrateButtonState) { // The state has changed.
- if (calibrateSwitchState == HIGH) { // If switch is closed,
- calibrateMaxLoad(); // calibrate the system.
- }
- }
- // Remember the current calibrate switch state.
- calibrateButtonState = calibrateSwitchState;
- // If the lamp is ON, monitor for changes in weight
- // and update the lamp hue accordingly.
- if (lampState == 1) {
- // Read the pressure sensors. Values range from 0-1023.
- // Add each reading to sumSensorValues.
- int sumSensorValues = 0; // variable to hold the sum the values from all the pressure sensors
- for (int i = 0; i < pressureSensorCount; i++) {
- sumSensorValues += analogRead(pressureSensorPin[i]);
- }
- // If the system has not been calibrated yet, monitor the load and
- // shift the lamp hue from blue to red to indicate when enough weight has been
- // added to the platter to exceed the pressureChangeThreshold.
- // If the system has already been calibrated, monitor the load and
- // shift the lamp hue from red to blue to indicate
- // when the load has dropped to the triggerPressure,
- // which is some percentage of the total load set at calibration.
- if (calibratedMaxLoad) {
- monitorEating(sumSensorValues);
- } else {
- monitorServing(sumSensorValues);
- }
- }
- }
- // We expect the load to increase as food is added to the platter.
- // Switch the lamp hue from blue to red once the load increases from its minimum
- // to an amount greater than pressureMin + 2*pressureChangeThreshold.
- // Argument sumSensorValues is the sum of current sensor readings.
- void monitorServing(int sumSensorValues) {
- queue.pop(); // pop the oldest reading from the queue
- queue.push(sumSensorValues); // push this reading into the queue
- pressureAve = calculateAveragePressure(); // Store the new average pressure
- if (pressureAve > pressureMax) {
- setPressureMax(pressureAve);
- }
- Serial.print("pressure (ave, min, max): ");
- Serial.print(pressureAve);
- Serial.print(", ");
- Serial.print(pressureMin);
- Serial.print(", ");
- Serial.println(pressureMax);
- // If the average pressure has increased by more than twice the threshold amount, update the hue.
- if (abs(pressureMax - pressureAve) > pressureChangeThreshold * 2) {
- // Blink red to indicate calibration can take place.
- BlinkM_fadeToHSB( blinkmAddr, hueMin, saturationMax, brightnessMin);
- delay(750);
- BlinkM_fadeToHSB( blinkmAddr, hueMin, saturationMax, brightnessMax);
- delay(750);
- } else {
- BlinkM_fadeToHSB( blinkmAddr, initialHue, saturationMax, brightnessMax);
- }
- }
- // We expect the load to decrease as food is eaten.
- // Shift the lamp hue from red to blue as pressureAve decreases to approach the trigger pressure.
- // Argument sumSensorValues is the sum of current sensor readings.
- void monitorEating(int sumSensorValues) {
- // If the pressure has changed from last time by
- // more than the threshold amount, update the hue.
- if (abs(sumSensorValues - pressureAve) > pressureChangeThreshold) {
- // Update the average pressure based on the current reading
- queue.pop(); // pop the oldest reading from the queue
- queue.push(sumSensorValues); // push this reading into the queue
- pressureAve = calculateAveragePressure(); // Store the new average pressure
- Serial.print("pressure (ave, min, max, trigger): ");
- Serial.print(pressureAve);
- Serial.print(", ");
- Serial.print(pressureMin);
- Serial.print(", ");
- Serial.println(pressureMax);
- // Map so that the lamp hue is red (0)
- // when the sensor reading is at its minimum (load is at its maximum)
- // and shifts to blue (160) as the sensor reading increases (load decreases).
- setLampHue(map(pressureAve, pressureMin, pressureMax, hueMin, hueMax));
- }
- }
- // Store the new hue value and update lamp hue
- void setLampHue(int value) {
- int hueValue = constrain(value, hueMin, hueMax); // Don't allow a negative number or a number greater than 255.
- // Store the new hue value.
- lastKnownHueValue = hueValue;
- // Set blinkms with hue; saturation and brightness are at maximum value.
- BlinkM_fadeToHSB( blinkmAddr, hueValue, saturationMax, brightnessMax);
- delay(50); // wait a bit because we don't need to go fast
- Serial.print("Set hue to ");
- Serial.println(hueValue);
- }
- // Turn the lamp on
- void lampOn() {
- // Set the pressureMax based on the initial state (platform is assumed to be empty)
- int pressure = calibrateMinLoad();
- // Ensure the queue is empty first.
- while (!queue.isEmpty()) {
- queue.pop();
- }
- // Then push the current pressure value into the queue.
- for (int i = 0; i < queueSize; i++) {
- queue.push(pressure);
- }
- // Turn on the lights
- BlinkM_fadeToHSB( blinkmAddr, initialHue, saturationMax, brightnessMax);
- lampState = 1;
- // Reset the state of calibration for the maximum load
- calibratedMaxLoad = 0;
- Serial.println("Lamp is ON");
- }
- // Turn the lamp off
- void lampOff() {
- // Pop all the sensor readings from the queue.
- while (!queue.isEmpty ()) {
- queue.pop();
- }
- BlinkM_fadeToHSB( blinkmAddr, lastKnownHueValue, saturationMin, brightnessMin );
- lampState = 0;
- Serial.println("Lamp is OFF");
- }
- void setPressureMin(int value) {
- pressureMin = constrain(value, pressureSensorCount * pressureSensorMin, pressureSensorCount * pressureSensorMax);
- Serial.print("Setting floor resistance to ");
- Serial.println(pressureMin);
- }
- void setPressureMax(int value) {
- pressureMax = constrain(value, pressureSensorCount * pressureSensorMin, pressureSensorCount * pressureSensorMax);
- Serial.print("Setting ceiling resistance to ");
- Serial.println(pressureMax);
- }
- // Set the pressureMax based on the initial state (platform is assumed to be empty)
- // and return the sum of sensor values.
- int calibrateMinLoad() {
- Serial.println("Calibrating for minimum load...");
- int sumSensorValues = 0; // variable to hold the sum the values from all the pressure sensors
- for (int i = 0; i < pressureSensorCount; i++) {
- int reading = analogRead(pressureSensorPin[i]);
- Serial.print("pin ");
- Serial.print(i);
- Serial.print(": ");
- Serial.println(reading);
- sumSensorValues += reading;
- }
- // Set the summed sensor reading as the minimum pressure (meaning the load to monitor will be added afterward).
- setPressureMax(sumSensorValues);
- return sumSensorValues;
- }
- void calibrateMaxLoad() {
- Serial.println("Calibrating for maximum load...");
- int sumSensorValues = 0; // variable to hold the sum the values from all the pressure sensors
- // Sum the current sensor readings.
- // Set this value as the minimum pressure,
- // thus assuming the sum of sensor readings will increase over time (meaning the load will decrease over time).
- for (int i = 0; i < pressureSensorCount; i++) {
- sumSensorValues += analogRead(pressureSensorPin[i]);
- }
- setPressureMin(sumSensorValues);
- Serial.print("pressureMin = ");
- Serial.println(pressureMin);
- Serial.print("pressureMax = ");
- Serial.println(pressureMax);
- // Map so that the lamp hue is red (0)
- // when the sensor reading is at its minimum (load is at its maximum)
- // and shifts to blue (160) as the sensor reading increases (load decreases).
- setLampHue(map(sumSensorValues, pressureMin, pressureMax, hueMin, hueMax));
- calibratedMaxLoad = 1;
- }
- // Calculate the average of the summed sensor values in the queue
- int calculateAveragePressure() {
- /*Serial.println("Calculating average pressure...");
- Serial.print("queue items: ");
- Serial.println(queue.count());*/
- if (queue.count() > 0) {
- int sum = 0;
- int size = 0;
- QueueArray<int> tempQueue;
- tempQueue.setPrinter(Serial);
- // Sum the values currently stored in queue.
- while (!queue.isEmpty()) {
- int value = queue.pop();
- sum += value;
- size++;
- tempQueue.push(value);
- /*Serial.println(value);
- Serial.print("queue items: ");
- Serial.println(queue.count());*/
- }
- while(!tempQueue.isEmpty()) {
- queue.push(tempQueue.pop());
- }
- //Serial.print("Average pressure = ");
- //Serial.println(sum/size);
- return sum/size; // We lose fractional amounts in this operation since the arguments are ints, but who cares? This ain't rocket science.
- }
- else {
- //Serial.print("Average pressure = 0");
- return 0; // If there are no values to be averaged, return 0.
- }
- }
Add Comment
Please, Sign In to add comment