简体   繁体   中英

python read multiple serial ports

I am trying to read from multiple serial ports in python. But contrary to this thread I want to be able to change the number of ports dynamically (reading it via command line option).

My idea was to put the ports into a file "ports", read this file and put the opened serial ports into a list, according to the number of lines in "ports". My minimal example:

import numpy as np
import serial

p = np.genfromtxt('ports',delimiter=',',dtype=None)
nser = p.size

ser = [serial.Serial(port=p[i][0], baudrate=p[i][1]) for i in xrange(nser)]

"ports" looks the following (at the moment):

'/dev/ttyUSB0',4800

The error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: 0-d arrays can't be indexed

Apparently the file is not correctly read to an array, and I already tried various different methods and ways (using pythons own methods or np.loadtxt).

Does anybody have an idea how to a) read the file correctly and b) solve the multiple port issue in a useful way? Thanks in advance.

Your config file format is very simple and can easily be parsed without numpy. You can use simple string splitting to load each port definition.

serial_ports = []
with open('ports') as f:
    for line in f:
        port, baud = line.split(',')
        serial_ports.append(serial.Serial(port, int(baud)))

Or you could use the csv module:

import csv

with open('ports') as f:
    serial_ports = [serial.Serial(port, int(baud)) for port, baud in csv.reader(f)]

The second part of your question is more difficult because you haven't provided many details about how the serial port readers will process the data received over the ports.

If the application is I/O bound, which is most likely the case, you can asynchronously check when a serial port has some data to read, then read it as required. That can be done with the select() module, or if you're using Python >= 3.4, the selectors module. You do not require multiple processes to do this.

If the application is CPU bound then you could use mutiprocessing.Process() or subprocess.Popen() . Instead of opening the serial ports in the parent, pass the serial port parameters to the child as arguments/command line arguments to the child function/process and let the child open the port, processes the data, and close the port.

NB Untested - don't know if this will work with a serial port . If you must open the ports in the parent, hook the stdin of the subprocess up to the serial port. You'll need to be careful with this as it's easy to deadlock processes where the parent and child are are mutually blocked on each other.

from subprocess import Popen, PIPE

s = serial.Serial(port, baud)
p = Popen(['python', 'port_reader.py'], stdin=s, stdout=PIPE, stderr=PIPE)
p.communicate()

If using multiprocessing you can pass the open serial port to the child as an argument. This might work... ?

from multiprocessing import Process

def child(port):
    while True:
        line = port.readline()
        if not line:
            break
        print('child(): read line: {!r}'.format(line))

port = serial.Serial(port, baud)
p = Process(target=child, args=(port,))
p.start()
p.join()

I didn't quite clearly understood what you are trying to do, but if I had a file like:

'/dev/ttyUSB0',4800
'/dev/ttyUSB1',4801,'/dev/ttyUSB3',4803

and want to read it and store as a list, a way to go would be:

with open('ports.txt') as f:
    lines = f.read().replace('\n', ',')
print lines 

which will give you:

>>> lines
'/dev/ttyUSB0',4800,'/dev/ttyUSB1',4801,'/dev/ttyUSB3',4803

and if you want to split the integers, you could do:

>>> l1 = [lines.pop(i) for i,j in enumerate(lines) if type(j)==int ]
>>> l1
[4800, 4801, 4803]
>>> lines
['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB3']

Now because you said that 'np.loadtxt' didn't work, a way to convert a python list to a numpy-array is:

>>> lines = ['/dev/ttyUSB0',4800,'/dev/ttyUSB1',4801,'/dev/ttyUSB3',4803]
>>>
>>> import numpy as np
>>> np.asarray(lines)
array(['/dev/ttyUSB0', '4800', '/dev/ttyUSB1', '4801', '/dev/ttyUSB3',
       '4803'],
      dtype='|S12')

But again I am not sure If that is what you are looking for.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM