The Introduction of Final Project

Interaction Process

1.Design Concept: In the time before ocean pollution, the ocean world was vibrant and colorful. However, as people’s attention towards the ocean gradually decreased and with the current pollution of the ocean, the brilliance of the ocean is slowly dissipating.

Corresponding Interaction Effect: After the device is powered on, the LED strip will first light up 30 LEDs in a flowing manner, then operate in a breathing light mode, symbolizing the vibrant and colorful nature of the ocean. After the breathing light program ends, the LED strip will gradually extinguish in a flowing manner, losing its brightness, which signifies the decreasing attention towards the ocean.

2.Design Concept: The ocean has lost its original colors, and there is a whale stranded on the shore, unable to find its way home. But if we are willing to care for the ocean, it may take some time, but our intentions will be transmitted to the world of the ocean. At that moment, our heartbeat will synchronize with the whale, with the jellyfish, and with the entire ocean. The sea will shimmer again, and the ocean will become vibrant and colorful once more. The sound of the waves echoing in our ears and the gentle sea breeze brushing against our face will bring new vitality to the ocean.

Corresponding Interaction Effect: When the finger touches the heart rate sensor, the sensor receives the values. When the heart rate value reaches the set range, the fan starts first, followed by the MP3 player. The LEDs in the whale blink twice, then the LED strips in both the whale and the jellyfish blink three times, signifying the synchronization of heartbeats. The LED strip first lights up in a random flowing manner, symbolizing the shimmering sea surface. Finally, the LED strip lights up in a breathing light mode, symbolizing the restoration of brightness on the sea surface.

Logic Flowchart

Based on the interaction process and design concept, the logic flowchart of the program’s operation is as shown in the diagram below:

Sensor Introduction

PulseSensor heart rate sensor

(1) Introduction: The pulse sensor is a sensor used to test heart rate. Students, artists, athletes, creators, game or mobile device developers can develop interactive works related to heart rate. The sensor can be worn on the finger or earlobe and can be connected to Arduino via an interconnect cable. It also has an open source app that can display the heart rate as a graph in real time. Essentially, it is an optical heart rate sensor that integrates amplification and noise cancellation circuits. For this final project, the heart rate sensor is used to obtain instantaneous heart rate values. The subsequent program will only be triggered when the heart rate value reaches the value of the conditional function.

(2) Sensor Verification: Before using the sensor, it is necessary to verify whether the sensor can work properly. When purchasing the PulseSensor, the seller will provide corresponding files for verification. However, the problem encountered is that when you do not use the given code, but modify it according to your own experimental requirements, error messages always appear. The solution to this problem will be discussed in detail later. The following code is the verification code for the heart rate sensor and pictures of the verification process.

