Traditional bicycle odometers only display current speed and total distance travelled. The bicycle computer aims to provide data comparable to that of a stationary bicycle, while allowing athletes to ride outside. Ideally, this data will contribute to better interval workouts and regular rides alike. Using a PIC32, we were able to implement a range of features including:
During training, many professional and elite athletes rely upon accurate metrics and telemetry to assess their performance and improve their weaknesses. Most of these systems come with a hefty price tag which precludes the vast majority of athletes from taking advantage of this type of technology. This exclusionary bias towards athletes and clubs with the financial means to purchase expensive equipment may mean that many athletes without the same means find themselves no longer able to compete at the same level.
In an attempt to rectify this, we have created a bicycle computer with an eye for price and versatility. The goal for our computer is to be cheap enough that any aspiring amateur cyclist can afford it, yet versatile and accurate enough to have a significant impact on their training. To achieve this, we selected 6 crucial features which give the user insight about their training, while utilizing only 2 inexpensive sensors.
In addition to our focus on price and versatility, we also wanted our computer to be modular and safe for use on busy streets. With a modular system, users can easily attach and detach various components, allowing for future integration of additional sensors as well as easy computer dismantling for competition. As for the safety of our system on public roads, we ensured that interacting with the computer did not require significant hand movement, and included turn signals to assist the user in making legal road maneuvers.
Where t is the time measured via Hall Effect sensors, in seconds.
Speed Determination (mph)
Where d is the wheel diameter in meters
Wheel diameter assumption & speed calculation
One key assumption made in our bicycle model is that the rear wheel diameter is constant. Since this diameter is used to calculate both speed and distance travelled, any inaccuracies from factors such as tire pressure or wheel deformation leads to output error. However, this implementation is much cheaper than alternatives such as GPS or a tire pressure sensor, making it ideal for this system. Additionally, whatever error is present from this assumption will be constant across a single workout. While this is not ideal for comparing performance across workouts, it does allow the user to structure their workout correctly, and closely approximate desired splits.
In order to increase the safety of the system, we created the turn signals on an independent circuit, with a separate power source. This ensures that the turn signals will remain functional in the event of the system losing power or an unforeseen bug. However, because the turn signals are independent from the microcontroller, they require separate inputs, and cannot be controlled by the microcontroller. If the turn signals were connected to the microcontrollers, additional safety features could be implemented, such as blinking “hazards” when the bicycle is traveling slowly or stopped, in order to alert nearby drivers of the rapidly approaching cyclist.
Despite the availability of wireless communication protocols such as bluetooth, we chose to connect our sensors via wires. This choice reduced the cost and complexity of the system, at the expense of additional steps to attach or remove the system.
For our hardware design we just started with an old road bike and added our sensors to the bike frame. We made a mount which could hold the TFT and buttons on the handlebar between the hands of the rider. We also had to run some wires along the frame to connect to the 2 hall sensors as well as the turn signals in the back of the bike. The hall sensors are both located near the bike crank. It is important that the hall sensor lign up with the magnets connected to the crank. There are also two magnets on the spokes of the rear wheel which also need to be aligned with the sensor on the inner side of the rear triangle of the bike. There should be no more than about a 10 mm air gap between the hall sensors and the magnets in order to make the sensors work properly. This distance also depends on the strength of the magnets and might need to be adjusted for best results.
The magnets are placed on the clips that connect to the pedal and also the wheel spokes. Here it is important that the two magnets are arranged in opposite polarities in order for the hall sensor to work properly and measure one ‘tick’ every revolution.
External interrupts are utilized to detect when a pair of mangets pass a hall effect sensor. We use external interrupt 0 to detect pedal rotations and interrupt 1 for the wheel. In order to how fast the pedal or wheels are turning, we have variables to track when the last time the interrupt fired was in milliseconds since startup. We can then subtract this time from the current time to get how long the previous rotation took. To find rpm, simply take 60,000ms (one minute) and divide it by how long it took for one rotation. To find speed, we divide a precomputed constant by the time between revolutions. Finding the constant, however, is much more involved. Essentially, the circumference of the wheel in miles is multiplied by the number of milliseconds in an hour to comput miles per hour. Incrementing distance with each wheel revolution is acheived simply by adding wheel circumference in miles to distance. Within the wheel interrupt, there's some additional logic to handle workout state such as incrementing the split number, switching to recovery, or finishing the workout. Along with this, the appropriate split is distance is incremented according to workout state.
For our time keeping, we utilized a thread with a one second yield. This thread was responsible for updating our total time and split time. If a split time or recovery time was reached, it would transition the workout to the appropriate state. Additionally, this thread was responsible for keeping the tft up to date. It would clear the previous contents and draw updated values to the screen.
This thread is fairly simple, but contains a ton of state logic. It runs every 50ms so user input feels crisp. It reads the inputs hooked up to the buttons and debounces the inputs. The button functions depend on which menu screen is currently displayed. If the user is configuring a workout, the up and down buttons navigate between options. The left and right buttons increment and decrement certain workout characteristics. Finally, the center button confirms and begins the workout. With each keypress, the screen is cleared and new screen state is written. When in the splits or workout menus, the left and right buttons are disabled, and the up and down buttons are used to navigate between screens containing more splits or more real time data. Users can switch back and forth between the workout and splits sets of screens using the middle button.
We implemented a variety of structures to help with tracking values and displaying them on the tft. One structure we have is ui_value. This simply contains two fix16s, one to hold the last value for this variable that was written to the screen, and one to hold the next value to be written to the screen. The previous value is important for being able to erase the contents of the tft without clearing the whole screen, reducing flicker. Along with this, we have stack_layout which contains two ui_value pointers and two function pointers to functions that properly format the values. This stack layout is good for consistently printing two values, such as speed and rpm, on the same screen while being able to scroll down to another screen that formats data differently. Finally, we have options_layout and split which simply groups appropriate variables together such as a time and a distance. The functions responsible for writing this data to the screen are all of the functions prefixed with "print_". These include sprintf logic for times, distances, rpm, etc.
Our code contains two very simple state machines for tracking progress through a workout and which menu the user is viewing. The workout state machine can be seen below:
Throughout the workout, the state machine alternates between the interval and recovery states. When in the interval state, the appropriate split in the split array collects time and distance data. Since recovery time is uniform for each interval, a dummy time is filled until the state transition is reached. Once the appropriate number of splits is achieved, the workout state switches to finished. If split count is left to 0, the state machine will alternate between interval and recovery indefinitely.
The first menu is the options menu where users configure their workout. Once the workout is configured and okayed, the user immediately begins the workout. In this state, users can view real time statistics such as speed and pedal rpm. During the workout, the user is free to switch between viewing the real time data and previous splits by pressing the middle button.
Over the course of a single minute in the highest gear, an error in the wheel diameter assumption can result in as much as 15 meters. While an athlete will likely not be pedaling at 120RPM while in the top gear for an entire workout, even pedaling at 90RPM in a middle gear can result in 8 meters of error. So, over the course of a typical hour-long workout, an error in wheel diameter of just 1cm can add up to ~500m of error in distance travelled.
We attempted to minimize screen flicker by only clearing previously drawn text rather than the whole screen. We were only able to do this for the real time data screens which update every second. The workout configuration screen and split recall screen relied on writing the whole tft to black before writing new text. Updates on these screens provided a large amount of flicker, but these screens updated so infrequently (ie whenever a user pressed a button) that it wasn’t a nuisance.
We initially looked at using an input capture to get clock cycle accuracy on wheel and pedal revolutions. We soon realized that revolutions happen too infrequently for this to work. We then settled for using the protothreads milliseconds counter to time events. This turned out to be much more suitable and easier to implement. However, as you speed up, accuracy degrades. The change in error can be visualized below. Speeds of 40 mph can reach wheel rotation speeds of around 500 rpm.
The design performed as expected when it comes to being used as a tool for workouts, however, there is tons of opportunity for improvement. A stretch goal we missed was the ability to analyze a user's force throughout each stroke. We realized it would be a huge effort to implement, and didn't have enough time to add it after finishing user defined splits. Another cool feature to add could've been automatic headlights to compliment the addition of turn signals.
Perhaps the lowest cost addition with highest gain would've been some way to automatically retreive workout splits. This could be through logging to an SD card or even a bluetooth interface. If we went the route of bluetooth, the whole TFT and buttons could've been swapped with a phone. In this case, the PIC32 would act to gather sensor data and relay it to a smartphone app. A smartphone would likely be much easier for viewing the data and having finer control over workouts.
Within the realm of mountable bicycle computers with peripheral sensors there are at least two existing patents on similar technology. The first is US Patent No. 6192300 B1 which describes the use of multiple microprocessors and a plurality of sensors to determine the bicycle speed and pedal RPM, among other quantities. Another is Patent No. 0887252 B1, entitled “Bicycle Computer with Cover”, which covers the mounting of a computer to a structural member of the bicycle. It also specifies a cover which swings to allow the user to view the computer. Both of these patents are filed by Shimano Inc., a prominent company within cycling technology.
Considering that this project was meant to be used while riding on the road, safety became a large consideration. One way we achieved this was through ensuring that the user interface was easy to read and interact with. We intentionally used large text on the screens users would interact with while riding. Smaller text was permitted on the workout customization screen and split recall screen because it was assumed users would view these screens while stopped, ie. before and after the workout. Button placement was such that riders would not have to remove their hand from the handlebars in order to interact with the computer. This ensures users remain stable while riding and don't have the distraction of looking down to find the buttons. In addition, we improved general cycling safety with turn signals so it's very clear where the cyclist is intending on turning.
In accordance with the IEEE Code of Ethics, we continually consulted the TAs for feedback on the project and asked for ideas for how to make it better. During development, we debated the accuracy limitations of our implementation and determined that even under extreme use cases, the data was accurate enough to provide a controlled workout. All fixtures consist of plastic clips which would not damage a user's metal bicycle.
There are no legal considerations relevant to this project.