Serial connections and threads in a GUI

2009-09-29 Thread Aaron Hoover
I have a wx-based GUI application that I'd like to have read  
"streaming" data from a serial port and plot that data using  
matplotlib and a figure canvas. It's a robotic application where the  
workflow goes something like this:


1) Connect to robot
2) Configure robot settings
3) Command robot to do something for time, t
- While robot does something, read sensor data and plot
4) End of t seconds, resume at (2)

I have the application reading from the serial port in a separate  
thread, but my problem is this - I'd like the user to be able to write  
to the serial port by interacting with the GUI between runs. However,  
the infinite loop running inside the thread responsible for receiving  
data has exclusive access to the serial connection object.


Because of how the application works, I know that I won't need to  
write to the serial port when I'm in the middle of receiving data, so  
that simplifies things somewhat. But, how can I allow the thread  
access to the connection for reading, but then have it give up control  
over the connection when it's done so the main GUI thread can access  
the connection again for writing?


Currently, I have the thread's run() method exit when it's done  
receiving data. But, that means that I can only receive data again  
using the same thread by calling run(), blocking the main GUI thread  
from updating the plot until it completes.


This is my first go at using threads in Python, so I'm sure there's a  
straightforward way to do this that I'm just missing. At any rate,  
thanks in advance for your patience and assistance.



Thanks,
Aaron
--
http://mail.python.org/mailman/listinfo/python-list


Threaded GUI slowing method execution?

2009-10-01 Thread Aaron Hoover
I have a wx GUI application that connects to a serial port in a  
separate thread, reads from the port, and then is supposed to put the  
data it finds into a queue to be used by the main GUI thread.  
Generally speaking, it's working as expected.


However, one method (that's part of a library I've written to parse  
the packet structure of the data that's coming over the serial port)  
executes approximately 1000 times slower (50ms vs. 50us) when called  
from the serial management thread in the GUI as compared to calling  
the same function from within a command line Python script. I checked  
it by wrapping the call as follows in both cases  (GUI and command  
line script):


tic = time.time()

print time.time() - tic

All the thread is doing most of the time is sitting around checking  
the serial port for waiting data, reading it, and appending it to a  
list when it finds it. Then, in the same thread, the method that seems  
to be remarkably slow works its way through that list looking for  
packets of data and appending the packet payloads it finds to a queue  
to be handled in some way by the GUI.


My question is, what am I missing about either threading or the fact  
that this is running in a GUI that might explain such a huge slowdown.  
I'm sending data over the serial at a true rate of about 24k bytes per  
second, or approximately 2 packets per ms. Is it too much to ask to be  
able to process this data in realtime from within a GUI (I'm not  
talking about plotting or anything - just read it and find packets)?  
Like I said, the process pretty much runs in realtime from a command  
line script.


This packet parsing needs to happen continuously, so it seems calling  
join() to ensure it's not interrupted by the GUI thread, won't work.


Thanks in advance for your help.

Aaron
--
http://mail.python.org/mailman/listinfo/python-list


Re: Threaded GUI slowing method execution?

2009-10-02 Thread Aaron Hoover


On Oct 2, 2009, at 12:30 PM, Dave Angel wrote:

(you responded off-list, which isn't the way these mailing lists  
work.  So I'm pasting your message back to the list, with my  
response at the end)




Sorry about that - a slip of the "reply" button.



Actually, I was thinking of the subprocess module (introduced in  
2.4).  But the multiprocessing module would be useful if you were  
porting threading code to a process model.


Previously, I had been using threads, so I just tried moving to  
multiprocessing because it required few changes.


There are tons of ways to communicate between processes, though you  
can't do the simple variable sharing that threads can (sometimes)  
get away with.  I would normally point you to queues, but there a  
number of possibilities.  And since the one process is running a GUI  
event loop, you might want to piggyback on the OS capability to post  
events between processes.  The code might end up OS-dependent, but  
I'd bet the overhead will be minimal.  What is your target operating  
system?


My target OS is Mac OS X Leopard. I've decided just to try and trigger  
WX events in the GUI based on data put in one of the queues by the  
processing thread.




Your numbers in the original message make me nervous;  sending an  
event between processes (or even threads) every 0.5 millisecond is  
impossible.  But I think you might have been confusing bytes and  
packets.


My external hardware is actually sending 2000 packets per second right  
now (but that can also be changed). Each packet currently contains 6  
bytes of data and 6 bytes of overhead. So, 12 bytes per packet * 2000  
packets per second is 24k bytes per second. However, the serial  
processing process should be finding the packet payload data and  
adding to a queue for the GUI to deal with and plot (obviously at a  
much lower framerate) (at an ideal rate of 2KHz).




There could very well be multiprocess support in wxPython.  I'd  
check there first, before re-inventing the wheel.  Presumably you  
know of the wxPython news group, hosted on Google groups?


I actually tried using multiprocess to create a separate process for  
reading the serial data. The process gets passed a TX queue and an RX  
queue in its constructor, then it's supposed to enter an infinite loop  
where it waits for commands on the TX queue and reads data and puts in  
in the RX queue. However, I've discovered for some reason that the  
infinite loop terminates after the first call I make to either of the  
queues. Perhaps this behavior should be expected, but this is my first  
go-round with processes, so I was a little surprised by this result.  
Maybe someone with more multiprocessing experience can give me some  
pointers.


Maybe I am barking up the wrong tree with Python from a speed  
perspective, but it's just some much faster and more fun to write than  
anything else...


Aaron

--
http://mail.python.org/mailman/listinfo/python-list


Re: Threaded GUI slowing method execution?

2009-10-03 Thread Aaron Hoover


On Oct 2, 2009, at 1:18 PM, sturlamolden wrote:


On 2 Okt, 21:30, Dave Angel  wrote:


There could very well be multiprocess support in wxPython.  I'd check
there first, before re-inventing the wheel.


I don't think there is. But one can easily make a thread in the
subprocess that polls a pipe and calls wx.PostEvent or wx.CallLater
when something is received. I particularly like the Queue object in
multiprocessing for this.

One could also use win32api.SendMessage from pywin32 to send the event
from one process to another. The parent must know the hwnd of the
subprocess main wx.Frame. The subprocess gets that from calling the
GetHandle() method of its wx.Frame, and must post it back to the
parent, presumably via a pipe.




So, I managed to solve all of this ultimately by simply creating a new  
process for managing the serial connection with a TX and RX queue.  
Then, in the GUI, I created a thread that's responsible for reading  
from the RX queue and posting the appropriate events based on the data  
it pulls off of the queue.


It's plenty fast for 2KHz sampling rates, so I'm happy with it for  
now. But, I'm also grateful for all the suggestions for different  
approaches to the problem - they've really opened to what's possible  
with Python and the various libraries that enable interfacing with  
"lower" level languages like C.



--
http://mail.python.org/mailman/listinfo/python-list