New control software


In recent news, I’ve combined the code from my various test harnesses into a single control process (plus the PRU firmware).

I’d be the first to confess the code is a bit ugly as it stands – it’s clearly several separate programs squished together with some threading and (far too many) globals! However, I’ve plenty of time to re-factor and tidy up the codebase, and it’s functional enough to get me started on the next steps. I’ve also added a rudimentary ncurses console interface for mode selection & feedback.



On the power side, I’m transmitting as an ANT+ power meter, broadcasting the ‘power only’ data page (0x10), which reports instant & accumulated power in watts (as well as optional cadence and L/R power balance values – which I’m ignoring). With a small patch to Golden Cheetah, I’m capturing the per-second data from both the PowerTap and Trainer devices into the training mode .csv files, from where I can export it into a spreadsheet for easy analysis. I’ve also got a small python script to extract all the power messages from the GC antlog.bin files (where all the ANT+ traffic is logged) in case I need a closer look at the original 4hz message data.

The data as graphed below came from a training .csv file, with the trainer firmware using a simple 4 sample (1 second) moving average for the acceleration component of the power figure.



With power tracking pretty well, I’ve also started thinking about speed reporting. ANT+ speed messages are essentially broadcasting the time taken for a single wheel revolution, where they are then converted to speed at the receiving side based on a pre-configured wheel size. The wheel rotations could be sent in either speed or power (wheel torque) messages.

From my trainer perspective, I can calculate the road speed very easily, but have no insight into the actual wheel size. If I were to store my own configuration parameter for wheel size, I could work back and provide the necessary fake wheel speed timestamps. The downside is that any changes to wheel size would need to be manually set in two places instead of one.

Another hiccup is that the power message that includes the wheel rotations is the ‘wheel torque’ data page (as broadcast by a PowerTap). Instead of power in watts, this transmits the data as wheel speed and torque, which is then converted to watts on the receiving side. Again, I could just work back and provide the necessary ‘fake’ torque figures to make it all add up, but is starting to feel like a lot of effort for minimal gain…

I suspect it may be easier to present as a dedicated speed sensor alongside the power sensor. But for the moment, I’ll just park the speed reporting in the ‘things to consider later’ pile. Both bikes that I’m testing with already have ANT+ speed data (coming from either a S&C sensor or PowerTap), so doesn’t actually gain me anything just yet.

ANT+ Trainer Profile

I’ve also been wondering whether the upcoming (and snappily named) ANT+ Fitness Equipment – Control (i.e. Trainer) profile might have a provision for either passing road speed to, or receiving wheel size from, a head unit. Either would help make the above speed situation a bit simpler. Unfortunately (for me), this profile is still in it’s ‘competitive advantage’ phase, where it’s only available to paid-up ANT+ Members, not to freeloading ANT+ Adopters like myself!

On a related note, I’ve been working on the assumption that this new ANT+ profile will be available by the time I’m ready to start adding the variable resistance control back in. However, nothing seems to be moving very fast (on either count) at the moment. I think I also have a plan B, which would be to respond to the control messages used by Wahoo for their Kickr trainer, which should at least allow me to hook up to some 3rd party trainer software platforms for further testing.

Next steps

Next job is to get back into the workshop, and make up some new magnets & mounts for the eddy current brake…

Optical speed sensor

For sensing the trainer speed, I have a choice between using the elapsed time between two events, or counting the frequency of events within a specific time period. For now, I’ve opted for this latter approach.

In order to keep things responsive, I need this time period to be quite short, therefore I also need quite a fast pulse train in order to get a reasonable count in this period. To achieve this, I’ve switched from the hall effect sensor to an optical solution, which can easily generate many more events per revolution.

I’m using a Hamamatsu 5587 photo-reflector in conjunction with a laser printed optical encoder pattern on the flywheel. This is quite an old sensor (possibly even discontinued), but gets good write-ups from the robotics community. For ease of mounting, I’ve soldered everything on one side of some protoboard, and stuck it to the trainer with double sided tape. This provides a nice stable mount, and ideally positions the sensor a couple of mm from the flywheel.


The encoder pattern was created using a postscript generator script, converted to PDF, and then laser printed on standard office paper. This was then stuck onto the inner face of the flywheel using a spray mount adhesive.


I’m using 16 black & 16 white segments, and capturing both rising and falling edges to give me 32 events per revolution. I’m currently sampling speed at 4hz (to match the ANT+ transmission rate) and have tested up to ~70pkh, which equates to ~1,000 events per sample.

From BudgetTrainer to BeagleTrainer

As mentioned in the previous update, until recently I’d been sending a serial data stream to a laptop for processing.

This was primarily due to the curve fitting & floating point maths that I’m using in the spindown calibration process. While this code could likely be replaced in the long term, as it stands now it’s a poor fit for a resource constrained 8-bit micro with no hardware floating point support!

