مانیتورینگ ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا

در این پروژه می‌خواهیم یک سیستم تشخیص و نظارت بر ضربان قلب بسازیم که با استفاده از بورد آردوینو و ThingSpeak (یکی از پلتفرم‌های اینترنت اشیا)، پیاده‌سازی می‌شود. این سیستم داده‌ها را با کمک سنسور تشخیص پالسی که در آن تعبیه می‌شود جمع‌آوری کرده و نتایج حاصل شده را با فرمت BPM (ضربان بر دقیقه) در LCD سیستم نمایش می‌دهد. علاوه بر آن این داده‌ها را با استفاده از ماژول وای‌فای ESP8266 که به آن متصل است، به سرور ThingSpeak نیز ارسال می‌کند و به این ترتیب ضربان قلب مذکور در هر نقطه‌ای از دنیا از طریق اینترنت قابل ملاحظه و کنترل است.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

اگر از قبل نام ThingSpeak را نشنیده‌اید، باید بگوییم ThingSpeak یکی از بزرگ‌ترین پلتفرم‌ها برای ارسال و دریافت آنلاین داده‌هاست که در هر زمان و هر مکانی که باشید می‌توانید به آن دسترسی پیدا کنید.

قبلا هم یک پروژه‌ی مانیتورینگ ضربان قلب را با هم پیاده‌سازی کرده‌ایم با این تفاوت که در آنجا داده‌ها را روی ThingSpeak ارسال نمی‌کردیم و قابلیت دسترسی از طریق اینترنت را نداشت. اما این بار می‌خواهیم  به قلمرو اینترنت اشیا قدم گذاشته و این قابلیت را نیز به پروژه اضافه کنیم.

آنچه که در ادامه نیاز خواهیم داشت.

نمودار مدار و توضیحات آن

ابتدا باید ماژول ESP8266 و بورد آردوینو را به هم متصل کنیم. این ماژول با ولتاژ ۳.۳ ولت کار می‌کند و اگر بخواهید ولتاژ ۵ ولت را از بورد آردوینو بگیرید و به آن متصل کنید، احتمال آنکه به درستی کار نکند و یا حتی آسیب ببیند وجود دارد. بنابراین VCC و CH_PD را به پین ۳.۳ ولت آردوینو متصل کنید.

پین RX ماژول وای‌فای با ۳.۳ ولت کار می‌کند. بنابراین اگر آن را مستقیما به آردوینو متصل کنید، کار نخواهد کرد. باید یک مدار مقسم ولتاژ را در میان آنها قرار دهیم که ولتاژ ۵ ولت را گرفته و ۳.۳ ولت آن را به پین RX بدهد. ساده‌ترین مداری که می‌توان در نظر گرفت، استفاده از سه مقاومت به صورت متوالی است. ما هم در بستن مدار از همین روش استفاده کرده‌ایم.

پین TX ماژول وای‌فای را به پین شماره ۹ بورد آردوینو، و پین RX ماژول وای‌فای را به پین شماره ۱۰ بورد آردوینو متصل کنید.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

وجود ماژول ارزان قیمت ESP8266 در سیستم شما موجب می‌شود که بتوانید به وای‌فای و اینترنت دسترسی داشته باشید. بنابراین بسیار آن را کاربردی‌تر خواهد ساخت. از دیگر قابلیت‌های این ماژول این است می‌تواند به راحتی با اغلب میکروکنترلر‌ها ارتباط برقرار کند و به همین علت به یکی از پرطرفدار‌ترین ماژول‌های وای‌فای در حوزه‌ی IoT تبدیل شده است.

در قدم بعدی باید سنسور تشخیص ضربان را به بورد آردوینو متصل کنیم. خوشبختانه این سنسور تنها سه عدد پین دارد و متصل کردن آن کار بسیار راحتی است. کافیست پین ۵ ولت و پین زمین آن را به ترتیب به پین‌های ۵ ولت و زمین بورد آردوینو متصل کنید و پین سیگنال آن را هم به پین A0 بورد.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

LED را هم به پین ۱۳ بورد آردوینو متصل کنید. دقت داشته باشید که پین شماره ۱۳ خود دارای یک مقاومت درونی است و نیازی نیست که شما برای وصل کردن LED به آن یک مقاومت هم در مسیر قرار دهید.