Code part: (The verification code used here is not the official code provided by the seller, but the relevant code was simplified based on information found independently. The reference link will be attached later.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#define USE_ARDUINO_INTERRUPTS true 
#include <PulseSensorPlayground.h>
#include <Wire.h>

const int PulseWire = 0;
const int LED= 5;
int Threshold = 550;
PulseSensorPlayground pulseSensor;
void setup()
{
pulseSensor.analogInput(PulseWire);
pulseSensor.blinkOnPulse(LED);
pulseSensor.setThreshold(Threshold);
Serial.begin(115200);
if(pulseSensor.begin()){}
}

void loop()
{
if (pulseSensor.sawStartOfBeat())
{
int myBPM = pulseSensor.getBeatsPerMinute();
Serial.println(myBPM);
}

}

Pictures of the verification process:

(3) Problems encountered during use: When using the PulseSensor, it is necessary to download the official Arduino PulseSensorPlayground library. Most tutorials only require calling this one library function, but in actual operation, it is often not enough, and there may be errors in the library functions column. In this case, you can add the Wire library to use together. However, even if both of these libraries are used simultaneously during the actual verification process, errors may still occur. After reviewing a lot of information and videos, I finally found a solution. Therefore, if you continue to use the heart rate sensor, it is recommended to use the following three lines of code to ensure the stability of the experiment. As shown in the figure:

2.WS2812B LED Strip

(1) Introduction: The WS2812B LED strip is an intelligent external controlled LED light source that integrates control circuitry and emitting circuitry into one. Its appearance is the same as a 5050 LED bead, with each component being a pixel. Each pixel contains an intelligent digital interface, a data latch signal, shaping and amplification driving circuitry, as well as a high-precision internal oscillator and a programmable constant current control section with a 12V high voltage. This effectively ensures the highly consistent color of the pixel’s light. The data protocol uses a single-line zero-code communication method. After power-on reset, the DIN end of the pixel receives data transmitted from the controller. The first 24-bit data is extracted by the first pixel and sent to the data latch inside the pixel. The remaining data is processed and amplified by the internal shaping circuitry and then forwarded to the DO port to output to the next cascaded pixel. With each transmission through a pixel, the signal decreases by 24 bits. The pixel adopts automatic shaping and forwarding technology, which means that the number of cascaded pixels is not limited by the signal transmission, but only by the requirements of signal transmission speed.

(2) Sensor verification: There are many examples of experiments with WS2812B, and typically the FastLED library is used to drive the LED strip. In the verification process, a simple function was used to verify the breathing light effect of the LED strip.
The verification code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int redPin = 9;   // 将RGB LED的红色引脚连接到Arduino的数字引脚9
int greenPin = 10; // 将RGB LED的绿色引脚连接到Arduino的数字引脚10
int bluePin = 11; // 将RGB LED的蓝色引脚连接到Arduino的数字引脚11

void setup() {
// 初始化RGB LED引脚为输出模式
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
}

void loop() {
breatheEffect();
}

void breatheEffect() {
int brightness;

// 从低到高,呼吸灯效果
for (brightness = 0; brightness < 255; brightness++) {
analogWrite(redPin, map(brightness, 0, 255, 0, 160)); // 从蓝色向紫色变化
analogWrite(greenPin, 0);
analogWrite(bluePin, map(brightness, 0, 255, 160, 255));
delay(10); // 控制变化速度
}

// 从高到低,呼吸灯效果
for (brightness = 255; brightness >= 0; brightness--) {
analogWrite(redPin, map(brightness, 0, 255, 0, 160)); // 从紫色向蓝色变化
analogWrite(greenPin, 0);
analogWrite(bluePin, map(brightness, 0, 255, 160, 255));
delay(10); // 控制变化速度
}
}

Pictures of the verification process:

3. DF Player

(1) Introduction: DF Player is a compact and low-cost MP3 module that can be directly connected to a speaker. The module can be used independently with power supply, speaker, and buttons, or controlled through a serial port as a module for Arduino UNO or any other microcontroller with a serial port. The module itself integrates MP3, WAV, and WMA hardware decoding perfectly. The software supports TF card driver and FAT16/FAT32 file systems. By using simple serial commands, you can play specified music and perform other functions, such as how to play music, without the need for complicated low-level operations. It is easy to use, convenient, and reliable.

(2) Verification process: The use of DF Player module requires other accessories: an SD card and an external speaker. First, save the required audio files to the SD card, and then trigger the corresponding track by setting the program. Here is a simple verification process that plays the first song on the SD card.
The verification code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(2, 3);

DFRobotDFPlayerMini myDFPlayer;

void setup()
{
mySoftwareSerial.begin(9600);

myDFPlayer.begin(mySoftwareSerial);

myDFPlayer.volume(20);

myDFPlayer.paly(1);
}

void loop()
{
}

Pictures of the verification process:

(3) Issues during the verification process: First, pay attention to the wiring and pin correspondence. From the diagram above, it can be observed that in this simple experiment, the other end pin of the module is not used. The pin connection should be based on the actual situation. Secondly, similar to the heart rate sensor, there may be issues with library functions. Firstly, DF Player also has an official library function. However, during the process of searching for information, I found two very similar library functions, namely DFPlayer_Mini_Mp3 library and DFRobotDFPlayerMini library. The second library can be downloaded directly in the Arduino IDE. Since I have not actually used the first library and do not know its effect, I have proven that the second library works and used it for this assignment. Additionally, DF Player needs to be used in conjunction with another library. The library function invocation is shown in the figure below:

4.DC Motor Fan

(1) Introduction: It is difficult for Arduino to directly drive a DC motor, so in this experiment, a relay is used to control the DC motor, and an external 1.5V battery is used for power supply.
The principle of the relay is weak current controlling strong current. On the left side, there are three pins: one is the input VCC, one is the ground GCC, and one is the signal IN.
On the right side, there are three pins: NC (normally closed), COM (common), and NO (normally open).
When IN is high, the normally closed terminal is connected to the common terminal; when IN is low, NO-COM is connected.

It should be noted that the relay does not provide power to the pins on the left side. The IN pin of the relay determines which side the switch is attracted to (using the electromagnetic effect). Therefore, in order to achieve the effect of the relay disconnecting/closing, we need to connect NC-COM or NO-COM on the left side to a powered main circuit.

(2) After connecting the motor to the relay and external power supply, the motor can be driven to rotate using the program. The verification code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
volatile boolean flag;
void setup(){
flag = 0;
pinMode(11, INPUT_PULLUP);
pinMode(6, OUTPUT);
}

void loop(){
if (digitalRead(11) == LOW) {
delay(20);
if (digitalRead(11) == LOW) {
flag = !flag;
while (digitalRead(11) == LOW) {
}
}
}
if (flag == 1) {
digitalWrite(6,HIGH);
} else {
digitalWrite(6,LOW);
}
}

Pictures of the verification process:

Explanation of the complete code

(1) The code starts by calling the necessary libraries and defining some parameters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
define USE_ARDUINO_INTERRUPTS true 
#include <PulseSensorPlayground.h>
#include <Wire.h>
#include <FastLED.h>
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#define BRIGHTNESS 150 // 呼吸灯的亮度
#define FADE_IN_OUT_DELAY 25 // 呼吸灯效果的渐变时间间隔,单位为毫秒
#define NUM_LEDS 30 // LED灯带中的LED数量
#define DATA_PIN 5 // LED灯带连接的数据引脚
#define COLOR CRGB::Blue // LED灯带颜色
#define WATERFALL_DELAY 120 // 流水灯间隔时间,单位为毫秒
#define BLINK_INTERVAL 2000 // 闪烁间隔时间,单位为毫秒const int PulseWire = 0;
#define BLINK_COUNT 10 // 闪烁次数

(2) The sensor’s connection pins and related parameters are defined.

1
2
3
4
5
6
7
8
9
10
11
12
const int PulseWire = 0;
SoftwareSerial mySoftwareSerial(2, 3);
const int fly= 4;
const int LED= 6;
const int LED1= 7;
const int LED2= 8;
int Threshold = 550;
int myBPM=0;
PulseSensorPlayground pulseSensor;
DFRobotDFPlayerMini myDFPlayer;
CRGB leds[NUM_LEDS];

(3) Sub-functions that will be called later are defined.

1
2
3
4
5
6
void blink1();
void blink2();
void blink3();
void blink5();
void breathing();

(4) The LED light and motor pins are set as output mode, and the motor is turned off.

1
2
3
4
5
6
pinMode(LED, OUTPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(fly, OUTPUT);
digitalWrite(fly, HIGH);

(5) DF Player initialization settings are done.

1
2
3
4
mySoftwareSerial.begin(9600);
myDFPlayer.begin(mySoftwareSerial);
myDFPlayer.volume(40);

(6) Heart rate sensor initialization settings are done.

1
2
3
4
5
pulseSensor.analogInput(PulseWire);
pulseSensor.setThreshold(Threshold);
Serial.begin(115200);
if(pulseSensor.begin()){}

(7) LED strip initialization settings are done. In order to achieve the desired interaction effect, code for creating a flowing light or breathing light effect is added in the SETUP function.

1
2
3
4
5
6
7
8
9
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS); // 设置呼吸灯的亮度
blink1();
breathing();
breathing();
blink2();
FastLED.clear();
FastLED.show();

(8) In the loop function, data from the heart rate sensor is read, and the heart rate value is checked to see if it reaches the desired threshold.

1
2
3
4
5
6
if (pulseSensor.sawStartOfBeat()) 
{
myBPM = pulseSensor.getBeatsPerMinute();
Serial.println(myBPM);
}

(9) The main code for the desired effects is written as separate sub-functions. It can be observed that many of the same sub-functions are called multiple times in the code. Attempts were made during the experimental process to use a counter in the sub-functions to achieve a blinking effect that occurs 10 times with a single function call. However, the Arduino IDE can only understand relatively simple code, and when too many conditional or loop functions are added, the program may freeze or produce errors, failing to achieve the expected results. Therefore, you will see multiple repeated sub-function calls in the code block.

Below is a screenshot showing part of the main effect code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
if (myBPM>65&&myBPM<100) {
digitalWrite(fly,LOW);
myDFPlayer.play(1);
blink4();
blink4();
blink3();
blink3();
blink3();
digitalWrite(LED,HIGH);
digitalWrite(LED1,HIGH);
digitalWrite(LED2,HIGH);
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
breathing();
breathing();
rainbow();
rainbow();
rainbow();
rainbow();
rainbow();
rainbow();
rainbow();
rainbow();
rainbow();
rainbow();
digitalWrite(LED,LOW);
digitalWrite(LED1,LOW);
digitalWrite(LED2,LOW);
digitalWrite(fly,HIGH);
}
else
{
FastLED.clear();
FastLED.show();
}


Finally, here is the complete code for the entire program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#define USE_ARDUINO_INTERRUPTS true 
#include <PulseSensorPlayground.h>
#include <Wire.h>
#include <FastLED.h>
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#define BRIGHTNESS 150 // 呼吸灯的亮度
#define FADE_IN_OUT_DELAY 25 // 呼吸灯效果的渐变时间间隔,单位为毫秒
#define NUM_LEDS 30 // LED灯带中的LED数量
#define DATA_PIN 5 // LED灯带连接的数据引脚
#define COLOR CRGB::Blue // LED灯带颜色
#define WATERFALL_DELAY 120 // 流水灯间隔时间,单位为毫秒
#define BLINK_INTERVAL 2000 // 闪烁间隔时间,单位为毫秒const int PulseWire = 0;
PulseSensorPlayground pulseSensor;
DFRobotDFPlayerMini myDFPlayer;
CRGB leds[NUM_LEDS];

const int PulseWire = 0;
SoftwareSerial mySoftwareSerial(2, 3);
const int fly= 4;
const int LED= 6;
const int LED1= 7;
const int LED2= 8;
int Threshold = 550;
int myBPM=0;

void blink1();
void blink2();
void blink3();
void blink5();
void breathing();

void setup(){
pinMode(LED, OUTPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(fly, OUTPUT);
digitalWrite(fly, HIGH);

mySoftwareSerial.begin(9600);
myDFPlayer.begin(mySoftwareSerial);
myDFPlayer.volume(40);// mp3初始化设置

pulseSensor.analogInput(PulseWire);
pulseSensor.setThreshold(Threshold);
Serial.begin(115200);
if(pulseSensor.begin()){}//心率传感器初始化设置

FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS); // 设置呼吸灯的亮度
blink1();
breathing();
breathing();
blink2();
FastLED.clear();
FastLED.show();
}

void loop(){
if (pulseSensor.sawStartOfBeat())
{
myBPM = pulseSensor.getBeatsPerMinute();
Serial.println(myBPM);
}

if (myBPM>65&&myBPM<100) {
digitalWrite(fly,LOW);
myDFPlayer.play(1);
blink4();
blink4();
blink3();
blink3();
blink3();
digitalWrite(LED,HIGH);
digitalWrite(LED1,HIGH);
digitalWrite(LED2,HIGH);
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
blink5();
breathing();
breathing();
rainbow();
digitalWrite(LED,LOW);
digitalWrite(LED1,LOW);
digitalWrite(LED2,LOW);
digitalWrite(fly,HIGH);
}
else
{
FastLED.clear();
FastLED.show();
}
}

void blink1()
{
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::Blue; // 设置每个LED的颜色为蓝色
FastLED.show(); // 显示当前状态
delay(100); // 延时100毫秒
}
}

