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); // 姿态解算的时间间隔,可根据需要调整
}
int16_t ax, ay, az;
: 声明了三个int16_t
类型的变量,用来存储从陀螺仪传感器读取的加速度数据的三个分量。
sensor.getAcceleration(&ax, &ay, &az);
: 调用了陀螺仪对象sensor
的getAcceleration
方法,用来获取加速度数据,并将数据存储到ax
、ay
、az
变量中。
double angle = atan2(ay, az) * 180.0 / PI;
: 使用atan2
函数计算了俯仰角度(pitch angle),这个角度表示相对于垂直向上的倾斜角度。使用加速度计的 Y 轴和 Z 轴的数值进行计算。得到的角度单位是弧度,乘以(180.0 / PI)
转换为度数。
Serial.print(" Angle: ");
: 打印字符串 " Angle: " 到串行监视器。
Serial.println(angle);
: 打印变量angle
的值(俯仰角度)到串行监视器,并在结尾添加换行符,使输出换行显示。
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("未知命令");
}
if (Serial.available() > 0) {
: 这行代码检查串口缓冲区中是否有可用的数据。如果有数据可用,条件成立,进入if
语句块。
int command = Serial.parseInt();
: 这行代码尝试从串口读取一个整数。Serial.parseInt()
函数会读取连续的数字字符,直到遇到非数字字符(如换行符或空格),然后将读取到的数字解析为整数。如果没有可用的数字字符,函数会返回 0。解析成功后,整数值存储在command
变量中。
executeCommand(command);
: 调用executeCommand
函数,将解析到的命令传递给它。
void executeCommand(int command) {
: 这是executeCommand
函数的定义,它接受一个整数参数command
。
switch (command) {
: 使用switch
语句检查command
的值,并根据不同的值执行相应的操作。
case 1:
: 如果command
的值为 1,则执行紧跟其后的代码块,执行第一个灯带的流水灯效果,并打印收到命令的信息到串口监视器。
case 2:
: 如果command
的值为 2,则执行紧跟其后的代码块,执行第二个灯带的流水灯效果,并打印收到命令的信息到串口监视器。
case 0:
: 如果command
的值为 0,则执行紧跟其后的代码块,关闭所有灯带,并打印收到命令的信息到串口监视器。
case 3:
: 如果command
的值为 3,则执行紧跟其后的代码块,点亮第三个灯带并显示白色光,并打印收到命令的信息到串口监视器。
case 4:
: 如果command
的值为 4,则执行紧跟其后的代码块,关闭第三个灯带,并打印收到命令的信息到串口监视器。
default:
: 如果command
的值不是上述任何一个值,则执行紧跟其后的代码块,打印未知命令信息到串口监视器。
}
:switch
语句的结束。
}
: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