DIY Smart Fitness Device That Counts Reps and Tracks Your Progress in the Gym

by michalshapira_ in Circuits > Arduino

563 Views, 7 Favorites, 0 Comments

DIY Smart Fitness Device That Counts Reps and Tracks Your Progress in the Gym

IMG_8702.jpg
IMG_8656.jpeg

In this instructable, we'll guide you through the process of building your own GymBuddy, a device that counts reps and tracks your progress automatically. Using Arduino IDE and an ESP32 controller, we'll integrate it with Blynk and Make.com to enhance your workout experience.

This project includes the following features:

  • Start tracking your exercise effortlessly by pressing a button in our custom Blynk app or using Siri shortcuts, perfect for when your hands are occupied with weights. You can easily keep count of your reps without needing to remember them, and the app supports multiple exercises, as demonstrated in the video below. Your workout details are automatically saved to a Google Sheet, allowing you to log your weights and track your progress over time.
  • Take control of your workout environment by managing the room's air quality, whether by turning on a fan or AC, depending on your setup. You can also activate a fun light mode to enhance your mood. These features can be controlled via the Blynk app or Siri shortcuts as well.

Here is a demo for how GymBuddy works: https://youtu.be/rm8J747FscE

Supplies

IMG_8646.jpeg
IMG_8648.jpeg

Our project utilizes services from Make.com and the Blynk interface. Make sure you have an account for these services.

We will also need the following software tools installed on our computers, If you’ve worked with ESP32 before, feel free to use the methods you're familiar with.

  • Arduino IDE
  • ESP32 driver

Now, let’s gather the necessary hardware components:

  • ESP32 controller
  • Keystudio ESP32 breadboard (or any other breadboard you like)
  • 4 x AAA batteries for your power supply
  • Battery compartment
  • IMU sensor
  • LED Strip
  • IR sender sensor
  • IR receiver sensor
  • 10 mm blue LED
  • Sensor hookup cables

For the case:

  • Cardboard sheets / suitable box for housing the components securely.
  • Self Adhesive Hook and Loop Fastener Tape
  • Scotch tape
  • Paper cutter knife
  • A ruler
  • A pencil

Feel free to get creative with the case part (and actually every part ). We recommend finding an empty box that fits the components perfectly. If you can't find one (like us), you can follow our steps.

With everything ready, we can dive into building your own GymBuddy.

Connecting the Wires

IMG_8648.jpeg
  • LED strip - pin 15
  • IR sender - pin 26 
  • Blue LED - pin 17
  • Accelerometer:
  • SCL - pin 22
  • SDA - pin 21

Writing the Code

IMG_8723.jpeg

Below is a detailed explanation of the code and the process of writing it.

If you prefer, you can skip this section and view the full code in the attached file.

Downloads

Counting the Number of Reps

IMG_8718.jpg
IMG_8719.jpeg
IMG_8720.jpeg

The process of counting the reps will be done using the accelerometer measurement of the IMU sensor.

First we are going to add configurations for the IMU sensor:

// IMU configurations
#include "I2Cdev.h"
#include "MPU6050.h"
MPU6050 accelgyro; // I2C address 0x68 by default
int16_t ax, ay, az;
int16_t gx, gy, gz;
#define OUTPUT_READABLE_ACCELGYRO

Now we are going to initialize the sensor inside the setup() function:

accelgyro.initialize();

Inside the loop() function we are going to read data from the IMU sensor

  // count reps if user has started exercise
  if (isInExercise && millis() - lastSendTime > sendInterval) {
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); // get data from the sensor
  
    // Detect direction change
    if ((ay > 0 && previousAccelY < 0) || (ay < 0 && previousAccelY > 0)) {
      directionChanges++;
    }
  
    // Count reps
    if (directionChanges >= 2) {
      reps++;
      // Send data to Blynk at specified intervals
      directionChanges = 0;
    }
  
    // Send to Blynk with delay (make sure not to accidentaly send too much)
    if (reps != lastSentReps) {
      Serial.println("sending update to Blynk");
      Blynk.virtualWrite(V2, reps); // Send rep count to Virtual Pin V2
      lastSentReps = reps;
    }
  
    previousAccelY = ay;

    lastSendTime = millis();
  }  

We are going to integrate Blynk and than we can see if this code works.

You can also modify it to only print to the Serial monitor before we integrate Blynk.

Add Blynk Support

IMG_31A4793BA036-1 2.jpeg
1.png
3.png
4.png
Untitled.png

