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
Related
While attempting to create a simple program to read data from a RS232 device, I noticed that I can't access the elements in a list inside a while loop.
This list are the bytes read from the serial port (using pyserial).
import serial
ser = serial.Serial('COM5', baudrate=115200, timeout=1)
ser.flushInput()
#To request Distances & Echoes, the following frame has to be sent
packet = bytearray()
packet.append(0xde)
packet.append(0x01)
packet.append(0x05)
packet.append(0x59)
packet.append(0x83)
try:
while 1:
ser.write(packet)
ser_bytes = ser.read(50)
listDistances = list(ser_bytes)
distance0_lsb = listDistances[4] #distance 0 (LSB)
distance0_msb = listDistances[5] #distance 0 (MSB)
finally:
ser.close()
listDistances[4] throws an "index out of range" error
Do I need threading to be able to be keep updating the list while extracting elements from it?
Python list indexes start with 0, which means that in your example listDistances[5] would raise "index out of range" if your list has only 5 elements.
If you want distance0_lsb and distance0_msb to read the last two elements in listDistances you could use:
distance0_lsb = listDistances[-2]
distance0_msb = listDistances[-1]
Negative indexes in python go through the list backwards.
I have been trying to have some serial communication between raspberry and my STM32 board (I use MBEDOS for the firmware).
Right now, I am able to do serial writing from my raspberry to the microcontroller, and succeed.
However, I wanted to try to write something from the microcontroller to the raspberry, and the raspberry should process it. But, it seems that it fails to do so.
The code of the raspberry is quite simple:
import time
import serial
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while 1:
x=ser.readline()
if x[2] == "e":
break
print x
print("stop")
A little explanation to my code, what I wanted to do is when my microcontroller send an "e", it should break from the loop. I used x[2] because I noticed when we print the serial data, it will print:
b'eeeeeee\n'
hence,I decided to use x[2].
In the microcontroller part, I used:
if(butn == 1) {
// raspi.putc('e');
raspi.printf("eeeeeee");
swo.printf("e is printed");
}
where butn is the user button. I already tried using .putc('e') but it is the same as well.
How can I deal with this problem?
Thank you!!
The problem in your code is that Serial.readline() return a bytes object, not a string. That's why you see the b when it gets printed.
Now, indexing with bytes objects doesn't count the b and the ' that appear in its string
representation; so if you want the first character, you should use x[0]. However, when you use indexing in the bytes object you won't get a character, you will get the number representation of the particular byte you requested.
x = b'eeeee'
print x[0]
>>> 101
Unsurpisingly, 101 is the ascii for 'e'.
You need to cast x[0] to a character. The result would be:
while 1:
x=ser.readline()
if chr(x[0]) == "e":
break
print x
Another option is to write the following:
x = hex(int.from_bytes((ser.readline()), 'big'))
if x[2] == 'e':
break
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")
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"
I am writing a python script that will communicate to a Fluke meter over a COM port. I am able to receive the data but want to parse it into a usable float. The code looks like this:
import serial
ser = serial.Serial('COM3', 115200, timeout=1)
#Decalring some variables
FlukeID = b'ID\r'
FlukeQM = b'QM\r'
#Requesting the meters ID to verify connection on terminal
ser.writelines(FlukeID)
line = ser.readline()
print(line)
#Declaring variables for my while loop
thermdata = 0
t=1
ser.writelines(FlukeQM)
thermdata = ser.readline()
while(t < 5):
ser.writelines(FlukeQM)
#thermdata = (thermdata + ser.readline()) /2
thermdata = ser.readline()
print(thermdata)
t+=1
The data returned by the device looks like this on the console:
8.597E3,OHM,NORMAL,NONE INCORRECT
EDIT: The data actually appears like this over the terminal:
b'0\r8.597E3,OHM,NORMAL,NONE\r'
I just want to be able to use the numerical value at the beginning so I can do some calculations over time. I also need to be able to use the scientific notion portion in my number as I will not know the range of my measurements before hand. I know there must be a simple way to do this and would greatly appreciate any help.
On a side note, I would also like to be able to graph these values or place them into some kind of .csv file. If you have any comments on where to look to learn how to do this also that would be great, but I am mostly concerned with the handling of the bytearray.
Use split() to break your string into the comma separated parts. Then the first part is the string '8.597E3', which you convert using the float() function.
s = '8.597E3,OHM,NORMAL,NONE'.split(',')
value = float(s[0])
How about something like:
def atof(text):
try:
return float(text)
except ValueError:
return text
thermdata = b'0\r8.597E3,OHM,NORMAL,NONE\r'
for line in thermdata.strip().split(b'\r'):
print(list(map(atof, line.split(b','))))
# [0.0]
# [8597.0, b'OHM', b'NORMAL', b'NONE']