实现功能
利用AI边缘检测,实现对电机停止,低速,高速和异常四个状态的分类,通过本地部署,反应很快。
系统框图

通过按键改变电机状态,加速度传感器将电机抖动数据传给MCU,MCU上部署的AI模型对数据进行分析,并将电机运行状态进行分类。
电路原理图


这张图展示了整个项目的硬件连接
启动
将代码烧录,并将各模块按照原理图连接,将串口连接上位机,打开电源后整个设备就能正常启动了。按下板子上的用户按键来改变电机状态,通过串口查看检测到的状态。
主要参数情况
加速度传感器采集到的数据也都非常准确,各个运行状态的数据通过串口打印分析一下,也都有明显的差别。

训练过程中的数据也都不错,软件上写的准确率100%

测试了一会,感觉识别成功率还是很高的,尤其是对异常的检测,之前没在数据中的异常抖动也被分入异常这一类。

软件调试
前面帖子中对遇到的问题大部分都解决了,在软件调试中没有遇到太大的困难,软件部分也是在前面代码的基础上修改,模块驱动代码没动,主要调整了一下主函数逻辑,新增了对异常情况的报警。
项目主要代码
/**
******************************************************************************
* 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 */新的体会
这次做下来,最大的感受是边缘AI确实很适合做电机状态检测这类任务。数据在本地采集、本地推理,响应很快,实际体验比预想的要流畅。
训练时准确率显示100%,一开始还有点担心是不是过拟合,但后面测试时发现,即使是一些没有参与训练的新异常抖动,模型也能正确识别,说明它学到的不是简单的背数据,而是确实抓住了不同状态之间的特征差异。
软件部分相对顺利,主要是在原有框架上继续完善。驱动层基本不用动,重点放在主循环里把数据采集、AI推理和状态输出串起来。加了一个异常报警后,整个系统看起来也更完整了。
整体来说,这个项目把传感器数据采集、AI模型部署和嵌入式控制结合得比较紧,做完之后对边缘AI在电机监测上的应用有了更直观的认识。
我要赚赏金
