煮还是不煮?这就是问题所在!

使用嵌入式 AI 检测水何时沸腾以防止沸腾!

项目介绍

在准备午餐时,每个人可能都遇到过这样的时刻:你让平底锅放在火上,水或牛奶开始沸腾并从锅里出来。

为了防止这种情况,你可以把火调得更低,但这并不好玩,让我向你介绍一种过度设计的方式:

  1. 拿一个Arduino板和一个加速度计
  2. 使用嵌入式 AI 检测水何时因振动而沸腾
  3. 启动风扇在锅上吹气,以防止水从锅中流出

很简单,对吧:)

第 1 步:设置

您需要一个 USB-A 平底锅、风扇和电炉或电磁炉。

然后,我们需要将加速度计连接到Arduino板。

使用跳线连接:

  1. VIN(麦克风)至 3.3V(板)
  2. GND 到板上的一个 GND
  3. SDA 为 SDA
  4. SCL 为 SCL

然后我们复制这个铸币厂:https://adam-meyer.com/arduino/images/2011/03/tip120-lightbulb1.png

(教程链接:https://adam-meyer.com/arduino/TIP120)

TIP120 晶体管的目标是作为开关进行控制。Arduino 引脚输出的逻辑 1 应打开风扇电源,逻辑 0 应停止风扇。在这里,我们将 A0 引脚与电阻器一起使用(请看图片中的橙色线)。

然后你可以用热胶固定平底锅上的设置,你需要找到一种方法来固定风扇。我使用了塑料夹(serflex)。

在Arduino IDE中:

确保您选择了正确的 COM 端口:工具>端口,然后选择正确的端口。

选择正确的电路板:

  1. Arduino Renesas UNO R4 > 开发板的工具>板 > Arduino UNO R4 WIFI
  2. 如果没有找到它,请单击“Tools > Boards > Boards Manager…”,查找 UNO R4 并安装软件包

第 2 步:收集加速度计数据

为了训练人工智能能够检测水何时沸腾,我们首先需要收集两种情况的数据:沸腾和不沸腾。

我们可以创建一些代码来从加速度计收集数据,但 NanoEdge 提供了一个自动生成数据的工具,因此我们可以使用它来获得一些时间:

  1. 打开 NanoEdge
  2. 使用数据记录仪
  3. 选择Arduino板
  4. 选择 LIS3DH

因为沸水产生的振动非常小,而且我们不需要很多数据,所以这里是要选择的参数:

  1. 数据速率(Hz):1600Hz
  2. 范围:2g
  3. 每轴采样数:512

(您可以测试其他参数,但要小心每个轴的样本,因为它需要越来越多的 RAM 用于缓冲区。

单击生成数据记录器,您将获得一个包含 .ino 文件的.zip,其中包含可在板上刷新的代码。

代码将通过串行打印缓冲区。在我们的例子中,它将以 3kHz 的频率发送大小为 512*1.6 的缓冲区。

在下一步中,我们将读取这些打印的缓冲区和日志数据集,然后训练模型。

警告:

如果您以前从未使用过加速度计,则可能需要安装加速度计的库:

  1. 在Arduino IDE中,转到草图>包括库>管理库…> adafruit LIS3DH

在数据记录代码中,注释了与 NanoEdge 相关的部分。在使用 NanoEdge AI Studio 获取 AI 库后,我们将稍后使用。

最后附上了NanoEdge的数据记录代码。

第 3 步:NanoEdge AI Studio

现在我们能够使用加速度计收集数据,下一步是使用 NanoEdge AI Studio 记录信号,并使用这些信号创建一个能够识别来自其他信号的沸水信号的 AI。

  1. 打开 NanoEdge AI Studio
  2. 创建 N 类分类项目

在项目设置中:

  1. 选择Arduino R4 WiFi作为目标
  2. 选择加速度计 3 轴作为传感器
  3. 其他一切都是可选的
  4. 单击“下一步”

在信号中:

在这里,我们将添加不沸水和沸水的数据,并在不同的水位下多次进行。

我们首先从简单开始,我选择坚持使用半满的平底锅并执行以下操作:

  1. 将平底锅放在电炉或电磁炉上(最大功率)
  1. 加热时记录非沸腾数据
  2. 当您认为它接近/开始沸腾时,停止记录非沸腾
  3. 稍等片刻,确保它真的沸腾了
  4. 开始记录沸水

每记录 10 个信号,我就会暂停日志并在火上稍微移动平底锅,以增加一些数据的多样性。

我记录了大约 150 个非沸水信号(开始沸腾所需的时间)和大约 50 到 100 个沸水。

然后我改变了水位并多次重复该过程。

要在NanoEdge中记录数据,请按以下步骤操作:

  1. 点击添加信号
  2. 从串行 (USB)
  3. 选择正确的 COM 端口
  4. 单击NanoEdge中的启动/停止以收集信号
  5. 满意时停止

我收集了多个沸腾类和多个非沸腾类。但是要启动基准测试,您需要将所有文件连接起来,最终只有 2 个:沸腾和不沸腾。

为此,您可以:

  1. 下载您记录的所有文件
  2. 返回 NanoEdge AI Studio 主页
  3. 转到数据操作
  4. 导入所有未沸腾的文件
  5. 点击上面的连接
  6. 单击提取行,然后单击运行
  7. 然后保存包含所有信号的文件
  8. 煮沸也一样
  9. 返回项目并导入包含所有内容的 2 个数据集

在 Benchmark 中:

基准测试是 NanoEdge AI Studio 的核心。在这里,我们将使用这两种信号来尝试找到数据预处理的最佳组合和能够区分数据的最佳模型。

  1. 点击新基准
  2. 选择所有数据集
  3. 点击开始

基准测试将迭代尝试对数据进行预处理和建模的组合,并评估性能。它将数据多次拆分为训练集和测试集,以获得可靠的结果。

基准测试可能需要数小时才能完成,具体取决于使用的数据量。如果分数达到 90% 或更高,您可以暂停/停止它并继续。基准测试将尝试尽可能地优化模型,但您可以在满意时停止它。

在验证中:

进行验证以在新数据上测试模型。训练机器学习或 AI 模型时可能发生的情况是模型过拟合。这意味着模型在训练过程中会有很好的结果,但不能很好地处理新数据,因为它背诵了训练数据集,而不是学习如何对数据进行分类……

要使用验证,您需要同时包含沸腾信号和非沸腾信号的新数据集。您可以返回上一步以收集更多数据并下载 csv 以在验证中使用它们。

要使用验证,请执行以下操作:

  1. 最多选择 10 个要测试的模型(第一个是最好的模型)
  2. 点击新建实验
  3. 选择不沸水和沸水的新数据集
  4. 点击开始

您将在新数据上获得所有选定模型的性能。

在这一部分,我花了相当多的时间来训练一个运行良好的模型。这意味着我删除了一些数据并记录了新数据,进行了其他基准测试和验证,直到我找到一个似乎按预期工作的模型。从简单开始,在检查模型是否有效的同时添加越来越多的多样性。

在编译中:

只需单击“编译”即可获得经过训练的模型。

第 4 步:将 NanoEdge AI 库添加到 Arduino

要将AI添加到我们的Arduino代码中,这很容易,这是我们需要做的:

  1. 包括模型和知识
  2. 初始化模型
  3. 执行检测

就是这样,一切都是使用函数完成的!

此外,我在 Led 矩阵上添加了一些印刷,并在检测到沸腾等级时启动风扇,以防止水从锅中泄漏出来。

现在我们有了异常检测库,我们需要将其添加到Arduino代码中:

  1. 打开得到的.zip,有一个Arduino文件夹,里面有另一个zip
  2. 在Arduino IDE中导入库:Sketch > Include library > Add .ZIP library…,然后选择Arduino文件夹中的.zip

如果您已经在ARDUINO IDE中使用了NANOEDGE AI库:

转到 Document/Arduino/Library 并删除 NanoEdge 的。然后按照上面的说明导入新库。

重要:

如果由于RAM而出现错误,则可能是由于NanoEdge中的库。回到 NanoEdge 中的 VALIDATION STEP,选择一个较小的库(单击右侧的表冠),然后在 Arduino IDE 中编译并替换它。

主代码附在最后,下面各导入部分的说明如下:

#include <NanoEdgeAI.h>     
#include "knowledge.h"     
//DON T FORGET TO CHANGE NEAI_MODE TO 1 to do detections     
#define NEAI_MODE 1     
/* Global variables definitions */     
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer     
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer     
uint8_t neai_code = 0; //initialization code     
uint16_t id_class = 0; // Point to id class (see argument of neai_classification fct)     
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities     
const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name     
	 "unknown",     
	 "boiling_test3",     
	 "not_boiling_test3",     
};     
void setup(){     
	 //some code     
	 /* Initialize NanoEdgeAI AI */     
	 neai_code = neai_classification_init(knowledge);     
	 if (neai_code != NEAI_OK) {     
	   Serial.print("Not supported board.\n");     
	 }     
}     
void loop(){     
	//some code     
	if (NEAI_MODE) {     
	   neai_classification(neai_buffer, output_class_buffer, &id_class);     
	   switch (id_class) {     
	     case 1:     
	       Serial.println("!!! Boiling !!!");     
	       break;     
	     case 2:     
	       Serial.println(" Not Boiling ");     
	     default:     
	       Serial.println(" Error ");     
	       break;     
	   }     
}     

id2class 变量取决于您在 NanoEdge 中使用的类的名称。煮沸或不煮沸类的顺序可以改变,您需要复制 NanoEdgeAI.h 中的一个进行编译.zip:

  1. YOUR_LIBRARY.zip\arduino\nanoedgeai_for_arduino.zip\nanoedgeai\src\NanoEdgeIA.h

使用矩阵显示消息:

#include "ArduinoGraphics.h"     
#include "Arduino_LED_Matrix.h"     
/* Declare matrix to display */     
byte frame[8][12] = {     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     
	 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }     
};     
//text to display     
char text[30];     
ArduinoLEDMatrix matrix;     
void setup(){     
	//some code     
	matrix.begin();     
}     
void loop(){     
	//some code     
	// if we want to write something we set our text     
	 strcpy (text, " OUR TEXT ");     
	// then display it and set some parameters     
	   matrix.beginDraw();     
	   matrix.stroke(0xFFFFFFFF);     
	   matrix.textScrollSpeed(50);     
	   matrix.textFont(Font_5x7);     
	   matrix.beginText(0, 1, 0xFFFFFF);     
	   matrix.println(text);     
	   matrix.endText(SCROLL_LEFT);     
	   matrix.endDraw();     
}     

激活风扇:

...     
void setup{     
	  //some code     
	  pinMode(A0, OUTPUT); //A0 is our pin, you can change it if you use another pin     
}     
void loop{     
	  // if you want to turn the fan on     
	  digitalWrite(A0, HIGH);     
	  // if you want to stop it     
	  digitalWrite(A0, LOW);     
}     

在我们的例子中,我们在 neai_classification() 之后在开关情况下打开/关闭风扇

如果您使用此处解释的所有内容,则最终将完全附加主代码!

感谢您阅读:)

