这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sdo2026第3期】基于边缘AI的电机状态检测--过程帖

共1条 1/1 1 跳转至页

Let'sdo2026第3期】基于边缘AI的电机状态检测--过程帖

菜鸟
2026-11-05 17:03:30     打赏

环境配置以及各个物料的使用在开箱帖中记录了,本次主要记录ai训练过程,同时完善了一下传感器的驱动。

训练我使用的是NanoEdge AI Studio。

数据采集

对于电机运行状态我分为停止,高速,低速,异常四个类别,按照NanoEdge AI Studio所要求的数据格式分别对以上几个类别的数据进行采集。

          input_signal[signal_index * 3 + 0] = (float)fifo_acc[i * 3 + 0]; // X
          input_signal[signal_index * 3 + 1] = (float)fifo_acc[i * 3 + 1]; // Y
          input_signal[signal_index * 3 + 2] = (float)fifo_acc[i * 3 + 2]; // Z
         printf("%d %d %d ", fifo_acc[i * 3 + 0], fifo_acc[i * 3 + 1], fifo_acc[i * 3 + 2]);
         count++;
         if(count >= 256)
         {
           printf("\r\n");
           count = 0;
         }

训练过程

打开软件后,新建工程。本次任务是对电机运行状态进行检测,对电机不同的运行状态进行分类,所以我选择Classify,在下一个界面选择开发板和传感器。选择好以后进入下一个环节,上传先前采集的数据,分好类后就可以进入训练环节了。

image.png

等待中

训练好以后进入导出文件环节,这个界面右边有示例代码,可以参考。将导出的.h和.a文件导入工程,按照示例代码进行编写就完成了。

在运行过程中,我的电机驱动是直接写在主函数中,通过延时调速,电机运行时卡卡的,很不丝滑,我修改了一下电机驱动,通过定时器中断触发,这下电机运行起来顺畅很多。

改动后再采集一次数据,重新训练,准确率大幅提高。

image.png

主程序代码


/**
  ******************************************************************************
  * file           : main.c
  * brief          : Main program body
  *                  Calls target system initialization then loop in main.
  ******************************************************************************
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32c5xx_hal_gpio.h"
#include <stdint.h>
#include <stdio.h>
#include "LIS3DHTR.h"
#include "MOTO.h"
#include "NanoEdgeAI.h"
#include <stdbool.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
float input_signal[NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER]; // Buffer of input values
float probabilities[NEAI_NUMBER_OF_CLASSES]; // Buffer of class probabilities
uint16_t wait = 0;
uint16_t key_num = 0;
#define MAX_FIFO_SAMPLES 32
int16_t fifo_acc[MAX_FIFO_SAMPLES * 3];
uint16_t signal_index = 0; // 当前蓄水池的水位
/* Private functions prototype -----------------------------------------------*/
void HAL_TIM_UpdateCallback(hal_tim_handle_t *htim)
{
    if (htim == mx_tim7_gethandle()) {
        MOTO_RUN(wait);
    }
}
int __io_putchar(int ch)
{
  uint8_t byte = (uint8_t)ch;
  HAL_UART_Transmit(mx_usart2_uart_gethandle(), &byte, 1, 1000);
  return ch;
}
uint16_t KEY_GET(uint16_t key_num)
{
  if(HAL_GPIO_ReadPin(HAL_GPIOC, HAL_GPIO_PIN_13) == HAL_GPIO_PIN_SET)
  {
    HAL_Delay(20);
    while(HAL_GPIO_ReadPin(HAL_GPIOC, HAL_GPIO_PIN_13) == HAL_GPIO_PIN_SET);
    HAL_Delay(20);
    key_num ++;
  }
  if(key_num > 2)
    {
      key_num = 0;
    }
  return key_num;
}
/**
  * brief:  The application entry point.
  * retval: none but we specify int to comply with C99 standard
  */
