头部姿态检测+语音控制转向灯的智能头盔项目

本文介绍了使用Arduino主控制器,配合MPU6050陀螺仪进行姿态解算、SU-03T语音模块实现语音控制以及WS2812BRGB灯带的交互项目。项目还包括光敏传感器的使用和基于串口的命令接收功能。
摘要由CSDN通过智能技术生成

1.材料使用

1.1 MPU6050陀螺仪模块

1.2 Arduino 主控制器(以此为例)

1.3 SU-03T语音模块

(抖音号:yyds00421)

1.4 WS2812B RGB灯带

 1.5 蜂鸣器模块

1.6 四节五号电池盒

1.7 头盔

 1.8 光敏传感器

2.项目代码解析

2.1 MPU6050姿态解算

void loop() {
  int16_t ax, ay, az;
  sensor.getAcceleration(&ax, &ay, &az);
  
  // 计算俯仰角度(相对于垂直向上的角度)
  double angle = atan2(ay, az) * 180.0 / PI;
  Serial.print(" Angle: ");
  Serial.println(angle);

  delay(100); // 姿态解算的时间间隔,可根据需要调整
}
  1. int16_t ax, ay, az;: 声明了三个 int16_t 类型的变量,用来存储从陀螺仪传感器读取的加速度数据的三个分量。

  2. sensor.getAcceleration(&ax, &ay, &az);: 调用了陀螺仪对象 sensorgetAcceleration 方法,用来获取加速度数据,并将数据存储到 axayaz 变量中。

  3. double angle = atan2(ay, az) * 180.0 / PI;: 使用 atan2 函数计算了俯仰角度(pitch angle),这个角度表示相对于垂直向上的倾斜角度。使用加速度计的 Y 轴和 Z 轴的数值进行计算。得到的角度单位是弧度,乘以 (180.0 / PI) 转换为度数。

  4. Serial.print(" Angle: ");: 打印字符串 " Angle: " 到串行监视器。

  5. Serial.println(angle);: 打印变量 angle 的值(俯仰角度)到串行监视器,并在结尾添加换行符,使输出换行显示。

  6. delay(100);: 添加一个 100 毫秒的延迟。这个延迟用于控制姿态解算的时间间隔,可以根据需要调整。

 2.2 语音控制

  // 检查串口是否有命令
  if (Serial.available() > 0) {
    int command = Serial.parseInt();
    executeCommand(command);
  }