数据记录器代码

/* =============
Copyright (c) 2024, STMicroelectronics

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that
the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the
  following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
  products derived from this software without specific prior written permission.

*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*
*/

/* If you want to use NEAI functions please, include NEAI library
 * in your Arduino libraries then, uncomment NEAI parts in the following code
 */

/* Libraries part */
#include <Wire.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
// #include <NanoEdgeAI.h>

/* Macros definitions */
#define SERIAL_BAUD_RATE  115200

/* Default address is 0x18 but, if SDO is powered at 3v3,
 *  address is set to 0x19, so you need to change it
 *  depending on your current hardware configuration.
 */
#define SENSOR_I2C_ADDR 0x19

/* Sensor data rates.
 * You can choose from:
 * LIS3DH_DATARATE_1_HZ
 * LIS3DH_DATARATE_10_HZ
 * LIS3DH_DATARATE_25_HZ
 * LIS3DH_DATARATE_50_HZ
 * LIS3DH_DATARATE_100_HZ
 * LIS3DH_DATARATE_200_HZ
 * LIS3DH_DATARATE_400_HZ
 * LIS3DH_DATARATE_LOWPOWER_1K6HZ
 * LIS3DH_DATARATE_LOWPOWER_5KHZ
 */
#define SENSOR_DATA_RATE	LIS3DH_DATARATE_400_HZ

