LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

prevent a control from updating during user interaction

I have a slow (couple of kBauds) serial link to a device that I want to control from within LabView.

 

There's an event loop that takes care of processing the control changes. When a control changes, the thread acquires a semaphore to access the serial link, sends out the new value and releases the semaphore again. In another thread, the device is periodically polled for actual values. All that works fine.

 

The problem is that, due to the lag of the link (and polling and sending happening in two different threads), the newly set parameters are returned with a delay. So let's say, I have a slider from 0-1000 and I slide it down from 1000 towards 0. While I hold the mouse down on the slider, dragging it, the communication thread returns a value that is different from where the slider is at and therefore sets the slider to an outdated value. That makes the slider jitter and that's what I need to get rid of.

 

I think this is a common problem, yet I couldn't find a straightforward solution. Basically, what I was looking for was a property "isEditing" or "isDragging" which I could check and then not update the control when this is true, to prevent that race between events. Does something like that exist? How do you guys tackle such a problem?

 

Thanks,

z

 

0 Kudos
Message 1 of 8
(2,437 Views)

You need to create some hysteresis. Put the serial update in a timeout event that is only enabled when the slider is moved. As long as the slider is moving the timeout will never occur. Once the slider stops moving the timeout event will fire updating the serial port and disabling itself again.

 

Mike...


Certified Professional Instructor
Certified LabVIEW Architect
LabVIEW Champion

"... after all, He's not a tame lion..."

For help with grief and grieving.
0 Kudos
Message 2 of 8
(2,420 Views)

@zeeed wrote:

I have a slow (couple of kBauds) serial link to a device that I want to control from within LabView.

 

...and therefore sets the slider to an outdated value. That makes the slider jitter and that's what I need to get rid of.

 

I think this is a common problem, yet I couldn't find a straightforward solution. Basically, what I was looking for was a property "isEditing" or "isDragging" which I could check and then not update the control when this is true, to prevent that race between events. Does something like that exist? How do you guys tackle such a problem?

 

Thanks,

z

 


THe first part of this post got wiped out by the goffy forum editor. I do not have time to retype it....

 

applied when you get a new value from a queue or by polling the current value.

 

While changing...

 

THe control must act as control and must over-ride the widget value. The natural thought would be to put that code in the value change event... but how to do it such that the value does not get over-riden?

 

Put SOMETHING inbetween that can mange the value. You could go as far as to develop an QMH (Queued Messae handler) or similar inplace to handle the logic but I don't think we have to go that far. I would first concider developing an Action Engine to act as the traffic control you need.

 

Applying an Action Engine

 

i would use the AE to intercat with the widget and store it curent value. YOu will need an Init Action and a Close action as is normal but I would include two mtehods that would help you with the Over-ride.

 

Get Value - This action will read (using serial query) the current value of the widget and return the value to the caller. You could also have a "Read' or similar that would retireve the value from a Shift Register inside the AE. This action would be called regularly in your T.O. event and will keep the contro lupdated as to the widget value.

 

Set Value - Would be the key action that can help you out. THe details depend  on the widget but in general the Action would acept the new over-ride value and use it to send the comand to the widget to set the new value AND will query the widget to ensure the widget took the seeting or reached that value. After the widget is done, the new value is cached in a SR in the AE so that the latter checks by the TO event give you the value you set.

 

If you read the Nugget i linked you will see how an Action Engine blocks calls while it is running. By putting the code to set the widget value in the AE, you can ensure the widget went to the new value before any update code can read an old value.

 

The above is just one idea and there are others. I would think other solutions would all involve putting some type of traffic control inplace so the AE is a natural solution.

 

Note:

I have used similar approaches in the past to enforce safety logic to ensure the automatic PID updates do not over-ride a safety-shutdwon scenario.

 

I hope this helped more than it hurt,

 

Ben

 

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 3 of 8
(2,419 Views)

thanks for the replies!

 

@mike: can't do - I need the value updates to end up on the serial link while dragging. Hence, the receiver side needs managing, not the transmitter side

@Ben: that sounds terribly overkill for the kind of simple problem that I'm having.

 

Is there really no way to simply query whether the slider is being dragged? Building an AE would solve the problem; however in essence, it's just a really complicated way of remodelling a single boolean that the control knows already.

 

