一、背景

随着人口老龄化的不断加剧,老年人的健康和安全问题备受关注。本设计旨在利用STM32单片机与MPU6050传感器相结合,实现基于角度变化的跌倒检测系统。这一系统不仅能够快速、准确地检测老年人是否发生跌倒,还通过整合通信模块实现了实时的跌倒提醒功能。设计目标包括通过C编写MPU6050传感器的驱动代码和数据滤波算法,确保系统对身体姿态的敏感性和准确性。同时,通过整合通信模块,老年人在发生跌倒时能够及时地向特定用户发送提醒信息,包括短信和坐标,以便他们能够及时作出相应的帮助。为确保系统的可用性和便携性,本设计采用小型电池供电,使老年人可以随时随地使用。

注:本设计由于前期调研不够充分,没有GPS模块,也没有无线传输功能。

二、项目材料清单

面包板已经各种公母线

stm32f103c8t6

蜂鸣器

0.96寸OLED显示模块

CH340串口

ESP8266-01s

三、主控器与传感器的连接

电路连接图

这里因为我已经将原来的电路给拆了,所以只能照着这张图去给大家说下,GND和VCC就省去了。

蜂鸣器:I/O 与PB12相接

OLED:SCL与PB8,SDAPB9

MPU6050:SCL与PB10,SDA与PB11

串口:TXD与PA10,RXD与PA9

ESP8266-01s我没有驱动成功,所以放在这里只是一个摆设。需要注意的是MPU6050最好像我这样连接,因为我们需要通过它获取俯仰角和翻滚角,要保证模块的平稳。

通过串口发送数据

四、跌倒检测算法的设计

使用MPU6050传感器获取加速度计和陀螺仪的原始数据,通过STM32的I2C接口与MPU6050进行通信,读取加速度和角速度数据。该算法可以根据以下步骤来实现

步骤:

1. 计算加速度计推导的俯仰角和横滚角:

   a. 使用 atan2(AY, sqrt(AX * AX + AZ * AZ)) 计算 accPitch,将结果转换为角度。

   b. 使用 atan2(-AX, AZ) 计算 accRoll,将结果转换为角度。

2. 对陀螺仪数据进行角速度积分:

   a. 通过积分陀螺仪数据 GY,按照灵敏度系数(131.0)进行缩放,计算 gyroPitch。

   b. 通过积分陀螺仪数据 GX,使用相同的灵敏度系数,计算 gyroRoll。

3. 应用互补滤波:

   a. 将互补滤波系数 alpha 定义为 0.98。

   b. 利用互补滤波,结合加速度计推导的角度(accPitch、accRoll)和陀螺仪积分得到的角度(gyroPitch、gyroRoll):

4. 输出:

   更新后的俯仰角和横滚角代表设备平稳和稳定的方向。

下面是我写的伪代码,帮助大家理解这里:

Algorithm UpdateAttitude(int16_t AX, int16_t AY, int16_t AZ, int16_t GX, int16_t GY, int16_t GZ):

Input: Acceleration and gyroscope data (AX, AY, AZ, GX, GY, GZ)

Output: None (updates global variables pitch and roll)

1:accPitch = atan2(AY, sqrt(AX * AX + AZ * AZ)) * (180.0 / M_PI)

2:accRoll = atan2(-AX, AZ) * (180.0 / M_PI)

    3:gyroPitch = pitch + (float)GY / 131.0  

    4:gyroRoll = roll + (float)GX / 131.0

    5:alpha = 0.98  

    6:pitch = alpha * gyroPitch + (1.0 - alpha) * accPitch

    7:roll = alpha * gyroRoll + (1.0 - alpha) * accRoll

五、主逻辑代码

软件使用的Keil5,这些库函数都可以从江科大的视频获得,所以这里仅仅展示主逻辑代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"
#include "Buzzer.h"
#include "Serial.h"
#include <math.h>
#include <stdbool.h>

bool pose1 = true;
bool pose2 = true;
#define M_PI (3.14159265358979323846264338327950288)
uint8_t ID;								//定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;			//定义用于存放各个数据的变量


// 定义全局变量用于存储姿态角度
float pitch = 0.0; // 俯仰角
float roll = 0.0;  // 横滚角