/* Sensor ranges.
 * You can choose from:
 * LIS3DH_RANGE_16_G
 * LIS3DH_RANGE_8_G
 * LIS3DH_RANGE_4_G
 * LIS3DH_RANGE_2_G
 */
#define SENSOR_RANGE	LIS3DH_RANGE_2_G

/* NanoEdgeAI defines part
 * NEAI_MODE = 1: NanoEdgeAI functions = AI Mode.
 * NEAI_MODE = 0: Datalogging mode.
 */
#define NEAI_MODE 0
#define SENSOR_SAMPLES	256
#define AXIS  3

/* In this example, we use I2C connection */
Adafruit_LIS3DH lis = Adafruit_LIS3DH();

/* Global variables definitions */
static uint16_t neai_ptr = 0;
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0};

/* NEAI library variables */
// static uint8_t neai_code = 0, similarity = 0;
// static uint16_t neai_cnt = 0;

/* Initialization function: In this function,
 *  code runs only once at boot / reset.
 */
void setup() {
  /* Init serial at baud rate 115200 */
  Serial.begin(SERIAL_BAUD_RATE);

  /* I2C workaround: Sometimes, on some boards,
   * I2C get stuck after software reboot, reset so,
   * to avoid this, we toggle I2C clock pin at boot.
   */
  pinMode(SCL, OUTPUT);
  for (uint8_t i = 0; i < 20; i++) {
    digitalWrite(SCL, !digitalRead(SCL));
    delay(1);
  }
  delay(100);

  /* Init I2C connection between board & sensor */
  if(!lis.begin(SENSOR_I2C_ADDR)) {
    Serial.print("Can't initialize I2C comm with LIS3DH sensor...\n");
    while(1);
  }

  /* Init LIS3DH with desired settings: odr & range */
  lis.setRange(SENSOR_RANGE);
  lis.setDataRate(SENSOR_DATA_RATE);

  /* Initialize NanoEdgeAI AI */
  // neai_code = neai_anomalydetection_init();
  // if(neai_code != NEAI_OK) {
  //   Serial.print("Not supported board.\n");
  // }
}

