如何确保您的咖啡机永不干涸

使用简单的分类模型,在冲泡咖啡之前提前确定水箱是否需要加满!

项目介绍

本教程的目标是在咖啡机发生之前检测咖啡机何时会缺水。事实上,在没有水的情况下使用机器的泵可能会损坏它。

我们将以完全非侵入性的方式进行,我们只在咖啡机上放置一个带有加速度计的Arduino板。

我们将使用 NanoEdge AI Studio(免费工具)自动创建一个 AI 模型,该模型能够对门铃是否响起或只是背景噪音进行分类。

别担心,您不需要 AI 知识即可遵循本教程:)

第 1 步:设置

首先将 STMicroelectronics 扩展板插入 Arduino 板上,然后使用 blu 粘性(或任何其他粘合剂)将板放在咖啡机上。

在Arduino IDE中:


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


选择正确的电路板:

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

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

我们使用 STMicroelectronics X-NUCLEO-ISK01A3 进行LSM6DSO。如果您有任何其他加速度计,则可以使用它。

为了获取数据记录代码,我们使用 Arduino 的 NanoEdge AI Studio 数据记录器生成器。

  1. 打开 NanoEdge AI Studio
  2. 转到数据记录器生成器
  3. 选择Arduino
  4. 选择LSM6DSO
  5. 选择最大数据速率 (1667Hz),范围为 8,缓冲区大小为 512。
  6. 单击生成数据记录器


NanoEdge 输出一个包含 .ino 文件的.zip,您可以直接在 Arduino IDE 中使用该文件:

  1. 提取并打开 .ino 文件
  2. 导入所需的库(Wire 和 STM32duino LSM6DSO)并刷新代码


代码附在下面,作为 main_datalogging.c


默认情况下,代码包含 NanoEdge AI 库的注释部分,但我们稍后将在创建模型后使用它。

Step 3: NanoEdge AI Studio
第 3 步:NanoEdge AI Studio


NanoEdge AI Studio 是意法半导体开发的一款免费软件,旨在帮助嵌入式用户轻松创建 AI 模型。而且它非常易于使用:

  1. 选择项目类型
  2. 导入数据
  3. 根据您的数据获取最佳模型
  4. 测试一下
  5. 编译和使用它的函数很少


在这里,我们将做一个异常检测项目(AD),我们想要检测有水煮咖啡的正常情况和没有水的异常情况。


我们也可以做一个 N 类分类模型,但最后会更多。

在“项目设置”中:


  1. 为项目命名

  2. 选择Arduino R4 Wifi作为目标

  3. 选择传感器:加速度计 3 轴

  4. (可选)添加 FLASH 和 RAM 限制(用于模型搜索)

在常规信号中:


在这里,我们记录正常信号,在我们的例子中,当咖啡机有足够的水来煮咖啡时。


您可以导入已有的数据(.txt或.csv文件)或直接登录 NanoEdge。


  1. 你要记录的是机器在喝咖啡。

  2. 避免空信号(当机器不做任何事情时)。

  3. 收集大约 50 到 100 个缓冲区。

To log data directly in NanoEdge:
要直接在 NanoEdge 中记录数据:

  1. 单击 ADD SIGNAL

  2. 然后从串行 (USB)

  3. 然后单击 START/STOP 收集数据(确保选择了正确的 COM 端口)

  4. 完成后,单击“继续”,然后单击“导入”

  5. 如果需要,请重命名文件

在异常信号中:


做同样的事情,但是当没有足够的水/根本没有水来做咖啡时。

基准:


现在我们有了 2 种数据,我们可以要求 NanoEdge AI Studio 获取这些数据并创建一个 AI 库,其中包含模型及其参数,以及应用于我们数据的预处理,例如 FFT。


单击“新基准”并选择两种数据,然后单击“开始”。


在基准测试期间,测试了数十万种组合,以找到对所提供数据最有效的组合。


该分数是一个指标,它考虑了模型的整体准确性及其RAM和闪存占用空间。


一旦精度达到 90% 或更高,就可以停止基准测试。尝试找到最佳库可能需要几个小时,但在这里,如果我们有一个有效的库,就足够了。

Validation:  验证:


在验证中,目标是测试在基准测试期间找到的模型是否适用于新数据。人工智能模型可能发生的情况是过度拟合,这意味着模型是用心学习数据的,而不是如何区分它们。然后发生的事情是,他不能很好地处理看不见的数据。


