[Twisted-Python] serial communication - getting started
Hi, I am new to Python. Trying to figure out how to use the serial port I started with pyserial. Works - but the CPU usage on my Raspberry Pi is at about 30% just for reading the port. Before I started to optimize the code it was even 90+%. So I tried twisted - and boom down to 3-4%. Even though twisted also uses pyserial (as far as I read) - obviously better than I do. So far so good. With copy&paste from the internet and some editing I got the PI to read from my Arduino. (code below) But the code seems to be blocking. I tried putting things in a thread - but I must have done something wrong. It is still blocking. I also don't know how to write. Does s.write("test") work? Would be great if someone could help me out here. Thanks a lot. Robert import logging from twisted.protocols.basic import LineReceiver from twisted.protocols.basic import LineReceiver from twisted.internet import reactor from twisted.internet.serialport import SerialPort from twisted.python import usage import thread class THOptions(usage.Options): optParameters = [ ['baudrate', 'b', 115200, 'Serial baudrate'], ['port', 'p', '/dev/ttyACM0', 'Serial port to use'],] class Echo(LineReceiver): def processData(self, data): print(data) def lineReceived(self, line): try: data = line.rstrip() #logging.debug(data) self.processData(data) #print(line.rstrip()) #pass except ValueError: logging.error('Unable to parse data %s' % line) return def SerialInit(): o = THOptions() try: o.parseOptions() except usage.UsageError, errortext: logging.error('%s %s' % (sys.argv[0], errortext)) logging.info('Try %s --help for usage details' % sys.argv[0]) raise SystemExit, 1 baudrate = o.opts['baudrate'] #int('115200') port = o.opts['port'] logging.debug('About to open port %s' % port) s = SerialPort(Echo(), port, reactor, baudrate=baudrate) reactor.run() thread.start_new_thread(SerialInit()) if __name__ == '__main__': print("-----") s.write('123456789') #s.write("\n")
On 10/21/2013 07:35 AM, Robert Voigtländer wrote:
def SerialInit(): ... reactor.run()
thread.start_new_thread(SerialInit())
if __name__ == '__main__': print("-----") s.write('123456789') #s.write("\n")
1. Twisted is not thread-safe, so you can't call methods on the protocol from another thread. 2. As a result, you're probably best off not using threads at all. 3. A reasonable place for the write() might be in your Protocol's connectionMade method.
Thanks for the fast reply. I don't yet understand your answer. I may have to dig more into Python. On 21 October 2013 13:45, Itamar Turner-Trauring <itamar@itamarst.org>wrote:
On 10/21/2013 07:35 AM, Robert Voigtländer wrote:
def SerialInit(): ...
reactor.run()
thread.start_new_thread(SerialInit())
if __name__ == '__main__': print("-----") s.write('123456789') #s.write("\n")
1. Twisted is not thread-safe, so you can't call methods on the protocol from another thread.
2. As a result, you're probably best off not using threads at all.
3. A reasonable place for the write() might be in your Protocol's connectionMade method.
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Robert, as Itamar said: don't use thread -- you likely don't need them in your scenario. shameless self-plug: http://www.youtube.com/watch?v=va7j86thW5M https://github.com/tavendo/AutobahnPython/tree/master/examples/wamp/serial2w... The example includes both Arduino code and Twisted/Autobahn code .. communicating over serial. No locking. Everything async. Maybe thats of use while learning .. /Tobias Von: twisted-python-bounces@twistedmatrix.com [mailto:twisted-python-bounces@twistedmatrix.com] Im Auftrag von Robert Voigtländer Gesendet: Montag, 21. Oktober 2013 13:57 An: Twisted general discussion Betreff: Re: [Twisted-Python] serial communication - getting started Thanks for the fast reply. I don't yet understand your answer. I may have to dig more into Python. On 21 October 2013 13:45, Itamar Turner-Trauring <itamar@itamarst.org<mailto:itamar@itamarst.org>> wrote: On 10/21/2013 07:35 AM, Robert Voigtländer wrote: def SerialInit(): ... reactor.run() thread.start_new_thread(SerialInit()) if __name__ == '__main__': print("-----") s.write('123456789') #s.write("\n") 1. Twisted is not thread-safe, so you can't call methods on the protocol from another thread. 2. As a result, you're probably best off not using threads at all. 3. A reasonable place for the write() might be in your Protocol's connectionMade method. _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com<mailto:Twisted-Python@twistedmatrix.com> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Thanks a lot! I'll dig throught the code. On 21 October 2013 14:20, Tobias Oberstein <tobias.oberstein@tavendo.de>wrote:
Robert,****
** **
as Itamar said: don't use thread -- you likely don't need them in your scenario.****
** **
shameless self-plug:****
** **
http://www.youtube.com/watch?v=va7j86thW5M****
https://github.com/tavendo/AutobahnPython/tree/master/examples/wamp/serial2w... ****
** **
The example includes both Arduino code and Twisted/Autobahn code .. communicating over serial. No locking. Everything async.****
** **
Maybe thats of use while learning ..****
** **
/Tobias****
** **
** **
*Von:* twisted-python-bounces@twistedmatrix.com [mailto: twisted-python-bounces@twistedmatrix.com] *Im Auftrag von *Robert Voigtländer *Gesendet:* Montag, 21. Oktober 2013 13:57 *An:* Twisted general discussion *Betreff:* Re: [Twisted-Python] serial communication - getting started****
** **
Thanks for the fast reply.****
I don't yet understand your answer. I may have to dig more into Python.*** *
** **
** **
On 21 October 2013 13:45, Itamar Turner-Trauring <itamar@itamarst.org> wrote:****
On 10/21/2013 07:35 AM, Robert Voigtländer wrote:****
def SerialInit():****
...****
reactor.run() ****
** **
** **
thread.start_new_thread(SerialInit())****
** **
if __name__ == '__main__':****
print("-----")****
s.write('123456789')****
#s.write("\n")****
** **
1. Twisted is not thread-safe, so you can't call methods on the protocol from another thread.
2. As a result, you're probably best off not using threads at all.
3. A reasonable place for the write() might be in your Protocol's connectionMade method.****
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python****
** **
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
On Oct 21, 2013, at 6:57 AM, Robert Voigtländer wrote:
Thanks for the fast reply. I don't yet understand your answer. I may have to dig more into Python.
On 21 October 2013 13:45, Itamar Turner-Trauring <itamar@itamarst.org> wrote:
<snip guidance to avoid threads>
3. A reasonable place for the write() might be in your Protocol's connectionMade method.
The Protocol has access to a .transport attribute, which is the SerialPort() instance. Therefore, you can write to the serial port (the transport) from within your protocol: class Echo(LineReceiver): def connectionMade(self): self.transport.write('HELLO\n') def lineReceived(self, line): self.transport.write(line + '\n') The connectionMade method will be called once the transport (the SerialPort instance) is ready (the serial port is open), making it an appropriate place to kick off an init sequence or similar. Lucas
On 07:42 pm, ltaylor.volks@gmail.com wrote:
On Oct 21, 2013, at 6:57 AM, Robert Voigtländer wrote:
Thanks for the fast reply. I don't yet understand your answer. I may have to dig more into Python.
On 21 October 2013 13:45, Itamar Turner-Trauring <itamar@itamarst.org> wrote:
<snip guidance to avoid threads>
3. A reasonable place for the write() might be in your Protocol's connectionMade method.
The Protocol has access to a .transport attribute, which is the SerialPort() instance.
Therefore, you can write to the serial port (the transport) from within your protocol:
class Echo(LineReceiver):
def connectionMade(self): self.transport.write('HELLO\n')
def lineReceived(self, line): self.transport.write(line + '\n')
Additionally, since the serial transport tries hard to look just like a tcp transport or an ssl transport, the generic protocol code in LineReceiver.sendLine will work just fine with it. So in addition to using the `lineReceived` callback to handle lines that arrive you can use `sendLine` to write lines out to the serial port: class Echo(LineReceiver): delimiter = b"\n" def connectionMade(self): self.sendLine(b"HELLO") def lineReceived(self, line): self.sendLine(line) This is part of the power of the transport/protocol separation: reusable protocol logic. :) Jean-Paul
The connectionMade method will be called once the transport (the SerialPort instance) is ready (the serial port is open), making it an appropriate place to kick off an init sequence or similar.
Lucas
This works. Thanks a lot. So sending and receiving works .. with low CPU usage. I need to dig into twisted.... As a Python starter I want something like serial.send usabel in the main loop and serial.receive to work in the background and only trigger something once data has been received. Obviously it is possible with python. Just have to find out how :-) Thanks for the support so far. Robert On 21 October 2013 22:21, <exarkun@twistedmatrix.com> wrote:
On 07:42 pm, ltaylor.volks@gmail.com wrote:
On Oct 21, 2013, at 6:57 AM, Robert Voigtländer wrote:
Thanks for the fast reply. I don't yet understand your answer. I may have to dig more into Python.
On 21 October 2013 13:45, Itamar Turner-Trauring <itamar@itamarst.org> wrote:
<snip guidance to avoid threads>
3. A reasonable place for the write() might be in your Protocol's connectionMade method.
The Protocol has access to a .transport attribute, which is the SerialPort() instance.
Therefore, you can write to the serial port (the transport) from within your protocol:
class Echo(LineReceiver):
def connectionMade(self): self.transport.write('HELLO\n'**)
def lineReceived(self, line): self.transport.write(line + '\n')
Additionally, since the serial transport tries hard to look just like a tcp transport or an ssl transport, the generic protocol code in LineReceiver.sendLine will work just fine with it. So in addition to using the `lineReceived` callback to handle lines that arrive you can use `sendLine` to write lines out to the serial port:
class Echo(LineReceiver): delimiter = b"\n"
def connectionMade(self): self.sendLine(b"HELLO")
def lineReceived(self, line): self.sendLine(line)
This is part of the power of the transport/protocol separation: reusable protocol logic. :)
Jean-Paul
The connectionMade method will be called once the transport (the SerialPort instance) is ready (the serial port is open), making it an appropriate place to kick off an init sequence or similar.
Lucas
______________________________**_________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.**com <Twisted-Python@twistedmatrix.com> http://twistedmatrix.com/cgi-**bin/mailman/listinfo/twisted-**python<http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python>
participants (5)
-
exarkun@twistedmatrix.com
-
Itamar Turner-Trauring
-
Lucas Taylor
-
Robert Voigtländer
-
Tobias Oberstein