/* Main function: Code run indefinitely */
void loop() {
  /* Get data in the neai buffer */
  while(neai_ptr < SENSOR_SAMPLES) {
     /* Check if new data if available */
    if(lis.haveNewData()) {
      /* If new data is available we read it ! */
      lis.read();
      /* Fill neai buffer with new accel data */
      neai_buffer[AXIS * neai_ptr] = (float) lis.x;
      neai_buffer[(AXIS * neai_ptr) + 1] = (float) lis.y;
      neai_buffer[(AXIS * neai_ptr) + 2] = (float) lis.z;
      /* Increment neai pointer */
      neai_ptr++;
    }
  }
  /* Reset pointer */
  neai_ptr = 0;

  /* Depending on NEAI_MODE value, run NanoEdge AI functions
   * or print accelerometer data to the serial (datalogging)
   */
  // if(NEAI_MODE) {
  //   if(neai_cnt < MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING) {
  //     neai_anomalydetection_learn(neai_buffer);
  //     Serial.print((String)"Learn: " + neai_cnt + "/" + MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING + ".\n");
  //     neai_cnt++;
  //   }
  //   else {
  //     neai_anomalydetection_detect(neai_buffer, &similarity);
  //     Serial.print((String)"Detect: " + similarity + "/100.\n");
  //   }
  // }
  // else {
    /* Print the whole buffer to the serial */
    for(uint16_t i = 0; i < AXIS * SENSOR_SAMPLES; i++) {
      Serial.print((String)neai_buffer[i] + " ");
    }
    Serial.print("\n");
  // }

  /* Clean neai buffer */
  memset(neai_buffer, 0.0, AXIS * SENSOR_SAMPLES * sizeof(float));
}

主代码

/* =============
  Copyright (c) 2024, STMicroelectronics

  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
  the following conditions are met:

  Redistributions of source code must retain the above copyright notice, this list of conditions and the
  following disclaimer.

  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  following disclaimer in the documentation and/or other materials provided with the distribution.

  Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
  products derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*
*/

/* If you want to use NEAI functions please, include NEAI library
   in your Arduino libraries then, uncomment NEAI parts in the following code
*/

/* Libraries part */
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
#include <Wire.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
#include <NanoEdgeAI.h>
#include "knowledge.h"

/* Macros definitions */
#define SERIAL_BAUD_RATE  115200

/* Default address is 0x18 but, if SDO is powered at 3v3,
    address is set to 0x19, so you need to change it
    depending on your current hardware configuration.
*/
#define SENSOR_I2C_ADDR 0x19

/* Sensor data rates.
   You can choose from:
   LIS3DH_DATARATE_1_HZ
   LIS3DH_DATARATE_10_HZ
   LIS3DH_DATARATE_25_HZ
   LIS3DH_DATARATE_50_HZ
   LIS3DH_DATARATE_100_HZ
   LIS3DH_DATARATE_200_HZ
   LIS3DH_DATARATE_400_HZ
   LIS3DH_DATARATE_LOWPOWER_1K6HZ
   LIS3DH_DATARATE_LOWPOWER_5KHZ
*/
#define SENSOR_DATA_RATE	LIS3DH_DATARATE_LOWPOWER_1K6HZ

