Project tutorial # Rate of Perceived Exertion Logger © GPL3+

Record your exertions on the Borg scale.

• 1,118 views
• 6 respects

## Components and supplies Arduino UNO & Genuino UNO
×1
 Deek Robot data logging shield v1.0
×1
×1

## Apps and online services

Rate of perceived exertion is one way of determining how hard you are working when exercising.

You are given an exertion scale of between 6 and 20 (Figure 1), with 6 meaning minimal exertion and 20 meaning flat out and you just mentally rate where you think your level of exertion falls.

This scale was invented by Dr Gunnar Borg and hence is often referred to as the Borg scale .

The numbers on the scale may seem a little weird but this range allows you to quickly estimate your heart rate simply by multiplying the scale number by 10, so if you rate your exertion at 20 your heart rate would be around 200 bpm.

I was playing around with a data logging shield and though it would be interesting to automate this idea.

### Hardware description:

The hardware consists of an Arduino UNO, a Deek robot data logging shield v1.0, and an LCD shield with buttons.

The UNO, data logging shield and LCD shield are layered together like a cake. The shields take care of all of the connections, there is nothing to wire up.

I have removed pin 10 from my LCD shield, this pin is used for the LCD backlight but has been implemented incorrectly on some shields such as the one I bought , this is no loss in the context of this project as the data logging shield uses this pin as chip select.

### Software description:

The software was an exercise in code reuse.

I took the clock read functions from project “ds3231.ino” from the RTClib library.

I used some simple code to run the LCD.

I used the Arduino SD ReadWrite example  to work out how to write the data to the SD card.

I initially tested the code using the Arduino serial console I think this a good way to debug changes so I have left it in place in the uploaded code; uncomment the line//#define test to switch off the writes to the SD card and send the data to the serial console.

### Assumption:

You have already set the clock on the logging shield as the program here does not do that.

SPI

SD

RTClib

LiquidCrystal

### Data format:

The data is stored as comma separated values (CSV) in the format of – Year, Month, Day, Hours, Minutes, Seconds, RPE value.

On pressing select to start the date, time and a RPE value 6 will be written to the data file, on pressing select at the end of a session the date, time and a RPE value zero will be written to the data file.

### Functioning:

At turn on the unit initializes the SD card and opens the file to record the data.

All records are appended to the same file whose name is coded into the program (data.txt).

You are warned if the SD card cannot be initialized, the data file opened or the data cannot be written to the card.

Hit the select key to begin logging and keep adjusting the level in line with your perceived exertion using the up and down buttons.

At the end of an exercise session hit the select key to stop recording.

### Granularity and limits:

The data is recorded to a minimum resolution of 1 second, if multiple button presses occur within that time frame each will be recorded as having occurred at the same time.

Multiple writes also occur at the limits, when you are at either 6 and press down additional times or at 20 when you press up additional times.

This is something to be aware of if you are going to run the data file through another program say to generate a graph.

### References:

https://en.wikipedia.org/wiki/Rating_of_perceived_exertion (Retrieved 18/June/2019)

 LCD shield errata link https://forum.arduino.cc/index.php?topic=96747.0(Retrieved 7/June/2019)

## Code

