【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 坐姿检测应用
[复制链接]
本帖最后由 鲜de芒果 于 2025-1-10 19:36 编辑
一、项目介绍
随着现代办公和学习方式的改变,长时间保持不正确的坐姿可能导致多种健康问题,如腰背疼痛、颈椎疾病等。为了帮助用户实时监测和纠正坐姿,提高健康管理能力,我决定开发一款基于 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 软件流程图
4.2 坐姿检测外设实现代码
坐姿检测外设基于本次活动开发板 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
- #define DATA_MULTIPLIER 100
- #define SITTING_STRAIGHT_THRESHOLD 1.0
- #define TOLERANCE 0.05
- GKalman xAccKalmanFilter(2, 2, 0.01);
- GKalman yAccKalmanFilter(2, 2, 0.01);
- GKalman zAccKalmanFilter(2, 2, 0.01);
- GKalman xGyroKalmanFilter(2, 2, 0.01);
- GKalman yGyroKalmanFilter(2, 2, 0.01);
- GKalman zGyroKalmanFilter(2, 2, 0.01);
-
-
- Madgwick filter;
- bool isSittingPostureOk = false;
- float Ax, Ay, Az;
- float Gx, Gy, Gz;
- float roll, pitch, yaw;
- float xAccOffset = 0;
- float yAccOffset = 0;
- float zAccOffset = 0;
- float xGyroOffset = 0;
- float yGyroOffset = 0;
- float zGyroOffset = 0;
- float xAcc = 0;
- float yAcc = 0;
- float zAcc = 0;
- float xGyro = 0;
- float yGyro = 0;
- float zGyro = 0;
- uint32_t previousMillis = 0;
-
-
- BLEService IMUService("19B10000-E8F2-537E-4F6C-D104768A1214");
-
- BLEBoolCharacteristic sittingPostureCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
- BLEFloatCharacteristic xAccCharacteristic("19B10002-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
- BLEFloatCharacteristic yAccCharacteristic("19B10003-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
- BLEFloatCharacteristic zAccCharacteristic("19B10004-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
- BLEFloatCharacteristic xGyroCharacteristic("19B10005-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
- BLEFloatCharacteristic yGyroCharacteristic("19B10006-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
- BLEFloatCharacteristic zGyroCharacteristic("19B10007-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);
-
- /**
- * 计算陀螺仪零漂
- */
- void calcOffsets(bool is_calc_gyro, bool is_calc_acc);
-
- void setup() {
-
- Serial.begin(115200);
- delay(1500);
-
- pinMode(LEDR, OUTPUT);
- pinMode(LEDG, OUTPUT);
- pinMode(LEDB, OUTPUT);
-
-
- 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!");
- }
-
- BLE.setLocalName("IMU Device");
- BLE.setAdvertisedService(IMUService);
-
- 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);
- yAcc = (Ay - yAccOffset);
- zAcc = (Az - zAccOffset);
- xGyro = (Gx - xGyroOffset);
- yGyro = (Gy - yGyroOffset);
- zGyro = (Gz - zGyroOffset);
- 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);
- yAccCharacteristic.writeValue(yAcc);
- zAccCharacteristic.writeValue(zAcc);
- xGyroCharacteristic.writeValue(xGyro);
- yGyroCharacteristic.writeValue(yGyro);
- zGyroCharacteristic.writeValue(zGyro);
-
- 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};
- 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);
- 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.3 作品源码
项目源码下载地址: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 进阶任务
|