void blink2()
{
for (int i = NUM_LEDS - 1; i >= 0; i--) {
leds[i] = CRGB(0, 0, 0); // 熄灭
FastLED.show();
delay(150);
}
}

void blink3(){
digitalWrite(LED, HIGH); // turn the LED on (HIGH is the voltage level)
digitalWrite(LED1, HIGH);
digitalWrite(LED2, HIGH);
fill_solid(leds, NUM_LEDS, COLOR);
FastLED.show();
delay(60000/myBPM); // 控制点亮持续的时间

digitalWrite(LED, LOW); // turn the LED off by making the voltage LOW
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
FastLED.clear();
FastLED.show();
delay(60000/myBPM); // 控制熄灭持续的时间 // 设置流水灯效果已完成
}

void blink4(){
digitalWrite(LED2, HIGH); // turn the LED on (HIGH is the voltage level)
delay(60000/myBPM); // 控制点亮持续的时间
digitalWrite(LED2, LOW); // turn the LED off by making the voltage LOW
delay(60000/myBPM); // 控制熄灭持续的时间 // 设置流水灯效果已完成
}

void blink5(){
for (int i = 0; i < 20; i++) {
int randomLed = random(NUM_LEDS); // 随机选择一个灯珠
CRGB randomColor = CHSV(random(160, 240), random(128, 255), random(128, 255)); // 生成一个青色到紫色之间的随机颜色
leds[randomLed] = randomColor; // 将随机选择的灯珠设置为随机颜色
}

FastLED.show(); // 更新灯带显示
delay(500); // 闪烁延迟时间为500毫秒

// 清除所有灯珠的颜色,以便下一次循环时重新选择随机灯珠和颜色
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::Black;
}
}

