I am writing a Python script that will show me running data when running on my treadmill because the display panel is broken. It's going to use GPIO pins on a Raspberry Pi, so whenever the belt on the treadmill goes around, it can have a metal piece that shorts pins (they act as a button). It calculates speed depending on how fast the belt went around.
This means time is very important here. I've set up a loop in rev_counter()
that gets the time and then when the "button" is pressed, it records the time again. Just to test it while I'm writing this program, I've simulated a button press with sleep()
. I set it to 1.27841272276
seconds because this would be the time the belt would go around for a 7:30-minute mile pace. I've been trying to get it as close to that pace as possible.
I have gotten it to work pretty well. It is right on or maybe one second off while showing the info in the middle of the workout. The problem is, when I end the workout with CTRL+C
so it goes to the results, the average mile pace ends up being off. It should be 7:30-7:31, but it ends up being 7:34-7:36. I'm pretty sure the time gets offset between when I stop the rev_counter()
loop and when it calculates the results in results()
. For some reason, when I ran the update_display()
function in rev_counter()
with Thread
, it seemed to help. Could stopping in the middle of this loop be causing a problem? Why does only results()
and not both rev_counter()
and results()
not get the time issue?
Here is my Python script:
import mathimport osimport time# from gpiozero import Buttonfrom threading import Threadfrom time import sleep# belt_button = Button(2)def display(original_time=None, total_distance=None, current_speed=None, prev_rev_time=None): os.system('clear') print('Current Workout Information') print('') if original_time is None: print(f'Time elapsed: --:--:--') print('') print('Distance') print(f'Miles: --') print(f'Kilometers: --') print('') print('Current Speed') print(f'M/H: --') print(f'KM/H: --') print('') print('Pace') print(f'Mile: --') print(f'Kilometer: --') else: seconds_elapsed = prev_rev_time - original_time time_elapsed = increment(seconds_elapsed) mi = total_distance / 5280 km = total_distance / 3280.84 mph = current_speed / 1.46667 kmph = current_speed * 1.09728 min_mi = 60 / mph min_km = 60 / kmph mi_pace_min = math.floor(min_mi) mi_pace_sec = round((min_mi * 60) % 60) if mi_pace_sec < 10: mi_pace_sec = f'0{mi_pace_sec}' km_pace_min = math.floor(min_km) km_pace_sec = round((min_km * 60) % 60) if km_pace_sec < 10: km_pace_sec = f'0{km_pace_sec}' print(f'Time elapsed: {time_elapsed}') print('') print('Distance') print(f'Miles: {round(mi, 2)}') print(f'Kilometers: {round(km, 2)}') print('') print('Current Speed') print(f'M/H: {round(mph, 2)}') print(f'KM/H: {round(kmph, 2)}') print('') print('Pace') if current_speed == 0: print(f'Mile: 0') print(f'Kilometer: 0') else: print(f'Mile: {mi_pace_min}:{mi_pace_sec}') print(f'Kilometer: {km_pace_min}:{km_pace_sec}')def increment(seconds_elapsed): seconds_elapsed = math.floor(seconds_elapsed) h = seconds_elapsed // 3600 m = (seconds_elapsed // 60) % 60 s = seconds_elapsed % 60 if h < 10: h = f'0{h}' if m < 10: m = f'0{m}' if s < 10: s = f'0{s}' return f'{h}:{m}:{s}'def rev_counter(): revolutions = 0 prev_rev_time = 0 original_time = time.time() try: while True: prev_rev_time = time.time() # GPIO stuff # sleep(0.25) # belt_button.wait_for_press() sleep(1.27841272276) rev_time = time.time() revolutions += 1 update_display(original_time, prev_rev_time, rev_time, revolutions) # Alternate code # thread = Thread(target=update_display, args=(original_time, prev_rev_time, rev_time, revolutions)) # thread.start() except KeyboardInterrupt: os.system('clear') total_distance = 15 * revolutions results(original_time, prev_rev_time, total_distance)def update_display(original_time, prev_rev_time, rev_time, revolutions): # feet * rev count # 15 = Length of my treadmill in feet total_distance = 15 * revolutions # feet / second rev_seconds = rev_time - prev_rev_time current_speed = 15 / rev_seconds display(original_time, total_distance, current_speed, prev_rev_time)def results(original_time, prev_rev_time, total_distance): try: os.system('clear') seconds_elapsed = prev_rev_time - original_time time_elapsed = increment(seconds_elapsed) print('Workout Results') print('') if total_distance == 0: print(f'Total time: {time_elapsed}') print('') print('Distance') print(f'Miles: 0') print(f'Kilometers: 0') print('') print('Average Speed') print(f'M/H: 0') print(f'KM/H: 0') print('') print('Average Pace') print(f'Mile: 00:00') print(f'Kilometer: 00:00') else: average_speed = total_distance / seconds_elapsed mi = total_distance / 5280 km = total_distance / 3280.84 mph = average_speed / 1.46667 kmph = average_speed * 1.09728 min_mi = 60 / mph min_km = 60 / kmph mi_pace_min = math.floor(min_mi) mi_pace_sec = round((min_mi * 60) % 60) if mi_pace_sec < 10: mi_pace_sec = f'0{mi_pace_sec}' km_pace_min = math.floor(min_km) km_pace_sec = round((min_km * 60) % 60) if km_pace_sec < 10: km_pace_sec = f'0{km_pace_sec}' print(f'Total time: {time_elapsed}') print('') print('Distance') print(f'Miles: {round(mi, 2)}') print(f'Kilometers: {round(km, 2)}') print('') print('Average Speed') print(f'M/H: {round(mph, 2)}') print(f'KM/H: {round(kmph, 2)}') print('') print('Average Pace') print(f'Mile: {mi_pace_min}:{mi_pace_sec}') print(f'Kilometer: {km_pace_min}:{km_pace_sec}') print('') input('Exit ') os.system('clear') except KeyboardInterrupt: os.system('clear')def main(): os.system('clear') while True: try: print('AC Treadmill Workout Program') print('') input('Start Workout ') display() rev_counter() except KeyboardInterrupt: print('\n') print('Quitting... ') breakif __name__ == '__main__': main()
To run this program without any issues, run it in a Unix environment or Windows if you change all the os.system('clear')
lines to os.system('cls')
. Also make sure to run it in the terminal because my IDE (PyCharm) doesn't allow it to clear even when I set the TERM environment variable.