// 定义函数进行姿态检测
void UpdateAttitude(int16_t AX, int16_t AY, int16_t AZ, int16_t GX, int16_t GY, int16_t GZ) {
    // 加速度计的角度计算
    float accPitch = atan2(AY, sqrt(AX * AX + AZ * AZ)) * (180.0 / M_PI);
    float accRoll = atan2(-AX, AZ) * (180.0 / M_PI);

    // 陀螺仪积分得到角速度
    float gyroPitch = pitch + (float)GY / 131.0; // 131 根据陀螺仪灵敏度调整
    float gyroRoll = roll + (float)GX / 131.0;

    // 综合加速度计和陀螺仪数据,使用互补滤波
    float alpha = 0.98; // 互补滤波系数,根据需要调整
    pitch = alpha * gyroPitch + (1.0 - alpha) * accPitch;
    roll = alpha * gyroRoll + (1.0 - alpha) * accRoll;
}

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	MPU6050_Init();		//MPU6050初始化
	Serial_Init();
	Buzzer_Init();
	
	/*显示ID号*/
	OLED_ShowString(1, 1, "ID:");		//显示静态字符串
	ID = MPU6050_GetID();				//获取MPU6050的ID号
	OLED_ShowHexNum(1, 4, ID, 2);		//OLED显示ID号
	
	//Serial_SendByte(0x41);
	while (1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);		//获取MPU6050的数据
		
		// 更新姿态角度
        UpdateAttitude(AX, AY, AZ, GX, GY, GZ);
        
        // 在OLED上显示姿态角度
        OLED_ShowString(2, 1, "Pitch: ");
        OLED_ShowSignedNum(2, 8, (int16_t)pitch, 5);
        
        OLED_ShowString(3, 1, "Roll: ");
        OLED_ShowSignedNum(3, 7, (int16_t)roll, 5);
		
		// 打印姿态
        if (pitch > 30) {
            OLED_ShowString(4, 1, "Back   ");
			pose1 = false;
        } else if (pitch < -30) {
            OLED_ShowString(4, 1, "Front  ");
			pose1 = false;
        } else {
            OLED_ShowString(4, 1, "Normal ");
			pose1 = true;
        }
        
        if (roll < -70) {
            OLED_ShowString(4, 10, "Right ");
			pose2 = false;
        } else if (roll > 0) {
            OLED_ShowString(4, 10, "Left  ");
			pose2 = false;
        } else {
            OLED_ShowString(4, 10, "Normal");
			pose2 = true;
        }
		
        if (!pose1 || !pose2) {
            // 触发蜂鸣器响
            Buzzer_ON();
        } else {
            // 关闭蜂鸣器
            Buzzer_OFF();
        }
		
        // 通过串口发送姿态角度
        Serial_SendString("Pitch: ");
        Serial_SendNumber((int16_t)pitch, 5);
        Serial_SendString(", Roll: ");
        Serial_SendNumber((int16_t)roll, 5);
        Serial_SendString("\r\n");
	}
}

简单来说下这个代码大致完成了什么功能,将面板板平放之后,我发现Pitch大约在-00006左右,roll大约在-00039左右,经过多次测试当俯仰角>30时判定为后倾,当俯仰角<-30时判定为前倾,当翻滚角>0时判定为左斜,当翻滚角<-70时判定为右斜。当满足上面任意请求时,蜂鸣器发出警报向周围人求助。

这里的阈值是可以修改的,在测试的时候也用OLED来显示了的,到一定的范围就打印出它的姿态,正常的就是normal,其他的就是使用的方向的英文来表示,大家想提供可以使用中文,因为我这个就是个课设作业,我也是才接触的stm32,花了一周的时间学习的江科大(有很多其实都没有用到),想拿高分最好就是把无线通信还有GPS的功能加上。

六、总结

本设计致力于解决老年人跌倒检测问题,采用了STM32F103C8T6主控制器,搭配蜂鸣器模块、MPU6050三轴加速度传感器、0.96寸OLED显示模块以及ESP8266-01s模块等组件,以实现全面的跌倒监测与通信功能。技术指标方面,STM32F103C8T6主控制器具备高性能、低功耗、丰富的I/O端口和通信端口等特点。MPU6050传感器具备消除敏感度、陀螺仪积分等先进特性,而0.96寸OLED屏为系统提供实时数据显示和系统调试支持。

尚待完善的地方:

(1)优化互补滤波算法的参数,以提高姿态角度计算的准确性和稳定性。

(2)进一步完善系统的无线通信功能,特别是考虑引入GPS功能,以确保在实际应用中能够可靠地向监护人发送准确的警报信息。同时还存在ESP8266-01s模块与STM32F103C8T6进行驱动时的连接及通信问题,目前尚需解决。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