Building a Better Interface for the Airdyne AD2 with a Raspberry Pi (Part 5)

The 4th part of this series was all about data and math. I like numbers, so it was exciting for me, but probably not for a lot of people.

Part 5: Version 1

I continued working on the user interface and tweaking how my app dealt with the data and formulas. Little changes in rounding decimal places could make a big difference. Eventually I got to the point where the UI had the basics to call it v1. It was just before midnight on the 20th, so I went from nothing to a functional interface over a weekend. It’s pretty much all I did for 2+ days.

I woke up on Monday and the damn calorie formula was still bugging me. I read through the Google Charts documentation again. I hadn’t even thought to try other types of trendlines, though I knew it wasn’t linear. The exponential example looked like the chart from the other Airdyne project I’d been referencing so I hadn’t thought twice about it. I couldn’t remember what a polynomial was so I looked it up. That project came up with a polynomial formula of degree 2.

I quickly changed my chart and immediately saw a better trendline with my plotted data. I’d been looking for the wrong type of trendline. I created a JSFiddle if you want to try your own.


The new calorie formula is nearly perfect! I’ve tweaked things a bit here and there and have seen less than a 2% difference from the actual display.

Go back to part 1 and check out the video of the Airdyne AD display if you don’t remember how it works and then compare to this new one…

I don’t show it until the end after I got off the Airdyne, but the toggling between imperial and metric distances can be done while working out too. Same with the switch from RPM to watts. I decided to keep the watts as an option even though I have no idea if they are right. It’s simply using the formula I found. What do you think? Which interface is better?

The code at this point was pretty ugly but function was the focus. The server listens for “beeps,” stores timestamps, and every second calculates new information for the different panels. Then it uses a Socket.IO Server to emit events with this data. Express handles all of the web server bits. What you see in this video is a browser in full screen mode with some simple HTML and CSS, a Socket.IO Client to listen for events from the server and emit a few action events back to the server, jQuery, and a little more javascript. Both the server and the client are on a single Raspberry Pi 3 Model B.

As a bonus, due to this structure, you don’t even need to have a display connected to a Raspberry Pi. If the Pi is connected to the same WiFi as a smart phone, tablet, or computer (something with touch is probably the best) you can use the device’s browser. In fact you don’t even need a Raspberry Pi. You can run the server from a Mac, which is how I’ve done all of the development.

This is a pretty simple UI but it does everything I was hoping I could do in a first version. The final post will show off the changes I’ve made in the last week (basically everything) and share my future plans.

Building a Better Interface for the Airdyne AD2 with a Raspberry Pi (Part 4)

In part 3, I explained the troubles I had reading microphone input through a USB adapter and how I eventually made progress by using a package to “listen” for sound.

Part 4: Calculations & Sample Data

Since the Airdyne sends a sound with each revolution of the flywheel, the RPMs were easy. I did some averaging over a number of revolutions to get a stable number. I had found formulas in a spreadsheet shared on the Airdyne Erg Trending post, so it was easy to plug in the formulas for calories and watts (even though my model doesn’t display watts). Distance and speed go off one another, so I jumped on the bike to collect some data.

When the machine stops/pauses, it continues to cycle through the 5 pieces of information and keeps the last number there. So I pedaled for 10 seconds or so, stopped, waited, and then recorded the speed (distance would be too inaccurate in such a short period of time) and rpms. Reset the display and repeat going faster each time. Threw the numbers in a spreadsheet, got a ratio, did some averaging, and worked both ways backwards with the average.


Looking back, I think I went a little overboard with getting so many samples. Miles per hour came out to be the RPMs divided by 3 ⅓. With a formula for every piece of info, my program output to the command line so I could see it in action. I jumped on the Airdyne, and used the audio cable splitter so I would get output on both displays. The RPM, distance, and speed were fairly accurate right away, but the calories were not even close.

I looked over the formulas to make sure I didn’t make a mistake, but didn’t see anything. I went back to the blog post and finally realized I had a different Airdyne model. I don’t know how I overlooked that when he was mentioning watts, which mine doesn’t show, and he has a big picture of the display right in the post. Anyone who has used several different models of the Airdyne can tell you that calories are much easier or harder to rack up from model to model.

In his post, Preston mentioning using an Excel chart, to get a formula from a trendline. I had no idea what this magic was. I don’t have Excel, so I searched to see if Google Spreadsheets could do the same thing. I found something even better, Google Charts does it, so I could write copy/paste code. 😉

