Built over March and April of 2022, this was a project to covert my exercise bike, a Bowflex C6, into a universal video game controller so I can play games while I ride. The controller is USB powered and windows reads it as a generic game controller. The bike connects to the controller over Bluetooth and the controller converts the speed of the pedaling into the right trigger of a gamepad. The handlebar can rotate in either direction to control the left joystick x axis so I can turn with the handlebar. The brakes are hooked up to springs and they control the left and right controller triggers with full analog control. There are also paddle buttons under the brake levers to act as left and right shoulder buttons. The rest of the buttons are laid out in a somewhat traditional Xbox controller style. The central controller housing features an LCD with some control buttons that feature different modes (some for specific games) and difficulty levels.
Hardware
The heart of the project began as Raspberry Pi Zero W, and later I changed to teensy LC + an ESP32, more on that later. I chose the Raspberry Pi first because I needed something that can be powered on the USB bus, could be read by windows as a USB device, with a decent number of inputs and outputs, I2C and SPI support, and Bluetooth support. The Raspberry Pi still isn’t the best option, since there are no ADC’s and its way overkill for something that just sends some button presses, in addition to slow boot times since it runs a full Linux OS. The upside though is that I had an extra one laying around.
First I setup the Raspberry Pi as a USB device called my Pistick (short for raspberry pi joystick). Then I connected to my bike over Bluetooth so I can read cadence, speed (in mph), resistance, and heart rate. I decided to use speed and set it so 20 mph is equal to pulling the right trigger of an Xbox controller all the way down. This way I can set the resistance (which is done manually with a knob) low and pedal fast or high and pedal slow and still achieve 20 mph. Once I got this working, I quickly found out how many games hate using 2 game controllers while I would pedal the pedal and sending the right trigger signals with my Pistick, I would use a wireless regular Xbox controller for everything else. So next was to start designing some hardware.
I custom deigned 3 circuit boards for this project. The first one to connect to the raspberry pi and have a ADC (Analog to Digital Converter) and an I/O extender chip for a few additional buttons and some cool LEDS. The second and third are the left and right controller and they are basically just to hold the buttons and joysticks in place so I can wire it all up. I used Cherry MX silver switches for my buttons and Alps joysticks. I designed and 3D printed all the cases and keycaps for all my buttons. The circuit boards were all designed in Kicad and the 3D parts in Autodesk Fusion 360.
I decided since I wasn’t really as comfortable with the road bike style lean forward riding as I am more classic upright mountain bike style riding I would just add on a short mountain bike handlebar. I used a pair of u bolts to bolt an aluminum plate that I bent at 2 points to create a shelf that hangs down from the handlebars. I then use a large bolt with some 1 1/4″ bearings on it that bolts to the plate. From there I could attach a standard bicycle yolk and standard handlebars. I then used some valve springs from an old parted out Honda engine with some 3D printed holders to put pressed on both sides of the handlebar. So now I have a handlebar that can turn. I 3D printed a small section of a large gear that fits on the handlebar bearings and rotates with the handlebar. Then I 3D printed a real small gear that fits on a potentiometer aligned with the other gear and as I turn the handlebar, about 10 degrees in either direction, the pot rotates. I applied a voltage to the pot and read it back with an ADC.
On top of the aluminum plate I put the central control unit with the raspberry pi and the LCD and that is where I ran the brake cables into. In there I have a small plastic piece with a screw that will clamp to the brake cable and screw to a spring that is connected inside. The the plastic piece is also connected to a slide potentiometer that slides back and forth when I pull the brakes. I apply a voltage across that and read back the value with the ADC to get the brake positions.
Back to the micro controllers. after completing the project, I still has some issues with the raspberry pi. Sometimes it wouldn’t output USB commands like I needed it to. I had issues shutting it down cleanly and the long boot times were just painful. So I decided to try an ESP32. I got one in hand and started working with it and found it did everything I needed, but because of the way I was doing my USB descriptor, windows just saw it as a generic gamepad so I had to use some middle man software to convert to Xbox buttons for some games. That’s when I found a library for the Teensy boards that made the teensy look like a bonifide Xbox controller to windows. Since the teensy doesn’t have Bluetooth and the larger teensy boards were all out of stock, so not really enough inputs for my projects, I knew I needed to either add some I/O extenders and a Bluetooth module or pair it up with the ESP32, which does have Bluetooth. The ESP32 was the cheaper solution and I gained the advantage of running my LCD screen off the ESP32 and the controller buttons off the Teensy. So I have two UART connections between the teensy and the esp32 for commination and that gives me everything I need to send messages to the LCD and receive Bluetooth data from my bike. Plus I also have the advantage now of an almost instant boot time.
Software
The rest of the project is basically software. I’m pretty agnostic when it comes to languages. My first inclination was to use C or C++ for this project, but there was a lot of documentation and simple to use tools for Python on that raspberry pi. So I decided to take the path of least resistance and wrote it all in Python. I run a script after Linux boots to apply a USB descriptor and that is what tells windows that this device is a generic joystick / gamepad. At least that was how version 1 worked. With the switch to the Teensy and ESP32, I had to reprogram everything from scratch. They are both written in C++ now and I used a library with the Teensy and makes windows think it is a genuine Xbox controller. Which that it seems to work perfect with every game I’ve tried it with.
Then the main program starts. There are several modes I built in to change the controls slightly. By default, It boots into a “clutch mode”, so after Bluetooth connects, pulling the right brake no longer controller the right trigger, but rather, disables the pedals from controlling the right trigger, acting as a kind of clutch that disengages the pedals. This is useful because you can’t just stop pedaling on a spin bike, the wheel keeps spinning and your feet have to slow it down over time. There is an override mode that just lets the right brake override the pedals if it is pulled. There is a couple modes for dedicated games like Descenders and Riders Republic that makes a couple tweaks to the controls.