Intro: Simple Arduino-based Ergometer Display With Differential Feedback
Cardio-workout is boring, particularly so, when exercising indoors. Several existing projects try to alleviate this by doing cool stuff such as coupling the ergometer to a game console, or even simulating a real bicycle ride in VR. Exciting as these are, technically, they don't really help much: Workout is still boring. So, instead, I'd like to be able to just read a book or watch TV while training. But then it's difficult to keep up a steady pace.
The idea, here, is to focus on the latter problem, and provide straight-forward feedback, on whether your current level of training is good enough, or you should put in some more effort. However, the "good enough" level will vary not only per person, but also over time (long term, as you get better, but also within a training session: for instance, it's near impossible to go at full speed before you've warmed up). Therefore, the idea behind this project is simply to record a) the previous run and b) the best run (aka highscore), and then provide direct feedback on how you are currently faring compared to those runs.
If that sounds a bit abstract, skip over to Step 7 for details on what the completed display will show.
A further goal of this project is to keep things really simple and cheap. Depending on where you order your parts, you can complete this project for around $5 (or about 30$ when ordering from premium domestic sellers), and if you have played with the Arduino environment, before, there is a fairly good chance that you already have most or all of the parts you need.
Step 1: Part List
Let's go through the list of things you need:
- An Arduino compatible microprocessor
Pretty much any Arduino sold during the past few years will do. The exact variant (Uno / Nano / Pro Mini, 8 or 16 MHz, 3.3. or 5V) does not matter. However, you will need an ATMEGA328 processor or better, because we will be using almost 2k of RAM, and 1k of EEPROM. If you are familiar with the ins and outs of the Arduino world, I recommend using a Pro Mini at 3.3V, as it will be cheapest, and most battery efficient. If you are (relatively) new to Arduino, I recommend a "Nano" as it provides the same functionality as an "Uno" in a smaller and cheaper package.
Note that this instructable will not talk you through the very basics. You should at least have the Arduino software installed, and know how to connect your Arduino and upload a sketch. If you have no idea, what I'm talking about, read these two easy tutorials, first: First, second.
- An 128*64 pixel SSD1306 OLED display (I2C variant, i.e. four pins)
This is one of the cheapest and easiest displays available, today. Agreed, it's tiny, but good enough. Of course, if you already have a display of similar or better resolution, it will be possible to use that, instead, but this instructable is written for an SSD1306.
- A "solderless breadboard" and some jumper wire, for building your prototype
- A 100nF ceramic capacitor (may or may not be needed; see Step 4)
- Either some croc-clips, or a magnet, a reed switch and some cable (see Step 4)
- A red and an green LED, each (optional; see Step 5)
- Two 220Ohm resistors (if using the LEDs)
- A pushbutton (also optional)
- A suitable battery (see Step 6)
Step 2: Connecting the Display
As the first thing, we'll hook up the display to the Arduino. Detailed instructions are available. However, the SSD1306 is really easy to hook up:
- Display VCC -> Arduino 3.3V or 5V (either will do)
- Display Gnd -> Arduino Gnd
- Display SCL -> Arduino A5
- Display SCA -> Arduino A4
Next, in your Arduino environment go to Sketch->Include library->Manage libraries, and install "Adafruit SSD1306". Unfortunately, you will have to edit the library in order to configure it for the 128*64 pixel variant: locate your arduino "libraries" folder, and edit "Adafruit_SSD1306/Adafruit_SSD1306.h". Search for "#define SSD1306_128_32", disable that line, and enable "#define SSD1306_128_64", instead.
At this point you should load File->Examples->Adafruit SSD1306->ssd1306_128x64_i2c in order to test your display is connected, correctly. Note that you may have to adjust the I2C-address. 0x3C appears to be the most common value.
In case of trouble, refer to the more detailed instructions.
Step 3: Upload the Sketch
If everything worked, so far, it's now time to upload the actual sketch to your Arduino. You'll find a copy of the sketch, below. For a potentially more recent version, refer to the github project page. (Since this is a single file sketch, it's enough to just copy the erogmetrino.ino file to your Arduino window).
Should you have had to modify the I2C address in the previous step, you will have to make the same adjustment, again, now, in the line starting with "display.begin".
After uploading, you should see some zeros showing up in your display. We'll look at the meaning of the various sections of the display, after everything else is hooked up.
Note that on the very first start, the display will be rather slow to light up (may take up to around ten seconds), as the sketch will zero any data stored in the EEPROM, first.
Step 4: Connecting the Ergometer
This step cannot really be described universally, since not all ergometers are the same. However, they are not all different, either. If your ergometer includes an electronic speed display at all, it must have an electronic sensor to detect revolutions of the pedals, or some (possibly internal) fly wheel, somewhere. In many cases, that will simply consist of a magnet passing close to a reed switch (see also, below). Each time the magnet passes, the switch will close, signalling one revolution to the speed display.
The first thing you should do is to examine the speed display on your ergometer for incoming cables. If you find a two wire cable coming somewhere from within the ergometer, you have almost certainly found the connection to the sensor. And with a bit of luck you can simply unplug this, and just connect it to your Arduino with some croc-clips (I'll tell you what pins to connect to in a minute).
However, if you cannot find such a cable, feel unsure if you found the right one, or you cannot disconnect it without damaging anything, you can simply tape a small magnet to one of the pedals, and fix a reed switch to your erogmeter's frame, such that the magnet will pass by it very closely. Connect two wires to the switch and lead them to your Arduino.
Connect the two wires (whether your own, or those from an existing sensor) will go to Arduino Gnd, and Arduino pin D2. If you have one on hand, also connect the 100nF capacitor between pin D2 and Gnd for some "debouncing". This may or may not be needed, but helps to stabilize the readings.
When done, it's time to power up your Arduino, and hop on the bike for a first quick test. The top left number should start showing a speed measure. If this does not work, check all wiring, and make sure that the magnet is close enough to the reed switch. If the speed measure seems consistently too high or too low, simply adjust the "CM_PER_CLICK" define near the top of the sketch (note: the sketch uses metric names, but no units are displayed or saved, anywhere, so just ignore that, and supply 100.000ths of a mile per click).
Step 5: Optional Quick Status LEDs
The LEDs described in this step are optional, but neat: If you're serious about reading a book / watching TV while exercising, you don't want to have to stare at the display too much. But two LEDs in different colors will easily be noticeable in peripheral vision, and will be enough to give you rough idea, of how you are doing.
- Connect the first (red) LED to pin D6 (the longer leg of the LED goes to the Arduino). Connect the short leg of the LED to Gnd via a 220Ohms resistor. This LED will light up, when you are 10% or more below your best speed in the current phase of the training. Time to put in some more effort!
- Connect the second (green) LED to pin D5, again with a resistor to Gnd. This LED will light up, when you are within 1%, or above of your best run. You're doing good!
You want the LEDs to light up depending on how you fare compared to your previous run, or some arbitrary average speed? Well, just connect a pushbutton between pin D4 and Gnd. Using that button you can toggle the reference between "your best run", "your previous run", or "your current speed". A small letter "P", or "C" in lower left corner will signify the latter two modes.
Step 6: Powering Your Ergometer Display
There are many ways to power your display, but I'll point out two which seem rather more practical than others:
- When using an Arduino Uno or Nano, you probably want to power it using a USB power-bank with built-in low battery indication.
- When using an Arduino Pro Mini @ 3.3V (my recommendation for advanced users), you can power that directly from either a single LiPo battery, or three NiMH cells. As the ATMEGA will tolerate supply voltages up to 5.5V, you can connect this to "VCC/ACC", directly, bypassing the on-board voltage regulator. In this setup, there will also be a "low battery" warning at around 3.4V, without any additional hardware (displayed in the lower right corner). As the ATMEGA can be expected to work correctly, at least down to 3.0V or so, that should leave you enough time to finish your training unit before recharging.
Step 7: Using Your Ergometer Display
Let's take a closer look at the various numbers on your display. The larger number of the top left is simply your current speed, and the larger number on the top right is the total distance in your current training.
The next line is your average speed since the start of the training (left), and the time since the start of the training (right). Note that the timing is stopped while the bike is stopped.
So far so trivial. The two further lines on the right hand side are where it gets interesting: These compare your current timing to your previous and best training, respectively. I.e. a "- 0:01:23" in the upper of these lines will mean that you have reached your current distance 1 minute and 23 seconds earlier than on your previous run. Good. A lower line of "+ 0:00:12" will mean that up to the current point, you are lagging 12 seconds behind your best run. (Note that these differential times will not be 100% exact. Time points are stored every .5 km / miles, and interpolated between that.) Unavoidably, of course, on your first run, no time references have been recorded, yet, and so both of the above lines will just show "--:--:--".
Finally, the lower left region of the display contains a graph of your speed over the last minute. This allows you to see at a glance, whether you are going steady, or slowing down. (Note that this line will be much smoother in real training - but it simply isn't easy to maintain a steady pace while trying to take a picture...) Horizontal lines indicate the previous / best speed you achieved near the current point of your previous trainings.
The LEDs mounted near the top compare your current speed to your best speed during this phase of the training. Green shows you are within 1% of your best, red shows you are more than 10% slower than your best training. When you see the red light, it's time to put in some more effort. Note that contrary to the differential times described above, these refer to the current part of the training, only, i.e. it is possible you're lagging behind in absolute time, but green shows you are catching up, and vice versa.
The reference speed used for the two LEDs can be changed using the push button. One press will switch it from best to previous recorded training (a small letter "P" will show up in the lower left). Another press and your current speed at the time of the button press will become the new reference speed (a small letter "C" will show). The latter is especially useful during your first training with your new ergometer display, when no reference has yet been recorded.
When done with your training, just disconnect the battery. Your training has already been saved in your Arduino's internal EEPROM.
As you can see, I ended up soldering my prototype. Sure sign that I liked the result, myself. I hope you'll find it useful, too. Happy exercising!