Anyway, should I decide to encapsulate it that way - how do I reference the wrapped widget from the two different threads then?

 

Thanks!

z

 

 

 

0 Kudos
Message 4 of 8
(2,411 Views)

@zeeed wrote:

thanks for the replies!

 

@Mike: can't do - I need the value updates to end up on the serial link while dragging. Hence, the receiver side needs managing, not the transmitter side

@Ben: that sounds terribly overkill for the kind of simple problem that I'm having.

 

Is there really no way to simply query whether the slider is being dragged? Building an AE would solve the problem; however in essence, it's just a really complicated way of remodelling a single boolean that the control knows already.

 

Anyway, should I decide to encapsulate it that way - how do I reference the wrapped widget from the two different threads then?

 

Thanks!

z

 

 

 


If you analyze your data path (as I understand it) the path itself is complicated. .... And semaphores are simple?

 

Re: refernce the widget from both threads...

 

If the AE has a ref to the widget and does the command internally, then no race condition.

 

I'll watch this thread for the "simple solution" you seek.

 

Ben 

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 5 of 8
(2,405 Views)

Hey Ben,

 

sounds like I didn't phrase my reply carefully enough - no offence meant.

 

First:

What I was trying to understand is whether there is a way of getting that boolean property ("isEditing") from a control or not. Is there?

 

Second:

I like the AE concept, in fact, I've seen the nugget before and I'm actually using it quite a lot. It has become a design pattern for me.

 

Third:

I'm too much of a noob to understand how to technically reference an AE that wraps a referenced widgets from two loops. I would very much appreciate an explanation on how to achieve this. What I can conceive is placing the AE subVI in two places in the code and simply making it not re-entrant. Is that how it's done? Or am I missing something.

 

Fourth:

My 'simple' way out would be to create a global boolean that is set when the slider gets a mouse down and released when the slider gets a mouse up. I know that this is not beautiful design. That's why I came here, to look for a better solution 🙂

 

Thanks again,

z

 

0 Kudos
Message 6 of 8
(2,401 Views)

You have mouse enter and mouse leave evnets to let you know when the mouse moves in/out ... but...

 

Tht puts the GUi in the middle of it and for me that is just an abuse of the GUI. The gui is an I/O device and not part of my normal data flow (aside from GUI updates).

 

I would put ALL of the interaction with the widget inside the AE so that there is no other mentod for touching the widget aside from the AE. Lets see if I can get through an edit this time.

 

Init- Accepts or find config info and inits the comm with the widget and the VISA ref is cached in a SR of the AE for use latter.

 

Set - Accept the paramter to go with the Set and uses the VISA ref to send the command and verify the "ack" and queries for new value then returns

 

Get New - Will use yet another action that uses the VISA ref to get the current value from the widget.

 

 

Now...

 

If you value changes and you invoke the "Set" the AE will keep running unitl the comm is completed and the new setting is aplied.

 

If the "Get New" is invoked while the "Set" is running, it will stall until the AE is available. If the Set is not operating then the Get just grabs the new value from the widget.

 

As I illustrated in the AE Nugget, LV uses semaphore like mechanisms to control access to the non-reentrant AE and ensure only one will be active at any one time.

 

Using an AE to do the above lets you have your "Value CHange" event in one VI and your "Update control" logic in another VI and the two thrads will be forced to play well together.

 

Stepping back and looking again...

 

Your control flickering issue is just a distraction from the real issue and that is you have a single device that needs to be controlled. Your handle to that device is the VISA resource (or whatever) and by protecting the VISA ref and using it only in a controlled manner from within the AE, you can dicate that no two operations occur at the same time.

 

This same construct scales and adapts to all kind of thingies and can be implemented to coordinate attempts to set values locally from the GUI (just another I/O device) or from another LV app running on another machine.

 

Just trying to help,

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 7 of 8
(2,390 Views)

more stuff...

 

If you read Jim Kring's suggestion in the AE thraed about using wrappers...

 

Put the AE in a LVLIB and mark it private.

 

Create a wrapper around each of the AE calls and create inputs as required for each call. These become your API.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 8 of 8
(2,386 Views)