选择 5 个最佳模型,单击“新建实验”并添加新的数据文件:

  1. 学习文件:NanoEdge 异常检测模型可以直接在微控制器上重新训练,这样通常可以给出更好的结果。在这里,您可以导入常规步骤中使用的常规文件(您可以在此处下载)。
  2. 常规文件:您想要导入包含新常规信号的新文件。(如果需要,您可以返回常规步骤,记录新数据并下载文件
  3. 异常文件:相同,但有新的异常信号。


过了一会儿,您将获得所有 5 个选定模型的新精度,您的精度应该接近基准测试期间获得的精度。如果没有,请使用更多数据进行新的基准测试。

Compilation:  汇编:


在这里,我们有两个选择:

  1. 使用在基准测试期间训练的模型
  2. 使用该模型,但直接在微控制器上重新训练它。

.
如果您不想重新训练它,只需单击编译即可。


如果您想要从基准测试中获得知识,请在编译前选中“包括来自基准测试的知识”框。


在本教程的后面,我将只更改几行代码,更多内容请见此处:

$ https://wiki.st.com/stm32mcu/wiki/AI:NanoEdge_AI_Library_for_anomaly_detection_(AD) $ 


第 4 步:将 NanoEdge 添加到 Arduino 代码

Now that we have the anomaly detection library, we need to add it to our Arduino code:
现在我们有了异常检测库,我们需要将其添加到Arduino代码中:


  1. 打开得到的.zip,有一个Arduino文件夹,里面有另一个zip

  2. 在Arduino IDE中导入库:Sketch > Include library > Add .ZIP library…,然后选择Arduino文件夹中的.zip


如果您已经在ARDUINO IDE中使用了NANOEDGE AI库:转到document/arduino/library并删除NanoEdge库。然后按照上面的说明导入新库。

IMPORTANT:  重要:


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


选项 A:重新训练模型


在我们用于数据记录的代码中,只需将 NEAI_MODE 更改为 1 并取消注释以下代码:

... #include <NanoEdgeAI.h>  #include < NanoEdgeAI.h>... #define NEAI_MODE 1 //0 is data logging code, 1 is detection code
#define NEAI_MODE 1 //0为数据记录码,1为检测码
... void setup(){  无效设置(){ ... neai_code = neai_anomalydetection_init(); //initialisation
neai_code = neai_anomalydetection_init();初始化
if(neai_code != NEAI_OK) {
if(neai_code != NEAI_OK) {
Serial.print("Not supported board.\n");
Serial.print(“不支持的板。\n”);
} } void loop(){  void loop(){ ... if(NEAI_MODE) {
if(NEAI_MODE) {
if(neai_cnt < MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING) {
如果(neai_cnt < MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING) {
neai_anomalydetection_learn(neai_buffer);
neai_anomalydetection_learn(neai_buffer);
Serial.print((String)"Learn: " + neai_cnt + "/" + MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING + ".\n");
Serial.print((String)“学习: ” + neai_cnt + “/” + MINIMUM_ITERATION_CALLS_FOR_EFFICIENT_LEARNING + “.\n”);
neai_cnt++; } else {
否则 {
neai_anomalydetection_detect(neai_buffer, &similarity);
neai_anomalydetection_detect(neai_buffer和相似性);
Serial.print((String)"Detect: " + similarity + "/100.\n");
Serial.print((String)“检测:” + 相似度 + “/100.\n”);
} } }


选项 B:使用基准测试中的知识

If you decided above to use the knowledge from the benchmark here is what to do:
如果您决定使用上面的基准测试中的知识,请执行以下操作:
1.在代码的 init() 部分添加:neai_anomalydetection_knowledge(knowledge);
2.在 loop() 中,在 if(NEAI_MODE) 之后删除 if 语句(以及 else { 和 })

    #include <NanoEdgeAI.h>  #include < NanoEdgeAI.h>
    #include "knowledge.h"  // DON T FORGET TO LOAD THE KNOWLEDGE 
    #include “knowledge.h” // 不要忘记加载知识
    void setup(){  无效设置(){
    ... 
    	 neai_code = neai_anomalydetection_init(); 
    	 neai_code = neai_anomalydetection_init();
    	 if (neai_code != NEAI_OK) { 
    	 if (neai_code != NEAI_OK) {
    	   Serial.print("Not supported board.\n"); 
    	   Serial.print(“不支持的板。\n”);
    	 } else { 
    	   neai_anomalydetection_knowledge(knowledge); //this part is to load the knowledge 
    	   neai_anomalydetection_knowledge(知识);这部分是加载知识
    	 } 
    } 
    void loop(){  void loop(){
    ... 
    	  if(NEAI_MODE) { 
    	  if(NEAI_MODE) {
    	     // no more learning part, but detect is the same 
    	     不再有学习部分,但检测是一样的
    	      neai_anomalydetection_detect(neai_buffer, &similarity); 
    	      neai_anomalydetection_detect(neai_buffer和相似性);
    	      Serial.print((String)"Detect: " + similarity + "/100.\n"); 
    	      Serial.print((String)“检测:” + 相似度 + “/100.\n”);
    	 } 
    ... 
    

    neai_anomalydetection_detect()是使用该模型进行检测的代码的一部分。
    如果相似性是100,这意味着我们有一个与标称数据(足够的水)100%相似的信号,如果它是0,我们有0%的机会成为标称数据。
    在默认代码中,我们只需打印相似性得分,您可以做一个if语句,如果相似性高于90,则写ok,或者在其他情况下写“您需要加水”,这取决于您:

    if (similarity > 90){     
    	Serial.print("OK");     
    } else {     
    	Serial.print("Not enough water, please add water");     
    }     
    


    感谢您阅读:)

    代码

    data logger code

    /* =============
    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 <LSM6DSOSensor.h>
    // #include <NanoEdgeAI.h>
    
    /* Macros definitions */
    #define SERIAL_BAUD_RATE  115200
    
    /* Define the data type you want to collect */
    #define ACCELEROMETER // Could be either ACCELEROMETER or GYROSCOPE
    
    /* Sensor data rates.
     * You can choose from the following values for both accel & gyro:
     * 12.5f, 26.0f, 52.0f, 104.0f, 208.0f, 417.0f, 833.0f & 1667.0f.
      */
    #define SENSOR_DATA_RATE	1667.0f
    
    /* Sensor ranges.
     * You can choose from:
     * 2, 4, 8 & 16 for accelerometer.
     * 125, 250, 500, 1000 & 2000 for gyroscope.
     */
    #define SENSOR_RANGE	8
    
    /* NanoEdgeAI defines part
     * NEAI_MODE = 1: NanoEdgeAI functions = AI Mode.
     * NEAI_MODE = 0: Datalogging mode.
     */
    #define NEAI_MODE 0
    #define SENSOR_SAMPLES	512
    #define AXIS  3
    
    /* Sensor object declaration using I2C */
    LSM6DSOSensor AccGyr(&Wire);
    
    /* Global variables definitions */
    static uint8_t drdy = 0;
    static uint16_t neai_ptr = 0;
    static int32_t sensor_values[3];
    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);
    
      Wire.begin();
      AccGyr.begin();
    #ifdef ACCELEROMETER
        AccGyr.Enable_X();
        AccGyr.Disable_G();
        AccGyr.Set_X_ODR(SENSOR_DATA_RATE);
        AccGyr.Set_X_FS(SENSOR_RANGE);
    #else
        AccGyr.Enable_G();
        AccGyr.Disable_X();
        AccGyr.Set_G_ODR(SENSOR_DATA_RATE);
        AccGyr.Set_G_FS(SENSOR_RANGE);
    #endif
    
      /* 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 */
    #ifdef ACCELEROMETER
          AccGyr.Get_X_DRDY_Status(&drdy);
    #else
          AccGyr.Get_G_DRDY_Status(&drdy);
    #endif
        if(drdy) {
          /* If new data is available we read it ! */
    #ifdef ACCELEROMETER
            AccGyr.Get_X_Axes(sensor_values);
    #else
            AccGyr.Get_G_Axes(sensor_values);
    #endif
          /* Fill neai buffer with new accel data */
          neai_buffer[AXIS * neai_ptr] = (float) sensor_values[0];
          neai_buffer[(AXIS * neai_ptr) + 1] = (float) sensor_values[1];
          neai_buffer[(AXIS * neai_ptr) + 2] = (float) sensor_values[2];
          /* 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));
    }

    main code option A

    use the benchmark model knowledge, no retraining

    /* =============
      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 <LSM6DSOSensor.h>
    #include <NanoEdgeAI.h>
    
    
    
    /* Macros definitions */
    #define SERIAL_BAUD_RATE  115200
    
    /* Define the data type you want to collect */
    #define ACCELEROMETER // Could be either ACCELEROMETER or GYROSCOPE
    
    /* Sensor data rates.
       You can choose from the following values for both accel & gyro:
       12.5f, 26.0f, 52.0f, 104.0f, 208.0f, 417.0f, 833.0f & 1667.0f.
    */
    #define SENSOR_DATA_RATE	1667.0f
    
    /* Sensor ranges.
       You can choose from:
       2, 4, 8 & 16 for accelerometer.
       125, 250, 500, 1000 & 2000 for gyroscope.
    */
    #define SENSOR_RANGE	8
    
    /* NanoEdgeAI defines part
       NEAI_MODE = 1: NanoEdgeAI functions = AI Mode.
       NEAI_MODE = 0: Datalogging mode.
    */
    #define NEAI_MODE 0
    #define SENSOR_SAMPLES	512
    #define AXIS  3
    
    /* Sensor object declaration using I2C */
    LSM6DSOSensor AccGyr(&Wire);
    
    /* Global variables definitions */
    static uint8_t drdy = 0;
    static uint16_t neai_ptr = 0;
    static int32_t sensor_values[3];
    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);
    
      Wire.begin();
      AccGyr.begin();
    #ifdef ACCELEROMETER
      AccGyr.Enable_X();
      AccGyr.Disable_G();
      AccGyr.Set_X_ODR(SENSOR_DATA_RATE);
      AccGyr.Set_X_FS(SENSOR_RANGE);
    #else
      AccGyr.Enable_G();
      AccGyr.Disable_X();
      AccGyr.Set_G_ODR(SENSOR_DATA_RATE);
      AccGyr.Set_G_FS(SENSOR_RANGE);
    #endif
    
      /* 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 */
    #ifdef ACCELEROMETER
        AccGyr.Get_X_DRDY_Status(&drdy);
    #else
        AccGyr.Get_G_DRDY_Status(&drdy);
    #endif
        if (drdy) {
          /* If new data is available we read it ! */
    #ifdef ACCELEROMETER
          AccGyr.Get_X_Axes(sensor_values);
    #else
          AccGyr.Get_G_Axes(sensor_values);
    #endif
          /* Fill neai buffer with new accel data */
          neai_buffer[AXIS * neai_ptr] = (float) sensor_values[0];
          neai_buffer[(AXIS * neai_ptr) + 1] = (float) sensor_values[1];
          neai_buffer[(AXIS * neai_ptr) + 2] = (float) sensor_values[2];
          /* 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));
    }
    
    

    main code option B

    use the benchmark model knowledge, no retraining

    /* =============
    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 <LSM6DSOSensor.h>
    #include <NanoEdgeAI.h>
    #include "knowledge.h"


    /* Macros definitions */
    #define SERIAL_BAUD_RATE 115200

    /* Define the data type you want to collect */
    #define ACCELEROMETER // Could be either ACCELEROMETER or GYROSCOPE

    /* Sensor data rates.
    You can choose from the following values for both accel & gyro:
    12.5f, 26.0f, 52.0f, 104.0f, 208.0f, 417.0f, 833.0f & 1667.0f.
    */
    #define SENSOR_DATA_RATE 1667.0f

    /* Sensor ranges.
    You can choose from:
    2, 4, 8 & 16 for accelerometer.
    125, 250, 500, 1000 & 2000 for gyroscope.
    */
    #define SENSOR_RANGE 8

    /* 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

    /* Sensor object declaration using I2C */
    LSM6DSOSensor AccGyr(&Wire);

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

    /* NEAI library variables */
    static uint8_t neai_code = 0, similarity = 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);

    Wire.begin();
    AccGyr.begin();
    #ifdef ACCELEROMETER
    AccGyr.Enable_X();
    AccGyr.Disable_G();
    AccGyr.Set_X_ODR(SENSOR_DATA_RATE);
    AccGyr.Set_X_FS(SENSOR_RANGE);
    #else
    AccGyr.Enable_G();
    AccGyr.Disable_X();
    AccGyr.Set_G_ODR(SENSOR_DATA_RATE);
    AccGyr.Set_G_FS(SENSOR_RANGE);
    #endif

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

    /* Main function: Code run indefinitely */
    void loop() {
    /* Get data in the neai buffer */
    while (neai_ptr < SENSOR_SAMPLES) {
    /* Check if new data if available */
    #ifdef ACCELEROMETER
    AccGyr.Get_X_DRDY_Status(&drdy);
    #else
    AccGyr.Get_G_DRDY_Status(&drdy);
    #endif
    if (drdy) {
    /* If new data is available we read it ! */
    #ifdef ACCELEROMETER
    AccGyr.Get_X_Axes(sensor_values);
    #else
    AccGyr.Get_G_Axes(sensor_values);
    #endif
    /* Fill neai buffer with new accel data */
    neai_buffer[AXIS * neai_ptr] = (float) sensor_values[0];
    neai_buffer[(AXIS * neai_ptr) + 1] = (float) sensor_values[1];
    neai_buffer[(AXIS * neai_ptr) + 2] = (float) sensor_values[2];
    /* 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_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));
    }

    类似文章

    发表回复