Why did I make it ?

1500 bucks elliptical trainer was unusable due to electronics failure. UI welcome screen was looping forever and it was not possible to set any training program or even a simple motion resistance. The trainer price is explained by high mechanical quality, but it is useless without electronic. After two failed reparation attempts, and prohibitive cost for replacement boards from resellers, we found preferable to made a new electronic board using cheap electronic modules.

How to drive the trainer resistance ?

As you can see on the picture below, the resistance is obtained using an electromagnet which field acts on a flywheel. After some research on internet, we found that electromagnet could be driven by a constant current source or by PWM. These second option would be less expensive but could cause issues due to the high inductive load.


Making the circuit

Having a look at the original board, we quickly recognize a PWM drive topology with a power MOSFET, a flywheel diode, LC filtering and fuse Resistor. So we were confident that inductive load will be well driven using this same topology.

pwm circuitry

Now we know the components needed to pwm drive the electromagnet. The rest of the board is much more classic: a PNP based interface for RPM switch and a ESP8266 module to bring all this to live. Here is the principle schematic we ended with:


Let's put all this on a breadboard and we are ready to program and test the circuit !

First test

First test objective is to feel trainer resistance versus PWM frequency and duty cycle.

As I had only limited access to the trainer, I made a software that enable change PWM settings using a webapp called PwmMonitor hosted by the ESP8266 in AP mode. This way I didn't need to bring a computer for programing. This was also proof of concept for the final UI as we will discuss later.

PwmMonitor uses websockets to send the commands and also displays received data in a textarea for debug concerns. Code is available on project repository. Picture below shows how it looks.

Here are the observations:

  1. Trainer resistance is obtained at any PWM frequency, but it is not sensitive to PWM duty cycle at frequencies above 10kHz.
  2. Resistance can be changed using PWM duty cycle for PWM frequencies below 1kHz. This is the case down to 100Hz, which is ESP8266 lower limit.
  3. For these low frequencies, resistance increased for duty cycle from 0 to 50% and decrease from 50% to 100%.
  4. Electromagnet makes audible sound with PWM frequency lower than 20kHz.

Well, at this point we know we can control the trainer, that is a good start !

However, the trainer makes audible sound which we tried to mitigate with a second test by lowering the PWM frequency below the ESP8266 limit of 100Hz.

Second test

The objective of this test was to try a PWM frequency below the human audible 20Hz limit. Since ESP8266 PWM supports is from 100Hz to 40kHz, we used timer to "manually" drive the output using ticker library which is already provided in ESP8266 Arduino core. Note that using delay() is not allowed since it would stop ESP8266 from handling WiFi connection.

The pwm works with 2 tickers. The first one sets periodically output HIGH and redefines once the second ticker to set output LOW after given duration. The period is 90ms and we can set durations from 0 to 45ms with 5ms steps. This gives 9 level of pwm from 0% to 50% duty cycle at 11 Hz frequency. Code is available in final OpenCross program (finally disabled from compiling with #ifndef FREQ).

Observations at 11Hz:

Conclusion was a bit disappointing: we lose in driver efficiency and we still have noise ! 

After all, 100Hz noise is similar to 50-60Hz humming sound from main AC we are all used to. So this is not that boring.

Final configuration

For the final software, 100Hz PWM frequency was retained, along with 10 levels of resistance. Since motion resistance was not linear with duty cycle (see graph above), PWM values were remap empirically to make a progressive adjustment which is far better for the end-user. The final map is shown in the graph below with 8bits PWM definition, meaning that 127 corresponds to 50% duty cycle.

pwm map

Now, it was time to work on the final UI.

How the User Interface works ?

After first test, the end-user was fine wiith the idea of webapp UI. In my opinion, if you are not reluctant to smartphones, the interface seems even more modern that the original ! So we keep on working with the ESP8266 and develop a nice webapp.

Here is how it works in principle:

In addition to PWM driving, the ESP8266 handles a wifi AccessPoint and a webserver. Basically, this means that when we connect a smartphone (the client) to the AP, we can display a web page that is hosted by the ESP8266 (the server). Web pages are written as usual in html, css and js files and put in ESP8266 flash memory. Then the software includes one handler for each file, ready to send it to the client on request. To see how captive portal works, see this funny prank application from yoursunny.com. One other interesting point is how the phone is prevented from going to sleep, which is done by playing a 1px width video in loop (see run.htm <video>).

Lastly, the ESP8266 also handles a websocket which enable real time communication and good responsivity to user inputs. I think this is where you go from a webpage to a webapp. To see a quick example on the subject, here is a nice tutorial from sinaptec.

Final software is provided in project repository and some screenshots are shown in pictures below.

Further development

At the time being, we were happy with that interface, but we can easilly imagine a more advanced UI, with e.g.:

On ESP8266 side :