void rainbow(){
static uint8_t hue = 0;
fill_rainbow(leds, NUM_LEDS, hue, 7);
FastLED.show();
hue++;
delay(10);
}

void breathing()
{
for (int brightness = 0; brightness <= BRIGHTNESS; brightness++) {
// 将每个LED的亮度从0逐渐增加到最大亮度
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(map(brightness, 0, BRIGHTNESS, 170, 255), 255, 255); // 设置每个LED的颜色为紫色
}
FastLED.show(); // 显示当前状态
delay(FADE_IN_OUT_DELAY); // 延时
}

for (int brightness = BRIGHTNESS; brightness >= 0; brightness--) {
// 将每个LED的亮度从最大亮度逐渐减小到0
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(map(brightness, 0, BRIGHTNESS, 170, 255), 255, 255); // 设置每个LED的颜色为紫色
}
FastLED.show(); // 显示当前状态
delay(FADE_IN_OUT_DELAY); // 延时
}
}

Finally, here are the reference cases for our final project:

  1. https://blog.csdn.net/weixin_41659040/article/details/120582966

  2. https://blog.csdn.net/qq_42767647/article/details/102918937

  3. https://blog.csdn.net/weixin_41659040/article/details/132465032

  4. https://blog.csdn.net/weixin_43031092/article/details/108712833

  5. https://blog.csdn.net/weixin_44887565/article/details/132874517

  6. https://blog.csdn.net/weixin_41659040/article/details/132161843


The Introduction of Final Project
https://nexmaker-fab.github.io/2023zjude-10-36/2023/10/23/make/
Author
Chenye Meng
Posted on
October 23, 2023
Licensed under