int main(void)
{
  /** System Init: this code placed in targets folder initializes your system.
    * It calls the initialization (and sets the initial configuration) of the peripherals.
    * You can use STM32CubeMX to generate and call this code or not in this project.
    * It also contains the HAL initialization and the initial clock configuration.
    */
  if (mx_system_init() != SYSTEM_OK)
  {
    return (-1);
  }
  else
  {
    /*
      * You can start your application code here
      */
    HAL_TIM_Start_IT(mx_tim7_gethandle());
    LIS3DHTR_Init();
    enum neai_state error_code = neai_classification_init();
    if (error_code != NEAI_OK) {
      printf("AI MODEL INIT FAILED\r\n");
      /* Check the returned error code (cf NanoEdgeAI.h). */
    }
    else {
      printf("AI MODEL INIT SUCCESS\r\n");
    }
    int id_class = 0;
    uint32_t last_time = HAL_GetTick();
    uint16_t key_num = 0;
    uint16_t key_num_last = 5;
    uint16_t class_count[4] = {0};
    uint16_t count = 0;
    
    while (1) {
      int16_t acc[3] = {0};
      key_num = KEY_GET(key_num);
      if ( key_num_last != key_num)
      {
          key_num_last = key_num;
          HAL_TIM_Stop_IT(mx_tim7_gethandle());
          HAL_TIM_SetCounter(mx_tim7_gethandle(), 0);
          if (key_num == 1)
          {
              
              HAL_TIM_SetPeriod(mx_tim7_gethandle(), 0x7CF);   // 1 kHz
              HAL_TIM_Start_IT(mx_tim7_gethandle());
          }
          else if (key_num == 2)
          {
              HAL_TIM_SetPeriod(mx_tim7_gethandle(), 0x4E1F);  // 100 Hz
              HAL_TIM_Start_IT(mx_tim7_gethandle());
          }
          else if(key_num == 0)
          {
            HAL_TIM_Stop_IT(mx_tim7_gethandle());
          }
      }
      int samples_read = LIS3DHTR_Read_FIFO_Data(fifo_acc);
      if(samples_read > 0) 
      {
      for (int i = 0; i < samples_read; i++) 
        {
          input_signal[signal_index * 3 + 0] = (float)fifo_acc[i * 3 + 0]; // X
          input_signal[signal_index * 3 + 1] = (float)fifo_acc[i * 3 + 1]; // Y
          input_signal[signal_index * 3 + 2] = (float)fifo_acc[i * 3 + 2]; // Z
          signal_index++;
          if(signal_index >= NEAI_INPUT_SIGNAL_LENGTH)
          {
            signal_index = 0;
            
            
             neai_classification(input_signal, probabilities, &id_class);
            
             switch (id_class) {
                case 0:
                    printf("STOP\r\n");
                    HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_RESET);
                    break;
                case 1:
                    printf("LOW\r\n");
                    HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_RESET);
                    break;
                case 2:
                    printf("FAST\r\n");
                    HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_RESET);      
                    break;
                case 3:
                    printf("ABNORMAL\r\n");
                    HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_SET);
                    break;
                default:
                    printf("Unknown class\r\n");
                    break;
             }
            }
         }
    }
    }
  }
} /* end main */

电机驱动代码

#include "MOTO.h"
void MOTO_RUN(uint16_t wait)
{
    static uint8_t step = 0;
    (void)wait;
    switch (step)
    {
        case 0: /* A+ */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
            break;
        case 1: /* A+B+ */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
            break;
        case 2: /* B+ */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
            break;
        case 3: /* A-B+ */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
            break;
        case 4: /* A- */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
            break;
        case 5: /* A-B- */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_SET);
            break;
        case 6: /* B- */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_SET);
            break;
        default: /* A+B- */
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_SET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
            HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_SET);
            break;
    }
    step = (uint8_t)((step + 1U) & 0x07U);
}

加速度传感器驱动代码.c文件

