py-serial + CSV

M

McBooCzech

Hi
I am just trying to analyze (parse) data from the serial port (I have
connected GPS receiver to the ttyS0, so I can read ASCII characters in
the CSV form on the serial port 1).
I am doing this just to understand how Python works (yes, you can call
me Python/Linux newbie :)
My environment is Fedora Core 4, Python 2.4.1

CSV alone (to read CSV data from the file) and py-serial alone (to
read data from the serial port) are working flawlessly.

Even I was trying to google through this group and through the
Internet, I am not able to read (and parse) CSV data directly from the
serial port.

data from my serial port (using py-serial) I am getting this way:
'$GPRMC,101236.331,A,5026.1018,N,01521.6653,E,0.0,328.1,230805,,*09\r\n'

my next intention was to do something like this:

import csv
r = csv.reader(s.readline())
for currentline in r:
if currentline[0] == '$GPRMC':
print currentline[2]
print currentline[4]

but it does not work

Thanks for your comments

Petr Jakes
 
M

McBooCzech

So do I have to save to the file first and analyze later on?

Or there is an other way how to process it (read from the serial and
analyze data) on the fly?

Petr Jakes
 
M

Michael Hoffman

McBooCzech said:
So do I have to save to the file first and analyze later on?

Certainly not.
Or there is an other way how to process it (read from the serial and
analyze data) on the fly?

I've never used py-serial, so I was hoping someone else would jump in
with the best way to do this (or perhaps you can find it in the
documentation). One way would be to use the iter() built-in to make it
into an iterable, like this:

iterable = iter(s.readline, "")

Note that you do not call s.readline() here; you are only supplying the
bound method itself as an argument. iter() will call it later. I'm
assuming that s.readline returns an empty string when there is no more
input. Please replace that with whatever end sentinel it actually uses.
(None?)

Another way would be to use s.readlines(), which returns a list, which
is iterable, but you would have to wait until the entire list were
collected before beginning processing.
 
G

Grant Edwards

'$GPRMC,101236.331,A,5026.1018,N,01521.6653,E,0.0,328.1,230805,,*09\r\n'

my next intention was to do something like this:

import csv
r = csv.reader(s.readline())
for currentline in r:
if currentline[0] == '$GPRMC':
print currentline[2]
print currentline[4]

but it does not work

For something that simple (the data itself doesn't contain any
commas), it's probably easier to use the string's split method
rahter than CSV. Try something like this:

line = s.readline()
words = line.split(',')
 
D

Dennis Lee Bieber

Note that you do not call s.readline() here; you are only supplying the
bound method itself as an argument. iter() will call it later. I'm
assuming that s.readline returns an empty string when there is no more
input. Please replace that with whatever end sentinel it actually uses.
(None?)

Another way would be to use s.readlines(), which returns a list, which
is iterable, but you would have to wait until the entire list were
collected before beginning processing.

The latter wouldn't work in this situation -- as the only way to end
the list is to disconnect the serial port <G>

Most GPS receivers, when set to send the messages, will do so at a
rate of one message every 1 or 2 seconds, as I recall.
--
 
M

McBooCzech

Sorry, I did not mentioned the data flow from the serial port is
permanent/continuous (as long as the GPS receiver is connected to the
serial port). The input data are commning every second, they are comma
separated and they are looking like:

$GPGGA,174525.617,5026.1080,N,01521.6724,E,1,05,1.8,306.5,M,,,,0000*0B
$GPGSA,A,3,02,09,05,06,14,,,,,,,,3.6,1.8,3.1*31
$GPGSV,3,1,09,30,74,294,,05,65,093,49,06,40,223,32,02,39,089,49*78
$GPRMC,174525.617,A,5026.1080,N,01521.6724,E,0.0,005.8,230805,,*0A
etc....
From the rows they are begining with $GPRMC I want to get following
data only (positions 2,4,6)
174525.617
5026.1080
01521.672

This (according to your suggestions) is my code which works for me

import serial
s = serial.Serial(port=0,baudrate=4800, timeout=20)
while 1:
line = s.readline()
words = line.split(',')
if words[0]=="$GPRMC":
print words[1], words[3], words[5]

