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.