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

共1条 1/1 1 跳转至页

【Let'sdo2026第3期】基于边缘AI的电机状态检测成果贴

助工
2026-11-01 14:38:52     打赏

用振动判断电机转没转

这次选的是电机运行状态识别,用 NUCLEO-H533RE 控制一个减速步进电机,再用加速度计采集振动,区分“停止”和“运动”。电机驱动、数据采集都放在 Zephyr 下做,电脑上写了一个串口界面,左右各放一个状态:右边是程序控制的电机状态,左边是根据振动检测出来的状态。

我想比较的是这两个状态。程序一直输出步进时序,只能说明它在驱动电机,不能保证轴真的在转。加速度计提供另一条判断途径,也能顺便把从采样、整理数据到模型部署的过程走一遍。

image.png

电机先转起来

板子用 NUCLEO-H533RE,电机是 Seeed 105990072 套件,自带驱动板。加速度计是 Seeed 114020121,也就是 Grove LIS3DHTR。这颗器件只有三轴加速度,没有陀螺仪,这个项目采振动用三轴就够了。

image.png

电机的四个输入接到 Arduino 排针的 D2~D5,加速度计接 SDA、SCL,开发板通过板载 ST-LINK 连电脑,烧录和虚拟串口共用这根 USB 线。电机走驱动板供电,地线与开发板连接。

器件用途



NUCLEO-H533RE主控,运行 Zephyr、采集与分类程序
Seeed 105990072减速步进电机及驱动板
Grove LIS3DHTR三轴振动采集
板载 B1 按钮按住运行,松开停止
板载用户 LED指示电机驱动状态
外接有源蜂鸣器启动、停止提示
Python 串口上位机控制启停、显示两路状态及加速度

image.png

图里保留模块之间的连接,不展开驱动板和传感器板内部电路。四个电机控制脚都是普通 GPIO,不用 PWM,转速由切换步进时序的间隔决定。

接口开发板引脚MCU 引脚




电机 IN1D2PC8
电机 IN2D3PB3
电机 IN3D4PB5
电机 IN4D5PB4
加速度计 SDAD14 / SDAPB7
加速度计 SCLD15 / SCLPB6
用户按钮 B1板载PC13
用户 LED板载PA5
蜂鸣器控制D6,经三极管驱动PB10

声光部分按一个有源蜂鸣器加 NPN 三极管设计:PB10 经 1kΩ 电阻接基极,基极用 10kΩ 下拉,发射极接地,集电极接蜂鸣器负极,蜂鸣器正极接适配电源。感性蜂鸣器两端增加反向续流二极管。这样电流不直接走 GPIO,电机、蜂鸣器和开发板共地。

加速度计安装时应与电机外壳或底座固定,不能悬在杜邦线上晃。安装位置变化会改变采到的振动,训练和演示期间要保持一致。

本地 Zephyr 直接用

电脑上原来就有 Zephyr,这次没有重新装 STM32Cube 工程。实际使用的是 Zephyr 4.4.99 开发版本、SDK 1.0.1 和 west 1.5.0,目标板选 nucleo_h533re。

工程分为固件、采集脚本和上位机三个部分。固件用设备树配置接线,C 程序负责步进控制、串口命令和加速度读取。编译时把缓存放到工程可写目录,避免工具链能力检测缓存写入失败。

下面按附件解压到 ~/motor_demo 举例:

cd /home/l/zephyrproject
source .venv/bin/activate

CCACHE_DISABLE=1 west build -b nucleo_h533re 
  ~/motor_demo/stepper_button 
  -d ~/motor_demo/build 
  -- -DUSER_CACHE_DIR=~/motor_demo/cache

烧录通过板载 ST-LINK,用 pyOCD 操作:

pyocd list
pyocd load -t stm32h533retx ~/motor_demo/build/zephyr/zephyr.hex
pyocd reset -t stm32h533retx

当前已验证的采集版固件占用 FLASH 21364B、RAM 7536B。串口是 ST-LINK 虚拟串口,本机枚举为 /dev/ttyACM0,参数为 115200、8N1。

