基于行空板K10的加速度计进行运动状态分类的Tiny ML
一、项目来源本项目基于新课标中对“人工智能与物联网”融合教育理念的要求,注重培养学生的科技创新思维与跨学科实践能力。让学生学会在边缘设备上部署Tiny ML模型,这不仅能让学生深入学习行空板的编程与应用,还能了解机器学习、模型训练与部署的概念。
二、项目介绍
1.项目背景
本项目是利用行空板K10主控上的加速度传感器,通过收集物体的运动数据,分析其不同的运动状态。主要目的是识别出物体是否处于静止状态、行驶中的车或是移动中的船。为实现这一目标,我们首先使用加速度传感器收集不同状态下的数据,然后在Edge Impulse平台上对这些数据进行模型训练,最终生成一个Tiny ML模型。该模型被部署到行空板K10上,能够实时分析加速度数据,并准确判断物体的运动状态(静止、车、船)。这个应用可以为物联网、智能监控等领域提供实时的识别和分析解决方案。
2.项目目标
总体目标让学生掌握数据收集与处理、模型训练和模型部署并应用的方法。具体目标如下:
(1)学习数据采集与预处理:学生将通过行空板K10主控的加速度传感器,学习如何采集物体在不同状态下的运动数据,并了解数据预处理的基本方法。
(2)掌握机器学习基础:学生将在Edge Impulse平台上进行数据分析和模型训练,学习机器学习的基本原理,并掌握如何使用平台训练一个Tiny ML模型。
(3)培养跨学科能力:通过完成此项目,学生将在数据科学、机器学习等领域获得实践经验,培养跨学科的综合能力。
3.项目所需硬件材料和软件
行空板K10
edge impulse平台账号
uartassist串口工具软件
三、项目原理
本项目的核心原理基于加速度传感器的数据采集和机器学习模型的应用。通过加速度传感器,我们能够实时监测物体的运动情况,并将这些数据用于分析物体的运动状态。项目的工作原理可以分为以下几个步骤:
[*]数据采集与标注:使用行空板K10主控上的加速度传感器,采集物体在不同运动状态下的加速度数据。不同状态(如静止、车行驶、船移动)下,物体的加速度值会表现出不同的特征,通过传感器可以实时获取这些数据。在采集加速度XYZ方向上的数据的过程中,数据会被标注为静止状态(stop)、车(car)和船(ship)等不同的类别。
[*]模型训练:通过Edge Impulse平台,使用标注后的数据进行机器学习模型的训练。平台会根据不同状态的加速度特征,自动调整模型参数,最终生成一个能够区分静止、车和船状态的Tiny ML模型。
[*]模型部署与实时识别:训练完成的Tiny ML模型被部署到行空板K10主控上,模型可以在硬件上实时运行,接收新的加速度数据并进行分类。通过对加速度数据的实时分析,模型可以自动识别物体的当前运动状态,并做出相应的分类(静止、车、船)。
[*]输出结果:模型通过对加速度数据的分类输出不同的运动状态,实时监测物体的运动情况,应用于智能监控、交通管理等多个场景。
项目的原理融合了传感器数据采集、机器学习和嵌入式系统技术,利用加速度传感器的特性和Tiny ML模型的高效性,实现了物体运动状态的自动识别。
四、项目知识点
1. 串口工具uartassist的使用
[*]功能:uartassist是一个串口调试工具,主要用于与嵌入式系统通过串口进行数据通信。在本项目中,行空板K10通过串口输出加速度传感器的数据,使用uartassist工具可以方便地接收并保存这些数据。
[*]使用方法:首先将行空板K10与电脑通过串口连接,确保串口通信正常。然后,通过uartassist工具配置正确的串口参数(如波特率、数据位、停止位等),启动数据接收。将接收到的加速度数据保存为CSV格式文件,方便后续的分析和处理。
2. 机器学习基础
(1)机器学习概念:
[*]监督学习:在监督学习中,模型通过已标注的训练数据(输入和对应的输出标签)进行训练。模型通过学习输入与输出之间的映射关系,在新数据上进行预测。常见的监督学习任务包括分类和回归。
[*]分类问题:分类问题是指将输入数据分为多个类别,输出的是一个类别标签。例如,物体运动状态的识别就是一个典型的分类问题,模型根据输入的数据判断物体是静止、车还是船。
(2)怎么使用Edge Impulse平台:
[*]数据采集:首先使用传感器(如加速度传感器)采集数据,然后将数据上传到Edge Impulse平台。
[*]特征提取:Edge Impulse平台可以从原始数据中自动提取特征,或者用户可以自定义提取合适的特征。
[*]模型训练:使用平台上的机器学习算法对数据进行训练,生成一个能够识别运动状态的模型。平台提供了直观的操作界面和工具,使得用户可以轻松调整模型参数并监控训练过程。
[*]模型部署:训练完成后,可以将模型导出并部署行空板K10上,实现实时数据处理。
(3)什么是模型评估的准确率和损失率:
[*]准确率(Accuracy):准确率是分类模型性能的衡量标准之一,表示正确预测的样本占总样本的比例。准确率越高,模型预测的准确性越好。
[*]损失率(Loss):损失率是衡量模型误差的指标,表示模型的预测值与实际值之间的差距。在训练过程中,损失率会逐步减少,表示模型在逐渐优化。
3. Tiny ML部署在边缘设备上的机器学习模型:
[*]什么是Tiny ML:Tiny ML指的是在低功耗、资源受限的嵌入式设备上运行机器学习模型。它通过优化算法和模型,使得机器学习可以在小型、低功耗的硬件(如微控制器)上高效执行。这使得物联网设备和其他嵌入式系统能够处理复杂的机器学习任务,而无需依赖云端计算。
[*]实时数据处理的好处:实时处理:实时数据处理指的是在数据生成的同时进行处理和分析,而不是将数据先存储后处理。这样可以立刻获得反馈,在许多应用中(如交通监控、健康监测等)是至关重要的。
五、项目实现
1.收集数据:
编写收集数据程序,并上传至行空板K10。
打开串口工具uartassist,收集串口数据并保存为CSV格式的文件。
数据收集完成如下:
2,在edge impulse平台上进行数据上传与处理,模型训练,模型部署文件下载。
首先打开edge impluse网页(需要注册好账号)
edge impulse网址:Edge Impulse - The Leading Edge AI Platform
(1)新建项目
(2)进行CSV文件配置向导
(3)上传stop.csv、car.csv、ship.csv文件
(4)创建脉冲,进行模型训练的功能配置
(5)数据特征处理
(6)开始训练模型。注意这里需要进行超参数的设置
(7)下载平台打包好的模型部署文件,以Arduino 库的形式的一个zip文件。(后面使用Arduino IDE进行模型的部署)
关于2个超参数的调整:如果你的模型训练完成后,准确率不高,可以调整2个超参数的值后再次进行学习。直到模型评估的准确率有一个不错的值,比如在85%以上。
【备注:关于edge impulse平台的使用,可以观看视频学习,这里就不详细的补充具体使用细节了。】
https://www.bilibili.com/video/BV1ADBUYmE8Q/?spm_id_from=333.999.0.0&vd_source=0be0123046a7f0132b29d51461f22290
3,在Arduino IDE上部署
(1)打开Arduino IDE后,通过“项目”——“导入库”——“添加.ZIP库”,安装在edge impuse平台下载的模型部署文件,比如我下载的“ei-k10_tiny-ml-arduino-1.0.1.zip”
(2)通过“文件”——“示例”——“ei-k10_tiny-ml-arduino-1.0.1”打开ei-k10_tiny-ml-arduino-1.0.1库下的通用示例文件“static_buffer”
(3)修改示例文件里的features特征数组的值,完成实时检测,通过串口查看模型推理预测的结果。
经过修改的模型部署Arduino IDE代码如下,里面增加了获取加速度传感器数据的相关代码:
<font face="微软雅黑" size="3">#include <K10_Tiny_ML_inferencing.h>
#include <Wire.h>
// SC7A20H 传感器 I2C 地址
#define SC7A20H_ADDR 0x19
// 加速度数据寄存器
#define ACC_X_L 0xA8// X轴低位数据寄存器
#define ACC_X_H 0xA9// X轴高位数据寄存器
#define ACC_Y_L 0xAA// Y轴低位数据寄存器
#define ACC_Y_H 0xAB// Y轴高位数据寄存器
#define ACC_Z_L 0xAC// Z轴低位数据寄存器
#define ACC_Z_H 0xAD// Z轴高位数据寄存器
// 初始化 SC7A20H 传感器
void initSC7A20H() {
Wire.begin();// 初始化 I2C 总线
delay(10);// 等待传感器初始化
// 配置 SC7A20H 进入正常工作模式
Wire.beginTransmission(SC7A20H_ADDR);
Wire.write(0x20);// 选择控制寄存器 1 (CTRL_REG1)
Wire.write(0x57);// 设置 100Hz 采样率,正常模式,启用 X/Y/Z 轴数据采集
Wire.endTransmission();
}
// 读取 SC7A20H 传感器单个轴的加速度数据
int16_t readAxis(uint8_t regL, uint8_t regH) {
// 读取低字节
Wire.beginTransmission(SC7A20H_ADDR);
Wire.write(regL);// 选择低字节寄存器
Wire.endTransmission();
Wire.requestFrom(SC7A20H_ADDR, 1);// 请求 1 字节数据
uint8_t lsb = Wire.read();// 读取低字节
// 读取高字节
Wire.beginTransmission(SC7A20H_ADDR);
Wire.write(regH);// 选择高字节寄存器
Wire.endTransmission();
Wire.requestFrom(SC7A20H_ADDR, 1);// 请求 1 字节数据
uint8_t msb = Wire.read();// 读取高字节
// 组合高低字节,右移 4 位,转换为 16 位加速度值
int16_t value = ((msb << 8) | lsb) >> 4;
// 如果数据为负数(补码转换)
if (value & 0x800) {
value -= 4096;
}
return value;
}
// 特征数据数组(存放加速度传感器采集的数据样本)
static float features[] = {
-47, 145, -1064, -46, 146, -1058, -40, 144, -1058, -39, 144,
-1067, -41, 141, -1061, -46, 139, -1056, -46, 139, -1056, -47,
141, -1048, -45, 141, -1043, -42, 142, -1048
};
// 获取数据的函数,填充特征数组
int raw_feature_get_data(size_t offset, size_t length, float *out_ptr) {
memcpy(out_ptr, features + offset, length * sizeof(float));
return 0;
}
// 推理结果打印函数声明
void print_inference_result(ei_impulse_result_t result);
void setup() {
// 设置串口输出,初始化通信
Serial.begin(115200);// 初始化串口,波特率 115200
while (!Serial);// 等待串口连接
Serial.println("Edge Impulse Inferencing Demo");
Wire.begin(47, 48);// 初始化 I2C 总线,设置 SDA=GPIO47,SCL=GPIO48
initSC7A20H();// 初始化 SC7A20H 传感器
}
void loop() {
// 打印推理信息
ei_printf("Edge Impulse standalone inferencing (Arduino)\n");
// 读取 10 个样本的加速度数据
for (int i = 0; i < 10; i++) {
// 读取每个轴的加速度数据
int accX = readAxis(ACC_X_L, ACC_X_H);
int accY = readAxis(ACC_Y_L, ACC_Y_H);
int accZ = readAxis(ACC_Z_L, ACC_Z_H);
// 填充每个样本的数据到特征数组
features = accX;// 存储 X 轴数据
features = accY;// 存储 Y 轴数据
features = accZ;// 存储 Z 轴数据
}
// 检查特征数组的大小是否符合预期
if (sizeof(features) / sizeof(float) != EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE) {
ei_printf("The size of your 'features' array is not correct. Expected %lu items, but had %lu\n",
EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, sizeof(features) / sizeof(float));
delay(1000);// 等待 1 秒后重试
return;
}
ei_impulse_result_t result = { 0 };// 初始化推理结果结构体
// 将特征数据存储在闪存中,而不是将所有数据加载到 RAM 中
signal_t features_signal;
features_signal.total_length = sizeof(features) / sizeof(features);
features_signal.get_data = &raw_feature_get_data;// 数据获取函数
// 执行推理
EI_IMPULSE_ERROR res = run_classifier(&features_signal, &result, false /* debug */);
if (res != EI_IMPULSE_OK) {
ei_printf("ERR: Failed to run classifier (%d)\n", res);
return;
}
// 打印推理结果
ei_printf("run_classifier returned: %d\r\n", res);
print_inference_result(result);// 输出推理结果
delay(1000);// 每 1 秒进行一次推理
}
// 输出推理结果的函数
void print_inference_result(ei_impulse_result_t result) {
// 打印推理的时间(DSP、推理、异常检测)
ei_printf("Timing: DSP %d ms, inference %d ms, anomaly %d ms\r\n",
result.timing.dsp,
result.timing.classification,
result.timing.anomaly);
// 打印分类结果
ei_printf("Predictions:\r\n");
for (uint16_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {
ei_printf("%s: ", ei_classifier_inferencing_categories);
ei_printf("%.5f\r\n", result.classification.value);// 打印每个分类的概率值
}
}
</font>
----------------------------------------------谢谢观看---------------------------------------------
页:
[1]