I just wonder if there is some beter (or as you are saying "more
pythonic":) aproach how to write such a piece of code.
 
S

Steve Holden

McBooCzech said:
Sorry, I did not mentioned the data flow from the serial port is
permanent/continuous (as long as the GPS receiver is connected to the
serial port). The input data are commning every second, they are comma
separated and they are looking like:

$GPGGA,174525.617,5026.1080,N,01521.6724,E,1,05,1.8,306.5,M,,,,0000*0B
$GPGSA,A,3,02,09,05,06,14,,,,,,,,3.6,1.8,3.1*31
$GPGSV,3,1,09,30,74,294,,05,65,093,49,06,40,223,32,02,39,089,49*78
$GPRMC,174525.617,A,5026.1080,N,01521.6724,E,0.0,005.8,230805,,*0A
etc....
From the rows they are begining with $GPRMC I want to get following
data only (positions 2,4,6)
174525.617
5026.1080
01521.672

This (according to your suggestions) is my code which works for me

import serial
s = serial.Serial(port=0,baudrate=4800, timeout=20)
while 1:
line = s.readline()
words = line.split(',')
if words[0]=="$GPRMC":
print words[1], words[3], words[5]

I just wonder if there is some beter (or as you are saying "more
pythonic":) aproach how to write such a piece of code.

That code is quite tidy. You could save yourself the split on lines that
weren't of interest, though frankly this isn't essential - this task
won't use 1% of CPU on almost any computer built in the last five years.
But, if you are interested in seeing other solutions you might consider
it, and it does avoid the split when it's not necessary.

while 1:
line = s.readline()
if line.startswith("$GPRMC"):
words = line.split(",")
print words[1], words[3], words[5]

regards
Steve
 
S

Sergei Organov

Steve Holden said:
McBooCzech wrote: [...]
$GPRMC,174525.617,A,5026.1080,N,01521.6724,E,0.0,005.8,230805,,*0A
etc....
[...]
s = serial.Serial(port=0,baudrate=4800, timeout=20)
while 1:
line = s.readline()
words = line.split(',')
if words[0]=="$GPRMC":
print words[1], words[3], words[5]
I just wonder if there is some beter (or as you are saying "more
pythonic":) aproach how to write such a piece of code.

That code is quite tidy. You could save yourself the split on lines
that weren't of interest, though frankly this isn't essential - this
task won't use 1% of CPU on almost any computer built in the last five
years. But, if you are interested in seeing other solutions you might
consider it, and it does avoid the split when it's not necessary.


while 1:
line = s.readline()
if line.startswith("$GPRMC"):

"$GPRMC," would be better, -- not to match something like "$GPRMC174...".
 
M

McBooCzech

Sergei, I do not realy understand your comment??? Am I missing
something?

BTW, is there some possibility to address lists like:

print words [1; 3; 5]
instead of
print words[1], words[3], words[5]

Petr Jakes
 
D

Dennis Lee Bieber

Sergei, I do not realy understand your comment??? Am I missing
something?

BTW, is there some possibility to address lists like:

print words [1; 3; 5]
instead of
print words[1], words[3], words[5]

Mix & Matching from two messages <G>

2>$GPRMC,174525.617,A,5026.1080,N,01521.6724,E,0.0,005.8,230805,,*0A
2>etc....
2>
2>>From the rows they are begining with $GPRMC I want to get following
2>data only (positions 2,4,6)
2>174525.617
2>5026.1080
2>01521.672
2>
Interesting that you don't want to handle conditions crossing
Greenwich/dateline, or equator (since you ignore the N/S, E/W tags.

2>This (according to your suggestions) is my code which works for me
2>
2>import serial
2>s = serial.Serial(port=0,baudrate=4800, timeout=20)
2>while 1:
2> line = s.readline()
2> words = line.split(',')
2> if words[0]=="$GPRMC":
2> print words[1], words[3], words[5]

Well... Let's see

#open port, etc...
while True:
line = s.readline()
if line.startswith("$GPRMC"):
(msg, timestamp, junk,
raw_latitude, NS_indicator,
raw_longitude) = line.split(",")[:6]
print timestamp, raw_latitude, raw_longitude

.... raw_latitude, NS_indicator,
.... raw_longitude) = line.split(",")[:6]
 
S

Sybren Stuvel

McBooCzech enlightened us with:
This (according to your suggestions) is my code which works for me

import serial
s = serial.Serial(port=0,baudrate=4800, timeout=20)
while 1:
line = s.readline()
words = line.split(',')
if words[0]=="$GPRMC":
print words[1], words[3], words[5]

I just wonder if there is some beter (or as you are saying "more
pythonic":) aproach how to write such a piece of code.

You could use regular expressions instead. And to make it even more
pythonic, replace the "while" and the "line = s.readline()" with
"for line in s:"

Sybren
 
G

Grant Edwards

import serial
s = serial.Serial(port=0,baudrate=4800, timeout=20)
while 1:
line = s.readline()
words = line.split(',')
if words[0]=="$GPRMC":
print words[1], words[3], words[5]

I just wonder if there is some beter (or as you are saying "more
pythonic":) aproach how to write such a piece of code.

You could use regular expressions instead.

"There is a programmer who has a problem to solve. He decides
to use regular expressions. Now he has two problems."
And to make it even more pythonic, replace the "while" and the
"line = s.readline()" with "for line in s:"

Serial port objects aren't iterable.
 
M

Michael Hoffman

McBooCzech said:
This (according to your suggestions) is my code which works for me

import serial
s = serial.Serial(port=0,baudrate=4800, timeout=20)
while 1:
line = s.readline()
words = line.split(',')
if words[0]=="$GPRMC":
print words[1], words[3], words[5]

I just wonder if there is some beter (or as you are saying "more
pythonic":) aproach how to write such a piece of code.

import csv

from serial import Serial

port = Serial(port=0, baudrate=4800, timeout=20)

for row in csv.reader(iter(port.readline, None)):
if row[0] == "$GPMRC":
print row[1], row[3], row[5]
 
M

McBooCzech

Thanks you all, guys, for your suggestions and help. Everything now
works great :)
Regards
Petr Jakes
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,266
Messages
2,571,318
Members
47,998
Latest member
GretaCjy4

Latest Threads

Top