Slow Python serial speed - python-2.7

I have connected an Arduino UNO to my raspberry pi and want to read from a connected Sensor with a Python Script.
When I try to read the sensor data from the Arduino IDE, it works perfectly fast, but with Python it is really slow.
This is my code:
import serial
from subprocess import call
from time import sleep
ser = serial.Serial('/dev/ttyACM0')
ser.baudrate = 9600
a = 0
stop = False
file = open("PulseData/MasterArrayData.txt","w")
if(ser.isOpen() == False):
ser.open()
print("Start scanning")
while stop == False:
test = ser.readline()
try:
testInt = int(test)
if testInt > 100 and testInt < 800:
print test
file.write(str(testInt))
file.write("\n")
a = a+1
except ValueError:
print "Not an integer"
if(a == 400):
stop = True
sleep(0.1)
file.close()
call(["./main", "PulseData/MasterArrayData.txt"])
I already tried to use a higher baud rate, or a shorter sleeping time, without success.
I've read that the speed can be improved with PyTTY, but unfortunately I didn't find any documentation about that.
I appreciate any help.

From comment by jasonharper:
Sleeping for a tenth of a second between readings is an absolute guarantee that you will get less than 10 readings per second. The occasional garbage value you're getting happens when the serial port buffer inevitably overflows and characters get lost.

Related

Is it possible to measure accurate Milliseconds time between few code statements using python?

I am developing a python application using Python2.7.
That application is using pyserial library to read some data bytes from serial port.
Using while loop to read 1 byte of data in each iteration. In each iteration
I have to measure execution time between statements if it is less than 10 ms wait for it to reach 10ms before starting next iteration. there are two questions here as follows:
Time measurement
What would be the best way to measure time between python statements to the accuracy (1ms or 2ms difference acceptable) of milliseconds.
Time delay
How can i use that measured time for delay in order to wait till total time is 10ms (total time = 10ms = code execution time+delay)
I have tried time library but it does not give a good resolution when in millisecond some time it does not give anything when small time duration.
for example:
import time
while uart.is_open:
uart.read()
start = time.time()
#user code will go here
end = time.time()
execution_time=end - start
if execution_time< 10ms:
remaining_time = 10ms - execution_time
delay(remaining_time)
You can get a string that is minutes:seconds:microseconds using datetime like so:
import datetime
string = datetime.datetime.now().strftime("%M:%S:%f")
And then turn it into a number to make comparison more handy:
m, s, u = string.split(":")
time_us = float(m)/60e6 + float(s)/1e6 + float(u)
In your example, that would look like this:
import datetime
def time_us_now():
h, m, s, u = (float(string) for string in datetime.datetime.now().strftime("%H:%M:%S:%f").split(":"))
return h/3600e6 + m/60e6 + s/1e6 + u
start = time_us_now()
# User code will go here.
end = time_us_now()
execution_time = end - start
Solution:
I have managed to get upto 1ms resolution by doing two things.
Changed (increased) the baud rate to 115200 from 19200.
Used time.clock() rather than time.time() as it has more accuracy and resolution.

Feedback requested: Global variables or classes in python2.7 countdown timer for Raspberry Pi

This is my first post to Stack Overflow. I started working with python 2.7 roughly 3 weeks ago and this is my first attempt at creating something in code (I have some basic experience with the Arduino IDE). Although the countdown timer now works for my purposes, I think I can make the code a lot better, especially where I keep declaring my global variable for color so that my digits appear to be flashing (red to black to red every second). I think I might need to use a class for color, but I don't know how. Would you have any tips for me?
This code is just bits and pieces collected and sewn together from code I found in online guides, mainly from this one: https://www.element14.com/community/community/code_exchange/blog/2012/12/17/raspberry-pi-workout-timer
Any feedback would be greatly appreciated, especially on any beginner mistakes I might be making.
All the best,
Katrien
digit_colour = pygame.Color(0, 255, 0)
# Colon between minutes and seconds
pygame.draw.rect(screen, digit_colour, pygame.Rect(left_offset + 2*(2*offset + digit_width), top_offset + offset + led_width / 2 - led_height, led_height, led_height))
pygame.draw.rect(screen, digit_colour, pygame.Rect(left_offset + 2*(2*offset + digit_width), top_offset + 3*offset + 3 * led_width / 2 - led_height, led_height, led_height))
print "Time is up!"
for j in range(0, timeIsUp):
# Draw time on screen
def colourChange():
global digit_colour
digit_colour = pygame.Color(255, 0, 0)
colourChange()
draw_time(screen, 0)
pygame.display.flip()
time.sleep(1)
def colourChange():
global digit_colour
digit_colour = pygame.Color(0, 0, 0)
colourChange()
draw_time(screen, 0)
pygame.display.flip()
time.sleep(1)
if __name__ == '__main__': main()
Hi I am new to and have experience with arduino IDE. You could've done a raw input asking you how long the countdown timer should last. And then you could have a loop with a minus -1 and a time.sleep(1) and a print of the time left example
import time
minutes = raw_input("Minutes? ")
seconds = raw_input("Seconds? ")
time = minutes*60 + seconds
while(remaintime = True)
time-1
time.sleep(1)
print(time," seconds left")
if time<0
remaintime = False
print("time out")
This is a much simpler countdown clock but it works!

Algorithm for get input(True) in raspberry and count its. similar old nokia mobile keyboard

Algorithm for get input(True) in raspberry and count its. similar old nokia mobile keyboard.
i was count how many receive True from GPIO raspberry in 1 of seconds?
I'm assuming you're wanting to know how many times you receive a True signal within a one second window from a pre-configured GPIO pin. If that's the case I'd utilize time.clock() and a while loop:
import time
x = 0
start_time = time.clock()
end_time = start_time + 1
while (start_time < end_time):
if (GPIO.input(17)):
x = x + 1
start_time = time.clock()
print(x)

Plot sine wave of higher frequencies

I am sending serial data from uart to pc and trying to plot sine wave(using Python) sent from function generator through ADC12 of MSP430F5438A.
I am able to plot the wave for lower sampling frequencies(<120Hz) but when I increase the sampling frequency the digits get concatenated i.e. if two values 2563 , 2879 are sent through uart then python reads them as 25632879. So, I am not able to plot the graph as values are not correct.
I am sending the values without new line between them, if I send with new line then the values are not read correctly - python reads them with space in between so then again I get another error: could not convert string to float.
I tried data = ser.readline() as well but no luck
I am attaching the code below.Please see if anything can be done to solve this problem.
import sys
import serial
import numpy as np
import matplotlib.pyplot as plt
from collections import deque
port = "COM11"
baud = 9600
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
a1 = deque([0.0]*100)
#ax = plt.axes(xlim=(0, 100), ylim=(0, 1000))
line, = plt.plot(a1)
plt.ion()
plt.ylim([0,1000])
try:
ser.open()
except:
sys.stderr.write("Error opening serial port %s\n" % (ser.portstr) )
sys.exit(1)
#ser.setRtsCts(0)
while 1:
# Read from serial port, blocking
data = ser.read(1)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data = data + ser.read(n)
#sys.stdout.write(data)
print(a1)
a1.appendleft((data))
datatoplot = a1.pop()
line.set_ydata(a1)
plt.draw()
Thanks
I can think of two ways for doing this reliably:
Use a delimiter . All you need is to parse the value correctly:
line = serial.readline()
reading = int(line)
If you don't want to use a delimiter then send a formatted reading from the msp:
uint8_t buffer[5];
snprintf(buffer, 4, "%04d", reading);
uart_print(buffer);
this way you will always get 4 characters per reading, so you can do this in the python code:
line = serial.read(4)
reading = int(line)
I'd still go for the first alternative, though.

plot goes to zero in between

import sys
import serial
import numpy as np
import matplotlib.pyplot as plt
from collections import deque
port = "COM11"
baud = 9600
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
a1 = deque([0.0]*100)
#ax = plt.axes(xlim=(0, 100), ylim=(0, 1000))
line, = plt.plot(a1)
plt.ion()
plt.ylim([0,1000])
try:
ser.open()
except:
sys.stderr.write("Error opening serial port %s\n" % (ser.portstr) )
sys.exit(1)
#ser.setRtsCts(0)
while 1:
# Read from serial port, blocking
data = ser.read(1)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data = data + ser.read(n)
#sys.stdout.write(data)
print(a1)
a1.appendleft((data))
datatoplot = a1.pop()
line.set_ydata(a1)
plt.draw()
I am using msp430f5438a board.If I send the data with a new line between each data then I am not able to plot the data because in python the sometimes data gets printed as 78_9, 7_89,_789 where _ means space so python gives me a error cannot convert string to float. But If I say send the data from uart without any new line between them then I get a nice plot but in the plot after some irregular short intervals the plot goes to zero and then becomes fine again although I checked in hyperterminal I am not receiving any zero values
My question is:
Are the two cases I described are related to each other?What can be done to rectify this problem of plot going to zero in between?Because of this I am not getting a smooth wave.
Thanks
The problem might be in the way you handle the serial interface. As you are not parsing the serial input when it comes, it is possible that you receive two messages as follows:
1.23
4.56
7.
and
89
10.11
etc. This is because your code may split the input at any point. It may be so fast that you get one digit at a time, which is probably not what you wanted.
I suggest that if you pad your data with newlines and if the data is good in a terminal program, you use the readline method.
while 1:
# read a line from the input
line = ser.readline()
# try to make a float out of it
try:
a1.appendleft(float(line))
except ValueError:
# in case we got bad input, print it and go to the next line
print "Received an invalid line '{0}'".format(line)
continue
# do the plotting
This most probably fixes your problem.
Reading asynchronous serial line is surprisingly complicated, you usually need to parse the input in-the-fly with timeouts. Fortunately, this is done by pyserial when using readline.