Guest User

Untitled

a guest
Jul 16th, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.55 KB | None | 0 0
  1. /* MEAL Project (Mindful Eating through Ambient Light)
  2. *
  3. * This sketch takes input from 3 pressure sensors (FlexiForce 100 lb)
  4. * and uses this data to track the weight of food consumed.
  5. * It outputs changes in a light source in response (BlinkM RGB LEDs).
  6. *
  7. * For example:
  8. *
  9. * Plug in the device.
  10. * Turn on the lamp by pressing the power button. Minimum load is recorded.
  11. * Place a dish or individual items on the load sensing platform.
  12. * Press the calibrate button to register the maximum load.
  13. * Begin removing items from the platter.
  14. *
  15. * If the load decreases, we infer that the person is eating.
  16. * The light source shifts from red (a color that stimulates appetite)
  17. * to blue (a color that promotes relaxation),
  18. * signalling the eater to pause and reflect.
  19. *
  20. * FlexiForce connections to Arduino
  21. * Sensor pin 1 -- Analog In 0
  22. * Sensor pin 1 -- 2M ohm resistor -- 5V
  23. * Sensor pin 2 -- Gnd
  24. *
  25. * BlinkM connections to Arduino
  26. * PWR - -- gnd -- black -- Gnd
  27. * PWR + -- +5V -- red -- 5V
  28. * I2C d -- SDA -- green -- Analog In 4
  29. * I2C c -- SCK -- blue -- Analog In 5
  30. *
  31. * Note: This sketch sends to the I2C "broadcast" address of 0,
  32. * so all BlinkMs on the I2C bus will respond.
  33. *
  34. * by Corinna Sherman
  35. * December 3, 2010
  36. */
  37.  
  38. #include <QueueArray.h>
  39. #include <Wire.h>
  40. #include "BlinkM_funcs.h"
  41.  
  42. // BlinkM constants
  43. const int blinkmAddr = 0; // general call to all BlinkMs
  44. const int initialHue = 20; // yellow
  45. const int hueMin = 0; // red
  46. const int hueMax = 160; // blue
  47. const int brightnessMin = 0;
  48. const int brightnessMax = 255;
  49. const int saturationMin = 0;
  50. const int saturationMax = 255;
  51.  
  52. // Pressure sensor constants
  53. const int pressureSensorCount = 3; // number of pressure sensors
  54. const int pressureSensorPin[pressureSensorCount] = { 0, 1, 2 }; // analog input pins for the pressure sensors
  55. const int pressureSensorMin = 0; // minimum value that can be produced by a pressure sensor (when load sensed is 100 lbs)
  56. const int pressureSensorMax = 1023; // maximum value that can be produced by a pressure sensor (when load sensed is 0)
  57. const int queueSize = 5; // variable to hold the size of the queue
  58. const int pressureChangeThreshold = 50; // variable to specify the threshold amount beyond which a change in pressure triggers a reaction
  59.  
  60. // Input pins
  61. const int powerSwitchPin = 7; // digital input pin for momentary switch that controls power to circuits
  62. const int calibrateSwitchPin = 12; // digital input pin for momentary switch that triggers calibration mode
  63.  
  64. // Variables
  65. int lampState; // variable to store ON/OFF state of lamp; set by lampOn() and lampOff()
  66. int powerButtonState; // variable to store state of the momentary switch that is the power button
  67. int calibrateButtonState; // variable to store state of the momentary switch that is the calibration button
  68. int calibratedMaxLoad = 0; // 0 if never calibrated, 1 if calibrated at least once
  69.  
  70. int lastKnownHueValue = hueMin; // variable to store the last known hue of the lamp light
  71.  
  72. // Variables related to the total pressure sensed by the system through all sensors
  73. int pressureMin = pressureSensorCount * pressureSensorMin; // variable to hold minimum total pressure value (set at calibration)
  74. int pressureMax = pressureSensorCount * pressureSensorMax; // variable to hold maximum pressure value
  75. int pressureAve = 0; // variable to hold the average of the summed sensor values from the last <queueSize> readings
  76. QueueArray <int> queue; // variable to hold the last <queueSize> summed values of sensor readings (for average smoothing purposes)
  77.  
  78. void setup() {
  79.  
  80. // Initialize serial communication
  81. Serial.begin(19200);
  82.  
  83. Serial.println("Initializing");
  84.  
  85. // Initialize the power switch.
  86. pinMode(powerSwitchPin, INPUT);
  87.  
  88. // Initialize the calibration switch.
  89. pinMode(calibrateSwitchPin, INPUT);
  90.  
  91. // Store the intial powerButtonState based on the powerpowerSwitchPin.
  92. powerButtonState = digitalRead(powerSwitchPin);
  93.  
  94. // Store the initial calibrateButtonState based on the calibrate switch
  95. calibrateButtonState = digitalRead(calibrateSwitchPin);
  96.  
  97. // Initialize all BlinkM modules on the I2C bus
  98. Serial.println("beginWithPower");
  99. BlinkM_beginWithPower();
  100. Serial.println("stopScript");
  101. BlinkM_stopScript(blinkmAddr); // turn off startup script
  102. Serial.println("lampOff");
  103. lampOff(); // The lamp is initially OFF.
  104.  
  105. // Set the printer of the queue
  106. queue.setPrinter(Serial);
  107.  
  108. Serial.println("Ready");
  109.  
  110. }
  111.  
  112. void loop() {
  113.  
  114. // Check if the momentary switch for power is being closed,
  115. // and turn the lamp on or off accordingly.
  116.  
  117. int powerSwitchState = digitalRead(powerSwitchPin);
  118. if (powerSwitchState != powerButtonState) { // The state has changed.
  119. if (powerSwitchState == HIGH) { // If switch is closed
  120. if (lampState == 0) { // and if lamp is OFF,
  121. lampOn(); // then turn lamp on.
  122. }
  123. else { // Else lamp is ON
  124. lampOff(); // then turn lamp off.
  125. }
  126. }
  127. }
  128.  
  129. powerButtonState = powerSwitchState; // Remember the current switch state.
  130.  
  131. // Check if the momentary switch for calibration is being closed
  132. // and, if it is, calibrate the sensor.
  133.  
  134. int calibrateSwitchState = digitalRead(calibrateSwitchPin);
  135. if (calibrateSwitchState != calibrateButtonState) { // The state has changed.
  136. if (calibrateSwitchState == HIGH) { // If switch is closed,
  137. calibrateMaxLoad(); // calibrate the system.
  138. }
  139. }
  140.  
  141. // Remember the current calibrate switch state.
  142. calibrateButtonState = calibrateSwitchState;
  143.  
  144. // If the lamp is ON, monitor for changes in weight
  145. // and update the lamp hue accordingly.
  146.  
  147. if (lampState == 1) {
  148.  
  149. // Read the pressure sensors. Values range from 0-1023.
  150. // Add each reading to sumSensorValues.
  151. int sumSensorValues = 0; // variable to hold the sum the values from all the pressure sensors
  152. for (int i = 0; i < pressureSensorCount; i++) {
  153. sumSensorValues += analogRead(pressureSensorPin[i]);
  154. }
  155.  
  156. // If the system has not been calibrated yet, monitor the load and
  157. // shift the lamp hue from blue to red to indicate when enough weight has been
  158. // added to the platter to exceed the pressureChangeThreshold.
  159. // If the system has already been calibrated, monitor the load and
  160. // shift the lamp hue from red to blue to indicate
  161. // when the load has dropped to the triggerPressure,
  162. // which is some percentage of the total load set at calibration.
  163. if (calibratedMaxLoad) {
  164. monitorEating(sumSensorValues);
  165. } else {
  166. monitorServing(sumSensorValues);
  167. }
  168.  
  169. }
  170.  
  171. }
  172.  
  173. // We expect the load to increase as food is added to the platter.
  174. // Switch the lamp hue from blue to red once the load increases from its minimum
  175. // to an amount greater than pressureMin + 2*pressureChangeThreshold.
  176. // Argument sumSensorValues is the sum of current sensor readings.
  177. void monitorServing(int sumSensorValues) {
  178.  
  179. queue.pop(); // pop the oldest reading from the queue
  180. queue.push(sumSensorValues); // push this reading into the queue
  181. pressureAve = calculateAveragePressure(); // Store the new average pressure
  182.  
  183. if (pressureAve > pressureMax) {
  184. setPressureMax(pressureAve);
  185. }
  186.  
  187. Serial.print("pressure (ave, min, max): ");
  188. Serial.print(pressureAve);
  189. Serial.print(", ");
  190. Serial.print(pressureMin);
  191. Serial.print(", ");
  192. Serial.println(pressureMax);
  193.  
  194. // If the average pressure has increased by more than twice the threshold amount, update the hue.
  195. if (abs(pressureMax - pressureAve) > pressureChangeThreshold * 2) {
  196.  
  197. // Blink red to indicate calibration can take place.
  198. BlinkM_fadeToHSB( blinkmAddr, hueMin, saturationMax, brightnessMin);
  199. delay(750);
  200. BlinkM_fadeToHSB( blinkmAddr, hueMin, saturationMax, brightnessMax);
  201. delay(750);
  202. } else {
  203. BlinkM_fadeToHSB( blinkmAddr, initialHue, saturationMax, brightnessMax);
  204. }
  205. }
  206.  
  207. // We expect the load to decrease as food is eaten.
  208. // Shift the lamp hue from red to blue as pressureAve decreases to approach the trigger pressure.
  209. // Argument sumSensorValues is the sum of current sensor readings.
  210. void monitorEating(int sumSensorValues) {
  211.  
  212. // If the pressure has changed from last time by
  213. // more than the threshold amount, update the hue.
  214. if (abs(sumSensorValues - pressureAve) > pressureChangeThreshold) {
  215.  
  216. // Update the average pressure based on the current reading
  217. queue.pop(); // pop the oldest reading from the queue
  218. queue.push(sumSensorValues); // push this reading into the queue
  219. pressureAve = calculateAveragePressure(); // Store the new average pressure
  220.  
  221. Serial.print("pressure (ave, min, max, trigger): ");
  222. Serial.print(pressureAve);
  223. Serial.print(", ");
  224. Serial.print(pressureMin);
  225. Serial.print(", ");
  226. Serial.println(pressureMax);
  227.  
  228. // Map so that the lamp hue is red (0)
  229. // when the sensor reading is at its minimum (load is at its maximum)
  230. // and shifts to blue (160) as the sensor reading increases (load decreases).
  231. setLampHue(map(pressureAve, pressureMin, pressureMax, hueMin, hueMax));
  232. }
  233. }
  234.  
  235. // Store the new hue value and update lamp hue
  236. void setLampHue(int value) {
  237.  
  238. int hueValue = constrain(value, hueMin, hueMax); // Don't allow a negative number or a number greater than 255.
  239.  
  240. // Store the new hue value.
  241. lastKnownHueValue = hueValue;
  242.  
  243. // Set blinkms with hue; saturation and brightness are at maximum value.
  244. BlinkM_fadeToHSB( blinkmAddr, hueValue, saturationMax, brightnessMax);
  245. delay(50); // wait a bit because we don't need to go fast
  246.  
  247. Serial.print("Set hue to ");
  248. Serial.println(hueValue);
  249. }
  250.  
  251. // Turn the lamp on
  252. void lampOn() {
  253.  
  254. // Set the pressureMax based on the initial state (platform is assumed to be empty)
  255. int pressure = calibrateMinLoad();
  256.  
  257. // Ensure the queue is empty first.
  258. while (!queue.isEmpty()) {
  259. queue.pop();
  260. }
  261.  
  262. // Then push the current pressure value into the queue.
  263. for (int i = 0; i < queueSize; i++) {
  264. queue.push(pressure);
  265. }
  266.  
  267. // Turn on the lights
  268. BlinkM_fadeToHSB( blinkmAddr, initialHue, saturationMax, brightnessMax);
  269. lampState = 1;
  270.  
  271. // Reset the state of calibration for the maximum load
  272. calibratedMaxLoad = 0;
  273.  
  274. Serial.println("Lamp is ON");
  275. }
  276.  
  277. // Turn the lamp off
  278. void lampOff() {
  279.  
  280. // Pop all the sensor readings from the queue.
  281. while (!queue.isEmpty ()) {
  282. queue.pop();
  283. }
  284.  
  285. BlinkM_fadeToHSB( blinkmAddr, lastKnownHueValue, saturationMin, brightnessMin );
  286. lampState = 0;
  287. Serial.println("Lamp is OFF");
  288. }
  289.  
  290. void setPressureMin(int value) {
  291. pressureMin = constrain(value, pressureSensorCount * pressureSensorMin, pressureSensorCount * pressureSensorMax);
  292. Serial.print("Setting floor resistance to ");
  293. Serial.println(pressureMin);
  294. }
  295.  
  296. void setPressureMax(int value) {
  297. pressureMax = constrain(value, pressureSensorCount * pressureSensorMin, pressureSensorCount * pressureSensorMax);
  298. Serial.print("Setting ceiling resistance to ");
  299. Serial.println(pressureMax);
  300. }
  301.  
  302. // Set the pressureMax based on the initial state (platform is assumed to be empty)
  303. // and return the sum of sensor values.
  304. int calibrateMinLoad() {
  305.  
  306. Serial.println("Calibrating for minimum load...");
  307.  
  308. int sumSensorValues = 0; // variable to hold the sum the values from all the pressure sensors
  309.  
  310. for (int i = 0; i < pressureSensorCount; i++) {
  311. int reading = analogRead(pressureSensorPin[i]);
  312. Serial.print("pin ");
  313. Serial.print(i);
  314. Serial.print(": ");
  315. Serial.println(reading);
  316. sumSensorValues += reading;
  317. }
  318.  
  319. // Set the summed sensor reading as the minimum pressure (meaning the load to monitor will be added afterward).
  320. setPressureMax(sumSensorValues);
  321.  
  322. return sumSensorValues;
  323. }
  324.  
  325. void calibrateMaxLoad() {
  326.  
  327. Serial.println("Calibrating for maximum load...");
  328.  
  329. int sumSensorValues = 0; // variable to hold the sum the values from all the pressure sensors
  330.  
  331. // Sum the current sensor readings.
  332. // Set this value as the minimum pressure,
  333. // thus assuming the sum of sensor readings will increase over time (meaning the load will decrease over time).
  334. for (int i = 0; i < pressureSensorCount; i++) {
  335. sumSensorValues += analogRead(pressureSensorPin[i]);
  336. }
  337.  
  338. setPressureMin(sumSensorValues);
  339.  
  340. Serial.print("pressureMin = ");
  341. Serial.println(pressureMin);
  342. Serial.print("pressureMax = ");
  343. Serial.println(pressureMax);
  344.  
  345. // Map so that the lamp hue is red (0)
  346. // when the sensor reading is at its minimum (load is at its maximum)
  347. // and shifts to blue (160) as the sensor reading increases (load decreases).
  348. setLampHue(map(sumSensorValues, pressureMin, pressureMax, hueMin, hueMax));
  349.  
  350. calibratedMaxLoad = 1;
  351. }
  352.  
  353. // Calculate the average of the summed sensor values in the queue
  354. int calculateAveragePressure() {
  355.  
  356. /*Serial.println("Calculating average pressure...");
  357. Serial.print("queue items: ");
  358. Serial.println(queue.count());*/
  359.  
  360. if (queue.count() > 0) {
  361.  
  362. int sum = 0;
  363. int size = 0;
  364. QueueArray<int> tempQueue;
  365. tempQueue.setPrinter(Serial);
  366.  
  367. // Sum the values currently stored in queue.
  368. while (!queue.isEmpty()) {
  369. int value = queue.pop();
  370. sum += value;
  371. size++;
  372. tempQueue.push(value);
  373. /*Serial.println(value);
  374. Serial.print("queue items: ");
  375. Serial.println(queue.count());*/
  376. }
  377.  
  378. while(!tempQueue.isEmpty()) {
  379. queue.push(tempQueue.pop());
  380. }
  381.  
  382. //Serial.print("Average pressure = ");
  383. //Serial.println(sum/size);
  384. return sum/size; // We lose fractional amounts in this operation since the arguments are ints, but who cares? This ain't rocket science.
  385. }
  386. else {
  387. //Serial.print("Average pressure = 0");
  388. return 0; // If there are no values to be averaged, return 0.
  389. }
  390. }
Add Comment
Please, Sign In to add comment