I have a python program that reads from a serial port, accesses registers then writes data to the CSV. Id like to perform a writing operation to the csv at a set frequency of 100Hz. Below is sample code related to the timing which attempts to limit writing to the csv. For simplicity it will only print to console rather than write to csv.
import datetime
from datetime import timezone
import time
FREQ = 5
CYCLETIME = 1/FREQ
def main():
while(1):
### Code that will read message bytes from a port
# Time start for Hz
start = time.monotonic()
delta = time.monotonic() - start
if delta < CYCLETIME:
time.sleep(CYCLETIME - delta)
# in the full program we write to a csv but in this simple program we will just print it
milliseconds_since_epoch = datetime.datetime.now(timezone.utc)
print(milliseconds_since_epoch)
if __name__ == "__main__":
main()
2020-08-24 18:57:15.572637+00:00
2020-08-24 18:57:15.773183+00:00
2020-08-24 18:57:15.973637+00:00
2020-08-24 18:57:16.174117+00:00
2020-08-24 18:57:16.374569+00:00
2020-08-24 18:57:16.575058+00:00
2020-08-24 18:57:16.775581+00:00
2020-08-24 18:57:16.976119+00:00
2020-08-24 18:57:17.176627+00:00
2020-08-24 18:57:17.377103+00:00
2020-08-24 18:57:17.577556+00:00
The output seems consistent for 5Hz but if I change it to 100Hz it seems inconsistent. It sounds like this could be a time accuracy drift associated to time.monotonic. Is this a good approach? Is time.montonic appropriate?
My knowledge with pythons thread library is limited but in the near future, I plan to create 2 child threads for each task. One which constantly reads from serial and another that will write (or in our case print to console every 100Hz).
Edit: I took the solution below and modified it. The original solution seemed to only print once. Here is my new attempt:
import datetime
from datetime import timezone
import time
FREQ = 5
CYCLETIME = 1/FREQ
def main():
t0 = time.perf_counter() # Time ref point in ms
time_counter = t0 # Will be incremented with CYCLETIME for each iteration
while 1:
### Code that will read message bytes from a port
now = time.perf_counter()
elapsed_time = now - time_counter
if elapsed_time < CYCLETIME:
target_time = CYCLETIME - elapsed_time
time.sleep(target_time)
# In the full program we write to a csv but in this simple program we will just print it
milliseconds_since_epoch = datetime.datetime.now(timezone.utc)
print(milliseconds_since_epoch)
time_counter += CYCLETIME
if __name__ == "__main__":
main()
Output:
I used matplot lib to determine the frequency to create this output. I take the rolling window difference of the current and previous value and inverse it since frequency=1/(time diff).