##### RPE logger code fileC/C++
```//RPE logger code file

//CHECK IF LCD SHIELD USES DIGITAL PIN 10 AS THIS IS USED AS CS FOR DATA LOGGING SHIELD
//CHECK TO SEE IF LCD IS ONE OF THE FAULTY ONES
//REFERENCE - https://forum.arduino.cc/index.php?topic=96747.0 (Retrieved 7/June/2019)

/*
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 10 for deek robot data logging shield v1.0
*
* RTC connections (I2C):
* gnd to gnd
* + to +5V
* SDA to A4
* SCL to A5
*
* LCD shield:
* Backlight - pin 10 removed
* B4 to D4
* B5 to D5
* B6 to D6
* B7 to D7
* RS to D8
* E to D9
*
* LCD shield buttons:
* Analog 0
*
*/

//#define test  //uncomment this line to send data to serial console instead of SD card

#include <SPI.h>
#include <SD.h>

const int chipSelect = 10;//CS for deek robot data logging shield v1.0

//for real time clock
#include "RTClib.h"

RTC_DS3231 rtc;

//for LCD shield
#include <LiquidCrystal.h>

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// these have been checked with http://www.robotshop.com/content/PDF/dfrobot-lcd-keypad-shield-schematic.pdf

File myFile;

//required to debounce switches
#define MAX_CHECKS 10
volatile uint8_t Debounced_State=0;//accessed by isr and main loop code
uint8_t State[MAX_CHECKS]={0};
uint8_t Index=0;

//rpe
const int rpe_max=20;
const int rpe_min=6;

//where we hold the filename
const String my_filename="data.txt";

void setup()
{

lcd.begin(16, 2); // start the library
lcd.setCursor(0,0);

// initialize timer1
noInterrupts();           // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1  = 0;

OCR1A = 625;              // compare match register  16MHX/256/100HZ
TCCR1B |= (1 << WGM12);   // CTC mode
TCCR1B |= (1 << CS12);    // 256 prescaler
TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
interrupts();

if (!SD.begin(chipSelect)) {
lcd.print("Not Initialized");
delay(5000);
return;
}

if (!SD.exists(my_filename)) {
lcd.print("No File");;
delay(5000);
}

lcd.setCursor(4,0);
lcd.print("Stopped");
lcd.setCursor(4,1);
lcd.print("RPE ");
lcd.print(rpe_min);

#ifdef test
Serial.begin(9600);
#endif

}

void loop()
{
//variables
static bool started=false;
static bool last_entry=false;
static bool do_update=false;
static bool button_up=false;
static bool button_stored=false;
static int Stored_State=0;
static int Decode_Me=0;
static int rpe_count=rpe_min;

noInterrupts();           // disable all interrupts
if (Debounced_State>Stored_State){Stored_State=Debounced_State;button_stored=true;}//store and flag as ready
if (Debounced_State<Stored_State){if(button_stored){button_up=true;Decode_Me=Stored_State;}Stored_State=Debounced_State;}//button has been released
interrupts();             // enable all interrupts

if(button_up && button_stored)
{
button_stored=false;
button_up=false;
do_update=true;

if (Decode_Me==1){if(started){rpe_count--;if(rpe_count<rpe_min){rpe_count=rpe_min;}do_update=true;}}//decrement rpe
if (Decode_Me==2){if(started){rpe_count++;if(rpe_count>rpe_max){rpe_count=rpe_max;}do_update=true;}}//increment rpe
if (Decode_Me==4){if(started){started=false;last_entry=true;}else{started=true;}rpe_count=rpe_min;do_update=true;}//start stop

}

if (do_update){
do_update=false;

if(!started){lcd.setCursor(0,0);lcd.print  ("    Stopped         ");}
if(rpe_count==6 && started){lcd.setCursor(0,0);lcd.print       ("  No exertion    ");}
if(rpe_count>=7 && rpe_count < 9){lcd.setCursor(0,0);lcd.print (" Extremely light ");}
if(rpe_count>=9 && rpe_count < 11){lcd.setCursor(0,0);lcd.print ("  Very light    ");}
if(rpe_count>=11 && rpe_count < 13){lcd.setCursor(0,0);lcd.print("     Light     ");}
if(rpe_count>=13 && rpe_count < 15){lcd.setCursor(0,0);lcd.print("  Somehwat hard ");}
if(rpe_count>=15 && rpe_count < 17){lcd.setCursor(0,0);lcd.print("     Hard       ");}
if(rpe_count>=17 && rpe_count < 19){lcd.setCursor(0,0);lcd.print("   Very hard    ");}
if(rpe_count>=19 && rpe_count < 20){lcd.setCursor(0,0);lcd.print(" Extremely hard ");}
if(rpe_count==20){lcd.setCursor(0,0);lcd.print("Maximum exertion");}

lcd.setCursor(8,1);
lcd.print(rpe_count);
if(rpe_count<10){lcd.print(" ");}

//In test mode we write to the serial console when not in test mode we write to the SD card.
#ifdef test
if(started){
Serial.print(get_time());
Serial.print('-');
Serial.println(rpe_count);}
else
{if(last_entry){
last_entry=false;
Serial.print(get_time());
Serial.print('-');
Serial.println(0);}}
#else
if(started){append_file(my_filename,get_time(),rpe_count);}else{if(last_entry){last_entry=false;append_file(my_filename,get_time(),0);}}
#endif

}

}

//my_functions

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
//
uint8_t temp=0x00;

//debounce
uint8_t i,j;

//for right hand
State[Index]= temp;
++Index;
j=0xFF;
for (i=0;i<MAX_CHECKS;i++){j=j&State[i];}
Debounced_State=j;
if(Index>=MAX_CHECKS){Index=0;}

}

//function to get time from clock and return it as a string
String get_time(void){
//check rtc available
if (! rtc.begin()) {
lcd.print("No RTC");
delay(5000);
}

String dataString = "";

DateTime now = rtc.now();

dataString += String(now.year());
dataString += ",";
dataString += String(now.month());
dataString += ",";
dataString += String(now.day());
dataString += ",";
dataString += String(now.hour());
dataString += ",";
dataString += String(now.minute());
dataString += ",";
dataString += String(now.second());

return dataString;
}

//function to append the rpe value and time to the data file
void append_file(String filename,String dataString,int rpe)
{

//append rate perceived exertion value to time dataString
dataString += ',';
dataString += rpe;
dataString += ',';

//write to file

myFile = SD.open(filename, FILE_WRITE);

// if the file opened okay, write to it:
if (myFile) {
myFile.println(dataString);
// close the file:
myFile.close();
} else {
lcd.print("Can't open file");//error file didn't open when writing data
delay(5000);
}

return;
}
//End
```

June 19, 2019

#### Members who respect this project

See similar projects
you might like

#### Measure Heart Rate and SpO2 with MAX30102

Project tutorial by SurtrTech

• 59,709 views
• 168 respects

#### Temperature and Humidity Logger Per Hour

Project tutorial by lefteris1993

• 3,595 views
• 13 respects

#### Heart Rate Monitoring System

Project tutorial by HRMS

• 24,649 views
• 38 respects

• 33,754 views
• 31 respects

#### Detecting Heart Rate with a Photoresistor

Project tutorial by 3 developers

• 14,973 views