Create Blynk application


  • In the Blynk dashboard, create a new device. Make sure you save the credentials to use later in your code.
  • Next we need to add virtual pins. Press on the "New Datastream -> Virtual Pin" buttons and create 4 virtual pins to integrate with our ESP32 - Exercise, Party Mode, Reps and Turn fan on.
  • Create your dashboard and save.
  • Download Blynk app on your phone and create a mobile dashboard as well.

Integrate Blynk in your code


Define your Blynk configurations.

#define BLYNK_TEMPLATE_ID ""
#define BLYNK_TEMPLATE_NAME ""
#define BLYNK_AUTH_TOKEN ""

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

Include Wifi and Blynk modules
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

Add your Wifi Credentials

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "";
char pass[] = "";

Integrate V0 virtual pin. We will edit this function in the next steps.

// This function will be called every time Switch Widget
// in Blynk app writes values to the Virtual Pin V0
// Controls the start/end of an excercise.
BLYNK_WRITE(V0)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V0 to a variable
  
  if (pinValue == 0) {
    // TODO: send HTTP to make.com
    
  }

  reps = 0; // reset the number of reps
}

And of course don't forget to add Blynk to void setup() function

  // Blynk
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
  Blynk.virtualWrite(V2, 0); // Reset rep count in Virtual Pin V2


Integrate Make.com

step 1.png
step 2.png
step 3.png
Step 4.png
Step 5.png
Step 6.png
Step 9.png
step 10.png
step 11.png
Untitled.png

Create a Make.com Automation


  1. First you will need to create an account. Next we want to create a new scenario by pressing the button.
  2. Now we will add a Webhook.
  3. Choose a name.
  4. Copy the URL received.
  5. Next send an http request to the URL using the browser.
  6. Now we want to create our google sheets integration. There are of course many options you can choose from in Make.com. Choose the add a row option.
  7. You will need to connect your google account if you haven't done this before.
  8. Create a new Google Sheets document and define the columns you want, and a reps column.
  9. Define the date format, and connect reps to the webhook we created.
  10. Add scheduling, meaning that Make.com will listen to data arriving from the webhook.


Send HTTP request via ESP32


We will use HTTPClient library in order to send HTTP request from our ESP32 whenever an exercise is finished.

#include <HTTPClient.h>
#include <WiFiClientSecure.h>

add your Make.com hook url:

const char* makeUrl = "https://hook.eu2.make.com/YOUR_MAKE_URL?reps=";

let's modify BLYNK_WRITE(V0) from before and add a report function that will be in charge of sending the number of reps to Make.com

BLYNK_WRITE(V0)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V0 to a variable
  
  if (pinValue == 0) {
    // Send the number of reps to Make.com
    report(reps);
  }
  reps = 0;
}


void report(int data) {
  Serial.println("starting report to make.com");
    WiFiClientSecure *client = new WiFiClientSecure;
  if (client) {
    client -> setInsecure(); {
      HTTPClient https;
      Serial.print("[HTTPS] begin...\n");
      Serial.print("Sending to ");
      Serial.println(String(makeUrl) + reps);
      if (https.begin(*client, String(makeUrl) + reps)) {  // HTTPS
        Serial.print("[HTTPS] GET...\n");
        int httpCode = https.GET();
        if (httpCode > 0) {
          Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
          if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
            String payload = https.getString();
            Serial.println(payload);
          }
        }
        else {
          Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
        }
        https.end();
      }
      else {
        Serial.printf("[HTTPS] Unable to connect\n");
      }
    }
    delete client;
  }
  else {
    Serial.println("Unable to create client");
  }
  Serial.println();
}

Now we expect to see that the exercise data has been added to our google sheets file via Make.com

Controlling Your Fan/AC and Integrating Siri Shortcuts

IMG_8633.PNG
IMG_8634.jpg
IMG_8635.jpg
IMG_8636.jpg
IMG_8637.PNG

Most fans and air conditioning today come with a remote and a build-in IR receiver.

We can take advantage of that and control the device using our ESP32, IR receiver and IR transmitter.

First you will need to run the following code on your ESP32 to record the command that turns on/off the AC.

#include <Arduino.h>
#define IR_RECEIVE_PIN          21
#define IR_SEND_PIN              5

#include <IRremote.hpp>

void setup() {
  Serial.begin(115200);
  Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));
  // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
  Serial.print(F("Ready to receive IR signals of protocols: "));
  printActiveIRProtocols(&Serial);
  Serial.printf("at pin %d\n", IR_RECEIVE_PIN);
}