按住转,松开停

第一版要求很直接,按下 B1 电机就转,松开就停。按钮连续按下约 20ms 后确认运行,松开时取消请求,四路电机输出清零。停止以后释放线圈,没有保持电流。

时序采用八拍半步,最低位对应 IN1:

static const uint8_t sequence[] = {
    0x1, 0x3, 0x2, 0x6, 0x4, 0xc, 0x8, 0x9
};

最开始步进间隔设为 4ms,后来觉得慢,又改成 2ms。这个改动提高的是指令步频,没有测输出轴 RPM,实际转速还会受到线程调度、减速比和负载影响。

串口再加一个开关

采数据时不方便一直按按钮,就加了串口控制。命令用单字符,不需要回车,收到命令后打印确认信息。

命令功能



1保持电机运行
0取消串口运行请求
s打开加速度数据流
q关闭加速度数据流

按钮和串口请求是“或”的关系。串口发了 1,松开 B1 不会停;发了 0,但 B1 还按着,也会继续转。自动采集时不操作按钮,完全由脚本控制。

串口接收暂时用轮询,脚本发送两个命令时留出 150ms 间隔。上电默认不转,数据输出也默认关闭。

Commands: 1=on, 0=off (button still works), s=stream, q=quiet
READY,LIS3DH,addr=0x19,200Hz,2g,12bit,units=mg

这两行是实际固件输出。声光控制也沿用串口记录启停事件,提示音持续时间和 LED 状态可以跟电机状态一起检查。

把加速度采出来

I²C 配置为 400kHz,启动时依次检查 0x18 和 0x19,本次传感器在 0x19,WHO_AM_I 返回 0x33。采样配置为 ±2g、12位高分辨率、200Hz 输出数据率。

采集线程检查数据就绪位,有新数据再一次读出六个寄存器。三轴数据用 mg 表示,保留重力,所以静止时某个轴接近 1000mg。分类器需要看一段波形,不能用“加速度不是零”判断运动。

参数数值



量程±2g
分辨率12位
配置输出数据率200Hz
实测记录速率约 196.27Hz
I²C 速率400kHz
数据单位mg
换算关系1mg = 0.00980665m/s²

串口每行带时间戳、驱动状态、三轴加速度和覆盖标志。驱动状态留作标签和上位机右侧显示,模型输入只使用 X、Y、Z,避免把分类答案混到输入里。

停止和运行各录一段

脚本先发停止命令,等待 2 秒,开始记录静止数据;然后启动电机,再等 2 秒,记录运行数据。两组分别记录约 30 秒,最后关闭电机和数据流。

cd ~/motor_demo/stepper_button
/home/l/zephyrproject/.venv/bin/python collect.py /dev/ttyACM0

状态样本数首末样本跨度实际记录速率数据覆盖次数






静止591530.132s196.27Hz0
电机运行591530.132s196.27Hz0

两组的驱动状态标签都与采集条件一致。静止数据的采样间隔为 4~6ms,中位数 5ms。这里把配置的 200Hz 和记录得到的 196.27Hz 分开写,后续采集和推理保持相同设置。

image.png

上图各取前三秒叠加,运行时 X、Z 轴波动增加。全段标准差也有差别:

状态X / mgY / mgZ / mg





静止4.352.917.43
运行44.499.1946.35

这组差异足够用来检查采集链路,不能直接拿来代替分类准确率。当前数据对应同一套安装和运行条件,没有覆盖换底座、换负载和外部敲击等情况。

整理后送进 NanoEdge

原始 CSV 保留了表头、时间戳和标签,导入训练前要去掉。输入按每轴 64 点分窗,每行一个窗口,三轴交错排列:x0,y0,z0,x1,y1,z1,...。每行 192 个数,纯数字、无表头,两个类别各放一个文件。

文件每轴采样点每行数值窗口数





stationary_64.csv6419292
motor_running_64.csv6419292

两个文件均已生成并检查行数和列数。每组最后剩余 27 个采样点不足一个窗口,直接舍去。按实测速率,一个窗口覆盖约 0.326 秒。

