【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 坐姿检测应用
[复制链接]
本帖最后由 鲜de芒果 于 2024-12-29 15:49 编辑
一、项目介绍
随着现代办公和学习方式的改变,长时间保持不正确的坐姿可能导致多种健康问题,如腰背疼痛、颈椎疾病等。为了帮助用户实时监测和纠正坐姿,提高健康管理能力,我决定开发一款基于 Arduino Nano RP2040 Connect 的坐姿检测应用。
本项目旨在开发一套智能坐姿检测系统,利用 Arduino Nano RP2040 Connect 进行数据采集与处理。系统通过传感器实时监测用户的坐姿,并在检测到不良坐姿时提供提醒,以帮助用户改善坐姿,减少因长时间不良坐姿导致的健康问题。
二、任务要求
- 坐姿检测,实时坐姿检测以帮助用户纠正不良坐姿。并将坐姿状态通过蓝牙传输至 Seeed Studio XIAO ESP32S3。
- 蓝牙通信,坐姿数据通过蓝牙同步,以帮助用户记录或分析坐姿数据。可以进一步优化算法和增加更多功能,如定制化的坐姿建议、长期数据分析等,为用户提供更全面的健康管理服务。
- Seeed Studio XIAO ESP32S3 根据接收到的坐姿状态是否良好,显示在OLED屏幕上。并且当坐姿不良时,通过蜂鸣器发出警示音。
三、 硬件准备
- Arduino Nano RP2040 Connect 搭载功能丰富的 Raspberry Pi RP2040 微控制器,将其融入到 Nano 尺寸封装中。充分利用双核32位Arm® Cortex®-M0+处理器,通过U-blox® Nina W102模块实现蓝牙和WiFi连接,集速度计、陀螺仪、RGB LED和麦克风于一体,是物联网应用的不错选择。
- Seeed Studio XIAO ESP32S3 Seeed Studio XIAO 系列是小型开发板,共享类似的硬件结构,尺寸实际上是拇指大小。这里的代号“XIAO”代表它的一半特征 “小”,另一半将是 “羊角面包”。 Seeed Studio XIAO ESP32S3 结合嵌入式ML计算能力和摄影能力,这款开发板可以成为您开始使用智能语音和视觉AI的绝佳工具。
四、代码实现
4.1 坐姿检测外设实现代码
坐姿检测外设基于本次活动开发板 Arduino Nano RP2040 Connect 来实现,搭戴一块锂电池安装到模拟设备身上进行坐姿检测。
/**
* FollowMe 2-4 任务4:
* 1. 坐姿检测
* 2. 蓝牙通信
* 3. 坐姿数据通过蓝牙传输
*/
#include <Arduino.h>
#include <ArduinoBLE.h>
#include <Arduino_LSM6DSOX.h>
#include <GyverFilters.h>
#include <WiFiNINA.h>
#include "Madgwick.h"
#define CALIB_OFFSET_NB_MES 1000 // 计算IMU零漂次数
#define DATA_MULTIPLIER 100 // 欧拉角数据放大100倍
#define SITTING_STRAIGHT_THRESHOLD 1.0 // 坐姿加速度阈值
#define TOLERANCE 0.05 // 坐姿加速度阈值允许的误差范围
GKalman xAccKalmanFilter(2, 2, 0.01); // x轴加速度计卡尔曼滤波
GKalman yAccKalmanFilter(2, 2, 0.01); // y轴加速度计卡尔曼滤波
GKalman zAccKalmanFilter(2, 2, 0.01); // z轴加速度计卡尔曼滤波
GKalman xGyroKalmanFilter(2, 2, 0.01); // x轴陀螺仪卡尔曼滤波
GKalman yGyroKalmanFilter(2, 2, 0.01); // y轴陀螺仪卡尔曼滤波
GKalman zGyroKalmanFilter(2, 2, 0.01); // z轴陀螺仪卡尔曼滤波
// 初始化 MadgwickAHRS 算法过滤器,用于姿态估
Madgwick filter;
bool isSittingPostureOk = false; // 坐姿状态是否正常
float Ax, Ay, Az; // 三轴加速度计数据
float Gx, Gy, Gz; // 三轴陀螺仪数据
float roll, pitch, yaw; // 欧拉角数据
float xAccOffset = 0; // x轴加速度计零漂
float yAccOffset = 0; // y轴加速度计零漂
float zAccOffset = 0; // z轴加速度计零漂
float xGyroOffset = 0; // x轴陀螺仪零漂
float yGyroOffset = 0; // y轴陀螺仪零漂
float zGyroOffset = 0; // z轴陀螺仪零漂
float xAcc = 0; // x轴加速度计
float yAcc = 0; // y轴加速度计
float zAcc = 0; // z轴加速度计
float xGyro = 0; // x轴陀螺仪
float yGyro = 0; // y轴陀螺仪
float zGyro = 0; // z轴陀螺仪
uint32_t previousMillis = 0; // tick
// roll = pitch = yaw = Ax = Ay = Az = Gx = Gy = Gz = 0.0f;
BLEService IMUService("19B10000-E8F2-537E-4F6C-D104768A1214"); // IMU 服务
// IMU 特征符
BLEBoolCharacteristic sittingPostureCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // 坐姿,1:正常,0:不良
BLEFloatCharacteristic xAccCharacteristic("19B10002-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // x轴加速度计
BLEFloatCharacteristic yAccCharacteristic("19B10003-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // y轴加速度计
BLEFloatCharacteristic zAccCharacteristic("19B10004-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // z轴加速度计
BLEFloatCharacteristic xGyroCharacteristic("19B10005-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // x轴陀螺仪
BLEFloatCharacteristic yGyroCharacteristic("19B10006-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // y轴陀螺仪
BLEFloatCharacteristic zGyroCharacteristic("19B10007-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // z轴陀螺仪
/**
* 计算陀螺仪零漂
*/
void calcOffsets(bool is_calc_gyro, bool is_calc_acc);
void setup() {
// 串口初始化
Serial.begin(115200);
delay(1500);
// 初始化三色 LED 为输出
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
// IMU 初始化并启动通信
while (!IMU.begin()) {
Serial.println("IMU(LSM6DSOXTR) 初始化失败, 延时1秒后重试!");
IMU.end();
delay(1000);
}
// 打印采样速率
Serial.print("加速度计采样速率 ");
Serial.print(IMU.accelerationSampleRate());
Serial.println(" Hz");
Serial.print("陀螺仪采样速率 ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println(" Hz");
// 蓝牙初始化
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy failed!");
}
// 设置发布的蓝牙服务本地名称和服务UUID
BLE.setLocalName("IMU Device");
BLE.setAdvertisedService(IMUService);
// 添加特征码至IMU服务
IMUService.addCharacteristic(sittingPostureCharacteristic);
IMUService.addCharacteristic(xAccCharacteristic);
IMUService.addCharacteristic(yAccCharacteristic);
IMUService.addCharacteristic(zAccCharacteristic);
IMUService.addCharacteristic(xGyroCharacteristic);
IMUService.addCharacteristic(yGyroCharacteristic);
IMUService.addCharacteristic(zGyroCharacteristic);
// 绑定蓝牙服务
BLE.addService(IMUService);
// 发布服务
BLE.advertise();
}
void loop() {
// 监听蓝牙外设连接
BLEDevice central = BLE.central();
// 中心连接到外设
if (central) {
Serial.print("Connected to central: ");
Serial.println(central.address());
// 连接状态
while (central.connected()) { // 连接成功,发布数据
uint32_t currentMillis = millis();
// 读取加速度计数据与陀螺仪数据
if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
IMU.readAcceleration(Ax, Ay, Az);
IMU.readGyroscope(Gx, Gy, Gz);
xAcc = (Ax - xAccOffset); // x轴加速度计
yAcc = (Ay - yAccOffset); // y轴加速度计
zAcc = (Az - zAccOffset); // z轴加速度计
xGyro = (Gx - xGyroOffset); // x轴陀螺仪
yGyro = (Gy - yGyroOffset); // y轴陀螺仪
zGyro = (Gz - zGyroOffset); // z轴陀螺仪
isSittingPostureOk = (SITTING_STRAIGHT_THRESHOLD - TOLERANCE) <= abs(xAcc) && abs(xAcc) <= (SITTING_STRAIGHT_THRESHOLD + TOLERANCE);
if(200 <= (currentMillis - previousMillis)) {
previousMillis = currentMillis;
sittingPostureCharacteristic.writeValue(isSittingPostureOk);
xAccCharacteristic.writeValue(xAcc); // x轴加速度计
yAccCharacteristic.writeValue(yAcc); // y轴加速度计
zAccCharacteristic.writeValue(zAcc); // z轴加速度计
xGyroCharacteristic.writeValue(xGyro); // x轴陀螺仪
yGyroCharacteristic.writeValue(yGyro); // y轴陀螺仪
zGyroCharacteristic.writeValue(zGyro); // z轴陀螺仪
Serial.print(xGyro);
Serial.print(",");
Serial.print(yGyro);
Serial.print(",");
Serial.print(zGyro);
Serial.print(",");
Serial.print(xAcc);
Serial.print(",");
Serial.print(yAcc);
Serial.print(",");
Serial.print(zAcc);
Serial.print(",");
Serial.println(isSittingPostureOk);
}
}
delay(50);
}
// 连接断开
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
}
/**
* 计算陀螺仪零漂
*/
void calcOffsets(bool is_calc_gyro, bool is_calc_acc) {
if(is_calc_gyro) {
xGyroOffset = 0;
yGyroOffset = 0;
zGyroOffset = 0;
}
if(is_calc_acc) {
xAccOffset = 0;
yAccOffset = 0;
zAccOffset = 0;
}
float ag[6] = {0,0,0,0,0,0}; // 3*acc, 3*gyro
for(int i = 0; i < CALIB_OFFSET_NB_MES; i++){
if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
IMU.readAcceleration(Ax, Ay, Az);
IMU.readGyroscope(Gx, Gy, Gz);
}
ag[0] += Ax;
ag[1] += Ay;
ag[2] += (Az-1.0); // 假设设备静止且Z轴向下
ag[3] += Gx;
ag[4] += Gy;
ag[5] += Gz;
delay(10);
}
if(is_calc_acc){
xAccOffset = ag[0] / CALIB_OFFSET_NB_MES;
yAccOffset = ag[1] / CALIB_OFFSET_NB_MES;
zAccOffset = ag[2] / CALIB_OFFSET_NB_MES;
}
if(is_calc_gyro){
xGyroOffset = ag[3] / CALIB_OFFSET_NB_MES;
yGyroOffset = ag[4] / CALIB_OFFSET_NB_MES;
zGyroOffset = ag[5] / CALIB_OFFSET_NB_MES;
}
}
4.2 作品源码
项目源码下载地址:https://download.eeworld.com.cn/detail/%E9%B2%9Cde%E8%8A%92%E6%9E%9C/635463
源码说明
- followme2_4_task1 文件夹:【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 入门任务源码,Arduino 工程。
- followme2_4_task2 文件夹:【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 基础任务源码,Arduino 工程。
- followme2_4_task3 文件夹:【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 进阶任务源码,Arduino 工程。
- followme2_4_task4 文件夹:【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 坐姿检测任务外设部分源码,Arduino 工程。
- followme2_4_task4_central 文件夹:【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 坐姿检测任务接收部分源码,PlatformIO Arduino 工程。
五、效果展示
5.1 坐姿检测模拟实验
5.2 坐姿正常
5.3 不良坐姿
5.4 作品演示视频
六、结语
本项目利用先进的Arduino Nano RP2040 Connect开发板,结合多种传感器和反馈机制,利用简单的硬件和软件工具帮助用户纠正不良坐姿,促进健康生活方式。实现了实时、准确的坐姿检测和纠正功能。未来,我们可以进一步优化算法和增加更多功能,如定制化的坐姿建议、长期数据分析等,为用户提供更全面的健康管理服务。
通过这个项目,我们不仅提高了对物联网技术的理解和运用能力,也学会了如何将理论转化为解决实际问题的应用。希望这些经验和心得能为未来的项目提供参考和启发。
七、参考资料
八、传送门
【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 入门任务
【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 基础任务
【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 进阶任务
|