How to Ensure Your Coffee Machine Never Runs Dry
Use a simple classification model to determine in advance if the water tank needs refilling before making coffee!
Components and supplies
1
Arduino® UNO R4 WiFi
1
ST X-NUCLEO-IKS01A3
Apps and platforms
1
Arduino IDE 1.8.19
1
NanoEdge AI Studio
Project description
Code
data logger code
c
1/* ============= 2Copyright (c) 2024, STMicroelectronics 3 4All rights reserved. 5 6Redistribution and use in source and binary forms, with or without modification, are permitted provided that 7the following conditions are met: 8 9* Redistributions of source code must retain the above copyright notice, this list of conditions and the 10 following disclaimer. 11 12* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 13 following disclaimer in the documentation and/or other materials provided with the distribution. 14 15* Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote 16 products derived from this software without specific prior written permission. 17 18*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 19INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.* 25*/ 26 27/* If you want to use NEAI functions please, include NEAI library 28 * in your Arduino libraries then, uncomment NEAI parts in the following code 29 */ 30 31/* Libraries part */ 32#include "Wire.h" 33#include <LSM6DSOSensor.h> 34// #include <NanoEdgeAI.h> 35 36/* Macros definitions */ 37#define SERIAL_BAUD_RATE 115200 38 39/* Define the data type you want to collect */ 40#define ACCELEROMETER // Could be either ACCELEROMETER or GYROSCOPE 41 42/* Sensor data rates. 43 * You can choose from the following values for both accel & gyro: 44 * 12.5f, 26.0f, 52.0f, 104.0f, 208.0f, 417.0f, 833.0f & 1667.0f. 45 */ 46#define SENSOR_DATA_RATE 1667.0f 47 48/* Sensor ranges. 49 * You can choose from: 50 * 2, 4, 8 & 16 for accelerometer. 51 * 125, 250, 500, 1000 & 2000 for gyroscope. 52 */ 53#define SENSOR_RANGE 8 54 55/* NanoEdgeAI defines part 56 * NEAI_MODE = 1: NanoEdgeAI functions = AI Mode. 57 * NEAI_MODE = 0: Datalogging mode. 58 */ 59#define NEAI_MODE 0 60#define SENSOR_SAMPLES 512 61#define AXIS 3 62 63/* Sensor object declaration using I2C */ 64LSM6DSOSensor AccGyr(&Wire); 65 66/* Global variables definitions */ 67static uint8_t drdy = 0; 68static uint16_t neai_ptr = 0; 69static int32_t sensor_values[3]; 70static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; 71 72/* NEAI library variables */ 73// static uint8_t neai_code = 0, similarity = 0; 74// static uint16_t neai_cnt = 0; 75 76/* Initialization function: In this function, 77 * code runs only once at boot / reset. 78 */ 79void setup() { 80 /* Init serial at baud rate 115200 */ 81 Serial.begin(SERIAL_BAUD_RATE); 82 83 /* I2C workaround: Sometimes, on some boards, 84 * I2C get stuck after software reboot, reset so, 85 * to avoid this, we toggle I2C clock pin at boot. 86 */ 87 pinMode(SCL, OUTPUT); 88 for (uint8_t i = 0; i < 20; i++) { 89 digitalWrite(SCL, !digitalRead(SCL)); 90 delay(1); 91 } 92 delay(100); 93 94 Wire.begin(); 95 AccGyr.begin(); 96#ifdef ACCELEROMETER 97 AccGyr.Enable_X(); 98 AccGyr.Disable_G(); 99 AccGyr.Set_X_ODR(SENSOR_DATA_RATE); 100 AccGyr.Set_X_FS(SENSOR_RANGE); 101#else 102 AccGyr.Enable_G(); 103 AccGyr.Disable_X(); 104 AccGyr.Set_G_ODR(SENSOR_DATA_RATE); 105 AccGyr.Set_G_FS(SENSOR_RANGE); 106#endif 107 108 /* Initialize NanoEdgeAI AI */ 109 // neai_code = neai_anomalydetection_init(); 110 // if(neai_code != NEAI_OK) { 111 // Serial.print("Not supported board.\n"); 112 // } 113} 114 115/* Main function: Code run indefinitely */ 116void loop() { 117 /* Get data in the neai buffer */ 118 while(neai_ptr < SENSOR_SAMPLES) { 119 /* Check if new data if available */ 120#ifdef ACCELEROMETER 121 AccGyr.Get_X_DRDY_Status(&drdy); 122#else 123 AccGyr.Get_G_DRDY_Status(&drdy); 124#endif 125 if(drdy) { 126 /* If new data is available we read it ! */ 127#ifdef ACCELEROMETER 128 AccGyr.Get_X_Axes(sensor_values); 129#else 130 AccGyr.Get_G_Axes(sensor_values); 131#endif 132 /* Fill neai buffer with new accel data */ 133 neai_buffer[AXIS * neai_ptr] = (float) sensor_values[0]; 134 neai_buffer[(AXIS * neai_ptr) + 1] = (float) sensor_values[1]; 135 neai_buffer[(AXIS * neai_ptr) + 2] = (float) sensor_values[2]; 136 /* Increment neai pointer */ 137 neai_ptr++; 138 } 139 } 140 /* Reset pointer */ 141 neai_ptr = 0; 142 /* Depending on NEAI_MODE value, run NanoEdge AI functions 143 * or print accelerometer data to the serial (datalogging) 144 */ 145 // if(NEAI_MODE) { 146 // if(neai_cnt < MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING) { 147 // neai_anomalydetection_learn(neai_buffer); 148 // Serial.print((String)"Learn: " + neai_cnt + "/" + MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING + ".\n"); 149 // neai_cnt++; 150 // } 151 // else { 152 // neai_anomalydetection_detect(neai_buffer, &similarity); 153 // Serial.print((String)"Detect: " + similarity + "/100.\n"); 154 // } 155 // } 156 // else { 157 /* Print the whole buffer to the serial */ 158 for(uint16_t i = 0; i < AXIS * SENSOR_SAMPLES; i++) { 159 Serial.print((String)neai_buffer[i] + " "); 160 } 161 Serial.print("\n"); 162 // } 163 164 /* Clean neai buffer */ 165 memset(neai_buffer, 0.0, AXIS * SENSOR_SAMPLES * sizeof(float)); 166}
main code option A
c
retrain the model on the microcontroller
1/* ============= 2 Copyright (c) 2024, STMicroelectronics 3 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that 7 the following conditions are met: 8 9 Redistributions of source code must retain the above copyright notice, this list of conditions and the 10 following disclaimer. 11 12 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 13 following disclaimer in the documentation and/or other materials provided with the distribution. 14 15 Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote 16 products derived from this software without specific prior written permission. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.* 25*/ 26 27/* If you want to use NEAI functions please, include NEAI library 28 in your Arduino libraries then, uncomment NEAI parts in the following code 29*/ 30 31/* Libraries part */ 32#include "Wire.h" 33#include <LSM6DSOSensor.h> 34#include <NanoEdgeAI.h> 35 36 37 38/* Macros definitions */ 39#define SERIAL_BAUD_RATE 115200 40 41/* Define the data type you want to collect */ 42#define ACCELEROMETER // Could be either ACCELEROMETER or GYROSCOPE 43 44/* Sensor data rates. 45 You can choose from the following values for both accel & gyro: 46 12.5f, 26.0f, 52.0f, 104.0f, 208.0f, 417.0f, 833.0f & 1667.0f. 47*/ 48#define SENSOR_DATA_RATE 1667.0f 49 50/* Sensor ranges. 51 You can choose from: 52 2, 4, 8 & 16 for accelerometer. 53 125, 250, 500, 1000 & 2000 for gyroscope. 54*/ 55#define SENSOR_RANGE 8 56 57/* NanoEdgeAI defines part 58 NEAI_MODE = 1: NanoEdgeAI functions = AI Mode. 59 NEAI_MODE = 0: Datalogging mode. 60*/ 61#define NEAI_MODE 0 62#define SENSOR_SAMPLES 512 63#define AXIS 3 64 65/* Sensor object declaration using I2C */ 66LSM6DSOSensor AccGyr(&Wire); 67 68/* Global variables definitions */ 69static uint8_t drdy = 0; 70static uint16_t neai_ptr = 0; 71static int32_t sensor_values[3]; 72static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; 73 74/* NEAI library variables */ 75 static uint8_t neai_code = 0, similarity = 0; 76 static uint16_t neai_cnt = 0; 77 78/* Initialization function: In this function, 79 code runs only once at boot / reset. 80*/ 81void setup() { 82 /* Init serial at baud rate 115200 */ 83 Serial.begin(SERIAL_BAUD_RATE); 84 85 /* I2C workaround: Sometimes, on some boards, 86 I2C get stuck after software reboot, reset so, 87 to avoid this, we toggle I2C clock pin at boot. 88 */ 89 pinMode(SCL, OUTPUT); 90 for (uint8_t i = 0; i < 20; i++) { 91 digitalWrite(SCL, !digitalRead(SCL)); 92 delay(1); 93 } 94 delay(100); 95 96 Wire.begin(); 97 AccGyr.begin(); 98#ifdef ACCELEROMETER 99 AccGyr.Enable_X(); 100 AccGyr.Disable_G(); 101 AccGyr.Set_X_ODR(SENSOR_DATA_RATE); 102 AccGyr.Set_X_FS(SENSOR_RANGE); 103#else 104 AccGyr.Enable_G(); 105 AccGyr.Disable_X(); 106 AccGyr.Set_G_ODR(SENSOR_DATA_RATE); 107 AccGyr.Set_G_FS(SENSOR_RANGE); 108#endif 109 110 /* Initialize NanoEdgeAI AI */ 111 neai_code = neai_anomalydetection_init(); 112 if (neai_code != NEAI_OK) { 113 Serial.print("Not supported board.\n"); 114 } 115} 116 117/* Main function: Code run indefinitely */ 118void loop() { 119 /* Get data in the neai buffer */ 120 while (neai_ptr < SENSOR_SAMPLES) { 121 /* Check if new data if available */ 122#ifdef ACCELEROMETER 123 AccGyr.Get_X_DRDY_Status(&drdy); 124#else 125 AccGyr.Get_G_DRDY_Status(&drdy); 126#endif 127 if (drdy) { 128 /* If new data is available we read it ! */ 129#ifdef ACCELEROMETER 130 AccGyr.Get_X_Axes(sensor_values); 131#else 132 AccGyr.Get_G_Axes(sensor_values); 133#endif 134 /* Fill neai buffer with new accel data */ 135 neai_buffer[AXIS * neai_ptr] = (float) sensor_values[0]; 136 neai_buffer[(AXIS * neai_ptr) + 1] = (float) sensor_values[1]; 137 neai_buffer[(AXIS * neai_ptr) + 2] = (float) sensor_values[2]; 138 /* Increment neai pointer */ 139 neai_ptr++; 140 } 141 } 142 /* Reset pointer */ 143 neai_ptr = 0; 144 /* Depending on NEAI_MODE value, run NanoEdge AI functions 145 or print accelerometer data to the serial (datalogging) 146 */ 147 if (NEAI_MODE) { 148 if (neai_cnt < MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING) { 149 neai_anomalydetection_learn(neai_buffer); 150 Serial.print((String)"Learn: " + neai_cnt + "/" + MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING + ".\n"); 151 neai_cnt++; 152 } 153 else { 154 neai_anomalydetection_detect(neai_buffer, &similarity); 155 Serial.print((String)"Detect: " + similarity + "/100.\n"); 156 } 157 } 158 else { 159 /* Print the whole buffer to the serial */ 160 for (uint16_t i = 0; i < AXIS * SENSOR_SAMPLES; i++) { 161 Serial.print((String)neai_buffer[i] + " "); 162 } 163 Serial.print("\n"); 164 } 165 166 /* Clean neai buffer */ 167 memset(neai_buffer, 0.0, AXIS * SENSOR_SAMPLES * sizeof(float)); 168}
main code option B
c
use the benchmark model knowledge, no retraining
1/* ============= 2 Copyright (c) 2024, STMicroelectronics 3 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that 7 the following conditions are met: 8 9 Redistributions of source code must retain the above copyright notice, this list of conditions and the 10 following disclaimer. 11 12 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 13 following disclaimer in the documentation and/or other materials provided with the distribution. 14 15 Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote 16 products derived from this software without specific prior written permission. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.* 25*/ 26 27/* If you want to use NEAI functions please, include NEAI library 28 in your Arduino libraries then, uncomment NEAI parts in the following code 29*/ 30 31/* Libraries part */ 32#include "Wire.h" 33#include <LSM6DSOSensor.h> 34#include <NanoEdgeAI.h> 35#include "knowledge.h" 36 37 38/* Macros definitions */ 39#define SERIAL_BAUD_RATE 115200 40 41/* Define the data type you want to collect */ 42#define ACCELEROMETER // Could be either ACCELEROMETER or GYROSCOPE 43 44/* Sensor data rates. 45 You can choose from the following values for both accel & gyro: 46 12.5f, 26.0f, 52.0f, 104.0f, 208.0f, 417.0f, 833.0f & 1667.0f. 47*/ 48#define SENSOR_DATA_RATE 1667.0f 49 50/* Sensor ranges. 51 You can choose from: 52 2, 4, 8 & 16 for accelerometer. 53 125, 250, 500, 1000 & 2000 for gyroscope. 54*/ 55#define SENSOR_RANGE 8 56 57/* NanoEdgeAI defines part 58 NEAI_MODE = 1: NanoEdgeAI functions = AI Mode. 59 NEAI_MODE = 0: Datalogging mode. 60*/ 61#define NEAI_MODE 1 62#define SENSOR_SAMPLES 512 63#define AXIS 3 64 65/* Sensor object declaration using I2C */ 66LSM6DSOSensor AccGyr(&Wire); 67 68/* Global variables definitions */ 69static uint8_t drdy = 0; 70static uint16_t neai_ptr = 0; 71static int32_t sensor_values[3]; 72static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; 73 74/* NEAI library variables */ 75 static uint8_t neai_code = 0, similarity = 0; 76 77/* Initialization function: In this function, 78 code runs only once at boot / reset. 79*/ 80void setup() { 81 /* Init serial at baud rate 115200 */ 82 Serial.begin(SERIAL_BAUD_RATE); 83 84 /* I2C workaround: Sometimes, on some boards, 85 I2C get stuck after software reboot, reset so, 86 to avoid this, we toggle I2C clock pin at boot. 87 */ 88 pinMode(SCL, OUTPUT); 89 for (uint8_t i = 0; i < 20; i++) { 90 digitalWrite(SCL, !digitalRead(SCL)); 91 delay(1); 92 } 93 delay(100); 94 95 Wire.begin(); 96 AccGyr.begin(); 97#ifdef ACCELEROMETER 98 AccGyr.Enable_X(); 99 AccGyr.Disable_G(); 100 AccGyr.Set_X_ODR(SENSOR_DATA_RATE); 101 AccGyr.Set_X_FS(SENSOR_RANGE); 102#else 103 AccGyr.Enable_G(); 104 AccGyr.Disable_X(); 105 AccGyr.Set_G_ODR(SENSOR_DATA_RATE); 106 AccGyr.Set_G_FS(SENSOR_RANGE); 107#endif 108 109 /* Initialize NanoEdgeAI AI */ 110 neai_code = neai_anomalydetection_init(); 111 if (neai_code != NEAI_OK) { 112 Serial.print("Not supported board.\n"); 113 } else { 114 neai_anomalydetection_knowledge(knowledge); 115 } 116} 117 118/* Main function: Code run indefinitely */ 119void loop() { 120 /* Get data in the neai buffer */ 121 while (neai_ptr < SENSOR_SAMPLES) { 122 /* Check if new data if available */ 123#ifdef ACCELEROMETER 124 AccGyr.Get_X_DRDY_Status(&drdy); 125#else 126 AccGyr.Get_G_DRDY_Status(&drdy); 127#endif 128 if (drdy) { 129 /* If new data is available we read it ! */ 130#ifdef ACCELEROMETER 131 AccGyr.Get_X_Axes(sensor_values); 132#else 133 AccGyr.Get_G_Axes(sensor_values); 134#endif 135 /* Fill neai buffer with new accel data */ 136 neai_buffer[AXIS * neai_ptr] = (float) sensor_values[0]; 137 neai_buffer[(AXIS * neai_ptr) + 1] = (float) sensor_values[1]; 138 neai_buffer[(AXIS * neai_ptr) + 2] = (float) sensor_values[2]; 139 /* Increment neai pointer */ 140 neai_ptr++; 141 } 142 } 143 /* Reset pointer */ 144 neai_ptr = 0; 145 /* Depending on NEAI_MODE value, run NanoEdge AI functions 146 or print accelerometer data to the serial (datalogging) 147 */ 148 if (NEAI_MODE) { 149 neai_anomalydetection_detect(neai_buffer, &similarity); 150 Serial.print((String)"Detect: " + similarity + "/100.\n"); 151 } 152 else { 153 /* Print the whole buffer to the serial */ 154 for (uint16_t i = 0; i < AXIS * SENSOR_SAMPLES; i++) { 155 Serial.print((String)neai_buffer[i] + " "); 156 } 157 Serial.print("\n"); 158 } 159 160 /* Clean neai buffer */ 161 memset(neai_buffer, 0.0, AXIS * SENSOR_SAMPLES * sizeof(float)); 162}
Downloadable files
data logger code
arduino-coffee-machine.ino
main code option A
retrain the model on the microcontroller
arduino-coffee-machine-learn.ino
main code option B
use the benchmark model knowledge, no retraining
arduino-coffee-machine-knowledge.ino
Comments
Only logged in users can leave comments