0

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.

asked Sep 27, 2016 at 8:55

2 Answers 2

2

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.

N.B. 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()
answered Sep 27, 2016 at 12:34
Sign up to request clarification or add additional context in comments.

Comments

1

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.

answered Sep 27, 2016 at 11:39

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.