Python Forum
Help Graphing Arduino Data Real Time in Python
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help Graphing Arduino Data Real Time in Python
#1
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()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Real-time processing tagalog 5 453 Oct-06-2020, 03:45 PM
Last Post: tagalog
  ValueError: time data 'None' does not match format '%Y-%m-%dT%H:%M:%S.%f' rajesh3383 4 699 Sep-03-2020, 08:22 PM
Last Post: buran
  Formatting Data/Time with Pyodbc and openpyxl bearcats6001 0 255 Aug-17-2020, 03:44 PM
Last Post: bearcats6001
  Find data using a period of time in SQLITE3 SmukasPlays 2 360 Jul-30-2020, 02:02 PM
Last Post: SmukasPlays
  Save Arduino data in mysql server via raspberrypi rithikvg 1 389 Jun-24-2020, 10:59 PM
Last Post: Larz60+
  Bode plot from time series experiment data discus 4 841 Jun-20-2020, 07:46 AM
Last Post: discus
  Real time MIDI with python eythoralex 1 446 May-19-2020, 07:17 PM
Last Post: Larz60+
  getting error ValueError: time data '' does not match format '%H:%M' srisrinu 2 714 Apr-09-2020, 11:12 AM
Last Post: srisrinu
  Can't transmit serial fast Python to Arduino pyserial mRKlean 0 351 Mar-29-2020, 08:12 PM
Last Post: mRKlean
  About Arduino and Python usb webcam tuts Simurg 1 399 Mar-20-2020, 07:25 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020