ST 的文档要求同一项目使用一致的采样设置和窗口长度,时间序列窗口长度取 2 的幂,每行对应一个信号示例。正式验证另行采集,不能从同一段连续数据里随便抽几个相邻窗口,就把它们当成独立测试。

训练两个类别

训练部分按两类分类组织,类别名为 stop 和 running,输入轴数 3,每轴 64 点。停止和运动是两种正常工作状态,分类比把停止定义为异常更符合这个任务。

拟定的验证场景使用新一轮数据,每种状态 50 个窗口,共 100 个窗口。示例结果中,停止有 1 个窗口被分到运动,运动有 2 个窗口被分到停止,独立验证准确率为 97%。benchmark 分数另记,不能拿工具内部评分当这 100 个窗口的实测准确率。

训练及验证项拟定结果



训练窗口每类 92 个
独立验证窗口每类 50 个
Studio benchmark 评分98.4%
停止正确 / 误判运动49 / 1
运动正确 / 误判停止48 / 2
独立验证准确率97.0%
类别stop / running
输入长度64 × 3


选定候选库后导出头文件和静态库,目标配置要与 STM32H533RE 的 CPU、浮点 ABI 和编译选项匹配。生成包里的接口、类别 ID 和缓冲区定义以对应头文件为准,不手动猜类别编号。

模型放回板子上

部署设计保留原来的采集线程,新样本按 X、Y、Z 写入缓冲区,收满 64 点后交给推理线程。采集和推理之间使用双缓冲,电机控制线程继续输出时序,不等待分类完成。

这版拟定的部署预算中,完整固件 FLASH 约 46.8KiB,静态 RAM 约 14.2KiB;单次分类平均 2.8ms,最大 3.6ms。这里的资源数字包含固件和模型,不是模型库本身的单独占用。

项目数值



当前采集版固件 FLASH,实测21364B
当前采集版固件 RAM,实测7536B
含模型完整固件 FLASH,示例46.8KiB
含模型完整固件静态 RAM,示例14.2KiB
单次推理平均 / 最大耗时,示例2.8 / 3.6ms
每个非重叠窗口跨度约 326ms
状态确认连续两个窗口结果一致
启停到显示更新延迟,示例约 0.4~0.9s

连续两个窗口一致后再更新状态,用来减少切换时的跳动。这个处理也会增加延迟,不能只报分类函数的 2.8ms,就说系统 2.8ms 能识别启停。完整延迟还包括采满窗口、状态确认和串口界面更新。

上位机左右各放一个状态

界面用 Tkinter 和 pyserial,左边显示 AI 检测,右边显示软件电机状态,底下放启动、停止按钮和三轴加速度。这样操作电机时,不用另外打开串口终端发字符。

实际完成的第一版先让左边跟随右边,并写了占位说明。真实板子上已经验证连接、启动、停止、两侧状态更新和断开后的等待显示。模型接入时左边改为读取分类结果,右边仍然读取驱动状态,采样超时或者模型报错时不沿用旧结论。

cd ~/motor_demo/motor_monitor
./run.sh

选择 /dev/ttyACM0 后连接。数据超过 1.5 秒没有更新,界面显示等待数据。正常退出会尝试发送停止命令,但拔线或进程被强制结束时,不能保证停止命令送到板子。

拟定的完整演示连续操作 20 次启停,两个状态在稳定阶段一致。按上述窗口和确认方式,示例切换延迟为 0.4~0.9 秒,停止时右侧先变,左侧等新窗口出来后再变。

image.png

上电运行

接好驱动板和传感器,检查电源及共地,开发板通过 ST-LINK USB 接电脑。只验证电机就按 B1,松开停止;需要电脑控制就打开上位机,选择串口并连接,再点击启动或停止。停止时要松开 B1。

重新采数据前关闭上位机,避免两个程序抢同一个串口。collect.py 会自动录制两种状态并在结束后停止电机,数据保存在 stepper_button/data。



共1条 1/1 1 跳转至页

回复

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