void executeCommand(int command) {
  switch (command) {
    case 1:
      // 控制第一个灯带呈现流水灯效果
      flowEffect(strip1);
      Serial.println("收到命令 1");
      break;
    case 2:
      // 控制第二个灯带呈现流水灯效果
      flowEffect(strip2);
      Serial.println("收到命令 2");
      break;
    case 0:
      // 关闭所有灯带
      turnOffStrips();
      Serial.println("收到命令 0");
      break;
    case 3:
      // 第三个灯带呈现白色灯光
      whiteLight(strip3);
      Serial.println("收到命令 3");
      break;
    case 4:
      // 关闭第三个灯带
      turnOffStrip(strip3);
      Serial.println("收到命令 4");
      break;
    default:
      Serial.println("未知命令");
  }
  1. if (Serial.available() > 0) {: 这行代码检查串口缓冲区中是否有可用的数据。如果有数据可用,条件成立,进入 if 语句块。

  2. int command = Serial.parseInt();: 这行代码尝试从串口读取一个整数。Serial.parseInt() 函数会读取连续的数字字符,直到遇到非数字字符(如换行符或空格),然后将读取到的数字解析为整数。如果没有可用的数字字符,函数会返回 0。解析成功后,整数值存储在 command 变量中。

  3. executeCommand(command);: 调用 executeCommand 函数,将解析到的命令传递给它。

  4. void executeCommand(int command) {: 这是 executeCommand 函数的定义,它接受一个整数参数 command

  5. switch (command) {: 使用 switch 语句检查 command 的值,并根据不同的值执行相应的操作。

  6. case 1:: 如果 command 的值为 1,则执行紧跟其后的代码块,执行第一个灯带的流水灯效果,并打印收到命令的信息到串口监视器。

  7. case 2:: 如果 command 的值为 2,则执行紧跟其后的代码块,执行第二个灯带的流水灯效果,并打印收到命令的信息到串口监视器。

  8. case 0:: 如果 command 的值为 0,则执行紧跟其后的代码块,关闭所有灯带,并打印收到命令的信息到串口监视器。

  9. case 3:: 如果 command 的值为 3,则执行紧跟其后的代码块,点亮第三个灯带并显示白色光,并打印收到命令的信息到串口监视器。

  10. case 4:: 如果 command 的值为 4,则执行紧跟其后的代码块,关闭第三个灯带,并打印收到命令的信息到串口监视器。

  11. default:: 如果 command 的值不是上述任何一个值,则执行紧跟其后的代码块,打印未知命令信息到串口监视器。

  12. }: switch 语句的结束。

  13. }: executeCommand 函数的结束。

3.项目源代码

#include <Wire.h>
#include <MPU6050.h>
#include <Adafruit_NeoPixel.h>

MPU6050 sensor;
int buzzer = 7;
double angleThreshold = 20; // 低头角度阈值,单位为度
unsigned long headDownTime = 0; // 记录低头的时间

// WS2812B LED strip configuration
#define LED_COUNT_1 4 // 第一个灯带上LED的数量
#define LED_COUNT_2 4 // 第二个灯带上LED的数量
#define LED_COUNT_3 6 // 第三个灯带上LED的数量
#define LED_PIN_1 9    // 第一个灯带的引脚
#define LED_PIN_2 11    // 第二个灯带的引脚
#define LED_PIN_3 6   // 第三个灯带的引脚

int lightSensorPin = 2; // 光敏传感器引脚

Adafruit_NeoPixel strip1(LED_COUNT_1, LED_PIN_1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2(LED_COUNT_2, LED_PIN_2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip3(LED_COUNT_3, LED_PIN_3, NEO_GRB + NEO_KHZ800);

void setup() {
  Wire.begin();
  sensor.initialize();
  pinMode(buzzer, OUTPUT);
  pinMode(lightSensorPin, INPUT); // 设置光敏传感器引脚为输入
  Serial.begin(9600);

  digitalWrite(buzzer, LOW);
  delay(200);
  digitalWrite(buzzer, HIGH);

  strip1.begin();
  strip2.begin();
  strip3.begin();
  
  // 初始化时关闭所有灯带
  turnOffStrips();
}

void loop() {
  // 读取光敏传感器的高低电平状态
  int lightSensorState = digitalRead(lightSensorPin);

  // 检查是否检测到黑暗环境(根据实际情况调整 HIGH 或 LOW)
  if (lightSensorState == HIGH) {
    // 处于黑暗环境,打开第三个LED灯带进行照明
    whiteLight(strip3);
    Serial.println("黑夜照明模式!!");
  } else {
    turnOffStrip(strip3);
  }

  int16_t ax, ay, az;
  sensor.getAcceleration(&ax, &ay, &az);
  double angle = atan2(ay, az) * 180.0 / PI;
  Serial.print(" Angle: ");
  Serial.println(angle);

  if (angle > angleThreshold) {
    if (headDownTime == 0) {
      headDownTime = millis();
    } else if (millis() - headDownTime > 3000) {
      urgentAlarm(buzzer);
      Serial.println("触发报警!!");
      headDownTime = 0;

      // 爆闪第一和第二灯带
      flashLEDs(strip1, strip2, 0, 0, 255);
    }
  } else {
    headDownTime = 0;
  }

  // 检查串口是否有命令
  if (Serial.available() > 0) {
    int command = Serial.parseInt();
    executeCommand(command);
  }
}


// 读取光敏传感器并返回true表示处于黑暗环境
bool isDark() {
  int lightSensorState = digitalRead(lightSensorPin);
  return lightSensorState == LOW; // 根据实际情况调整 HIGH 或 LOW
}


void executeCommand(int command) {
  switch (command) {
    case 1:
      // 控制第一个灯带呈现流水灯效果
      flowEffect(strip1);
      Serial.println("收到命令 1");
      break;
    case 2:
      // 控制第二个灯带呈现流水灯效果
      flowEffect(strip2);
      Serial.println("收到命令 2");
      break;
    case 0:
      // 关闭所有灯带
      turnOffStrips();
      Serial.println("收到命令 0");
      break;
    case 3:
      // 第三个灯带呈现白色灯光
      whiteLight(strip3);
      Serial.println("收到命令 3");
      break;
    case 4:
      // 关闭第三个灯带
      turnOffStrip(strip3);
      Serial.println("收到命令 4");
      break;
    default:
      Serial.println("未知命令");
  }
}

void urgentAlarm(int buzzerPin) {
  for (int i = 0; i < 10; i++) {
    digitalWrite(buzzerPin, LOW);
    delay(50);
    digitalWrite(buzzerPin, HIGH);
    delay(50);
  }
}

void flashLEDs(Adafruit_NeoPixel &strip1, Adafruit_NeoPixel &strip2, uint8_t red, uint8_t green, uint8_t blue) {
  for (int i = 0; i < 5; i++) {
    strip1.fill(strip1.Color(red, green, blue));
    strip1.show();
    
    strip2.fill(strip2.Color(red, green, blue));
    strip2.show();
    
    delay(100);
    
    strip1.fill(strip1.Color(0, 0, 0));
    strip1.show();
    
    strip2.fill(strip2.Color(0, 0, 0));
    strip2.show();
    
    delay(100);
  }
}


void flowEffect(Adafruit_NeoPixel &strip) {
  // 实现流水灯效果的逻辑在这里
  while (true) {
    for (int i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, strip.Color(255, 0, 0)); // 设置颜色为红色
      strip.show();
      delay(100);
      strip.setPixelColor(i, strip.Color(0, 0, 0)); // 关闭LED

      // 检查是否收到命令0,如果是,则退出循环
      if (Serial.available() > 0) {
        int command = Serial.parseInt();
        if (command == 0) {
          turnOffStrip(strip);
          return;
        }
      }
    }
  }
}

void whiteLight(Adafruit_NeoPixel &strip) {
  // 设置第三个灯带的所有LED为白色
  strip.fill(strip.Color(255, 255, 255));
  strip.show();
}

void turnOffStrip(Adafruit_NeoPixel &strip) {
  // 关闭灯带上的所有LED
  strip.fill(strip.Color(0, 0, 0));
  strip.show();
}

void turnOffStrips() {
  // 关闭所有灯带
  turnOffStrip(strip1);
  turnOffStrip(strip2);
  turnOffStrip(strip3);
}

硬件接线图以及语音模块烧录固件私信我,免费发放!

抖音有粉丝群哦,免费分享开源小项目,以及交流嵌入式!

抖音号:yyds00421

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌兮.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值