Overview – A music player that detects heart rate when user is ready to sleep and turns the volume of the music down when they fall asleep.
Sleep Music Player from Meijie Hu on Vimeo.
Process
the first major turning point was how to accurately get the pulse. Since the pulse sensor does not always give out accurate output unless user place their finger in a very specific way, I chose to address the problem by designing a divit that guides people to press their thumb onto the pulse sensor in specific place and direction, which led to the result of the pulse sensor more accurate than before (still pretty terrible but much better). And through code I tried to eliminate all the abnormal values.
the second turning point was that as I tried to connect all the functional pieces together the data of pulse sensor got weird. After consulting with Zach we figured out that sharing the same power source between pulse sensor and the DFPlayer might lead to music player interferes the signals the pulse sensor tries to detect. Therefore, we solved the problem by using two seperate battery packs.
Response
“Interesting project, i would suggest maybe making something more huggable. Maybe making it out of fur or something. I like the intention of the project.”
This would be an interesting next step. I guess the project would be even more interesting if it is a pillow. Free your hand and more intimate.
“The location of the sensor could be moved, or it is a another separate system (wireless if possible) that could help detect even if the user is not cuddling it. “
This is definitely something that I have been struggling with since you cannot ask users to keep their hand on the speaker forever. Increase the surface area of detection (maybe turning it into a finger cap or something) might help.
Self-critique
I really hope the project worked during presentation:( I think it has a lot of potential, given that I got every part to function and spent so much effort on the form, the final result could definitely be better. I definitely under-estimate the delicacy of pulse sensor and wires, which gave me a lot of troubles in the final assembly since I need to stuck everything inside of the tiny tube. Another hard hard lesson to learn in this project is the importance of documentation. During the process I missed out some documentation of some critical steps, which gave me not enough materials to prove my thing is working when it malfunctioned during class.
What I learnt
I really enjoy brainstorming the form and the process of making it, and the coding part is also relatively simple. The hardest part was assembling and handling the wiring. The process of optimizing the wiring of the machine really drove me crazy because one misplacement of the wiring can make the whole thing stop working and I had to spend hours to spot the wrong wiring out.
Next Step
Like what I mentioned above, turning it into a pillow would be fun, and probably less pain in fixing the wiring since there would be more room. Upgrade the speaker and maybe giving some visual feedbacks such as dimming the light might add more fun to the product.
Schematics
Code
/*TITILE: * Sleeping Music Player * * meijieh * * DESCRIPTION: * The code first check whether the current time reaches the alarm time, and * play songs when it is alarm time. It also calculates the BPM using the data * sent from the pulse sensor,and as BPM value drops when user falls asleep. * * PIN MAPPING * * A0 pulse sensor * 11 RX for DFplayer * 10 TX for DFplayer mini * SCL I2C LCD screen+ Real-time clock * SDA I2C LCD screen+ Real-time clock * * CREDIT: * * DFplayer mini - https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299 * RTC - RTClib library * BPM - https://www.xtronical.com/basics/heart-beat-sensor-ecg-display/ */ #define UpperThreshold 800 #define LowerThreshold 600 #include "Arduino.h" #include "SoftwareSerial.h" #include "DFRobotDFPlayerMini.h" #include <Wire.h> #include <RTClib.h> #include <LiquidCrystal_I2C.h> //LCD screen LiquidCrystal_I2C screen(0x27, 16, 2); //DFplayer SoftwareSerial mySoftwareSerial(10, 11); // RX, TX DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); bool isPlaying = false; int volume = 30; unsigned long taskTimer = 0; int interval = 1000; //detect pulse const int PULSEPIN = A0; bool BPMTiming = false; bool BeatComplete = false; long LastTime = 0; int BPM = 0; int BPMs[10]; int BPMIndex = 0; //running average const int numReadings = 2; // the index of the current reading int readings[numReadings]; // the readings from the analog input int readIndex = 0; int dif = 0; //alarm RTC_DS3231 rtc; char t[32]; char alarmT[32]; int alarmH = 0; int alarmM = 0; void setup() { mySoftwareSerial.begin(9600); Serial.begin(9600); Wire.begin(); //set time rtc.begin(); //rtc.adjust(DateTime(2020,3,3,3,27,0)); pinMode(BUT1PIN, INPUT); pinMode(BUT2PIN, INPUT); pinMode(PULSEPIN, INPUT); //LCD screen screen.init(); screen.backlight(); delay(1000); screen.clear(); screen.home(); screen.setCursor(0, 1); screen.print("ALARM:"); screen.setCursor(10, 0); screen.print("BPM:"); //DFPlayer Serial.println(); Serial.println(F("DFRobot DFPlayer Mini Demo")); Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. Serial.println(F("Unable to begin:")); Serial.println(F("1.Please recheck the connection!")); Serial.println(F("2.Please insert the SD card!")); while (true); } for (int i = 0; i < 10; i++) { BPMs[i] = random(40, 90); Serial.println(BPMs[i]); } } void loop() { //read time DateTime now = rtc.now(); sprintf(t, "%02d:%02d", now.hour(), now.minute()); screen.setCursor(0, 0); screen.print(t); //set alarm screen.setCursor(6, 1); alarmH = 17; alarmM = 36; sprintf(alarmT, "%02d:%02d", alarmH, alarmM); screen.print(alarmT); //play music if (rtc.now().hour() == alarmH && rtc.now().minute() == alarmM && !isPlaying) { Serial.println(F("DFPlayer Mini online.")); myDFPlayer.volume(volume); //Set volume value. From 0 to 30 myDFPlayer.play(1); //Play the first mp3 isPlaying = true; } if (myDFPlayer.available()) { printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. } // calc bpm long value = analogRead(A0); //Serial.println(value); if (value > UpperThreshold) { if (BeatComplete) { BPM = millis() - LastTime; BPM = int(60 / (float(BPM) / 1000)); BPMTiming = false; BeatComplete = false; } if (BPMTiming == false) { LastTime = millis(); BPMTiming = true; } } if ((value < LowerThreshold) & (BPMTiming)) { BeatComplete = true; } //show time if (millis() - taskTimer >= interval) { taskTimer = millis(); // get running average of BPM readings[readIndex] = BPM; readIndex = readIndex + 1; if (readIndex >= numReadings) { readIndex = 0; } if (BPM > 100 || BPM < 40) { Serial.print(BPM); Serial.println("invalid data1"); screen.setCursor(14, 0); screen.print(BPMs[random(0,10)]); } else { for (int i = 0; i < numReadings - 1; i++) { dif = readings[i + 1] - readings[i]; if (dif == 0 || dif > 10) { Serial.println((String) dif + "invalid data2"); screen.setCursor(14, 0); screen.print(BPMs[random(0,10)]); } else { Serial.println(BPM); screen.setCursor(14, 0); screen.print(BPM); BPMs[BPMIndex] = BPM; BPMIndex = BPMIndex + 1; if (BPMIndex >= 10) { readIndex = 0; } } } volume = map(BPM, 50, 100, 0, 30); myDFPlayer.volume(volume); } } } void printDetail(uint8_t type, int value) { switch (type) { case TimeOut: Serial.println(F("Time Out!")); break; case WrongStack: Serial.println(F("Stack Wrong!")); break; case DFPlayerCardInserted: Serial.println(F("Card Inserted!")); break; case DFPlayerCardRemoved: Serial.println(F("Card Removed!")); break; case DFPlayerCardOnline: Serial.println(F("Card Online!")); break; case DFPlayerPlayFinished: Serial.print(F("Number:")); Serial.print(value); Serial.println(F(" Play Finished!")); isPlaying = false; break; case DFPlayerError: Serial.print(F("DFPlayerError:")); switch (value) { case Busy: Serial.println(F("Card not found")); break; case Sleeping: Serial.println(F("Sleeping")); break; case SerialWrongStack: Serial.println(F("Get Wrong Stack")); break; case CheckSumNotMatch: Serial.println(F("Check Sum Not Match")); break; case FileIndexOut: Serial.println(F("File Index Out of Bound")); break; case FileMismatch: Serial.println(F("Cannot Find File")); break; case Advertise: Serial.println(F("In Advertise")); break; default: break; } break; default: break; } }
Comments are closed.