#include "LIS3DHTR.h"
void LIS3DHTR_Read(uint8_t reg, uint8_t *value, uint8_t len)
{
  HAL_I2C_MASTER_MemRead(mx_i2c1_i2c_gethandle(), LIS3DHTR_ADDRESS_UPDATED << 1,
                        reg, 1, value, len, 100);
}
void LIS3DHTR_Write(uint8_t reg, uint8_t value)
{
  HAL_I2C_MASTER_MemWrite(mx_i2c1_i2c_gethandle(), LIS3DHTR_ADDRESS_UPDATED << 1,
                          reg, 1, &value, 1, 100);
}  
void LIS3DHTR_Init(void)
{
  uint8_t id = 0;
  LIS3DHTR_Read(LIS3DHTR_REG_WHO_AM_I, &id, 1);
  if(id != 0x33)
  {
    return;
  }
  else
  {
    LIS3DHTR_Write(LIS3DHTR_REG_CTRL_REG1, 0x97);
    LIS3DHTR_Write(LIS3DHTR_REG_CTRL_REG4, 0x88);
    LIS3DHTR_Write(LIS3DHTR_REG_CTRL_REG5, 0x40);
    LIS3DHTR_Write(LIS3DHTR_REG_FIFO_CTRL_REG, 0x8F);
    // LIS3DHTR_Write(LIS3DHTR_REG_FIFO_CTRL_REG, 0xDF); 
  }
}
// void LIS3DHTR_Read_XYZ(int16_t *acc)
// {
//   uint8_t acc_buf[6] = {0};
//   LIS3DHTR_Read(0x28 | 0x80, acc_buf, 6);   // 自动递增读 6 字节
//   acc[0] = (int16_t)(((uint16_t)acc_buf[1] << 8) | acc_buf[0]) >> 4;
//   acc[1] = (int16_t)(((uint16_t)acc_buf[3] << 8) | acc_buf[2]) >> 4;
//   acc[2] = (int16_t)(((uint16_t)acc_buf[5] << 8) | acc_buf[4]) >> 4;
// }
#define FIFO_SIZE 32
int LIS3DHTR_Read_FIFO_Data(int16_t *fifo_data)
{
    uint8_t raw_buf[FIFO_SIZE * 6];
    uint8_t fifo_src = 0;
    
    LIS3DHTR_Read(LIS3DHTR_REG_FIFO_SRC_REG, &fifo_src, 1);
    
    uint8_t sample_count = fifo_src & 0x1F; 
    if (sample_count == 0) {
        return 0; // FIFO为空
    }
    uint8_t read_len = sample_count * 6;
    LIS3DHTR_Read(LIS3DHTR_REG_OUT_X_L | 0x80, raw_buf, read_len);
    
    for (int i = 0; i < sample_count; i++) 
    {
        int offset = i * 6;
        fifo_data[i*3 + 0] = (int16_t)(((uint16_t)raw_buf[offset+1] << 8) | raw_buf[offset+0]) >> 4; // X
        fifo_data[i*3 + 1] = (int16_t)(((uint16_t)raw_buf[offset+3] << 8) | raw_buf[offset+2]) >> 4; // Y
        fifo_data[i*3 + 2] = (int16_t)(((uint16_t)raw_buf[offset+5] << 8) | raw_buf[offset+4]) >> 4; // Z
    }
    
    return sample_count;
}

.h文件

#ifndef LIS3DHTR_H
#define LIS3DHTR_H
#include "main.h"
#define LIS3DHTR_ADDRESS_UPDATED (0x19)
#define LIS3DHTR_REG_STATUS_REG (0x07) // Status Register
#define LIS3DHTR_REG_WHO_AM_I (0X0F)
#define LIS3DHTR_REG_TMEP_CFG_REG (0X1F)//温度使能
#define LIS3DHTR_REG_CTRL_REG0 (0X1E)
#define LIS3DHTR_REG_CTRL_REG1 (0X20)//速率,低功耗,XYZ使能
#define LIS3DHTR_REG_CTRL_REG2 (0X21)
#define LIS3DHTR_REG_CTRL_REG3 (0X22)
#define LIS3DHTR_REG_CTRL_REG4 (0X23)//分辨率
#define LIS3DHTR_REG_CTRL_REG5 (0X24)//FIFO启动
#define LIS3DHTR_REG_CTRL_REG6 (0X25)
#define LIS3DHTR_REG_OUT_X_L (0X28)
#define LIS3DHTR_REG_OUT_X_H (0X29)
#define LIS3DHTR_REG_OUT_Y_L (0X2A)
#define LIS3DHTR_REG_OUT_Y_H (0X2B)
#define LIS3DHTR_REG_OUT_Z_L (0X2C)
#define LIS3DHTR_REG_OUT_Z_H (0X2D)
#define LIS3DHTR_REG_FIFO_CTRL_REG (0X2E)
#define LIS3DHTR_REG_FIFO_SRC_REG (0X2F)
void LIS3DHTR_Read(uint8_t reg, uint8_t *value, uint8_t len);
void LIS3DHTR_Write(uint8_t reg, uint8_t value);
void LIS3DHTR_Init(void);
void LIS3DHTR_Read_XYZ(int16_t *acc);
int LIS3DHTR_Read_FIFO_Data(int16_t *fifo_data);
#endif /* LIS3DHTR_H */






共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]