task gui for position encoder

14 views
Skip to first unread message

Michael Graupner

unread,
Mar 14, 2017, 11:28:03 AM3/14/17
to ac...@googlegroups.com
Hello, 

I have added a rotary encoder to our setup which allows to resolve the rotational position of a treadmill. Instead of recording the raw ChannelA and ChannelB pulse trains (as 'di'), I am writing a device class which should immediately display/store rotary position and velocity. This class uses the DAQGeneric class. The new device can also be used for linear encoders. 

Where could I look to get an inspiration of how to create widgets for, update and display secondary variables (which secondary I mean variables which are derived from the raw daq channel recordings)? 
I am recording the two pulse trains and at the end of each task, I want to calculate the rotary position and display the position instead of the raw pulse trains which are hard to read. 

Thanks in advance.

Cheers,
Michael 


Luke Campagnola

unread,
Mar 22, 2017, 11:49:59 AM3/22/17
to acq4
Well the minimum you will need is:

1) You will need to make a subclass of TaskGui  (which is defined in devices/Device.py) for your device. TaskGui is itself just a subclass of QWidget, and instances of this class are displayed in the TaskRunner module. Within this widget, you will add the GUI controls and displays that are used to interact with the device during tasks.
2) In your device class, the method taskInterface() must return an instance of your TaskGui subclass. This method is called whenever you activate the device from the task runner.
3) The most important TaskGui methods to implement are generateTask() and handleResult(). The former returns the data structure that will be passed to Device.createTask(cmd) when the user starts the task, and the latter receives and displays the task results.

Hmmm..  As an example, let's look at the Laser task interface:

1) In devices/Laser/Laser.py, the method Laser.taskInterface() returns the widget that is to be displayed in the task runner module.
2) In devices/Laser/LaserTaskGui.py, I define the LaserTaskGui class, which is probably a bit more complicated than you will need. In this case it actually reuses a lot of the DAQGenericTaskGui, and augments it with laser-specific controls. For your purposes, I suggest subclassing directly from TaskGui (unless you are sure that there is some part of DAQGenericTaskGui that you want to reuse).
3) LaserTaskGui.generateTask() creates the command structure that drives the laser's behavior during the task (this structure is used when calling Laser.createTask(cmd)), and LaserTaskGui.handleResult() is actually done entirely by DAQGenericTaskGui.


I'm thinking perhaps I should make a dummy / example device class that just generates random data.. 

--
You received this message because you are subscribed to the Google Groups "ACQ4" group.
To unsubscribe from this group and stop receiving emails from it, send an email to acq4+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/acq4/CAFVjdWLndh6tzup6awrxdPgo3_J3i9hP4Zsgday2Tb_k6B7JtA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Michael Graupner

unread,
Mar 27, 2017, 11:03:50 AM3/27/17
to ac...@googlegroups.com
Great. Thanks. 

I built the positionEncoderTaskGui as subclass of TaskGui and managed to display angle and speed in ChannelWidgets. The calculation of angle and speed is currently done in handleResults() .

The implementation needs further improvements. At this point, I have two follow-up questions : 
- How I can extract 'numpts' and 'rate' from the 'results' metaArray which is the input argument to handleResults? 
- And how can I save the angle and speed arrays? Also, how is the view in the Data Manager defined?

The current state can be seen here : 
 

Thanks, 
Michael

Luke Campagnola

unread,
Mar 28, 2017, 6:08:35 PM3/28/17
to acq4
On Mon, Mar 27, 2017 at 8:03 AM, Michael Graupner <graupner...@gmail.com> wrote:
Great. Thanks. 

I built the positionEncoderTaskGui as subclass of TaskGui and managed to display angle and speed in ChannelWidgets. The calculation of angle and speed is currently done in handleResults() .

Looks great!
 
The implementation needs further improvements. At this point, I have two follow-up questions : 
- How I can extract 'numpts' and 'rate' from the 'results' metaArray which is the input argument to handleResults? 

 
- And how can I save the angle and speed arrays?

Look at the default implementation of DeviceTask.storeResult() in devices/Device.py. Your options are:
1) Combine the angle and speed data into the same MetaArray that is returned by PositionEncoderTask.getResult(); this will be stored as a single MetaArray file
2) Have PositionEncoderTask.getResult() return a dict containing multiple MetaArrays; in this case a directory will be created containing one MetaArray for each value in the dictionary
3) Reimplement PositionEncoderTask.storeResult() to handle any other behavior you need