So now I’ve switched development to a BeagleBone Black. This is a small development board capable of running Linux on a 1GHz ARM Cortex A8 processor.


One great thing about the TI Sitara processor on this board is that it includes a pair of Programmable Realtime Units (or PRUs). These run independently of the main processor, with a 200MHz clock speed (5ns per instruction), and are perfect for guaranteed real-time tasks. They are programmed in their own assembly language, but there is also a C compiler (currently in beta) available from TI.

For my purposes, I’ll be using PRU assembly for the timing sensitive hardware interaction (frequency measurement, PWM etc), with the main C code running in Linux userspace on the ARM processor, and using an ANT2 USB stick for the comms.

I’ve already written some initial test code for speed measurement, spindown processing, curve fitting, power calculation, and the ANT+ transmission. The individual pieces are all working separately, now I just need to tie them together under a single control program. Once it’s all been tidied up a bit, I’ll post a link to a new github repo for this code.

When that’s done, I’ll be getting back to some metalwork & preparing new electromagnets for the adjustable resistance control.

Period vs frequency

In my previous post, I was struggling a bit with accuracy on the acceleration component of the power tracking.

I’d originally been calculating instantaneous roller speed from the period between the last two sensor pulses, but I think this was suffering with a bit of jitter in the measurements. For the next attempt, I started to calculate the speed from the pulse count over a set period.

These frequency based results (based on pulses per second) were somewhat smoother, but in order to remain responsive to speed changes, I needed to make the period shorter. The data in the graph below was generated at 4hz, but still smoothed over 4 samples.


To maintain accuracy, with a reasonable number of pulses per period, I’ve also needed to increase the pulse rate. For the above test, I just stuck another three magnets onto the roller, but have since ordered an optical sensor. This should allow very easy adjustments of the pulse rate, just by printing up new encoder disks.


Until now, I’ve been sending the raw speed data over a serial link to a PC, where it’s saved and then post-processed in a spreadsheet. Next post I’ll cover a new development platform, where I’m able to do the curve fitting and power calculations in real time.

Summer slowdown

In a fairly predictable turn of events, my development efforts pretty much ground to halt over summer. But a recent touch of autumnal chill in the air has shuffled the trainer project a couple of notches back up the todo list..

So, progress since the last post? Not much – just the addition of a micro and hall effect sensor to the prototype for some more accurate speed measurement.


This is presently just dumping a serial datastream to the PC for post-processing, while I wrestle with the maths for the un-braked roller assembly. There is obviously work to do, but the very first attempts at calculating speed & power weren’t entirely terrible.



The trainer power consists of the steady state power derived from a spindown test, plus an estimate for acceleration/deceleration (see shonky graph above).

While the steady state power is tracking pretty well already, it’s fair to say the acceleration component needs some work! I think this is primarily down to a very slack update rate from the initial firmware. I’m only sending speed updates to the PC every second, which is then averaging the acceleration over a 2 second window, so it’s this area that I’m aiming to improve on next..

Wheel inertia and a quick sanity check

Rear wheel inertia

After previously calculating the moment of inertia for the roller assembly, the next step was to get a more accurate figure for the rear wheel.

For this, I used the approach given at I’d be the first to confess I don’t quite follow the maths involved, but am happy enough to trust the answer it spat out – 0.079619 kg m².

Just for the record, the complete wheel (excluding skewer) weighed in at 1669 grams on my trusty kitchen scales – and consists of a 2012 PowerTap Pro hub, 11-32 SRAM cassette, 32 hole Kinlin XR300 rim, Sapim laser spokes with alloy nipples, 23mm GP4000S clincher, a random inner tube, plus a light smattering of road grime ;)

Rotational kinetic energy

Now I have a moment of inertia for both the roller assembly and the rear wheel, it’s possible to calculate the kinetic energy of both at any given speed.

The first step is obtaining the angular velocity for both the wheel and the roller. To get this, we convert the road speed in kilometres per hour into metres per second, and from there into angular velocity (radians per second);

ω = (road speed * 0.27777777777778) * circumference * 2π

Then, from the moment of inertia and the angular velocity, can we obtain the rotational kinetic energy;

KE = ½ I ω²

Rolldown test

Prior to building up the speed sensor, I thought I’d perform a quick sanity check of my calculations (and my assumptions) based on some ANT+ data. So, with GC running in training mode on my laptop & collecting data via a USB ANT+ stick, I performed a number of steady speed efforts, along with couple of roll down tests.

The roll down test gives speed against time, but more usefully (thanks to the equations above) kinetic energy against time. From this data I can generate a polynomial expression for the curve, and then differentiate to get the rate of change of kinetic energy at any given speed.

