This research was conducted as a self-study by three students in the department of Information Science and Culture. As one of them, I participated in the whole process of research and development for 4 months. (July to October, 2016)
The study aims to improve user experiences in CPR training. We set the target user as people who are getting retraining , so that they can be remind on how to conduct CPR more effectively .
It is designed to help participants decide whether the CPR is needed or not in particular situations .
For example, There are three situations: drunken , epilepsy , and cardiac arrest .
Participants should do CPR only when the manikin is on cardiac arrest situation. If he/she does CPR when the manikin is in a drunken or epileptic state, the device will die. Also when the trainee makes a good choice and then does CPR, whether he/she pressed the chest appropriately will be checked (in matters of both depth and speed). In case of success, the manikin will be revived and its face becomes bright with a burst of applause. X)
Components
CPR manikin, 2 Arduinos, Arduino-music-maker-shield, LED, pressure sensor, speaker
Description
LED : is for showing manikin's face color - dark when it is dying, bright when being saved, flushed when revived
Pressure sensor : is made up of the velostat(conductive fabric) with foil for covering the area of manikin's chest
Sound systems : 3 status of manikin(drunken/epilepsy/cardiac arrest), 2 kinds of 100bpm music during CPR, error sound(died), applause(success)
Design Structure
Design structure for interactive CPR manikin
Pressure Sensor : inside the chest of manikin
LED : attached on the cheek of manikin
Sound Shield : attached on the Arduino board to play sounds
Connect all things : Arduino board, Pressure Sensor, LED and Speaker
Arduino circuit image
Installation
installation pictures
Demonstration
Storyboard
The user approaches the Manikin.
Listen to the sound of the Manikin, determine whether it is epilepsy, dead drunken or cardiac arrest.
If the situation is epileptic or drunken, do not take any action.
If the situation is cardiac arrest, perform CPR 100 times.
Music of 100bpm is played when CPR begins.
Successful CPR would get applause.
If CPR doesn't last more than a few seconds with due to insufficient pressure or strength, get failure with the sound of dead.
different face colors according to conditions
a. off LED : before the incident / dead
b. white : epilepsy
c. purple : cardiac arrest
d. light red : dead drunk
e. strong red : successfully cope with all the situations including CPR
VIDEO
Source Codes
Arduino source code 1: Setting sound systems and the status of manikin
#include "stdio.h"
// Library: SPI, MP3, SD
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//LED Library
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
//Set up Library Pins
#define BREAKOUT_RESET 9
#define BREAKOUT_CS 10
#define BREAKOUT_DCS 8
#define SHIELD_RESET -1
#define SHIELD_CS 7
#define SHIELD_DCS 6
#define CARDCS 4
#define DREQ 3
#define FACE_PIN 2
#define CHEST_PIN 5
#define PRESSURE_PIN A3
#define MANIKINSTATE_PIN A0
#define MANIKINSTATECONFIRM_PIN A1
//Music player shield
Adafruit_VS1053_FilePlayer musicPlayer =
Adafruit_VS1053_FilePlayer ( SHIELD_RESET , SHIELD_CS , SHIELD_DCS , DREQ , CARDCS );
//LED set
Adafruit_NeoPixel point = Adafruit_NeoPixel ( 2 , FACE_PIN , NEO_GRB + NEO_KHZ800 );
Adafruit_NeoPixel ring = Adafruit_NeoPixel ( 24 , CHEST_PIN , NEO_GRB + NEO_KHZ800 );
//The real status of manikin (setting situations)
boolean started = false ;
boolean isHeartAttack = false ;
boolean isEpilepsy = false ;
boolean isDrunk = false ;
boolean inAction = false ;
const int STATECOUNT = 3 ;
// Setting up the status button, LED, speaker, timer and variables of pressure sensor
int manikinState = 0 ;
int manikinStateConfirm = 0 ;
int ledColor [ 3 ] = { 0 , 0 , 0 };
int sound = 0 ;
int pressure = 0 ;
int pressCount = 0 ;
int hotime = 0 ; // hands-off time
boolean action = false ;
boolean startPlay = true ;
boolean counthelp = false ;
boolean counthelp2 = false ;
// Timer
unsigned long startTime = 0 ;
unsigned long actionTime = 0 ;
unsigned long timePast = 0 ;
unsigned long timeCount = 0 ;
void setup () {
//Sound
Serial . begin ( 9600 );
Serial . println ( "Adafruit VS1053 Simple Test" );
if ( ! musicPlayer . begin ()) {
Serial . println ( F ( "Couldn't find VS1053, do you have the right pins defined?" ));
while ( 1 );
}
Serial . println ( F ( "VS1053 found" ));
// sd-card setting
SD . begin ( CARDCS );
// The lower the numer, the louder the sound
musicPlayer . setVolume ( 20 , 20 );
// audio playing
musicPlayer . useInterrupt ( VS1053_FILEPLAYER_PIN_INT ); // DREQ int
#if defined (__AVR_ATtiny85__)
if ( F_CPU == 16000000 ) clock_prescale_set ( clock_div_1 );
#endif
// Pin setup
pinMode ( PRESSURE_PIN , INPUT );
pinMode ( MANIKINSTATE_PIN , INPUT );
pinMode ( MANIKINSTATECONFIRM_PIN , INPUT );
point . begin ();
point . show ();
ring . begin ();
ring . show ();
}
void loop () {
// Choose initial status
if ( ! started ) setState ();
if ( isHeartAttack ) {
currentState ( 0 );
if ( millis () - startTime > 60000 && ! inAction ) dead ();
if ( takeAction ()) {
inAction = true ;
actionTime = millis ();
}
if ( inAction ) {
musicPlay ();
startPlay = false ;
pressure = readFlex ();
countPress ( pressure );
//Show current state of pressure
for ( int i = ring . numPixels () - 1 ; i >= 0 ; i -- ) {
ring . setPixelColor ( i , ring . Color ( 0 , 0 , 0 ));
ring . show ();
}
chestColor ( pressure );
Serial . println ( pressCount );
if ( millis () - actionTime > 10000 ) dead ();
if ( pressCount > 30 ) recovery ();
}
}
else if ( isEpilepsy ) {
currentState ( 1 );
if ( millis () - startTime > 30000 && ! inAction ) recovery ();
pressure = readFlex ();
countPress ( pressure );
if ( pressCount > 4 ) hurt ();
}
else if ( isDrunk ) {
currentState ( 2 );
if ( millis () - startTime > 30000 && ! inAction ) recovery ();
pressure = readFlex ();
countPress ( pressure );
if ( pressCount > 4 ) hurt ();
}
}
Arduino source code 2: Setting the LED color for the face of manikin
void currentState ( int state ) {
if ( state == 0 ) { //heartattack
cheekColor ( point . Color ( 127 , 0 , 127 ));
//sound
if ( ! inAction && musicPlayer . playingMusic == false ) {
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 005" ));
musicPlayer . startPlayingFile ( "track005.mp4" );
}
}
else if ( state == 1 ) { //epilepsy
cheekColor ( point . Color ( 127 , 127 , 127 ));
//sound
if ( musicPlayer . playingMusic == false ) {
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 004" ));
musicPlayer . startPlayingFile ( "track004.mp3" );
}
}
else if ( state == 2 ) { //drunk
cheekColor ( point . Color ( 250 , 50 , 50 ));
//sound
if ( musicPlayer . playingMusic == false ) {
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 003" ));
musicPlayer . startPlayingFile ( "track003.mp3" );
}
}
}
void musicPlay () {
if ( musicPlayer . playingMusic == false || startPlay ) {
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 002" ));
musicPlayer . startPlayingFile ( "track002.mp3" );
}
}
void recovery () {
cheekColor ( point . Color ( 255 , 0 , 0 ));
//sound
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 006" ));
musicPlayer . startPlayingFile ( "track006.mp3" );
reset ();
}
void hurt () {
cheekColor ( point . Color ( 30 , 30 , 30 ));
//sound
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 007" ));
musicPlayer . startPlayingFile ( "track007.mp3" );
reset ();
}
void dead () {
cheekColor ( point . Color ( 0 , 0 , 0 ));
//sound
musicPlayer . stopPlaying ();
Serial . println ( F ( "Playing track 008" ));
musicPlayer . startPlayingFile ( "track008.mp3" );
reset ();
}
void reset () {
isHeartAttack = false ;
isEpilepsy = false ;
isDrunk = false ;
inAction = false ;
started = false ;
pressCount = 0 ;
Serial . println ( String ( millis ()));
for ( int i = ring . numPixels () - 1 ; i >= 0 ; i -- ) {
ring . setPixelColor ( i , ring . Color ( 0 , 0 , 0 ));
point . setPixelColor ( i , point . Color ( 0 , 0 , 0 ));
}
ring . show ();
point . show ();
}
void cheekColor ( uint32_t c ) {
for ( int i = 0 ; i < point . numPixels (); i ++ ) {
point . setPixelColor ( i , c );
point . show ();
}
}
void chestColor ( int pressure ) {
int converted = map ( pressure , 0 , 1023 , 0 , 24 );
//Serial.println("converted:" + String(converted));
uint16_t i ;
for ( i = 0 ; i < converted ; i ++ ) {
ring . setPixelColor ( i , ring . Color ( 127 , 0 , 0 ));
ring . show ();
delay ( 1 );
}
}
Arduino source code 3: Setting the pressure sensor of manikin
void setState () {
manikinStateConfirm = analogRead ( MANIKINSTATECONFIRM_PIN );
while ( manikinStateConfirm < 500 ) {
Serial . println ( manikinStateConfirm );
manikinStateConfirm = analogRead ( MANIKINSTATECONFIRM_PIN );
manikinState = ( int ) map ( analogRead ( MANIKINSTATE_PIN ), 0 , 1024 , 0 , STATECOUNT );
Serial . println ( manikinState );
}
switch ( manikinState ) {
case 0 : // cardiac arrest true
isHeartAttack = true ;
break ;
case 1 :
isEpilepsy = true ;
break ;
case 2 :
isDrunk = true ;
break ;
}
started = true ;
startTime = millis ();
Serial . println ( String ( startTime ));
}
int readFlex () {
int sensorpin = PRESSURE_PIN ;
int value = analogRead ( sensorpin );
Serial . println ( "pressure : " + String ( value ));
delay ( 1 );
return value ;
}
boolean takeAction () {
if ( readFlex () > 900 ) {
action = true ;
}
else {
action = false ;
}
return action ;
}
void countPress ( int temp ) {
if ( temp > 900 ) counthelp = true ;
if ( temp < 500 ) counthelp2 = true ;
if ( counthelp && counthelp2 ) {
pressCount ++ ;
counthelp = false ;
counthelp2 = false ;
}
}
You can see the research report(Korean) here .
Here is our Github repository .