/* Sensor ranges.
   You can choose from:
   LIS3DH_RANGE_16_G
   LIS3DH_RANGE_8_G
   LIS3DH_RANGE_4_G
   LIS3DH_RANGE_2_G
*/
#define SENSOR_RANGE	LIS3DH_RANGE_2_G

/* NanoEdgeAI defines part
   NEAI_MODE = 1: NanoEdgeAI functions = AI Mode.
   NEAI_MODE = 0: Datalogging mode.
*/
#define NEAI_MODE 1
#define SENSOR_SAMPLES	512
#define AXIS  3

/* In this example, we use I2C connection */
Adafruit_LIS3DH lis = Adafruit_LIS3DH();

/* Global variables definitions */
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer

uint8_t neai_code = 0; //initialization code
uint16_t id_class = 0; // Point to id class (see argument of neai_classification fct)
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
  "unknown",
  "bouepas_concat",
  "boue_concat",
};

/* Declare matrix to display */
byte frame[8][12] = {
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

char text[30];

ArduinoLEDMatrix matrix;


/* Initialization function: In this function,
    code runs only once at boot / reset.
*/
void setup() {
  /* Init serial at baud rate 115200 */
  Serial.begin(SERIAL_BAUD_RATE);
  delay(10);
  matrix.begin();

  pinMode(A0, OUTPUT);

  /* I2C workaround: Sometimes, on some boards,
     I2C get stuck after software reboot, reset so,
     to avoid this, we toggle I2C clock pin at boot.
  */
  pinMode(SCL, OUTPUT);
  for (uint8_t i = 0; i < 20; i++) {
    digitalWrite(SCL, !digitalRead(SCL));
    delay(1);
  }
  delay(100);

  /* Init I2C connection between board & sensor */
  if (!lis.begin(SENSOR_I2C_ADDR)) {
    Serial.print("Can't initialize I2C comm with LIS3DH sensor...\n");
    while (1);
  }

  /* Init LIS3DH with desired settings: odr & range */
  lis.setRange(SENSOR_RANGE);
  lis.setDataRate(SENSOR_DATA_RATE);

  /* Initialize NanoEdgeAI AI */
  neai_code = neai_classification_init(knowledge);
  if (neai_code != NEAI_OK) {
    Serial.print("Not supported board.\n");
  }
}

/* Main function: Code run indefinitely */
void loop() {
  /* Get data in the neai buffer */
  while (neai_ptr < SENSOR_SAMPLES) {
    /* Check if new data if available */
    if (lis.haveNewData()) {
      /* If new data is available we read it ! */
      lis.read();
      /* Fill neai buffer with new accel data */
      neai_buffer[AXIS * neai_ptr] = (float) lis.x;
      neai_buffer[(AXIS * neai_ptr) + 1] = (float) lis.y;
      neai_buffer[(AXIS * neai_ptr) + 2] = (float) lis.z;
      /* Increment neai pointer */
      neai_ptr++;
    }
  }
  /* Reset pointer */
  neai_ptr = 0;

  /* Depending on NEAI_MODE value, run NanoEdge AI functions
     or print accelerometer data to the serial (datalogging)
  */
  if (NEAI_MODE) {
    neai_classification(neai_buffer, output_class_buffer, &id_class);
    switch (id_class) {
      case 1:
        strcpy (text, " !!! Boiling !!! ");
        digitalWrite(A0, HIGH);
        break;
      case 2:
        strcpy (text, " Not Boiling ");
        digitalWrite(A0, LOW);
        break;
      default:
        strcpy (text, " ERROR ");
        break;
    }
    Serial.print(output_class_buffer[1]);
    Serial.print(' ');
    Serial.print(output_class_buffer[0]);
    Serial.println(' ');

    matrix.beginDraw();
    matrix.stroke(0xFFFFFFFF);
    matrix.textScrollSpeed(50);
    matrix.textFont(Font_5x7);
    matrix.beginText(0, 1, 0xFFFFFF);
    matrix.println(text);
    matrix.endText(SCROLL_LEFT);
    matrix.endDraw();

  }
  else {
    /* Print the whole buffer to the serial */
    for (uint16_t i = 0; i < AXIS * SENSOR_SAMPLES; i++) {
      Serial.print((String)neai_buffer[i] + " ");
    }
    Serial.print("\n");
  }
  /* Clean neai buffer */
  memset(neai_buffer, 0.0, AXIS * SENSOR_SAMPLES * sizeof(float));
}

Similar Posts

Leave a Reply