That last sentence is actually the key point of this whole weighing and measuring exercise on the un-braked roller assembly. We have calculated the kinetic energy (in joules per second) that is being lost through rolling resistance at any speed, and by extension the wattage (1 watt = 1 joule per second) we would need to put back in to overcome this resistance and hold a steady state.

The final sanity check against the training mode ANT+ data consists of comparing the actual wattage required for the steady speed efforts against the expected rate of change obtained from our calculations.


At this point, I’ll call that a win! Next step is to build up the speed sensor to get some more accurate data..


Moments of inertia


In order to calculate an overall moment of inertia for the roller assembly, it helps to break it down into a series of simpler geometric shapes. For each of these shapes, the moment of inertia can be calculated independently, and once complete, the results for each section can be added (or subtracted) to produce a total for the entire roller assembly.

As an example, here is the process I followed for the brake disk assembly.

Brake disk

The brake assembly has a thinner (4mm) disk that ends up sandwiched between the electromagnets, and a larger central cylindrical section that fits onto the tapered roller, with both a truncated cone and a cylinder removed from the centre. In these pictures, this is turned onto it’s side, rotating around a central vertical axis. Apart from fitting the page layout better, this orientation makes more sense of the radius and height elements of the equations.


The first step is to calculate the volume of each ‘feature’ from the measured dimensions. From this we can determine the mass, and then use these figures to find the moment of inertia.


There are a couple of equations needed for calculating the volume;

volume of a cylinder:

V = π r² h

volume of a truncated cone:

V = 1/3 π (r1² + r1+r2 + r2²) h

Starting with the thinner section of the disk – the first step is to calculate the volume of a cylinder representing the entire width of the disk (r = 66.5mm, h = 4mm).

We can then calculate the volume of a smaller cylinder, representing everything inside the central section (r = 25mm, h = 4mm). Then if we subtract one from the other, we are left with the volume of just the thin external section. Hopefully the image below makes sense of these three steps;


Then we can perform a very similar process for the thicker central section. First we calculate the volume of the solid cylinder (r = 25mm, h = 26mm), then the volume of the features removed from the centre – in this instance a smaller cylinder (r = 10mm, h = 7mm) and a  truncated cone (r1 = 10mm, r2 = 12mm, h = 19mm). We then subtract the volume of both these features from the starting cylinder, leaving just the remaining material.



Now we know the volume of all the features (and therefore the volume of the entire assembly), we can simply calculate the mass of each feature as a proportion of the overall weight of the brake assembly.

Moment of Inertia

The next step is to calculate the moment of inertia for each feature, just as we did for the volume calculations. The equations needed for this are;

moment of inertia of a solid cylinder:

I = 1/2 m r²

moment of inertia of a cone:

I = 3/10 m r²

You may notice this last equation is for a full cone, so in order to calculate the moment of inertia for our truncated cone, we need to perform one additional step. We calculate the volume, mass, and moment of inertia of both a full cone, and a smaller cone representing the portion that is removed. Subtracting one from the other will then leave us with the value we want for the remaining truncated portion. Again, hopefully the image below makes more sense of these steps;


Once we have the moment of inertia for each individual feature, we can calculate the overall moment of inertia for the brake assembly. This is done by following exactly the same steps of adding and subtracting features that we used for the volume calculations above (i.e. large thin cylinder minus small thin cylinder, large central cylinder minus small central cylinder and small truncated cone).

Roller and flywheel

The same approach was then taken for both the main roller and the flywheel.

For the threaded sections of the roller, I cheated a little and treated them as cylinders with a diameter somewhere in-between the minor and major thread diameters.

Nuts and bearings

For the hex nuts, I cheated a lot and treated them as having an outer diameter  somewhere in-between the flats and the points. At this stage I’ve ignored the mass/inertia of the bearings completely.

I think all this cheating is an acceptable nod to reality, as these aspects only account for a tiny fraction of the overall moment of inertia.

Putting it all together

Finally we can sum the moment of inertia of each part (brake, roller, flywheel, nuts) to come up with an overall figure for the roller assembly,  which by my current reckoning is 0.005418 kg m² (allowing for howlers in my calculations/spreadsheet which I may yet uncover!).

There are elements outside of the roller assembly that will need to be considered, primarily the moment of inertia of the rear wheel. It is notable that my calculated moment of inertia for the roller assembly is considerably smaller than a very rough estimate of the moment of inertia for a rear wheel (~ 0.1 kg m²) .

Of course the roller is rotating a lot faster than the wheel, which greatly increases the angular momentum, but even so – my gut feel is that I ought to double check my figures. Either way, any gross errors should become apparent once I start performing some spin down and power testing…

Next steps

Next up will be measuring the moment of inertia of my powertap wheel, and then putting together a speed sensor to feed the roller data back to the PC for processing.