203|3

32

帖子

4

TA的资源

一粒金砂(中级)

楼主
 

【得捷电子Follow Me第二季第4期】Arduino Nano RP2040 Connect 坐姿检测应用 [复制链接]

  本帖最后由 鲜de芒果 于 2024-12-29 15:49 编辑

一、项目介绍

        随着现代办公和学习方式的改变,长时间保持不正确的坐姿可能导致多种健康问题,如腰背疼痛、颈椎疾病等。为了帮助用户实时监测和纠正坐姿,提高健康管理能力,我决定开发一款基于 Arduino Nano RP2040 Connect 的坐姿检测应用。

 

        本项目旨在开发一套智能坐姿检测系统,利用 Arduino Nano RP2040 Connect 进行数据采集与处理。系统通过传感器实时监测用户的坐姿,并在检测到不良坐姿时提供提醒,以帮助用户改善坐姿,减少因长时间不良坐姿导致的健康问题。

 

二、任务要求

  1. 坐姿检测,实时坐姿检测以帮助用户纠正不良坐姿。并将坐姿状态通过蓝牙传输至 Seeed Studio XIAO ESP32S3。
  2. 蓝牙通信,坐姿数据通过蓝牙同步,以帮助用户记录或分析坐姿数据。可以进一步优化算法和增加更多功能,如定制化的坐姿建议、长期数据分析等,为用户提供更全面的健康管理服务。
  3. 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 进阶任务

最新回复

坐姿检测,这个应用前景非常多呀,比如对人员的疲劳预警,老人的久坐提醒。  详情 回复 发表于 2024-12-30 22:22
点赞 关注
 
 

回复
举报

6387

帖子

9

TA的资源

版主

沙发
 

这小接收板看着不错,估计明年的活动会出现它 

个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 
 
 

回复

7083

帖子

2

TA的资源

版主

板凳
 

如果只是单轴的话,站姿估计和坐姿数据是一样的。

 
 
 

回复

6953

帖子

11

TA的资源

版主

4
 
坐姿检测,这个应用前景非常多呀,比如对人员的疲劳预警,老人的久坐提醒。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
推荐帖子
AVR单片机4个I/O口可以设计出12个按键!!

AVR单片机的I/O口有4个状态(输出0,输出1,内部电阻拉高(输入),高阻态)。如上图所示当IO1为输入(内部电阻拉高)、IO2输出低电平、其 ...

KOMAT'SU工控触摸屏

有块大芯片查不到DATASHEET,有哪位高人乐意帮忙啊?29844

【一个模拟电路憋倒众多英雄汉,期待高手】请教一个本网站上的带阻滤波器?

先贴上电路图,呵呵,我在pspice里仿真这个电路的传递函数挺正常的,不知道为啥,实际搭了一个电路(op4558双电源+-5V供电)出来 ...

一步一步教你使用uCOS-II

前言篇 前段时间看了Linux版块“zjw50001”网友上传的资料《一步一步教你开发嵌入式 Linux 应用程序》感觉对于学习Linux的新 ...

基于LKS32MC061C6T8的多功能电机驱动控制器原理

分享给大家一款多功能控制器,可应用于电动自行车,滑板车,三轮车等,给大家参考一下,欢迎批评指正。:)

音频功率放大器设计手册(第6版)

《音频功放设计手册》的作者是功率放大器设计方面的专家,书中给出大量音响发烧友苦心寻觅的经典功率放大器的资料,该书的译者是 ...

板子使用USB供电,工作一段时间后异常,将示波器的地接到板子的地就能恢复正常,

板子使用USB供电,工作一段时间后异常,将示波器的地接到板子的地就能恢复正常,使用一段时间之后又会出现异常状况。 这个是 ...

管脚分配的问题

如果原来的工程管脚已经分配过了,比如下图: 711533711534 那还能不能够重新批量修改管脚分配? 我在网上找了个例子, ...

Fluke有奖直播:示波器的基础知识及其校准 火热报名中

直播时间:5月29日(周三)上午10:00 直播主题:示波器的基础知识及其校准 直播简介: 1、示波器的基础知识介 ...

【Follow me第二季第2期】 进阶任务 智能家居3 MQTT接入HA(homeassistant)

本帖最后由 zarkx 于 2024-9-26 16:15 编辑 任务可以分为3个阶段 1安装HAhttps://bbs.eeworld.com.cn/thread-1293173- ...

关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表