void loop() {
  if (IrReceiver.decode()) {
    IrReceiver.printIRResultShort(&Serial);
    IrReceiver.printIRSendUsage(&Serial);
    if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
      Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
      // We have an unknown protocol here, print more info
      IrReceiver.printIRResultRawFormatted(&Serial, true);
    }
    Serial.println();

    /*
       !!!Important!!! Enable receiving of the next value,
       since receiving has stopped after the end of the current received data packet.
    */
    IrReceiver.resume(); // Enable receiving of the next value
  }
}

After succefully compiling the code and uploading to your ESP32, open the Serial Monitor of you Arduino IDE and press the button on the remote that you want to imitate. You will see the command that is being sent, remember it for later, as we will send that command in our final code.

Now that we know which command we need to send, we can continue writing our code.

#define IR_SEND_PIN              4  // D4
#define DISABLE_CODE_FOR_RECEIVER
#include <IRremote.hpp> 

uint8_t sCommand = 0x47; // the command that you found in the code above
uint8_t sRepeats = 0;

Next we will add the BLYNK_WRITE in our code to control the virtual pin that is attached to the turn fan on switch in our Blynk app.

BLYNK_WRITE(V3)
{
  param.asInt();
  Serial.println("Received IR request");
  IrSender.sendNEC(0x00, sCommand, sRepeats);
  delay(1000);
}

We also need to add some setup instructions which are available in the full code.

Creating a Siri shortcut

This part is only relevant for those who have iPhone, but I am sure there is a way to do this on Android as well!

  • Open the "Shortcuts" app
  • Press the + button to create a new shortcut
  • Select "Add action"
  • Search for "Open URLs"
  • Press the "URL" placeholder and paste the following URL: https://blynk.cloud/external/api/update?token=<your-token-goes-here>&V0=0
  • This will turn the fan off. Do the same with V0=1.
  • Rename the shortcut however you want. We called it Gym Buddy Start, as you can hear in the demonstrating video.

Do the same for the light mode and fan control!

Fun Light Mode

IMG_8721.jpg
IMG_8722.jpeg

Let's add some lights to make things more interesting and fun!

We will use the following functions in our code, so we can use them later in our BLYNK_WRITE functions

#define LED_PIN 15
#define LED_COUNT 12

#include <Adafruit_NeoPixel.h>
#include <Adafruit_Sensor.h>

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);


int funMode = 0;
unsigned long previousFunMillis = 0;
unsigned long funWait = 40;
long funFirstPixelHue = 0;

void run_fun_mode() {
  unsigned long currentMillis = millis();
  if (funMode && currentMillis - previousFunMillis > funWait) {
    if (funFirstPixelHue >= 5 * 65536){
      funFirstPixelHue = 0;
    } 
    strip.rainbow(funFirstPixelHue);
    strip.show(); // Update strip with new contents
    funFirstPixelHue += 256;
  }
}

void clearLEDs() {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, 0); // Set color to 'black' which is off
  }
  strip.show(); // Update the strip to turn off all LEDs
}

Now connect to the virtual pin you created in Blynk

BLYNK_WRITE(V1)
{
  funMode = param.asInt();
  if (funMode == 0) {
    clearLEDs();
  } 
}


Final Assembly and Test Run

IMG_8651.jpeg
IMG_8652.jpeg
IMG_8653.jpeg
IMG_8654.jpeg
IMG_8656.jpeg
IMG_8658.jpeg

In this final assembly step, we’ll bring together all the components into a single device. This process includes attaching the electronics, securing the connections, and making sure the device is both operational and comfortable to use.

  • Start by placing your ESP32 and battery compartment on the cardboard, leaving enough margin for the LED strip, LED blue light and IR sender cuts.
  • Cut the cardboard using the cutter knife, and use it to measure and cut another base from the cardboard.
  • Mark and cut slots for the LED strip, blue light and IR sender.
  • We want to turn this into a box, so use the sides of the base to measure and cut sides for out box.
  • Secure the components to your box using a strong tape.
  • Secure the box using a tape suitable for paper, so it doesn't rip the cardboard if you want to open the box.
  • Glue the adhesive fastener tape to the back of the box, and to the weights you are going to be using in your next exercise.
  • Attach the device to the weight, make sure it is turned on and secure

Final step

Once you've completed all the setup steps and verified the connections and configurations, it’s time to test the system and enjoy the peace of not having to forget how many reps you just did. Make sure all components are powered on and working properly.

Remember to open the Google Sheet we’ve created after your workout and log the weights you used for the best results.