It looks like you have done both (1) and (3); probably you do not need to reimplement storeResult() in this case.
 
Also, how is the view in the Data Manager defined?

This is a little more complicated. If you really want to be able to customize the way DataManager displays this data, then let me know how you think it should behave differently, and I'll see if I can help.
However, I would encourage you to consider letting the DataManager behave as-is, and implementing deeper analysis of this data elsewhere.  


Luke


Michael Graupner

unread,
Mar 30, 2017, 4:47:35 AM3/30/17
to ac...@googlegroups.com
On Wed, Mar 29, 2017 at 12:08 AM, Luke Campagnola <luke.ca...@gmail.com> wrote:
On Mon, Mar 27, 2017 at 8:03 AM, Michael Graupner <graupner...@gmail.com> wrote:
Great. Thanks. 

I built the positionEncoderTaskGui as subclass of TaskGui and managed to display angle and speed in ChannelWidgets. The calculation of angle and speed is currently done in handleResults() .

Looks great!


I have fixes a couple of bugs and created a PR for the new device class. 
 
 
The implementation needs further improvements. At this point, I have two follow-up questions : 
- How I can extract 'numpts' and 'rate' from the 'results' metaArray which is the input argument to handleResults? 

The way you are doing it here looks correct to me:
 
- And how can I save the angle and speed arrays?

Look at the default implementation of DeviceTask.storeResult() in devices/Device.py. Your options are:
1) Combine the angle and speed data into the same MetaArray that is returned by PositionEncoderTask.getResult(); this will be stored as a single MetaArray file
2) Have PositionEncoderTask.getResult() return a dict containing multiple MetaArrays; in this case a directory will be created containing one MetaArray for each value in the dictionary
3) Reimplement PositionEncoderTask.storeResult() to handle any other behavior you need

It looks like you have done both (1) and (3); probably you do not need to reimplement storeResult() in this case.

Indeed, I managed to add the arrays including infos to the same MetaArray. The stored results and the depiction in DataManager is very satisfactory so. 

In case I would like to store data with different lengths, I presume I have to create a new MetaArray and store it alongside the existing one (your option 2). How would such an implementation look like? 

 
 
Also, how is the view in the Data Manager defined?

This is a little more complicated. If you really want to be able to customize the way DataManager displays this data, then let me know how you think it should behave differently, and I'll see if I can help.
However, I would encourage you to consider letting the DataManager behave as-is, and implementing deeper analysis of this data elsewhere.  


The display of the data in DataManager looks perfect as it is. 

Thanks,
Michael
 

Luke


--
You received this message because you are subscribed to the Google Groups "ACQ4" group.
To unsubscribe from this group and stop receiving emails from it, send an email to acq4+unsubscribe@googlegroups.com.

Luke Campagnola

unread,
Mar 31, 2017, 10:36:27 PM3/31/17
to acq4
On Thu, Mar 30, 2017 at 1:47 AM, Michael Graupner <graupner...@gmail.com> wrote:
Look at the default implementation of DeviceTask.storeResult() in devices/Device.py. Your options are:
1) Combine the angle and speed data into the same MetaArray that is returned by PositionEncoderTask.getResult(); this will be stored as a single MetaArray file
2) Have PositionEncoderTask.getResult() return a dict containing multiple MetaArrays; in this case a directory will be created containing one MetaArray for each value in the dictionary
3) Reimplement PositionEncoderTask.storeResult() to handle any other behavior you need

It looks like you have done both (1) and (3); probably you do not need to reimplement storeResult() in this case.

Indeed, I managed to add the arrays including infos to the same MetaArray. The stored results and the depiction in DataManager is very satisfactory so. 

In case I would like to store data with different lengths, I presume I have to create a new MetaArray and store it alongside the existing one (your option 2). How would such an implementation look like? 


That's right, MetaArray is only good for storing a single array. If your getResult() method returns a dict, then the default behavior of storeResult() it to create a directory and store each item of the dict as a new file inside that directory. That should be sufficient?

 
Luke
Reply all
Reply to author
Forward
0 new messages