Now I needed sample calorie data that I could plot on a chart. I was back out to the garage and hopped on the Airdyne. This was tricky. Since my goal was to find out what different average RPMs for 1 second would equate to in calories, I tried to maintain a constant speed for 36 seconds. Had to do 36 because it takes 30 seconds to cycle through the display and another 6 to get back to calories. I adjusted my program to keep track of the RPMs and calculate an average over the 36 seconds. I recorded both numbers in a spreadsheet and repeated the process over many times, with increasing speeds.

After getting a calorie per second average I plotted the points on the chart and voila! I got a trendline and a formula. The calories were looking much better. Still not awesome, but I figured it could be due to how I was averaging out RPMs, how I was rounding, or how often I was calculating everything. I started building a graphical display because I was getting tired of looking at command line output. At some point I got in a 10 minute “workout” and recorded a sound file on my computer and kept track of the calories so that I could pipe that back through my app for testing. I wish I had written some kind of simulator to eat through the data and spit out numbers.

I kept going back to the formula though. It was bugging me. What was I doing wrong? Finally it dawned on me how to get perfect data out of the Airdyne. Feed it perfect data and take the human element out of it. I could use a metronome since all the computer cared about was hearing something! Back out to the garage. I already had MetroTimer on my iPhone, so I plugged it into the Airdyne computer and recorded new calorie data at different speeds. I had new chart points and a much better formula. Still not accurate enough, but at least I was confident it wasn’t a problem with my data.


In the next post, I’ll give you a look at version 1 of the app.


Building a Better Interface for the Airdyne AD2 with a Raspberry Pi (Part 3)

In the previous post of the series, I discussed the plan, which included my shopping list for the project.

Part 3: Getting Started

I had gotten pretty excited (yeah, I’m a geek!) while I waited for the parts to arrive. I swore I had some 3.5 mm extension cables, but couldn’t find them, so I had to order them a couple of days after placing my initial order. This gave me a day or two to take my time installing software and setting up the Raspberry Pi. There are countless resources available, so Google or ask if you want to set one up. I did share some tips.

As you may recall, I had tried a really quick test…

At some point I plugged the cable into my iPhone and attempted to record some input using the Voice Memos app, but didn’t get anything. Not encouraging.

I wasn’t satisfied with that, so when a cable came in, the first thing I did was feed the machine into my laptop so I could listen to it “speaking” to me. I was pleasantly surprised with how simple the communication was. Have a listen…

Each time the flywheel goes around, the Airdyne sends a crackle (?) over the line. From here on out, I’m going to call it a beep, because it sounds better. At this point I remember thinking, “This may actually be really easy.” You’d think I would know better after years of programming.

I decided I was going to use Node.js for my app with Express on the server-side and React (eventually) for the interface. With Raspbian and MacOS both built on Linux it would make testing easy and I could get a lot of packages others have already written via npm. A smarter braver man may have chosen C++.

audio-loopbackThe first thing I needed to do was try to read in the data from the microphone over the USB adapter. I wasn’t going to sit in the garage and keep using the Airdyne, so I recorded some of the input to an audio file, which I looped through the speaker out and then back in through the microphone.

I whipped up a very basic app with command line output and starting trying out different USB packages.

I was getting nowhere, other than finding out what didn’t work. While reading comments in a forum or bug tracker, I saw a mention of USB HID. Turns out operating systems make it hard for you to access human input devices in code because the OS wants them to keep working. Even node-hid still didn’t help.

I changed my Google searches from a focus on USB to the actual sound itself. I found a clap-detector package, which analyzed the sound input. Since the Airdyne communication was so simple, I didn’t need to be concerned with what was being said; I only cared about when something was said. Some simple changes to the configuration and I was successfully detecting revolutions. ✔️ ✔️

Getting to this point took a lot longer than I expected. Now that I was getting data in my app, I didn’t know if I’d be able to determine what the AirDyne was doing with rpms. I really like working with numbers, so the next post will be a fun one for me. I’ll share a really cool charting feature (available in some spreadsheets) I learned about and focus on some math.

Building a Better Interface for the Airdyne AD2 with a Raspberry Pi (Part 2)

In part 1 I wrote about the problem, but how would I make something better?

Part 2: The Plan

From the original assembly of the Airdyne, I remembered the cable going from the machine into the display was a simple audio cable. I figured it should be easy enough to read the data being sent over the wire. A quick check of the cable determined it was a 3.5 mm TS jack (TS?), which is very simple.


I immediately thought a Raspberry Pi would be a great little computer for the project. I’d been wanting an excuse to play around with version 3 Model B. Some quick research determined microphone input had to be done via USB. I created a shopping list:

