├── LICENSE ├── README.md ├── heartBeats.py └── requirements.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Udayan Kumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Heart Beat sensor using Raspberry Pi and Pulse Sensors 2 | 3 | Setup steps are [here](http://udayankumar.com/2016/05/17/heart-beat-raspberry/) 4 | -------------------------------------------------------------------------------- /heartBeats.py: -------------------------------------------------------------------------------- 1 | # Simple heart beat reader for Raspberry pi using ADS1x15 family of ADCs and a pulse sensor - http://pulsesensor.com/. 2 | # The code borrows heavily from Tony DiCola's examples of using ADS1x15 with 3 | # Raspberry pi and WorldFamousElectronics's code for PulseSensor_Amped_Arduino 4 | 5 | # Author: Udayan Kumar 6 | # License: Public Domain 7 | 8 | import time 9 | # Import the ADS1x15 module. 10 | import Adafruit_ADS1x15 11 | 12 | 13 | if __name__ == '__main__': 14 | 15 | adc = Adafruit_ADS1x15.ADS1015() 16 | # initialization 17 | GAIN = 2/3 18 | curState = 0 19 | thresh = 525 # mid point in the waveform 20 | P = 512 21 | T = 512 22 | stateChanged = 0 23 | sampleCounter = 0 24 | lastBeatTime = 0 25 | firstBeat = True 26 | secondBeat = False 27 | Pulse = False 28 | IBI = 600 29 | rate = [0]*10 30 | amp = 100 31 | 32 | lastTime = int(time.time()*1000) 33 | 34 | # Main loop. use Ctrl-c to stop the code 35 | while True: 36 | # read from the ADC 37 | Signal = adc.read_adc(0, gain=GAIN) #TODO: Select the correct ADC channel. I have selected A0 here 38 | curTime = int(time.time()*1000) 39 | 40 | sampleCounter += curTime - lastTime; # # keep track of the time in mS with this variable 41 | lastTime = curTime 42 | N = sampleCounter - lastBeatTime; # # monitor the time since the last beat to avoid noise 43 | #print N, Signal, curTime, sampleCounter, lastBeatTime 44 | 45 | ## find the peak and trough of the pulse wave 46 | if Signal < thresh and N > (IBI/5.0)*3.0 : # # avoid dichrotic noise by waiting 3/5 of last IBI 47 | if Signal < T : # T is the trough 48 | T = Signal; # keep track of lowest point in pulse wave 49 | 50 | if Signal > thresh and Signal > P: # thresh condition helps avoid noise 51 | P = Signal; # P is the peak 52 | # keep track of highest point in pulse wave 53 | 54 | # NOW IT'S TIME TO LOOK FOR THE HEART BEAT 55 | # signal surges up in value every time there is a pulse 56 | if N > 250 : # avoid high frequency noise 57 | if (Signal > thresh) and (Pulse == False) and (N > (IBI/5.0)*3.0) : 58 | Pulse = True; # set the Pulse flag when we think there is a pulse 59 | IBI = sampleCounter - lastBeatTime; # measure time between beats in mS 60 | lastBeatTime = sampleCounter; # keep track of time for next pulse 61 | 62 | if secondBeat : # if this is the second beat, if secondBeat == TRUE 63 | secondBeat = False; # clear secondBeat flag 64 | for i in range(0,10): # seed the running total to get a realisitic BPM at startup 65 | rate[i] = IBI; 66 | 67 | if firstBeat : # if it's the first time we found a beat, if firstBeat == TRUE 68 | firstBeat = False; # clear firstBeat flag 69 | secondBeat = True; # set the second beat flag 70 | continue # IBI value is unreliable so discard it 71 | 72 | 73 | # keep a running total of the last 10 IBI values 74 | runningTotal = 0; # clear the runningTotal variable 75 | 76 | for i in range(0,9): # shift data in the rate array 77 | rate[i] = rate[i+1]; # and drop the oldest IBI value 78 | runningTotal += rate[i]; # add up the 9 oldest IBI values 79 | 80 | rate[9] = IBI; # add the latest IBI to the rate array 81 | runningTotal += rate[9]; # add the latest IBI to runningTotal 82 | runningTotal /= 10; # average the last 10 IBI values 83 | BPM = 60000/runningTotal; # how many beats can fit into a minute? that's BPM! 84 | print 'BPM: {}'.format(BPM) 85 | 86 | if Signal < thresh and Pulse == True : # when the values are going down, the beat is over 87 | Pulse = False; # reset the Pulse flag so we can do it again 88 | amp = P - T; # get amplitude of the pulse wave 89 | thresh = amp/2 + T; # set thresh at 50% of the amplitude 90 | P = thresh; # reset these for next time 91 | T = thresh; 92 | 93 | if N > 2500 : # if 2.5 seconds go by without a beat 94 | thresh = 512; # set thresh default 95 | P = 512; # set P default 96 | T = 512; # set T default 97 | lastBeatTime = sampleCounter; # bring the lastBeatTime up to date 98 | firstBeat = True; # set these to avoid noise 99 | secondBeat = False; # when we get the heartbeat back 100 | print "no beats found" 101 | 102 | time.sleep(0.005) 103 | 104 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | adafruit-ads1x15==1.0.1 2 | --------------------------------------------------------------------------------