Hello all.
I'm entirely new to programming so bear with me. I only know (a bit of) python language so I'm trying to control my arduino nano through pyfirmata, because I am completely unfamiliar with the arduino IDE language. I know, I'm sorry, let me work on that.
I uploaded the sketch 'StandardFirmata' onto the arduino.
This post may look like a python-forum-question in the beginning, but it will be arduino-related, I promise.
Now: I'm measuring analog IN values and I need the moments in time with every measurement, so I can plot a graph.
I'm using a while-loop to store measurements in a list using read(), and use the python time.perf_counter() to store the 'timestamps' in another list.
The loop also checks some if-statements so it breaks after a maximum and minimum value is detected, along with the reading returning to begin value.
The begin value is the variable 'equilibrium'.
I made sure there is a minimum of commands inside the loop, so voltages and time differences are all computed outside of the loop to make it more efficient. Time is measured in nanoseconds instead of seconds because I let somebody tell me that an integer is less CPU-consuming than a float.
the main measuring-loop function looks like this:
def collect_data(analog_in, equilibrium, times_ns, readings, main_flag=500):
"""
Collect data from an analog IN pin from Arduino, with timestamps.
When min and max peaks are collected, will collect some more data
to show a return to equilibrium in the graph.
Parameters
analog_in : Analog IN pin on Arduino
equilibrium : Equilibrium reading (float)
times_ns : list for storing timestamps
readings : list for storing datapoints
main_flag : int, optional. Default is 500.
Returns
None.
"""
Set some flags.
min_flag = equilibrium - 0.2
max_flag = equilibrium + 0.2
equilibrium_flag = round(equilibrium, ndigits=1)
while True:
Get time and reading.
reading = analog_in.read()
t_x = time.perf_counter_ns()
if main_flag <= 0:
When main flag reaches zero, measurements stop.
break
elif (
min(readings) < min_flag
and max(readings) > max_flag
and round(reading, ndigits=1) == equilibrium_flag
):
When a minimum and maximum reading is collected
and reading goes back to equilibrium: collect some more
data and reduce the main flag.
main_flag -= 1
times_ns.append(t_x)
readings.append(reading)
else:
Collect data.
times_ns.append(t_x)
readings.append(reading)
This all works pretty good, and it gives me a nice plot afterwards (figure_1, attached tot this post).
Nevermind the Dutch language axes labels, above the figure is the calculated time delta_t between the minumum and maximum reading. This is not correct. I timed the real time with a stopwatch at 5 seconds, more or less. So if the delta_t was around 5 seconds I would have bought it. A difference of 15 seconds however, is somewhat more than my reaction time I reckon.
I made these functions to calculate the readings and delta_t:
Convert nanoseconds in times_ns to seconds.
times = []
for t in times_ns:
times.append(
(t - t_0) / (10**9)
)
Convert readings into voltages.
voltages = []
for r in readings:
voltages.append(
r * 5.0
)
def get_delta_t(voltages, times):
"""
Get the time gap between low voltage and high voltage.
Parameters
voltages : list of voltage readings.
times : list of time readings
Returns
delta_t : time gap in seconds (float)
"""
Copy and sort voltages list.
voltages_sorted = voltages.copy()
voltages_sorted.sort()
Get index of highest value.
index_high = voltages.index(voltages_sorted[-1])
Get index of lowest value.
index_low = voltages.index(voltages_sorted[0])
Get time interval.
t_low = times[index_low]
t_high = times[index_high]
delta_t = t_high - t_low
return delta_t
After this I plot the voltages list as a function of the time list, and display delta_t above the figure. I will save you that function, as it is not relevant to the questions.
With everything I have shown, it comes down to this: I read an analog measurement from the arduino, and immediately register the time from my computer. When I do this once or twice, it turns out okay, with probably a little error.
When I do it a couple of million(?) times, like in the main loop, I get a vast error (around 300%) in measured times and calculated delta_t. This is unacceptable for my project so it's an issue.
So here they come: the arduino questions.
-Is this error because of some or other delay in the serial connection? I tried to measure the time before the analog_in, and the other way around. This did not help.
-Is it maybe because I 'overflow' something? (I nicked the term 'overflow' from the internet, no idea what it means) So maybe I should give the poor little arduino some time to recover between looping?
-Should I use pyserial to flush the serial buffer in the loop? (no idea what it does. Again, internet wisdom) Or does board.exit() do that for me? Is once enough?
-In the arduino IDE language, I read about the millis() function, which I think is similar to python's time.perf_counter() function, only with millis() it is the time registered by the arduino instead of my computer. Might this be a way to eliminate the delay in the serial connection? Is there a way to read millis() in pyfirmata? I can't find it in the docs.
-If not, is there some kind of timestamp related to the values of read()? If so, how can I obtain them?
Like maybe a function that looks like millis.read()?
Thanks for reading this. If I posted this in the wrong category please let me know.