و در نهایت برای اتصال LCD و بورد به یکدیگر مراحل زیر را انجام دهید.

  • پین ۱ (VEE) را به زمین متصل کنید.
  • پین شماره ۲ (VDD یا VCC) را به ۵ ولت متصل کنید.
  • پین شماره ۳ (V0) را به پین وسطی پتانسیومتر متصل کنید و دو پایه‌ی دیگر پتانسیومتر را به زمین و ۵ ولت وصل کنید. نقش پتانسیومتر در تنظیم کنتراست صفحه‌ی LCD است بنابراین اگر پتانسیومتری با مقادیر غیر از 10K داشته باشید هم احتمالا قابل استفاده هستند.
  • پین شماره ۴ (RS) را به پین شماره ۱۲ بورد آردوینو متصل کنید.
  • پین شماره ۵ (Read/Write) را که از آن استفاده‌ای نمی‌کنیم؛ به زمین وصل کنید.
  • پین شماره ۶ (E) را هم به پین شماره ۱۱ آردوینو متصل کنید. پین‌های RS و E پین‌های کنترلی هستند و برای ارسال داده و کاراکتر از آنها استفاده می‌شود.
  • این ۴ پین هم پین‌های تبادل اطلاعات هستند که باید به این ترتیب متصل شوند.

– پین ۱۱ (D4) به پین شماره ۵ آردوینو

– پین ۱۲ (D5) به پین شماره ۴ آردوینو

– پین ۱۳ (D6) به پین شماره ۳ آردوینو

– پین ۱۴ (D7) به پین شماره ۲ آردوینو

  • پین شماره ۱۵ را از طریق مقاومت ۲۲۰ اهمی ‌به VCC وصل کنید. این مقاومت برای تنظیم شدت نور صفحه‌ی نمایشگر است. اگر از مقاومت‌های بزرگتری استفاده کنید صفحه تاریک‌تر خواهد شد.
  • پین ۱۶ را به زمین وصل کنید.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

تنظیمات مربوط به ThingSpeak

همانطور که ابتدای این مطلب هم گفتیم، ThingSpeak ابزار بسیار مناسب و پرطرفداری در اجرای پروژه‌ها و سیستم‌های مربوط به اینترنت اشیا محسوب می‌شود. با استفاده از سایت ThingSpeak، می‌توانیم داده‌های خود را از طریق اینترنت ببینیم و کنترل کنیم. در حقیقت ThingSpeak بستری است که داده‌ها را از سنسورهایی که به آن متصل شده‌اند دریافت و جمع‌آوری کرده، آنها را آنالیز و دسته‌بندی می‌کند و در صورت نیاز می‌تواند پاسخ‌هایی را نیز با توجه به داده‌های دریافت شده ارسال کند. در ادامه مختصری در رابطه با چگونگی کار کردن این ابزار توضیح خواهیم داد.

مطلب پیشنهادی:  راه اندازی سنسور دما LM35 با آردوینو

در ابتدا هر کاربر باید یک حساب کاربری بر روی سایت ThingSpeak.com ایجاد کند. پس از آن وارد حساب خود شده و Get Started را انتخاب می‌کنیم.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

در حساب کاربری خود به قسمت channels رفته و create a new channel را انتخاب می‌کنیم. نام‌ها را انتخاب کرده و در قسمت پایین صفحه، تیک Make Public را می‌زنیم و در نهایت save می‌کنیم.

حالا کانال اختصاصی ما ساخته شده است.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

پس از آن به قسمت API keys رفته و کلیدی که در آنجا می‌بینید را کپی کنید. از این کلید در زمان نوشتن کد استفاده خواهیم کرد. (کد را به صورت کامل در انتهای آموزش برا‌یتان قرار داده‌ایم)

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

توضیح چگونگی عملکرد

ابتدا باید سنسور تشخیص ضربان را به قسمتی از بدن که امکان تشخیص ضربان وجود داشته باشد (مثلا به سر انگشت‌ها) وصل کنیم.

این سنسور تغییرات حجم خون عبوری از رگ‌ها را اندازه‌گیری می‌کند. می‌دانیم که در هر بار پمپاژ شدن خون به بدن توسط قلب، حجم خون عبوری تغییر می‌کند. بنابراین این تغییر حجم نمایانگر ضربان قلب خواهد بود. اگر دقیق‌تر بخواهیم بگوییم؛ تغییر حجم خون موجب تغییر شدت نور ساطع شده از رگ شده و سنسور قادر است این تغییر شدت نور را تشخیص داده و به آن عنوان ضربان ثبت کند. آردوینو این داده را دریافت کرده و آن را به تعداد ضربان بر دقیقه (BPM) تبدیل می‌کند و این مقدار بر روی LCD نمایش داده می‌شود. LED متصل به بورد هم با هر بار رسیدن ضربان یک بار چشمک می‌زند.