I already had a 3.5 mm male to male cable that would prove to be extremely useful. I wanted to splitter so that I’d be able to intercept the signal, while being able to continue using the actual Airdyne AD2 display as well.

While waiting for the Amazon Prime deliveries to show up, I did some Googling to see if anyone else had tried anything like this with an Airdyne. There was one hit. The author went a different route by installing a cycling cadence sensor on the crankshaft and someone in the comments went another route yet, with an optical sensor to measure the fan wheel rotations.

Finding that others had been able to take data in different ways and figure out to do with it gave me hope, but I really had no idea if I was going to waste a bunch of time on this project. At some point I plugged the cable into my iPhone and attempted to record some input using the Voice Memos app, but didn’t get anything. Not encouraging.

I was keeping a bunch of notes and ideas, but my initial scope was very small. Could I read the data from the cable, determine what it was saying, calculate all 5 pieces of information (time, calories, distance, speed, and rpms), and display everything on a single user interface? Now that I write that it doesn’t actually seem very small at all.

Stay tuned for part 3, where I got started.

Building a Better Interface for the Airdyne AD2 with a Raspberry Pi

When I bought the Raspberry Pi 3, I hinted at a project. I spent most of last weekend working on it and thought it was an interesting process to share.

Part 1: The Problem

A few years ago I added a Schwinn Airdyne AD2 to my garage gym. You move your arms and your legs at the same time for more of a full body workout than just a bike.


Here’s an example of the machine’s interface in action.

The screen rotates through 5 pieces of information (time, calories, distance, speed, and rpms), spending 6 seconds on each piece of data. Not shown in the video is the single button below the screen, which can start/reset the display. When not using the machine for a workout, you can reconfigure it to use kilometers instead of miles.

Several things have always troubled me:

  1. With no backlight it’s hard to read, especially in my garage.
  2. You only see one piece of data at a time and have to wait 24 seconds to see that item again. This really limits how I can use the machine in CrossFit workouts, which typically see intervals based on a number of calories or certain distance. I’ve always had to stick to time intervals.
  3. It’s not easy to switch between miles/kilometers and can only be done before starting a workout.
  4. You can’t select/program/save custom workouts.

Not great, right? I thought I could do better.

Part 2 will cover the plan.

Goodbye Firefox

I’ve been a Firefox user for a long time, but it’s time to throw in the towel. The most common issue I run into is video playback not even starting, but overall the entire browser experience seems to be getting slower. I also run into development issues at work where team members uncover a Chrome bug, where Firefox works fine and as I’d expect it to. Yeah, I know, I should get better at testing. 😉 One recent example is the default behavior in Chrome is to allow a form to be submitted multiple times; double-click the submit button or even keep smashing it and Chrome will send as many requests until your page reloads. Am I the only one who thinks this behavior is really dumb? Firefox doesn’t do this.

The long holiday weekend seems like a good time to make the switch. I looked back to see the first time I mentioned FF on my blog. It was more than 12 years ago, where I mentioned testing in FF and IE6! Times have changed.

Pibow PiTFT+

Found this case for the Raspberry Pi 3 Model B and the 3.5″ TFT LCD. Got it from Adafruit, where I tend to look first for any accessories, but you can also buy it directly from Pimoroni (they make similar cases for other Pi models or if you don’t have a connected display). The fact that it’s blue (hard to see from this photo) helped make it a quick purchase.

The case is a really neat design, using 10 different layers (there are also 2 extras depending on your display and Pi model) that fit around the board and all of the ports. The 4 plastic screws don’t even go through the Pi board itself at all, which you may think wouldn’t be secure. The way the different layers fit together around the ports means nothing moves even if you shake it. It’s snug. Here’s also a close shot of the clear bottom.

.blog Domains Are Now Available to Everyone!

Will be switching this site over to use soon. Get your own .blog now! News

Today’s the day! Now you can search for the .blog domain of your choice and associate it with your site.

As we announced in May, the launch of .blog, a new top-level domain extension, means there are millions of easy-to-remember addresses now available for your website. Pricing for .blog domains will start at around USD$30 per year, with some premium names offered at higher prices.

Which .blog will you choose?

Whether it’s your brand, your business, or your own name, you’ll have a lot of options to choose from. To search for a .blog domain name for your blog or website, go to My Sites > Domains and search for the .blog domain name you’d like.

Why .blog?

There’s always one big question that comes up when users start creating a site on “What should I call it?”

Finding the right name is hard enough —…

View original post 358 more words

%d bloggers like this: