How to quickly read single byte serial data using Python - python

I am reading serial data in Python using the following code:
port = "COM11"
baud = 460800
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
while 1:
# Read from serial port, blocking
data =ser.read(1)
print data
# some further processing of data
I am sending data at very fast rate but when I use this code I am getting data at a very slow rate, maybe around 2 - 3 data per second. This is too slow because I want to do real time plotting.
So, instead of above code I tried:
while 1:
# Read from serial port, blocking
data =ser.read(1)
data1=(data)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data1 = (data1 + ser.read(n))
print data1
Now the speed at which data is updated is the same but instead of a single byte I am checking a number of bytes in input queue and reading them. I am receiving around 3850 bytes per loop so this one appears much faster to me but in fact it is almost the same, the only change is that I am not reading a greater number of bytes.
I want to read a single byte and check for the real time it was received. To do so I cannot use second method where I use ser.inWaiting(). How can I read single byte data faster than using the approaches above?

Here's some test code I wrote for a project that you can try different baud settings with. Basically it sends out some data on Tx (which could be connected directly to Rx) and expects the data to be echoed back. It then compares the returned data with the sent data and lets you know if/when errors occur. Note that if there are no errors then the output will remain blank and at the end of test it will print "0 Comm Errors".
import serial, time
test_data = "hello this is so freakin cool!!!" + '\r' #Must always be terminated with '\r'
echo_timeout = 1 #the time allotted to read back the test_data string in seconds
cycleNum = 0
errors = 0
try:
ser = serial.Serial(port="COM1", baudrate=115200, timeout=1)
ser.flush()
print "starting test"
for x in xrange(100):
cycleNum += 1
d = ser.write(test_data)
ret_char = returned = ''
start_time = time.time()
while (ret_char <> '\r') and (time.time() - start_time < echo_timeout):
ret_char = ser.read(1)
returned += ret_char
if not returned == test_data:
errors += 1
print "Cycle: %d Sent: %s Received: %s" % (cycleNum, repr(test_data), repr(returned) )
except Exception as e:
print 'Python Error:', e
finally:
if 'ser' in locals():
print "%d Comm Errors" % errors
if ser.isOpen():
ser.close()
print "Port Was Successfully Closed"
else:
print "Port Already Closed"
else:
print "Serial Variable Was Never Initialized"

Related

Data saved to text file is inconsistent

My controller is receiving data from a radio module through a serial port, it's recording temperature and humidity to two decimal places every 1 second, using 'a' as a signal to time stamp it. For example:
a21.12 65.43
a21.13 65.40
Here is the code I'm using:
import serial
import datetime
connected = False
locations=['/dev/ttyUSB0','/dev/ttyUSB1','/dev/ttyUSB2','/dev/ttyUSB3']
for device in locations:
try:
print "Trying...",device
ser = serial.Serial(device, 9600)
break
except:
print "Failed to connect on",device
while not connected:
serin = ser.read()
connected = True
with open('tempdata.txt', 'w') as text_file:
while 1:
if ser.read() is 'a':
text_file.write(datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'))
text_file.write(" ")
x = ser.read()
text_file.write(x)
text_file.flush()
ser.close()
When I check my text file afterwards the result seems to be different every time. If I let it run for just 2 or 3 seconds I sometimes get a correct result, sometimes I only get the humidity, sometimes I get the time stamp with a number that is half temperature, half humidity (like 2.16.3). If I let it run for more than a few seconds the file is just completely blank.
The basis for my code is from a question previously asked on here and it worked fine until I added the time stamp part. I tried changing the radio transfer rate from 9600 to 4800 but that just turned the numbers into garbage characters.
I'm running this on a Raspberry Pi 2 model B so I could be demanding too much from it in a short time.
You are calling read() twice and writing only the output of the second call. I don't imagine that is your intent.
You can change this section:
with open('tempdata.txt', 'a') as text_file:
while 1:
content = ser.read()
if content is 'a':
text_file.write(datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'))
text_file.write(" ")
text_file.write(content)
text_file.flush()

Converting Data From Serial Port to Display as Decimal in Python

I am starting a program that reads data from a radio receiver. The data is 6 bytes long and updates every 1 second. The program reads the serial port USB data, but the data is in some format that does not display correctly. What I do know is that it should be in an unsigned integer.
Each data string comes in as 6 bytes and each byte represents a number corresponds to the data the receiver has logged.
import serial
t = 0
while t == 0:
ser = serial.Serial('/dev/tty.SLAB_USBtoUART', 9600, bytesize=8, stopbits=1, timeout=None, xonxoff=0, rtscts=0, dsrdtr=0)
s=ser.readline(6)
#s=ser.read(6)
print("Streams received during interval: ")
print (s)
print("__________")
end
I am expecting an output that looks like:
0 101 0 0 91 145
but what I am getting is:
eV�
I think there is something off in the data coming in and how it prints in the print statement. I just need to make sure the data is coming in correctly before I move on.
That's because you are converting bytes to a string with your '%s' % s statement. It's showing up as whatever random ASCII character corresponds to your bytes.
Instead, try printing the bytes as integers:
print ' '.join([ord(ss) for ss in s])
Okay I figured it out and thought I would post my solution for the problem. Using NumPy I was able to easily output the correct data. I am working with a Dorji DRF4432S receiver and a Dorji DRF5150S transmitter. These are setup to send analog voltages from a sensor that basically outputs nothing until it is triggered, the the voltages with remain high for a few seconds then return to the zero value. Hopefully this might help someone looking for coding help with this sensor.
import serial
import numpy as np
t = 0
while t == 0:
ser = serial.Serial('/dev/tty.SLAB_USBtoUART', 9600, bytesize=8, stopbits=1, timeout=None, xonxoff=0, rtscts=0, dsrdtr=0)
s=ser.readline(6)
#s=ser.read(6)
print("Streams received during interval: ")
ss=np.fromstring(s, dtype=np.uint8, count=6)
sen_1_group=ss[0]
sen_1_id=ss[1]
sen_1_voltage=ss[2]+ss[3]
sen_1_battery=ss[4]
sen_1_signal=ss[5]
print (ss)
print "Group Id = ", sen_1_group , "Sensor ID = ", sen_1_id
print "Sensor ", sen_1_id, " Voltage = ", sen_1_voltage
print "Sensor ", sen_1_id, " Battery = ", sen_1_battery
print "Sensor ", sen_1_id, " Signal Strength = ", sen_1_signal
print("__________")
end
This resulted in the data coming out correctly as can be seen below:
>> Streams received during interval:
>>[ 0 101 0 0 84 169]
>>Group Id = 0 Sensor ID = 101
>>Sensor 101 Voltage = 0
>>Sensor 101 Battery = 84
>>Sensor 101 Signal Strength = 169
>>__________

Python 2.7 simple packet sniffer

I wrote simple packet sniffer in Python. I need to receive packets non-stop and send one packet every 10 seconds. I tried this:
current = time.time()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("xx.xx.xx.xx",xxxx))
time.sleep(0.5)
while True:
msg = str(s.recv(4096))
time.sleep(0.010)
print msg
if current==current+10:
s.send("<myPacket/>")
current = time.time()
but it doesn't work good. Anyone have better idea?
Your time handling is bad, use this instead:
While True:
...
time.sleep(10)
Your code doesn't work because:
'current' can never be equal to itself+10.
Also note that time.time() returns a float value e.g: 1440185304.78
which is very accurate to that exact moment, you should never assume you can find that exact float +10 back.
Using a larger/smaller statement is better in this case since the exact value might have passed while your loop is running whatever is in it, e.g:
t = time.time()
while True:
while time.time() < t + 10:
time.sleep(0.1)
t = time.time()
print ("hi")

check the byte length before sending back to severs in socket programming in python

My client sends a message to server. The server collects the message 16 bytes each time and when it receives anything less than 16 bytes, it returns the message (after concatenation) back to the client.
Here is the code from server.py:
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sock.bind(address)
sock.listen(1)
try:
while True:
conn,add=sock.accept()
addr=(conn,add)
print add
try:
data = ''
while True:
recvdata=conn.recv(16)
print recvdata
data+=recvdata
if len(recvdata)<16:
print >>log_buffer,"sending data"
conn.sendall(data)
break
finally:
conn.close()
except KeyboardInterrupt:
sock.close()
The code works well for messages above 16 and less than 16 byte length, when it is exactly 16 or mutliples of 16, it is not sending back to client. how do I fix for this?
`
you don't say anything about what it should do at exactly a multiple of 16.
The code you posted will not send it back though.
Change < to <=.
< means less than.
<= means less than or equal to (multiple of).
Code:
if len(recvdata)<=16:
print >>log_buffer,"sending data"
conn.sendall(data)
break
Edit:
If you are just getting the message and returning whole bytes you can do the following:
while True:
conn,add=sock.accept()
addr=(conn,add)
print add
try:
recvdata=conn.recv(2048) #however much you need
wholebytes = len(recvdata) / 16 # get the number of whole bytes
# loop to send messages of length 16 with whole bytes
for i in range(wholebytes):
data = recvdata[i*16:(i+1)*16]
print >>log_buffer,"sending data"
conn.sendall(data)
break

python split string and pick substring

I am having a lot of trouble with the list returned by the split function in python. I am probably being incredibly dense.
My python code is as follows
str = "XXX:YYY:ZZZ"
var+=1
ins = str.split(':')
print ins
When the script runs it returns the following result
['XXX','YYY','ZZZ']
What i am struggling to do is pull out the string contained the second string in the list. I would have thought the following code at the end of the python code would work.
print ins[1]
but when i run it i get the following error
IndexError: list index out of range
Any help would be much appreciated
full code
import time
ser = serial.Serial("COM3", 9600)
print ser
time.sleep(3)
print "Sending serial data"
var = 0
while var<=10:
str = ser.readline()
print str
var+=1
ins = str.split(':')
print ins
print ins[0]
if (str.split(':')=='end\n'):
break
if(ser.isOpen()):
print "Serial connection is still open."
ser.close();
print "Serial connectionnow terminated."
This returns
Serial<id=0x2a7fc50, open=True>(port='COM3', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Sending serial data
Program Initiated
['Program Initiated\n']
Program Initiated
0:addsd:1
['0', 'addsd', '1\n']
0
1:addsd:2
['1', 'addsd', '2\n']
1
2:end:2
['2', 'end', '2\n']
2
Your code will not work in instances where the input you're analyzing has a length <= 1.
Try checking for that and handling it in your code.
One of the lines you are reading probably has a two '\n' characters in a row. When that string is read with readlines() and then spit it has no [1] index only a [0] index.
What output do you get for the program:
import serial // Or is serial a builtin for the version of python you are using?
print repr(serial.Serial("COM3", 9600))
Thanks,
Marlen

Categories