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

Arduino Pro Mini 328 - 5V/16 MHz Arduino Pro Mini 328 - 5V/16 MHz x 1
Sparkfun Luminati 4-pack Sparkfun Luminati 4-pack x 1
Seeed Studio Heart Rate sensor board Seeed Studio Heart Rate sensor board x 1
Quad Alphanumeric Display - Pure Green 0.54 Digits w/ Backpack - STEMMA QT / Qwiic Quad Alphanumeric Display - Pure Green 0.54 Digits w/ Backpack - STEMMA QT / Qwiic x 1

Software apps and online services

Arduino IDE Arduino IDE

Story

SeeedStudio has very good ear-lobe heartbeat sensor. I combined it with Illuminated LED display stand for crystal ball and installed RGB controllable LEDs. So you attach sensor to your earlobe, and crystal ball begins flashing in sync with your hearbeats, and the color of flash depends on your pulse rate. It is green when your pulse is at rest, and turns into bluish when the pulse slows down or to red/purple when the heart beats faster. For your convenience device also displays your current pulse rate. After some experimenting I found that flashing on every heartbeat is somewhat disturbing (most people will be surprised to see how fast the heart works even at rest); So I made it flashing on every other heartbeat and this produces pleasant and relaxing rhythm.

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);
}

Credits

Photo of StanChicago

StanChicago

Database Developer. Arduino as pet projects. Background in biophysics.

   

Leave your feedback...