Python Datalogger - Using pySerial to Read Serial Data Output from Arduino

Later I became expert with Arduino I plant myself trapped in its development surround (IDE). I needed to escape from the simplicity of the serial port and transform the platform into a usable engineering science tool. I tried saving to SD cards, but decided adding more hardware was superfluous; I tried Bluetooth and WiFi, but again, barring specific Net of Things applications, I found those to be roundabout ways of achieving what I wanted: a simple datalogging system. I ultimately arrived at Python's pySerial library, which reads directly form the series port and was a complete solution to my predicament.

Using pySerial is much easier than one might expect, as the most fundamental implementation consists of but three lines of code:

                    import                    serial                    ser                    =                    serial.Serial('/dev/ttyACM0') ser_bytes                    =                    ser.readline()                  

These three uncomplicated lines read a single row of information from the serial port. In the instance of Raspberry Pi, the serial port (on my Arduino) is located at '/dev/ttyACM0'. You may too notice yours there, or at an integer increment (ttyACM1, ttyACM2, etc.), or peradventure a dissimilar address completely. Bank check your Arduino IDE serial port for the exact location. After successfully reading a line from your Arduino, verify that it is in the desired format. I chose to print and read a single line, merely you may prefer comma separated or like formats. The code above isn't peculiarly interesting, just it verifies that pySerial is working and that you lot are parsing data correctly from your serial port. Once the method above is understood, we can accelerate onto loops and recording data in existent-time.

NOTE: I will be using a DHT11 temperature sensor to produce data on the Arduino end. Since this is a tutorial on reading data from the series port using Python, not Arduino, I recommend visiting a DHT11 tutorial to learn how to impress temperature information from the sensor to the serial port (see here, or here).

Serial Read Loop

I will be using a while loop and keyboard interrupt (CTL-C) to loop and halt the datalogging. The information from the serial port also needs to exist converted from unicode to float (or another datatype) then that the data tin be processed in Python. In my case, I am using "utf-8" to decode, which is Arduino's default encoding and the most commonly used character encoding format. You may too discover the 'ser.flushInput()' control - this tells the series port to articulate the queue then that data doesn't overlap and create erroneous data points. Sometimes the conversion via float() tin create errors, simply this is due to overprinting from the Arduino's end. If you receive such an error, restart the python script and try once again.

                    import                    serial                    ser                    =                    serial.Serial('/dev/ttyACM0') ser.flushInput()                    while                    Truthful:                    effort:         ser_bytes                    =                    ser.readline()         decoded_bytes                    =                    bladder(ser_bytes[0:len(ser_bytes)-2].decode("utf-8"))                    print(decoded_bytes)                    except:                    print("Keyboard Interrupt")                    intermission                  

Now we have a working existent-fourth dimension data printer in Python. Decidedly, this isn't particularly interesting considering nosotros aren't saving or plotting the data, so we'll cover how to do both of those next.

Saving Serial Information to CSV File

In the code below I have implemented a mode to salvage the serial information in real-fourth dimension to a .csv file.

                    import                    serial                    import                    time                    import                    csv                    ser                    =                    series.Serial('/dev/ttyACM0') ser.flushInput()                    while                    Truthful:                    try:         ser_bytes                    =                    ser.readline()         decoded_bytes                    =                    bladder(ser_bytes[0:len(ser_bytes)-2].decode("utf-eight"))                    print(decoded_bytes)                    with                    open("test_data.csv","a")                    as                    f:             writer                    =                    csv.author(f,delimiter=                    ",")             writer.writerow([time.time(),decoded_bytes])                    except:                    print("Keyboard Interrupt")                    break                  

At present we take a working datalogger! This is equally elementary as it gets, and it'due south remarkably powerful. The three lines that offset as: '' with open("test_data.csv","a") as f: '' look for a file called 'test_data.csv' and create information technology if it doesn't be. The "a" in parentheses tells Python to append the serial port data and ensure that no data is erased in the existing file. This is a grand result because it not only takes care of saving the data to the .csv file, but it creates one for u.s.a. and prevents overwriting and (most times) corruption. How considerate!

Alive Plotting Serial Data Using matplotlib

