I am new to programming and after a few weeks have made some programs to do simple things; like capture serial data from an arduino and save it to a text file.
Now I want to combine a couple things. I want to use python to capture serial data, prompt for port and filename, take that data and plot it real time, then when the arudino is no longer connected, save and close file. Here is the code I have so far.
problem is the graph is not real time at all. The sensors show almost no change. I also sometimes get a matplotlib depreciation warning. I wondering if there is a quick fix or if I am missing something crucial. Thank you so much!
import numpy
import matplotlib.pyplot as plt
import math
import time
import pylab
from drawnow import drawnow
import csv
import serial
import os
import glob
import sys
filename = raw_input("Save file as: ")
saveFile = open(filename, 'w')
print "Available ports: "
def serial_port():
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range (256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
ports = glob.glob('/dev/tty/[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported Platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
pass
return result
if __name__ == '__main__':
print serial_port()
serialport = raw_input("Enter Port: ")
port1 = serialport
print "Connecting to port...", port1
arduino1 = serial.Serial(port1, 115200)
print "Arduino Detected"
#create arrays with the following names
Time = []
analog0 = []
analog1 = []
voltage0 = []
voltage1 = []
Temp = []
RH = []
#reading data from the serial port
#telling Matplot.lib to plot live data
plt.ion()
#creates a function to make a plot we want
def Fig1():
plt.plot(analog0, 'r-')
plt.title("Analog0 Data")
plt.ylim(405, 425)
plt.grid(True)
plt.ylabel("analog")
plt.xlabel("milliseconds")
x = os.path.exists(port1)
while x==0:
arduinoString = arduino1.readline()
saveFile.write(arduinoString)
dataArray = arduinoString.split(',')
time = float(dataArray[0])
a0 = float(dataArray[1])
a1 = float(dataArray[2])
v0 = float(dataArray[3])
v1 = float(dataArray[4])
temp = float(dataArray[5])
rh = float(dataArray[6])
#filling our arrays with those new data values (floats)
Time.append(time)
analog0.append(a0)
analog1.append(a1)
voltage0.append(v0)
voltage1.append(v1)
Temp.append(temp)
RH.append(rh)
drawnow(Fig1)
plt.pause(0.00010)
else:
saveFile.close()
I also had a same problem.
It was solved by using set_data() like blow link.
Draw now and Matplotlib
Related
I am a newbie in machine automation. I am working on collecting data from 2 Micrometers using python. I am collecting data from 2 induvial COM ports. I run the following python script to record the data and display it on python shell.
import time
import datetime
import serial
import matplotlib.pyplot as plt
import pandas as pd
# configure the serial connections
ser1 = serial.Serial(
port='COM4', baudrate=115200,
bytesize=8,
stopbits=1, timeout=0.02)
print("Connected to: " + ser1.port)
ser2 = serial.Serial(
port='COM5', baudrate=115200,
bytesize=8,
stopbits=1, timeout=0.02)
print("Connected to: " + ser2.port)
ser1.isOpen()
ser2.isOpen()
# Read data from the serial port, which will run in an infinite loop.
print("Instrument Type: Micrometer")
file_name = str(input('\nInsert Filename: '))
run_time = float(input('\nInsert Runtime: '))
start = time.time()
with open('./' + file_name + '.csv', 'w+') as output_file:
output_file.write('Timestamp,Data1, Data2\r')
while time.time()-start < run_time:
timestamp = str.format('{0:.3f}', (time.time()-start))
data1 = ser1.readline().decode().rstrip()
data2 = ser2.readline().decode().rstrip()
output_file.write(timestamp + ',' + data1 + ',' + data2 + '\r')
time.sleep(0.01 -(time.time()-start)%0.01)
print(timestamp, data1, data2)
print('Data Recorded')
It gives me the following output that I want (don't worry about the values).
Now, I want to apply shift() like function on data1(i.e., ser1) values to create a new column alongside, which will start storing data1 values from 4th row onwards and first 3 will be null/nan. Needless to say, it needs to be completed in real-time as a continuous output.
The following code should read the serial interface into log file. The code can log with significantly high sampling rates (yes, serial synchronization is missing). But since the code is faster than the data rate of the serial device (which should be the case), it reads duplicate points.
Clarification edit: As we can see from the source code, thread is reading the serial port and writing it to the buffer rawData. Another function getSerialData() should unpack the rawData into 4 variables and write to the log file. But as it is faster than data rate of serial device, it reads rawData even when no new reading available. I would like to make the function getSerialData() unpack rawData only when thread writes new data to rawData.
I want to make sure that the code only gets last sample from serial device. This could be done by comparing the new sample with the previous sample, but it is too slow.
There are many examples of how it is done, but not for a raw connection.
#!/usr/bin/env python
from threading import Thread
import serial
import time
import collections
import struct
import copy
import pandas as pd
import numpy as np
import sys
import os
import h5py
class serialPlot:
def __init__(self, serialPort, serialBaud, bufferLength, dataNumBytes, numVal):
self.port = serialPort
self.baud = serialBaud
#self.plotMaxLength = bufferLength
self.dataNumBytes = dataNumBytes # number of bytes for single value
self.numVal = numVal
self.rawData = bytearray(numVal * dataNumBytes)
self.data = []
for i in range(numVal): # give an array for each type of data and store them in a list
self.data.append(collections.deque(
[0] * bufferLength, maxlen=bufferLength))
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):
# start thread if not started yet
if self.thread == None:
self.thread = Thread(target=self.retrieveData)
self.thread.start()
# Block till we start receiving values
while self.isReceiving != True:
time.sleep(0.01)
def getSerialData(self, bufferLength):
hdf5Buffer = [[0 for x in range(self.numVal)] for y in range(
bufferLength)] # Create array to hold data
# Calculate time delta between data points
currentTimer = time.perf_counter_ns()
# the first reading will be erroneous
self.plotTimer = int((currentTimer - self.previousTimer) / 1000)
self.previousTimer = currentTimer
for e in range(bufferLength):
privateCopy = copy.deepcopy(self.rawData[:])
for i in range(self.numVal):
bytedata = privateCopy[(i * self.dataNumBytes):
(self.dataNumBytes + i * self.dataNumBytes)]
value, = struct.unpack('f', bytedata)
# get the latest data point and append it to our array
self.data[i] = value
for f in range(self.numVal):
hdf5Buffer[e][f] = self.data[f]
hdf5Buffer[e].insert(0, self.plotTimer)
return hdf5Buffer
def retrieveData(self): # retrieve data
time.sleep(0.1) # give some buffer time for retrieving data
self.serialConnection.reset_input_buffer() # flush input buffer
while (self.isRun):
# read n bytes into array (rawData) and return num of bytes read
self.serialConnection.readinto(self.rawData)
self.isReceiving = True
def close(self):
self.isRun = False
self.thread.join()
self.serialConnection.close()
print('Disconnected...')
def main():
time.sleep(0.1)
portName = 'COM15'
baudRate = 230400
bufferLength = 10 # number of samples buffered before saving it to HDF5
dataNumBytes = 4 # number of bytes for single data point
numData = 4 # number of data points in single sample
rawData = bytearray(numData * dataNumBytes)
s = serialPlot(portName, baudRate, bufferLength,
dataNumBytes, numData) # initializes all required variables
# Starts background thread
s.readSerialStart()
dataArray = s.getSerialData(bufferLength)
while(True):
# Prepare data to write
dataArray = s.getSerialData(bufferLength)
'''
PROCEDURE FOR WRITING LATEST DATA INTO HDF5
'''
# TESTING
print(str(dataArray[-1]), end=' \r')
s.close()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('Interrupted')
try:
sys.exit(0)
except SystemExit:
os._exit(0)
I am getting the error in Python 3.6 TypeError:
'>' not supported between instances of 'list' and 'int'
I am trying to take data from another Python program and use it to show when flexing or not but I do not know the syntax for this. My code is pasted below.
I just need to get the 8 bit unsigned integer to be compared to the data being taken in.
import pyglet
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import socket
import threading
import sys
import os
import math
#Un-comment this if using OS-X.
#os.system('defaults write org.python.python ApplePersistenceIgnoreState NO')
WindowSize = 5000
SampleRate = 1000.0
VoltsPerBit = 2.5/256
#Define global variables
Fs = 1000
FlexWindowSize = 0.25
data = []
displayData = [-2 for i in range(WindowSize)]
flexing = False
# This reads from a socket.
def data_listener():
global data
UDP_PORT = 9000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
newdata, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
data.extend(list(newdata))
#Handle command line arguments to get IP address
if (len(sys.argv) == 2):
try:
UDP_IP = sys.argv[1]
socket.inet_aton(UDP_IP)
except:
sys.exit('Invalid IP address, Try again')
else:
sys.exit('EMG_Acquire <Target IP Address>')
#Connect the UDP_Port
UDP_PORT = 9000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
print('Connected to ', str(UDP_IP))
print("Listening for incoming messages...")
print('Close Window to exit')
#Start a new thread to listen for data over UDP
thread = threading.Thread(target=data_listener)
thread.daemon = True
thread.start()
#Load and place image resources
pyglet.resource.path = ['./resources']
pyglet.resource.reindex()
ForeArm_image = pyglet.resource.image("forearm.png")
Bicep_image = pyglet.resource.image("Bicep.png")
ForeArm_image.anchor_x = 7
ForeArm_image.anchor_y = ForeArm_image.height-150
Bicep_image.anchor_x = Bicep_image.width/2
Bicep_image.anchor_y = Bicep_image.height/2
#Define the moving ForeArm class
class ForeArm(pyglet.sprite.Sprite):
def __init__(self, *args, **kwargs):
super(ForeArm,self).__init__(img=ForeArm_image,*args, **kwargs)
self.rotate_speed = 100.0
self.rotation_upper_limit = -10
self.rotation_lower_limit = -100
self.rotation = self.rotation_upper_limit
self.key_handler = pyglet.window.key.KeyStateHandler()
def update(self, dt):
if flexing:
if not ((self.rotation-self.rotate_speed*dt) <= self.rotation_lower_limit):
self.rotation -= self.rotate_speed*dt
else:
self.rotation = self.rotation_lower_limit
else:
if not((self.rotation+self.rotate_speed*dt) >= self.rotation_upper_limit):
self.rotation += self.rotate_speed*dt
else:
self.rotation = self.rotation_upper_limit
#Setup the main window
main_window = pyglet.window.Window(1000,600)
main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
foreground = pyglet.graphics.OrderedGroup(1)
bicep = pyglet.sprite.Sprite(img=Bicep_image,x=350,y=150,batch=main_batch,group=background)
forearm = ForeArm(x=510, y=115,batch=main_batch,group=foreground)
pyglet.gl.glClearColor(1, 1, 1, 1)
main_window.push_handlers(forearm)
main_window.push_handlers(forearm.key_handler)
def update(dt):
global displayData, data, flexing
newData = list(data)
data = []
newDisplay = list(displayData[len(newData):len(displayData)] + newData)
displayData = list(newDisplay)
#Put your flex algorithm code here!
#If flexing is detected, set the 'flexing' variable to True.
#Otherwise, set it to False.
#############################
#ALL OF YOUR CODE SHOULD GO BELOW HERE
if displayData > 20:
flexing = True
else:
flexing = False
#ALL OF YOUR CODE SHOULD GO ABOVE HERE
forearm.update(dt)
#main_window.event
def on_draw():
main_window.clear()
main_batch.draw()
pyglet.clock.schedule_interval(update, 1/120.0)
pyglet.app.run()
First, you are already instantiating newDisplay as a list, so there is no need to do displayData = list(newDisplay). You can just do displayData = newDisplay.
Secondly, when you try to evaluate displayData > 5, you are comparing a list to an integer. This is like asking, "is this list greater than 5?". That doesn't make logical sense.
A much more common paradigm is to ask if a list's length is greater than some number. Are you trying to say, "If the length of the displayData list is greater than 20, do something" ? If so, use if len(displayData) > 5.
However, you have some bigger logical issues in these lines of your code:
newDisplay = list(displayData[len(newData):len(displayData)] + newData)
displayData = list(newDisplay)
You are trying to use displayData within your newDisplay definition, but displayData doesn't exist yet at that point in your code.
As another person mentioned, we can help you more effectively if you post just enough code to convey your problem, along with the full error message.
I would like some help. I'm trying to send a variable to T0. I've tried but I cannot send a variable value. Please help.
CODE
import serial
import time
import struct
from requests import get
ip = get('https://api.ipify.org').text
ser = serial.Serial("/dev/ttyAMA0")
time.sleep(1)
k=struct.pack('B', 0xff )
while True:
ser.write(b't0.txt=ip')
ser.write(k)
ser.write(k)
ser.write(k)
You have to wrap your string in quotation marks (") for Nextion to read the string.
Not a Python expert, but this should give you a clue:
Change ser.write(b't0.txt=ip') to something like ser.write(b't0.txt="' + ip + '"').
This works for me.
port=serial.Serial(port='/dev/ttyAMA0',baudrate=9600, timeout=1.0)
eof = "\xff\xff\xff"
tn = str(datetime.now().time())
alt = 'page0.T0.txt="'+tn+'"'+eof
dimCmd = "dim=0"
undimCmd = "dim=100"
cmd1 = "https://api.thingspeak.com/apps/thinghttp/send_request?api_key=YOUR_API_KEY" #IF USING THINGSPEAK
#get temp Sub - USING THINGSPEAK GET LOCAL WEATHER
def GetTemp():
global temp
response = urllib.urlopen(cmd1)
temp = response.read()
temp = temp[:-2] #gets all characters in temp except the last 2
while True:
port.write(alt) #writes time to T0 textbox on screen
port.write(undimCmd + eof) #set screen brightness to 100%
port.write("page 1")#set screen to page 1 for multiple page setups
I'm trying to collect serial data from a device, timestamp and export it to a .csv file.
The following program writes date and time to csv but not the data returned from the device module:
import time
import csv
import fio2
def Csv_creator():
my_file = open('test_csv.csv', 'w+')
with my_file:
new_file = csv.writer(my_file)
def Timestamp():
date_now = time.strftime('%d/%m/%y')
time_now = time.strftime('%H:%M:%S')
return [date_now,time_now]
def Write_loop():
Csv_creator()
fio2.Initialize()
with open('test_csv.csv', 'a') as f:
csv_file = csv.writer(f)
for num in range(0,20):
[date_now,time_now] = Timestamp()
fio2_data = fio2.Reader()
print(fio2_data)
csv_file.writerow([date_now,time_now,fio2_data])
Write_loop()
The device module is as shown below. It returns the data and I'm able to print it. The only problem is not being able to write it on to the csv file.
import serial
ser = serial.Serial("COM4",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
def Initialize():
global ser
try:
ser.isOpen()
print("\n Serial is open")
except:
print ("Error: serial Not Open")
def Reader():
global ser
if (ser.isOpen()):
try:
x = ser.readline().decode()
x = (x)
return x
except:
return "unable to print"
else:
return "cannot open serial port"
I figured it out. I had to remove some garbage letters that were associated with the decimal values. First, I change the received data to string and replaced the garbage letters. Here's how I changed it:
[date_now,time_now] = Timestamp()
fio2_data = str(fio2.Reader()).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
write_list = [date_now,time_now,fio2_data]