Crystal Ball - Biofeedback And Meditation
About the project
Use at your own risk!
Project info
Difficulty: Moderate
Platforms: Arduino
Estimated time: 3 days
License: GNU General Public License, version 3 or later (GPL3+)
Items used in this project
Hardware components
Story
Details
So the crucial question for any project -
Well, it is a nice aid for meditation/crystal ball gazing practice;
Besides, one can exercise biofeedback, trying to slow down heartbeat with mental efforts (no instruction given!) and expect improved mind/body balance.
The most important part of this project - pulse sensor from SeeedStudio. And the most important part of this sensor - proprietary controller that comes with sensor:
Controller ( a tiny circuit board inside this white box) generates a short square pulses when heartbeat is sensed. Works like a charm. Looks like this sensor and controller originates from Kyto Electronics product.
This is how assembled project looks:
Here is a video demonstrating how flash color changes with pulse rate:
This is how it works with sensor attached to the ear lobe:
I am trying to change pulse rate with mental effort:
Custom parts and enclosures
Innards
Small green PCB at the lower right - pulse sensor controller (originally was enclosed in a white box connected to pulse sensor)
Schematics: Code://#define DEBUG 1 #include <FastLED.h> #include <Adafruit_GFX.h> #include "Adafruit_LEDBackpack.h" #include <RunningAverage.h> #define DATA_PIN 11 #define CLOCK_PIN 13 #define NUM_LEDS 4 Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4(); volatile unsigned long current_time,previous_time, rr_raw, button_time; unsigned int heart_rate;//the measurement result of heart rate unsigned int rr, n1,n2; boolean no_sensor=true; RunningAverage myRA(10); //initialize running average internal array for 8 measurements CRGB strip[NUM_LEDS]; int v_delay = 10; byte n,j1,j2,j3; int hue; CRGB v_rgbcolor=CRGB::Blue; volatile bool data_arrived=false; byte skip_counter=0; byte skip_limit=2; //const byte skip_max=4; boolean start_flash=true; boolean show_dot=true; void setup() { #ifdef DEBUG Serial.begin(9600); #endif alpha4.begin(0x70); alpha4.clear(); alpha4.writeDisplay(); pinMode(6, INPUT_PULLUP); //side button setup; for debugging only FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, BGR>(strip, NUM_LEDS); FastLED.clear(); FastLED.show(); delay(50); for (int i = 0 ; i <3; i++) { fill_solid(strip,NUM_LEDS,v_rgbcolor); FastLED.show(); delay(400); FastLED.clear(); FastLED.show(); delay(400); } FastLED.clear(); FastLED.show(); myRA.clear(); n=0; previous_time=millis(); cli();//stop interrupts attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2 sei();//allow interrupts } void show_Alpha(char c1, char c2,boolean v_show_dot=false) { alpha4.writeDigitAscii(2, c1); alpha4.writeDigitAscii(3, c2,v_show_dot); alpha4.writeDisplay(); } void loop() { if (millis()>current_time+3000) { no_sensor=true; myRA.clear(); n=0; //when no data reset counter previous_time=0; } else no_sensor=false; if (no_sensor) { idle(); } if (data_arrived){ if (n<11) n++; //dont show first 10 measurements of heart rate myRA.addValue(rr_raw); rr=myRA.getAverage(); heart_rate=60000.0/rr; if (heart_rate<100) { n1=heart_rate/10+48; n2=heart_rate%10+48; } else { n1=(heart_rate-100)/10+48; n2=(heart_rate-100)%10+48; } if (n>10) show_Alpha(char(n1),char(n2),show_dot); else show_Alpha('_','_',show_dot); show_dot=!show_dot; if (rr_raw<100) { data_arrived=false; return; } v_delay=(rr_raw-50)/35; //if (v_delay>40) v_delay=25; #ifdef DEBUG Serial.print("v_delay=");Serial.println(v_delay); #endif hue=map(heart_rate,60,90,0,170); if (heart_rate>100) heart_rate=100; fill_solid(strip, NUM_LEDS, CHSV(170-hue,255,255)); #ifdef DEBUG Serial.print("Skip Counter=");Serial.print(skip_counter); Serial.print("Skip_limit-1=");Serial.println(skip_limit-1); #endif if (skip_counter>=skip_limit-1) { skip_counter=0; FastLED.show(); while(j1<35) { j1++; fadeLightBy(strip,4,20); FastLED.show(); delay(v_delay); // check_button(); } } else skip_counter++; delay(v_delay); data_arrived=false; // check_button(); j1=0; //while(j1<35 && !data_arrived) { } } //loop void interrupt(){ data_arrived=true; current_time=millis(); if (previous_time==0) previous_time=current_time-833; rr_raw=current_time-previous_time; previous_time=current_time; } void idle(){ FastLED.clear(); delay(50); FastLED.show(); int i=random(4); randomSeed(analogRead(0)); j1=random(255); j2=random(255); j3=random(255); strip[i].setHSV(j1,j2,j3); FastLED.show(); show_Alpha('*','*'); delay(50); }
Leave your feedback...