To take things a chip further, I decided to aggrandize the content here and include a real-fourth dimension plot. I find real-time plotting a useful tool when acquiring information of any kind. It is much easier to notice faults in visualizations than it is to observe them in streaming values.

NOTES: while I was using Raspberry Pi, I came across an issue between reading the serial port, saving to .csv, and updating the plots. I found that updating the plot occupied a lot of processing fourth dimension, which resulted in slower reading of the series port. Therefore, I advise anyone who is using the method below to appraise whether you are reading all the bytes that are beingness outputted by the Arduino. I found that I was missing bytes or they were getting backed upwardly in the queue in the buffer. Do some tests to verify the speed of your loop. This will prevent lost bytes and dropouts of data. I found that my loop took roughly half a second to consummate, which means that my serial port should not be outputting more than 2 points per second. I actually used 0.viii seconds every bit the time between data records and it appeared to grab all data points. The tedious loop is a result of the plotting, so in one case you comment out all of the plot code, y'all will go a much higher data rate and .csv relieve rate (just as above).

                    import                    serial                    import                    time                    import                    csv                    import                    matplotlib                    matplotlib.use("tkAgg")                    import                    matplotlib.pyplot                    as                    plt                    import                    numpy                    every bit                    np                    ser                    =                    serial.Serial('/dev/ttyACM0') ser.flushInput()  plot_window                    =                    20                    y_var                    =                    np.array(np.zeros([plot_window]))  plt.ion() fig, ax                    =                    plt.subplots() line,                    =                    ax.plot(y_var)                    while                    True:                    try:         ser_bytes                    =                    ser.readline()                    try:             decoded_bytes                    =                    float(ser_bytes[0:len(ser_bytes)-                    two].decode("utf-8"))                    impress(decoded_bytes)                    except:                    go along                    with                    open("test_data.csv","a")                    every bit                    f:             writer                    =                    csv.writer(f,delimiter=                    ",")             writer.writerow([time.time(),decoded_bytes])         y_var                    =                    np.append(y_var,decoded_bytes)         y_var                    =                    y_var[1:plot_window+                    1]         line.set_ydata(y_var)         ax.relim()         ax.autoscale_view()         fig.canvas.draw()         fig.canvas.flush_events()                    except:                    print("Keyboard Interrupt")                    break                  

dht11_serial_read.png

Effigy 1: DHT11 Alive Plot from Serial Port

Plot produced by matplotlib in Python showing temperature data read from the series port. During this plot, the sensor was exposed to a rut source, which can be seen here equally an increase from 31 to 35 degrees C.

Conclusion

This tutorial was created to demonstrate that the Arduino is capable of acting equally an independent data logger, carve up from wireless methods and SD cards. I found Python's pySerial method a while ago, and I wanted to share its capabilities with makers and engineers that may exist having the aforementioned issues that I was encountering. Printing information to Arduino's serial port and so reading it through Python gives the user the freedom to investigate the data further, and take advantage of the advanced processing tools of a reckoner, rather than a micro controller. This method also allows the user to span the gap betwixt live data and laboratory measurements. With real-time datalogging via the serial port, 1 can mimic the laboratory setup of acquisition, analysis, and live ascertainment. Often, with Arduino the user is trapped in the serial port, or is relegated to advice via protocols, which can have time and free energy. Withal, importing the data into Python frees the user of middle-men and allows the data to be candy in any way preferred. I use pySerial often, whether for recording temperature information using thermocouples, or high-frequency hall sensor measurements to monitor moving parts. This method can be used to take pressure measurements in the laboratory, or even record calibration data to improve your instrumentation accurateness; the possibilities are truly countless.

"As an Amazon Associates Plan fellow member, clicking on links may result in Maker Portal receiving a small-scale commission that helps support futurity projects."

See More than in Arduino and Python:

Arduino, Data Assay, Programming, Python, Most Pop

pySerial, Python, programming, serial, bytes, datalogger, data, Arduino, Analyze, Data Analysis, Serial Port, DHT11, matplotlib, loop, while loop, csv, tkAgg, interrupt, figure, 2018 #1, About Popular 2018