از طرفی ماژول ESP8266 که به بورد آردوینو متصل است، داده‌ی تولیدی آن را دریافت کرده و از طریق اینترنت آن را به ThingSpeak ارسال می‌کند. اتصال این ماژول به شبکه، به واسطه‌ی روتری است که در کد برنامه مشخص می‌کنیم.

داده‌های دریافت شده در ThingSpeak ذخیره شده و در هر لحظه به صورت نموداری قابل دسترس هستند؛ چه داده‌های مربوط به آن لحظه‌ و چه داده‌های لحظات قبل.

کنترل ضربان قلب با استفاده از آردوینو در بستر اینترنت اشیا (ThingSpeak)

توضیحات کد پروژه

مانند همیشه در ابتدای کار، کتابخانه‌های مرتبط را اضافه می‌کنیم. کتابخانه‌ی Software serial برای فعال کردن Rx و Tx بر روی پین‌های شماره‌ی ۹ و ۱۰ است. دقت داشته باشید که پین‌های پیش‌فرض برای Rx و Tx در آردوینو، پین‌های شماره‌ی ۰ و ۱ هستند. اگر بخواهیم پین‌های دیگری را به این منظور استفاده کنیم ، باید از این کتابخانه استفاده کنیم. کتابخانه‌ی LiquidCrystal.h را هم برای اتصال و استفاده از LCD نیاز داریم. پس از آوردن آن پین‌هایی که قرار است LCD به آنها متصل شود را هم تعیین می‌کنیم.

#include <SoftwareSerial.h>
#define DEBUG true
SoftwareSerial esp8266(9,10); 
#include <LiquidCrystal.h>
#include <stdlib.h>
LiquidCrystal lcd(12,11,5,4,3,2);

نام شبکه وای‌فای، پسورد و آدرس آی‌پی ماژول ESP8266 را وارد می‌کنیم و سپس همان کلیدی که در مرحله‌ی قبل از ThingSpeak کپی کرده بودیم را هم وارد می‌کنیم.

#define SSID "Your Wifi Name"
#define PASS "Your Wifi Password"
#define IP "184.106.153.149"
String msg = "GET /update?key=9YS21NU0HY5YS1IKU";

تکه‌ی بعدی از کد، LCD را راه‌اندازی کرده و بادریت را تنظیم می‌کند. بادریت را با توجه به ماژول ESP8266 مشخص می‌کنیم. (هر کدام از ماژول‌های ESP8266 بادریت مخصوص به خود را دارند. برخی از آنها ۹۶۰۰، برخی ۱۱۵۲۰۰ و تعدادی دیگر بادریت‌های دیگری دارند)

void setup()
{
  lcd.begin(16, 2);
  lcd.print("circuitdigest.com");
  delay(100);
  lcd.setCursor(0,1);
  lcd.print("Connecting...");
  Serial.begin(9600); //or use default 115200.
  esp8266.begin(9600);
  Serial.println("AT");
  esp8266.println("AT");
  delay(5000);
  if(esp8266.find("OK")){
    connectWiFi();
  }
  interruptSetup(); 
}

تابع ()updatebeat، داده‌های جمع‌آوری شده را به آدرس آی‌پی که مشخص کردیم ارسال کرده و همچنین داده را در همان فرمتی که برای ضربان قلب مشخص کرده‌ایم تنظیم می‌کند.

