Tuesday, 5 August 2025

Designing my own physics-based gym product

 



A common question I see asked in the gym is 'How many reps was that?' When you are pushing your body to the limits of what it can do, it is pretty much impossible to count the number of times you do an exercise, especially near the end of the workout. There are definitely devices that can already measure movements such as bench and deadlifts, but I wanted to make something that would integrate itself into most gym machines, and not require you to buy a £200 Apple Watch.

I wanted to use an Arduino for this project, with an accelerometer that could detect changes in velocity and add one to a counter. The issue with this is that I needed 5V to run the Arduino, which meant that my product would require 4 AAA batteries to run. In the future, I would like to find a smaller board that only requires 1.5V, so that I could use a smaller button cell and make the whole design a lot more compact.

To start 3d modelling the case, I needed to start modelling the batteries. It would be a lot more convenient to have a premade battery case, as they are already made as compact as possible. My plan was to buy a battery case that could support 4 AAA batteries, which could consistently supply 6V. The 6V could then be cut down with a potential divider circuit to 5V, to the Arduino. The battery case could be modelled as a cube:

Which we could design the bottom half of the case around. I did this by modelling a smooth curved surface around the cube with a few millimetres of space to allow for 3D printing tolerances:
This could be extruded and made thicker with the 'Thin' extrude feature on Onshape.:
I could then model on endcaps to make a shell that housed the battery case well, with ridges for better grip for your fingers.
It was here that I realised I needed a way to actually thread the pin that goes into the weight stack into the case. This would not be possible in the current design, as the highest part of the shell is in the middle. To remedy this, I made the lowest part of the case in the middle, to allow a hole to be drilled that would thread into the pin.
Here, you can see the fit of the battery case in the shell, using a Section View that shows the cross-sectional profile of parts.
I then needed a way to bolt the top and bottom halves together. The reason for this is that the battery case needs to be accessible to change the batteries, and having glued halves would prevent this. I added ridges, with around 5mm of extra space now available for threaded bolts.

I could then model in 4 M3 threaded holes, equally spaced due to the mirror tool, and another hole tapped into the middle of the shell with an M8 hole, which is the standard for a gym weight selector pin.

This is what the bottom half of the shell, with the selector pin threaded in, then split both halves to make it much easier to 3d print without supports, looks like:


This is where I had my biggest redesign. I realised that an Arduino board, despite being limited to 5V, can easily take 9V inputs over the VIN and GND connections. The 9V is automatically brought down to 5V without much wasted energy, allowing the board to function as if it were powered by USB. Since a 9V battery has less than half the volume of the 4.5V AA arrangement I originally planned, I fully scrapped the previous idea and switched to a case centred around a 9V battery. I also decided to switch to a protoboard instead of a breadboard, due to its lower profile and infinitely more professional and durable characteristics, with solder joints instead of jumper cables.

 This is what the Arduino Nano and MPU6050 looked like connected together on the protoboard. 2 wires connected the power lines of the chips together, and the MPU can send 6-axis gyro data using just 2 more wires connected to the analog pins of the Arduino.

The other side of the protoboard looks like this. You can see the strip of copper that was removed with a knife to isolate both sides of the Arduino's board. The legs were bent after this image to reduce the effective height of the circuit board.

 The board could then be trimmed down using scissors and then filed down to its final size. In this state, the board could then be programmed, which ended up taking the most time, as per usual.

The MPU can export data at a very high refresh rate, specifically on its acceleration and the direction of the acceleration. To effectively program a detector for reps, you must reverse engineer what occurs in terms of acceleration every rep. The weight firstly accelerates upwards, then reaches a constant speed near the middle of the rep. Regardless of exercise, as you approach the top of the rep, you decelerate until the velocity of the weight is 0. There is often a brief pause here, then the weight decelerates back down, typically at a slower rate than the acceleration on the way up. This completes one repetition of a cable exercise. 

The MPU doesn't know what counts as a rep, so the code must reflect this behaviour so that the data from the chip can be converted to reps. The code first defines some 'boundaries'. These boundaries are set so that when the chip is stationary, small bumps or jolts don't count as repetitions - only large accelerations above the threshold are registered. Once a large acceleration is registered, the code waits for a deceleration in the opposite direction. If this event also happens, the code then waits to check if there is a final deceleration as the weight stops at the end of the rep. If each of these conditions is met, the Arduino can be sure that a rep has been done. Since most people take around 2 seconds to complete a rep, I also set a time limit of 0.5 seconds. If the Arduino, for whatever reason, detects 2 reps in the span of 0.5 seconds, it discards one of them as a false reading, since no one can realistically move a working weight that quickly.

After tuning the threshold values, I got the Arduino to perfectly detect the faster reps at the start of sets, as well as the slower, shakier reps near the ends of sets. 

A 9V battery connector was then soldered on, and hot-glued for good measure, so that the stresses of changing the battery wouldn't be concentrated in the solder connections alone. 

This is the case I designed for the new pin design. It was made using measurements of the board and battery, and when printed, housed the components like so:


The issue was now how to display the number of reps in the most optimal way possible. I considered many options, with a pros and cons list below:

1- Screen (Display number of reps on small onboard screen, reset to 0 with button press)

Easiest to read and most user-friendly

Expensive, bulky, and reduces damage resistance

High power consumption and uses the I2C protocol, so the MPU can't be used

2-Speaker (Read out number of reps from small onboard speaker, reset to 0 with button press)

Low power consumption

Not suitable for non-English-speaking consumers

Can be inconvenient in noisy environments (most gyms)

3-Haptic (Haptically buzz device, the number of reps completed with a small haptic motor, reset to 0 with a button press)

Not user-friendly

Hands are usually numb or less sensitive after sets

4-Light code (Flash LED lights set amount of times, reset to 0 with button press)

Low power consumption

Fairly user-friendly and universal across languages

From these options, I decided that a light code would be optimal. Since the majority of sets take between 3 to 18 reps, I decided on a code that was optimised for this scenario. A multicoloured LED (that can change colors based on which pins are set to 5V) would be used. 

The LED would flash red for every 5 reps that have been completed, and then green for every remaining rep. Some examples are below

3 reps : 3 green

6 reps: 1 red 1 green

11 reps: 2 red 1 green

16 reps: 3 red 1 green 

With this system, assuming a maximum rep count of 18, the most flashes that would ever have to be read is 6, which is a lot more user-friendly than trying to count 18 flashes. I wanted to have this flash system repeat, so that you could note down the number of reps even if you miscount the first few times. The system was decided to be as follows.

1- Insert the device into the stack

2-Power on the device, will start counting reps

3-Do set

4- Device will automatically start flashing after 5 seconds of inactivity

5-Device will flash with the red and green sequence, then flash blue when the sequence is over

6-Device will continuously flash this sequence until it is reset by turning it off and on again.