Help Graphing Arduino Data Real Time in Python - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Help Graphing Arduino Data Real Time in Python (/thread-24966.html) |
Help Graphing Arduino Data Real Time in Python - nschulz - Mar-12-2020 Hey folks, I am currently trying to plot my sensor data from my arduino live using python. I have been following the information from https://www.thepoorengineer.com/en/arduino-python-plot/. The problems that I am running into are: 1) How to implement the arduino code he posts into arduino, my serial monitor goes nuts when I put this in. 2) For some reason the graphs don't show up as separate windows when I run the Python code. 3) My graphs don't keep updating, python connects to my arduino and after a little bit disconnects. Attached is my code, thanks! Arduino Reciever: //Include Libraries #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <Wire.h> #include "SparkFunBME280.h" #include <MLX90393.h> float previousRemoteHumidity = 0.1; float previousRemoteTemperature = 0.1; float previousRemotePressure = 0.1; float previousRemoteAltitude = 0.1; float previousRemoteMagX = 0.1; float previousRemoteMagY = 0.1; float previousRemoteMagZ = 0.1; float remoteHumidity = 0.0; float remoteTemperature = 0.0; float remotePressure = 0.0; float remoteAltitude = 0.0; float remoteMagX = 0.0; float remoteMagY = 0.0; float remoteMagZ = 0.0; struct package { float temperature; float humidity; float pressure; float altitude; float magX; float magY; float magZ; }; MLX90393 mlx; MLX90393::txyz data1; //create an RF24 object RF24 radio(9, 10); // CE, CSN BME280 mySensor; //address through which two modules communicate. const byte address[6] = "00001"; typedef struct package Package; Package data; void setup(void){ Serial.begin(9600); startWirelessCommunication(); } void loop(void){ checkForWirelessData(); printRemoteTemperature(); printRemotePressure(); printRemoteHumidity(); printRemoteAltitude(); printRemoteMagX(); printRemoteMagY(); printRemoteMagZ(); } void startWirelessCommunication() { radio.begin(); radio.openReadingPipe(1, address); radio.startListening(); //delay(1000); } void checkForWirelessData(){ if ( radio.available()) { while (radio.available()) { radio.read( &data, sizeof(data) ); remoteTemperature = data.temperature; remoteAltitude = data.altitude; remoteHumidity = data.humidity; remotePressure = data.pressure; remoteMagX = data.magX; remoteMagY = data.magY; remoteMagZ = data.magZ; } Serial.print("Temperature:"); Serial.print(data.temperature); Serial.print(","); Serial.print("Humidity:"); Serial.print(data.humidity); Serial.print(","); Serial.print("Pressure:"); Serial.print(data.pressure); Serial.print(","); Serial.print("Altitude:"); Serial.print(data.altitude); Serial.print(","); Serial.print("MagX:"); Serial.print(data.magX); Serial.print(","); Serial.print("MagY:"); Serial.print(data.magY); Serial.print(","); Serial.print("MagZ:"); Serial.println(data.magZ); } } void printRemoteTemperature(){ String temperature; if (remoteTemperature != previousRemoteTemperature) { if (remoteTemperature == 0.0) //We just booted up { temperature = "---"; } else if (remoteTemperature >= 100) { temperature = String(remoteTemperature, 0); } else { temperature = String(remoteTemperature, 1); } previousRemoteTemperature = remoteTemperature; } } void printRemoteHumidity() { String humidity; if (remoteHumidity != previousRemoteHumidity) { if (remoteMagX == 0.0 && remoteMagY == 0.0 && remoteMagZ == 0.0 && remoteAltitude == 0.0 && remoteHumidity == 0.0 && remoteTemperature == 0.0 && remotePressure == 0.0) //We just booted up { humidity = "---"; } else { humidity = String(remoteHumidity, 1); } previousRemoteHumidity = remoteHumidity; } } void printRemotePressure() { String pressure; if (remotePressure != previousRemotePressure) { if (remoteMagX == 0.0 && remoteMagY == 0.0 && remoteMagZ == 0.0 && remoteAltitude == 0.0 && remoteHumidity == 0.0 && remoteTemperature == 0.0 && remotePressure == 0.0) //We just booted up { pressure = "---"; } else if (remotePressure >= 100) { pressure = String(remotePressure, 0); } else { pressure = String(remotePressure, 1); } previousRemotePressure = remotePressure; } } void printRemoteAltitude() { String altitude; if (remoteAltitude != previousRemoteAltitude) { if (remoteMagX == 0.0 && remoteMagY == 0.0 && remoteMagZ == 0.0 && remoteAltitude == 0.0 && remoteHumidity == 0.0 && remoteTemperature == 0.0 && remotePressure == 0.0) //We just booted up { altitude = "---"; } else if (remoteAltitude >= 100) { altitude = String(remoteAltitude, 0); } else { altitude = String(remoteAltitude, 1); } previousRemoteAltitude = remoteAltitude; } } void printRemoteMagX() { String magX; if (remoteMagX != previousRemoteMagX) { if (remoteMagX == 0.0 && remoteMagY == 0.0 && remoteMagZ == 0.0 && remoteAltitude == 0.0 && remoteHumidity == 0.0 && remoteTemperature == 0.0 && remotePressure == 0.0) //We just booted up { magX = "---"; } else if (remoteMagX >= 100) { magX = String(remoteMagX, 0); } else { magX = String(remoteMagX, 1); } previousRemoteMagX = remoteMagX; } } void printRemoteMagY() { String magY; if (remoteMagY != previousRemoteMagY) { if (remoteMagX == 0.0 && remoteMagY == 0.0 && remoteMagZ == 0.0 && remoteAltitude == 0.0 && remoteHumidity == 0.0 && remoteTemperature == 0.0 && remotePressure == 0.0) //We just booted up { magY = "---"; } else if (remoteMagY >= 100) { magY = String(remoteMagY, 0); } else { magY = String(remoteMagY, 1); } previousRemoteMagY = remoteMagY; } } void printRemoteMagZ() { String magZ; if (remoteMagZ != previousRemoteMagZ) { if (remoteMagX == 0.0 && remoteMagY == 0.0 && remoteMagZ == 0.0 && remoteAltitude == 0.0 && remoteHumidity == 0.0 && remoteTemperature == 0.0 && remotePressure == 0.0) //We just booted up { magZ = "---"; } else if (remoteMagZ >= 100) { magZ = String(remoteMagZ, 0); } else { magZ = String(remoteMagZ, 1); } previousRemoteMagZ = remoteMagZ; } } Python Code: from threading import Thread import serial import time import collections import matplotlib.pyplot as plt import matplotlib.animation as animation import struct import copy class serialPlot: def __init__(self, serialPort='COM3', serialBaud=9600, plotLength=100, dataNumBytes=2, numPlots=1): self.port = serialPort self.baud = serialBaud self.plotMaxLength = plotLength self.dataNumBytes = dataNumBytes self.numPlots = numPlots self.rawData = bytearray(numPlots * dataNumBytes) self.dataType = None if dataNumBytes == 2: self.dataType = 'h' # 2 byte integer elif dataNumBytes == 4: self.dataType = 'f' # 4 byte float self.data = [] self.privateData = None # for storing a copy of the data so all plots are synchronized for i in range(numPlots): # give an array for each type of data and store them in a list self.data.append(collections.deque([0] * plotLength, maxlen=plotLength)) self.isRun = True self.isReceiving = False self.thread = None self.plotTimer = 0 self.previousTimer = 0 print('Trying to connect to: ' + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.') try: self.serialConnection = serial.Serial(serialPort, serialBaud, timeout=4) print('Connected to ' + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.') except: print("Failed to connect with " + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.') def readSerialStart(self): if self.thread == None: self.thread = Thread(target=self.backgroundThread) self.thread.start() # Block till we start receiving values while self.isReceiving != True: time.sleep(0.1) def getSerialData(self, frame, lines, lineValueText, lineLabel, timeText, pltNumber): if pltNumber == 0: # in order to make all the clocks show the same reading currentTimer = time.perf_counter() self.plotTimer = int((currentTimer - self.previousTimer) * 1000) # the first reading will be erroneous self.previousTimer = currentTimer self.privateData = copy.deepcopy(self.rawData) # so that the 3 values in our plots will be synchronized to the same sample time timeText.set_text('Plot Interval = ' + str(self.plotTimer) + 'ms') data = self.privateData[(pltNumber*self.dataNumBytes):(self.dataNumBytes + pltNumber*self.dataNumBytes)] value, = struct.unpack(self.dataType, data) self.data[pltNumber].append(value) # we get the latest data point and append it to our array lines.set_data(range(self.plotMaxLength), self.data[pltNumber]) lineValueText.set_text('[' + lineLabel + '] = ' + str(value)) def backgroundThread(self): # retrieve data time.sleep(1.0) # give some buffer time for retrieving data self.serialConnection.reset_input_buffer() while (self.isRun): self.serialConnection.readinto(self.rawData) self.isReceiving = True def close(self): self.isRun = False self.thread.join() self.serialConnection.close() print('Disconnected...') def makeFigure(xLimit, yLimit, title): xmin, xmax = xLimit ymin, ymax = yLimit fig = plt.figure() ax = plt.axes(xlim=(xmin, xmax), ylim=(int(ymin - (ymax - ymin) / 10), int(ymax + (ymax - ymin) / 10))) ax.set_title(title) ax.set_xlabel("Time") ax.set_ylabel("Arduino Output") return fig, ax def main(): # portName = 'COM5' portName = 'COM3' baudRate = 9600 maxPlotLength = 100 # number of points in x-axis of real time plot dataNumBytes = 4 # number of bytes of 1 data point numPlots = 7 # number of plots in 1 graph s = serialPlot(portName, baudRate, maxPlotLength, dataNumBytes, numPlots) # initializes all required variables s.readSerialStart() # starts background thread # plotting starts below pltInterval = 50 # Period at which the plot animation updates [ms] lineLabelText = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] title = ['Temperature (F)', 'Humidity (%RH)', 'Pressure (Pa)', 'Altitude (Feet)', 'X Field (microT)', 'Y Field (microT)', 'Z Field (microT)'] xLimit = [(0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength)] yLimit = [(-1, 1), (-1, 1), (-1, 1), (-1, 1), (-1, 1), (-1, 1), (-1, 1)] #style = ['r-', 'g-', 'b-'] # linestyles for the different plots anim = [] for i in range(numPlots): fig, ax = makeFigure(xLimit[i], yLimit[i], title[i]) lines = ax.plot([], [], label=lineLabelText[i])[0] timeText = ax.text(0.50, 0.95, '', transform=ax.transAxes) lineValueText = ax.text(0.50, 0.90, '', transform=ax.transAxes) anim.append(animation.FuncAnimation(fig, s.getSerialData, fargs=(lines, lineValueText, lineLabelText[i], timeText, i), interval=pltInterval)) # fargs has to be a tuple plt.legend(loc="upper left") plt.show() s.close() if __name__ == '__main__': main() |