void updatebeat(){
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += IP;
  cmd += "\",80";
  Serial.println(cmd);
  esp8266.println(cmd);
  delay(2000);
  if(esp8266.find("Error")){
    return;
  }
  cmd = msg ;
  cmd += "&field1=";   
  cmd += BPM;
  ..... .....
  ...... .....

بخش بعدی کد ماژول ESP8266 را به شبکه‌ای که تعیین کرده‌ایم متصل کرده و داده‌ها را از طریق آن به سرورهای ThingSpeak ارسال  می‌کند.

boolean connectWiFi(){
  Serial.println("AT+CWMODE=1");
  esp8266.println("AT+CWMODE=1");
  delay(2000);
  String cmd="AT+CWJAP=\"";
  cmd+=SSID;
  cmd+="\",\"";
  cmd+=PASS;
  cmd+="\"";
  .... .....
  ..... .....

برای خواندن داده‌ها از سنسور و تبدیل آنها از مقادیر خام به مقادیر BPM و چشمک زدن LED با هر یک از ضربان‌های دریافتی کد زیر را وارد کنید.

ISR(TIMER2_COMPA_vect){
  cli();
  Signal = analogRead(pulsePin);
  sampleCounter += 2;
  int N = sampleCounter - lastBeatTime;
  if(Signal < thresh && N > (IBI/5)*3){
    if (Signal < T){
      T = Signal; 
      ... ....
       ...... ..

بقیه‌ی قسمت‌های کد تقریبا به صورت کامل کامنت‌گذاری شده‌‌اند و می‌توانید به راحتی کارکرد بخش‌های مختلف آن را کشف کنید.

کد

#include <SoftwareSerial.h>
#define DEBUG true
SoftwareSerial esp8266(9,10); 
#include <LiquidCrystal.h>
#include <stdlib.h>
LiquidCrystal lcd(12,11,5,4,3,2);
#define SSID "Your Wifi Name"     // "SSID-WiFiname" 
#define PASS "Your Wifi Password"       // "password"
#define IP "184.106.153.149"// thingspeak.com ip
String msg = "GET /update?key=9YS21NU0HY5YS1IKU"; //change it with your api key like "GET /update?key=Your Api Key"
//Variables
float temp;
int hum;
String tempC;
int error;
int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 13;                // pin to blink led at each beat
int fadePin = 5;
int fadeRate = 0;
// Volatile Variables, used in the interrupt service routine!
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded! 
volatile boolean Pulse = false;     // "True" when heartbeat is detected. "False" when not a "live beat". 
volatile boolean QS = false;        // becomes true when Arduino finds a beat.
// Regards Serial OutPut  -- Set This Up to your needs
static boolean serialVisual = true;   // Set to 'false' by Default.  Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse 
volatile int rate[10];                    // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0;          // used to determine pulse timing
volatile unsigned long lastBeatTime = 0;           // used to find IBI
volatile int P =512;                      // used to find peak in pulse wave, seeded
volatile int T = 512;                     // used to find trough in pulse wave, seeded
volatile int thresh = 525;                // used to find instant moment of heart beat, seeded
volatile int amp = 100;                   // used to hold amplitude of pulse waveform, seeded
volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = false;      // used to seed rate array so we startup with reasonable BPM
void setup()
{
  lcd.begin(16, 2);
  lcd.print("circuitdigest.com");
  delay(100);
  lcd.setCursor(0,1);
  lcd.print("Connecting...");
  Serial.begin(9600); //or use default 115200.
  esp8266.begin(9600);
  Serial.println("AT");
  esp8266.println("AT");
  delay(5000);
  if(esp8266.find("OK")){
    connectWiFi();
  }
  interruptSetup(); 
}
void loop(){
  lcd.clear();
  start: //label 
  error=0;
  lcd.setCursor(0, 0);
  lcd.print("BPM = ");
  lcd.print(BPM);
  delay (100);
  lcd.setCursor(0, 1); // set the cursor to column 0, line 2
  delay(1000);
  updatebeat();
  //Resend if transmission is not completed 
  if (error==1){
    goto start; //go to label "start"
  }
  
  delay(1000); 
}
void updatebeat(){
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += IP;
  cmd += "\",80";
  Serial.println(cmd);
  esp8266.println(cmd);
  delay(2000);
  if(esp8266.find("Error")){
    return;
  }
  cmd = msg ;
  cmd += "&field1=";   
  cmd += BPM;
  cmd += "\r\n";
  Serial.print("AT+CIPSEND=");
  esp8266.print("AT+CIPSEND=");
  Serial.println(cmd.length());
  esp8266.println(cmd.length());
  if(esp8266.find(">")){
    Serial.print(cmd);
    esp8266.print(cmd);
  }
  else{
   Serial.println("AT+CIPCLOSE");
   esp8266.println("AT+CIPCLOSE");
    //Resend...
    error=1;
  }
}
boolean connectWiFi(){
  Serial.println("AT+CWMODE=1");
  esp8266.println("AT+CWMODE=1");
  delay(2000);
  String cmd="AT+CWJAP=\"";
  cmd+=SSID;
  cmd+="\",\"";
  cmd+=PASS;
  cmd+="\"";
  Serial.println(cmd);
  esp8266.println(cmd);
  delay(5000);
  if(esp8266.find("OK")){
    Serial.println("OK");
    return true;    
  }else{
    return false;
  }
}
void interruptSetup(){     
  TCCR2A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
  TCCR2B = 0x06;     // DON'T FORCE COMPARE, 256 PRESCALER 
  OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
  TIMSK2 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A
  sei();             // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED      
} 
ISR(TIMER2_COMPA_vect){                       // triggered when Timer2 counts to 124
  cli();                                      // disable interrupts while we do this
  Signal = analogRead(pulsePin);              // read the Pulse Sensor 
  sampleCounter += 2;                         // keep track of the time in mS
  int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise
    //  find the peak and trough of the pulse wave
  if(Signal < thresh && N > (IBI/5)*3){      // avoid dichrotic noise by waiting 3/5 of last IBI
    if (Signal < T){                         // T is the trough
      T = Signal;                            // keep track of lowest point in pulse wave 
    }
  }
  if(Signal > thresh && Signal > P){        // thresh condition helps avoid noise
    P = Signal;                             // P is the peak
  }                                         // keep track of highest point in pulse wave
  //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  // signal surges up in value every time there is a pulse
  if (N > 250){                                   // avoid high frequency noise
    if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){        
      Pulse = true;                               // set the Pulse flag when there is a pulse
      digitalWrite(blinkPin,HIGH);                // turn on pin 13 LED
      IBI = sampleCounter - lastBeatTime;         // time between beats in mS
      lastBeatTime = sampleCounter;               // keep track of time for next pulse
      if(secondBeat){                        // if this is the second beat
        secondBeat = false;                  // clear secondBeat flag
        for(int i=0; i<=9; i++){             // seed the running total to get a realistic BPM at startup
          rate[i] = IBI;                      
        }
      }
      if(firstBeat){                         // if it's the first time beat is found
        firstBeat = false;                   // clear firstBeat flag
        secondBeat = true;                   // set the second beat flag
        sei();                               // enable interrupts again
        return;                              // IBI value is unreliable so discard it
      }   
      word runningTotal = 0;                  // clear the runningTotal variable    
      for(int i=0; i<=8; i++){                // shift data in the rate array
        rate[i] = rate[i+1];                  // and drop the oldest IBI value 
        runningTotal += rate[i];              // add up the 9 oldest IBI values
      }
      rate[9] = IBI;                          // add the latest IBI to the rate array
      runningTotal += rate[9];                // add the latest IBI to runningTotal
      runningTotal /= 10;                     // average the last 10 IBI values 
      BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
      QS = true;                              // set Quantified Self flag 
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }                       
  }
  if (Signal < thresh && Pulse == true){   // when the values are going down, the beat is over
    digitalWrite(blinkPin,LOW);            // turn off pin 13 LED
    Pulse = false;                         // reset the Pulse flag so we can do it again
    amp = P - T;                           // get amplitude of the pulse wave
    thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
    P = thresh;                            // reset these for next time
    T = thresh;
  }
  if (N > 2500){                           // if 2.5 seconds go by without a beat
    thresh = 512;                          // set thresh default
    P = 512;                               // set P default
    T = 512;                               // set T default
    lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        
    firstBeat = true;                      // set these to avoid noise
    secondBeat = false;                    // when we get the heartbeat back
  }
  sei();     
  // enable interrupts when youre done!
}// end isr

ویدئو

منبع: ترجمه از سایت circuitdigest.com

مطلب پیشنهادی:  راه اندازی سنسور دمای مادون قرمز MLX90614 + اتصال به آردوینو

امیدواریم که این مطلب برای شما مفید واقع شده باشد و بتوانید با ترکیب اینترنت اشیا و پروژه‌های آردوینو گجت‌های کاربری را بسازید که زندگی انسان‌ها را هوشمندتر کند. کامنت یادتون نره:)

اگر این نوشته‌ برایتان مفید بود لطفا کامنت بنویسید و ما را نیز دعا کنید. همچنین دوست داشتین اپلیکیشن اندویدی ما را هم نصب کنید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

3 دیدگاه

  1. خیلی عالی بود

  2. کاش پی دی اف هم برای دانلود نوشته ها میزاشتید