I used win7 before to read the GPS data from the com port. From now on I would like to read the data under Ubuntu but the same code is not working. Here is my code:
import serial, sys, time, threading
from datetime import datetime, timedelta
class MeasureModule():
def __init__(self, port, baudrate, sync_time=0, sync_nr=0):
self.port = port;
self.baudrate = baudrate;
def start(self):
try:
self.serial = serial.serial_for_url(self.port, self.baudrate, timeout=1)
except AttributeError:
self.serial = serial.Serial(self.port, self.baudrate, timeout=1)
start = time.clock()
while(time.clock()-start<11):
data = self.readline()
print(data)
self.stop();
def stop(self):
self.serial.close()
def readline(self, timeout=1, endline='\n'):
buff='';
try:
tic = time.clock()
ch = self.character(self.serial.read(1))
# you can use if not ('\n' in buff) too if you don't like re
while ((time.clock() - tic) < timeout) and (not ch in endline):
buff += ch
ch = self.character(self.serial.read(1))
except serial.SerialException, e:
return buff
return buff
def character(self,b):
if sys.version_info >= (3, 0):
return b.decode('latin1')
else:
return b
I called the function in the following way:
for i in range (0,4):
try:
print "Starting measurement /dev/ttyACM%d" % i
gs = GPSModule('/dev/ttyACM%d' % i, 4800, 1, 1)
gs.start()
except:
print "Unable to connect"
run#FXR:/dev$ dmesg | grep tty
[ 0.000000] console [tty0] enabled
[ 4.764464] cdc_acm 2-1.6:1.1: ttyACM0: USB ACM device
[ 4.767620] cdc_acm 2-1.6:1.3: ttyACM1: USB ACM device
[ 4.771525] cdc_acm 2-1.6:1.9: ttyACM2: USB ACM device
[ 4.808622] usb 2-1.4.4: pl2303 converter now attached to ttyUSB0
But I'm not receiving anything.
How can I do the same things under Ubuntu? How can I read the GPS data from com port?
Ok!
This code is VEEERY Ugly and Old I did that in 2006 I was a beginner and naive.
Now baby steps!
Use the command dmesg or check your console messages to know WHICH USB device is attached your GPS. In MY CASE was USB0
After that play with this code
import serial
import socket
ser = serial.Serial('/dev/ttyUSB0', 4800, timeout=1)
latitude = ''
longitude = ''
def readgps(latitude,longitude):
"""Read the GPG LINE using the NMEA standard"""
while True:
line = ser.readline()
if "GPGGA" in line:
latitude = line[18:26] #Yes it is positional info for lattitude
longitude = line[31:39] #do it again
return(latitude,longitude)
print "Finished"
Sure you have to call the function ;) please do not forget.
Remeber the gps is always sending data and communicating.
For educational purposes do a :
print line after ser.readline()
so you can see the whole data not only lat and long coordinates.
Remeber the USB GPS is just a fancy serial device ;)
This code is very simple and I am sure you will understand and make WAY better code/programs.
You don't open /dev/ttyUSB0 with your program. How is your GPS module plugged ?
What happens if you do :
stty -F /dev/ttyACM0 4800
cat /dev/ttyACM0
in a console ?
You probably have to add yourself to the group that the gps is under. This is posted really late, but I recently tried to configure a usb gps puck on linux, and I had to do sudo adduser -aG USERMAME dialout in the terminal. This just adds the user to the group (dialout) which the gps is under. If you don't know the group, cd to /dev (in terminal) and type ll (or ls -Flh if that doesn't work) This will diplay all of the permissions and groups. There is one column that is of particular interest; this is one of the last columns (I think third to last -- sorry, I'm on Windows right now), and you might see about six or seven items in the list called "dialout". If your file -- your usb -- shows up there, then that is the group. Otherwise, just look for the group and sudo adduser... yourself.
Be sure you log out first, and then -- after logging back in -- go to the terminal again and type cat /dev/ttyACM0. If you still see nothing, then you need to configure and tell it the correct rate at which to dump its info (the baud rate); so, type (as someone else mentioned) stty -F /dev/ttyACM0 4800 which configures the baud rate to 4800. You should google the correct baud rate, but the last command essentially says, take this file (-F) and speak to me at this rate (4800).
I hope this helps someone because I certainly had some trouble getting my usb gps puck to work on linux-mint. Good luck to all linux users (I'm a recent convert). :D
Related
I'm working on a script to send a list of commands to a device and return the output.
When the device first boots up, it has a few prompts. I am able to get through the prompts.
However, after completing the prompts, when I try to send a command the command isn't sent.
Commands
The commands.txt is set up like this:
200,
2,no
2,
The first line (200) is to let the device boot up.
The 2nd and 3rd lines answer 2 different prompts.
Issues
The issues come after these 3 inputs. The code runs and completes. Python prints out each of the commands. So the list is processed by Python. However, I don't think the device is receiving the commands.
In the log, the \n and no are written out, but none of the commands after it are. The commands do show when I use ser.inWaiting()
When I access the device through putty and run the commands through the console, everything works as expected.
Why aren't the commands going through?
Small update:
I read somewhere that python may be sending the commands to quickly, so I tried sending the commands 1 char at a time with a .01 delay.
It still didn't work:
for i in lines[1]:
cmd = i
encoded_cmd = cmd.encode("utf-8")
ser.write(encoded_cmd)
sleep(0.1)
print(cmd)
Code
import serial
import time
from time import sleep
from datetime import datetime
# create list of commands
with open('commands.txt') as commands:
list_of_commands = [tuple(map(str, i.split(','))) for i in commands]
# open and name log file
date = datetime.now().strftime("%Y-%m-%d")
log = open(f'{date}.txt', 'w+')
# serial configuration
info = open('info.txt', 'r')
lines = info.readlines()
port = lines[0].strip('\n')
baud = int(lines[1].strip('\n'))
try:
# open port
ser = serial.Serial(port=port, baudrate=baud, timeout=5, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, write_timeout=0)
except ConnectionError:
log.write(''.join('There was a connection error'))
else:
# run commands
x = 0
for lines in list_of_commands:
ser.close()
ser.open()
sleep(2)
cmd = lines[1]
encoded_cmd = cmd.encode("utf-8")
sleep_time = int(lines[0])
ser.write(encoded_cmd)
time.perf_counter()
# log output
while 1:
test = ser.readline()
text = test.decode('utf-8')
print(text)
log.write(''.join(text))
print(time.perf_counter())
print(time.perf_counter() - x)
if time.perf_counter() - x > sleep_time:
x = time.perf_counter()
ser.flushInput()
ser.flushOutput()
break
print(cmd)
# close port
ser.close()
# close files
log.close()
From the question it's obvious that multiple issues are intermingled. The same observation comes when reading the code. So I tried to list some of those I struggled with.
Issues
Try-except-else
What is the intention behind try .. except .. else ?
Not sure, its used correctly on purpose here. See try-except-else explained:
The else clause is executed if and only if no exception is raised. This is different from the finally clause that’s always executed.
The serial connection
Why opening and closing inside the loop:
ser.close()
ser.open()
Why the misleading comment:
# close server
ser.close()
Usage of sleep_time
What is the purpose of using the first column sleep_time of your CSV commands.txt inside a conditional break inside you read-loop?
sleep_time = int(lines[0])
Instead the sleep is fix 2 seconds before sending the command:
sleep(2)
How to debug
I would recommend adding some print (or log) statements to
verify the list_of_commands has been read correctly
verify which commands (cmd or even encoded_cmd) have been sent to the serial output
I am trying to communicate with a microcontroller through a serial port.
For example, I write 7 to the microcontroller and I read a series of (47) numbers back, I then send 7 to it again and I read the same numbers back. I can keep going like this.
I have tried using Matlab and I can finish what I want to write and read from serial port very well. However, when I turn to use Spyder 3, under Win10, I can only write and read once. As I mentioned, if I write 7 and I can get 47 numbers back, but after that when I send 7 I can not get anything back and I need to re-plug serial port. My code is shown below. Thank you.
import serial
import time
"""Cmd definition"""
cmd_readreg = [7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
regNo = 47
""" setup serial """
with serial.Serial() as ser:
#ser = serial.Serial()
ser.port = 'COM8'
ser.bandrate = 19200
""" open serial """
ser.open()
if ser.is_open:
print ("Device connected.")
else:
print ("Check device connection.")
""" send read register cmd to serial, cmd = 7 """
ser.write(cmd_readreg)
time.sleep(.1)
#print (ser.BYTESIZES)
""" read from serial"""
if ser.readable():
reg1 = ser.read(size=regNo)
print (reg1)
else:
print ("no readable data")
""" send read register cmd to serial, cmd = 7 """
ser.write(cmd_readreg)
time.sleep(.1)
#print (ser.BYTESIZES)
""" read from serial"""
if ser.readable():
reg2 = ser.read(size=regNo)
print (reg2)
else:
print ("no readable data")
I am reading serial data on my Raspberry Pi with the console:
stty -F /dev/ttyUSB0 1:0:9a7:0:3:1c:7f:15:4:5:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
cat < /dev/ttyUSB0 &
echo -n -e '\x2F\x3F\x21\x0D\x0A' > /dev/ttyUSB0
And I am getting data line for line:
/ISk5MT174-0001
0.9.1(210832)
0.9.2(1160808)
0.0.0(00339226)
0.2.0(1.03)
C.1.6(FDF5)
1.8.1(0004250.946*kWh)
1.8.2(0003664.811*kWh)
2.8.1(0004897.813*kWh)
2.8.2(0000397.465*kWh)
F.F.0(0000000)
!
Now I am trying to do this with python:
import serial
SERIALPORT = "/dev/ttyUSB0"
BAUDRATE = 300
ser = serial.Serial(SERIALPORT, BAUDRATE)
print("write data")
ser.write("\x2F\x3F\x21\x0D\x0A")
time.sleep(0.5)
numberOfLine = 0
while True:
response = ser.readline()
print("read data: " + response)
numberOfLine = numberOfLine + 1
if (numberOfLine >= 5):
break
ser.close()
But I only get "write data" and no response from my USB0 device.
Any suggestions?
Kind Regards
I'm guessing your device is the same as discussed here:
https://www.loxforum.com/forum/faqs-tutorials-howto-s/3121-mini-howto-z%C3%A4hlerauslesung-iskra-mt174-mit-ir-schreib-lesekopf-und-raspberry
If so, you need to know that by default, pySerial opens ports with 8 databits and no parity.
(see: https://pythonhosted.org/pyserial/pyserial_api.html -> __init__)
So, at the very least you want to:
ser = serial.Serial(SERIALPORT, BAUDRATE, SEVENBITS, PARITY_EVEN)
Perhaps you also need to set other flags, but I don't read stty :)
To see what that string of numbers means, run the first stty command and then run:
stty -F /dev/ttyUSB0 -a
It'll output the settings in human readable form, that might bring you closer to a solution.
Good luck!
When I run this script in terminal I can receive data serially, but eventually my entire computer freezes up. Could someone explain why this is happening?
#!/usr/bin/env python
from sys import argv
from msppg import Parser
import serial
if len(argv) < 2:
print('Usage: python %s PORT' % argv[0])
print('Example: python %s /dev/ttyUSB0' % argv[0])
exit(1)
def handler(pitch, roll, yaw):
print(pitch, roll, yaw)
port.write(request)
pitch, roll, yaw = 5, 15, 20
port = serial.Serial(argv[1])
parser = Parser()
request = parser.serialize_ATTITUDE_Request()
parser.set_ATTITUDE_Handler(handler)
def cycle(value):
return (value + 1) %360
while True:
print port.read(1)
if port.read(1) != None:
port.write(parser.serialize_ATTITUDE(pitch, roll, yaw))
pitch = cycle(pitch)
roll = cycle(roll)
yaw = cycle(yaw)
Could someone explain why this is happening?
while True: without a break.
It looks like the app is trying to read from a physical port and your while loop is constantly reading. This behavior will look up your computer as there are no waits or callbacks for reading the data.
Your issue is with the port.read(1) line. According to PySerial's Documentation you're specifying that you only want one byte to be read from the USART hardware buffer. However, if there isn't a byte to be read PySerial by default will wait for some data, causing your program to "freeze".
My suggestion is to add a timeout arg to the port init line (where 12 means 12 seconds, it can be anything you want)
port = serial.Serial(argv[1], timeout=12)
I'm using Windows Vista and Python 2.7.2, but answers needn't be in Python.
So I can start and interact with a subprocesses stdin/stdout normally (using python), for command-line programs such as `dir'.
- however -
the program I now want to call likes to make a new console window for itself on Windows (not curses), with new handles, even when run from a pre-existing cmd.exe window. (Odd, as it's the "remote control" interface of VLC.) Is there any way of either:
getting the handles for the process-made console's stdin/out; or
getting the new shell to run within the old (like invoking bash from within bash)?
Failing that, so that I can hack the subprocesses' code, how would a new console be set up in Windows and in/output transferred?
Edit:
I.e.
>>> p = Popen(args=['vlc','-I','rc'],stdin=PIPE,stdout=PIPE)
# [New console appears with text, asking for commands]
>>> p.stdin.write("quit\r\n")
Traceback:
File "<stdin>", line 1, in <module>
IOError: [Errno 22] Invalid argument
>>> p.stdout.readline()
''
>>> p.stdout.readline()
''
# [...]
But the new console window that comes up doesn't accept keyboard input either.
Whereas normally:
>>> p = Popen(args=['cmd'],stdin=PIPE,stdout=PIPE)
>>> p.stdin.write("dir\r\n")
>>> p.stdin.flush()
>>> p.stdout.readline() #Don't just do this IRL, may block.
'Microsoft Windows [Version...
I haven't gotten the rc interface to work with a piped stdin/stdout on Windows; I get IOError at all attempts to communicate or write directly to stdin. There's an option --rc-fake-tty that lets the rc interface be scripted on Linux, but it's not available in Windows -- at least not in my somewhat dated version of VLC (1.1.4). Using the socket interface, on the other hand, seems to work fine.
The structure assigned to the startupinfo option -- and used by the Win32 CreateProcess function -- can be configured to hide a process window. However, for the VLC rc console, I think it's simpler to use the existing --rc-quiet option. In general, here's how to configure startupinfo to hide a process window:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.Popen(cmd, startupinfo=startupinfo)
Just to be complete -- in case using pipes is failing on your system too -- here's a little demo I cooked up using the --rc-host option to communicate using a socket. It also uses --rc-quiet to hide the console. This just prints the help and quits. I haven't tested anything else. I checked that it works in Python versions 2.7.2 and 3.2.2. (I know you didn't ask for this, but maybe it will be useful to you nonetheless.)
import socket
import subprocess
from select import select
try:
import winreg
except ImportError:
import _winreg as winreg
def _get_vlc_path():
views = [(winreg.HKEY_CURRENT_USER, 0),
(winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_64KEY),
(winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_32KEY)]
subkey = r'Software\VideoLAN\VLC'
access = winreg.KEY_QUERY_VALUE
for hroot, flag in views:
try:
with winreg.OpenKey(hroot, subkey, 0, access | flag) as hkey:
value, type_id = winreg.QueryValueEx(hkey, None)
if type_id == winreg.REG_SZ:
return value
except WindowsError:
pass
raise SystemExit("Error: VLC not found.")
g_vlc_path = _get_vlc_path()
def send_command(sock, cmd, get_result=False):
try:
cmd = (cmd + '\n').encode('ascii')
except AttributeError:
cmd += b'\n'
sent = total = sock.send(cmd)
while total < len(cmd):
sent = sock.send(cmd[total:])
if sent == 0:
raise socket.error('Socket connection broken.')
total += sent
if get_result:
return receive_result(sock)
def receive_result(sock):
data = bytearray()
sock.setblocking(0)
while select([sock], [], [], 1.0)[0]:
chunk = sock.recv(1024)
if chunk == b'':
raise socket.error('Socket connection broken.')
data.extend(chunk)
sock.setblocking(1)
return data.decode('utf-8')
def main(address, port):
import time
rc_host = '{0}:{1}'.format(address, port)
vlc = subprocess.Popen([g_vlc_path, '-I', 'rc', '--rc-host', rc_host,
'--rc-quiet'])
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((address, port))
help_msg = send_command(sock, 'help', True)
print(help_msg)
send_command(sock, 'quit')
except socket.error as e:
exit("Error: " + e.args[0])
finally:
sock.close()
time.sleep(0.5)
if vlc.poll() is None:
vlc.terminate()
if __name__ == '__main__':
main('localhost', 12345)
With reference to monitoring the stdOut which appears in the new Spawned Console Window.
Here´s another question/answer that solves the problem.
In summary (as answered by Adam M-W ):
Suppress the new spawned console by launching vlc in quiet mode --intf=dummy --dummy-quiet or --intf=rc --rc-quiet.
Monitor stdErr of launched process
Note: As for stdIn commands for the rc interface, the --rc-host solution is described by eryksun´s answer