LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Question about QSM complexity with several parallel tasks


@Nokaroa wrote:

I've got two loops that need access to the context: The main consumer loop and the loop that acquires and displays to the user every frame/tick/value. Since the context contains states such as "The hardware has been initialized" and "the application has stopped", every single iteration of the bottom loop needs that info. Additionally, the main loop needs that for certain commands to do processing and analysis. So if I send it in a message, I'm either having a new queue where every message is identical, or I'm making a queue which has duplicate data from a separate one in order to keep the front element from getting popped by multiple loops. 

 

 


Ah... Yeah Queues can have more than one Enqueue but only one Dequeue. 

 

The Tag Channel Wire is similar in that aspect and in my CMH I used more than one Tag Channel to communicate between my loops.

 

  1. "DAQ" Channel 
    1. Control Loop talks to Yokogawa/SOL Loop
    2. GUI Loop talks to Yokogawa/SOL Loop
  2. "LOG" Channel 
    1. Control Loop talks to Log/Display Loop
  3. "ACK" Channel
    1. DAQ Loop talks to Control Loop
    2. Log/Display Loop talks to Control Loop
    3. GUI Loop talks to Control Loop

Multiple Chanel Wires sure is a lot less messy than multiple Queues...

========================
=== Engineer Ambiguously ===
========================
0 Kudos
Message 11 of 19
(1,479 Views)

We developed our own framework many, many years ago and it is based on a publish/subscribe model. I like this architecture since it is very flexible and very easy to add more components the system. It does have a draw back that there is a central message broker to broadcast the messages to all interests tasks/processes. We have streamed lined this quite a bit and haven't found it to be too much of an issue. Our tasks have a single system queue which uses a network queue. The message type is a string and with a defined naming convention messages can be queued to only the task/process queue, be forwarded to the message router as a message which may be broadcasted to all subscribers or directed to a single different task. The message format is very generic in terms of the message routing. Only the sender and receiver of a message need to be concerned with the specific data type of the message data. Since the messages are TCP based messages can be defined to communicate with processes developed in other languages.

 

One of the nice things about our framework is that individual tasks don't care if there are any listeners. The tasks will simply send the message out and let the message router handle it. Tasks register with the message router for any messages it wishes to receive. This way it will get messages from other tasks including those generated by a different application or from a process on another machine.

 

Since it is a publish/subscribed system it is easy to add/remove tasks. There is very little coupling of tasks. Tasks can run even if no message router exists. This has been a very reliable framework that we have been using for close to 15 years now. It has been proven to be very flexible.

 

There are aspects of the actor framework that I like and I will use it for small parallel tasks. I couldn't see developing the entire application using it. having messages only being sent to yourself, your caller or a single nested actor is too limiting. However, for small independent processes it comes in handy at times. I developed a nice timer actor which can generate messages based on the scheduled timer. This is very useful to generate events/messages on a periodic basis for the controlling task to handle. The timer self corrects for drift so the timing is pretty accurate even when run for extended periods of time. This little actor makes it easy for a state machine to get periodic events. For example, I have an alert system which receives alerts from the tasks in the system. Every minute it will check to see if there are any new alerts. If so, it will send an e-mail to all registered users for the event. The event system will then send repeat alerts every 10 minutes for any alerts that are still active. After an hour, any open alerts are resent at the top of the hour. So, the alerts tasks creates three timers. One triggers once every minute, one triggers the message every 10 minutes (synchronized to the tens during the hour and the last is generated every hour at the top of the hour. Since the timers self correct for the clock drift the triggers occur very accurately over very long extended times. For small tasks like this I find the AF to be useful. Putting together an entire system using AF gets more complex.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
0 Kudos
Message 12 of 19
(1,471 Views)

I just tried this, and I'm reading the data position data and the camera images in the idle state. This makes sense with the local variable context issue, as now I can just have that data in a shift register. But the way I have the stages move, the "Move to absolute position" functions poll until the device is not moving. I could remove that functionality, but I lose the automatic knowledge I have that a new command is not going to be executed while the stages are still moving. 

 

How would you solve this? I can think of a few dirty ways to do it (more boolean flags everywhere), but I'd appreciate more ideas

0 Kudos
Message 13 of 19
(1,464 Views)

@Nokaroa wrote:

I just tried this, and I'm reading the data position data and the camera images in the idle state. This makes sense with the local variable context issue, as now I can just have that data in a shift register. But the way I have the stages move, the "Move to absolute position" functions poll until the device is not moving. I could remove that functionality, but I lose the automatic knowledge I have that a new command is not going to be executed while the stages are still moving. 

 

How would you solve this? I can think of a few dirty ways to do it (more boolean flags everywhere), but I'd appreciate more ideas


I am a bit confused. Do you want to be able to take images while the stage is moving? I am not sure of the application space here, so it is hard to suggest. Could you describe your problem with a few more details?

 

I like to use JKI State Machines. They are a type of queued state machine where the queue is a string shift register. Everything is self contained in a single loop. If I need more than a single loop, I like to use multiple JKI loops that are linked through User Events. User Events are like queues, lossless, except you can have one to many, many to one, different messages to the "same mailbox", etc.

 

If I was using a JKI State Machine, I would have the following:

On Startup, find and initialize all hardware. Once initialized and ready, wait for a "Start" Event (User presses Start button). Then I would go into a scan state: Move, Acquire data, Check if Scan complete, if not repeat Move, Acquire, etc.

 

mcduff

0 Kudos
Message 14 of 19
(1,459 Views)

Okay, I'll elaborate. The camera moves to positions to image light sources in certain places. The device will be physically separated from the operator in a completely dark room. We want to have the operator able to see a live-view from the camera and a live readout from the motorized stages because if something goes wrong, the operator will be able to tell from watching, and it won't always be obvious from the data.

 

So the actual data that I'm going to record will only happen once everything is done moving, but the image and position displays need to be live, hence why I opted for the parallel loops in the first place. 

 

The more I look at it, the simpler it seems to just remove the "wait until Idle" function from the move VIs and add a check for movement before any processing that actually needs everything to stop... I may have forgotten why I made that early decision, but monday me was a younger and more impulsive person.

0 Kudos
Message 15 of 19
(1,455 Views)

@Nokaroa wrote:

Okay, I'll elaborate. The camera moves to positions to image light sources in certain places. The device will be physically separated from the operator in a completely dark room. We want to have the operator able to see a live-view from the camera and a live readout from the motorized stages because if something goes wrong, the operator will be able to tell from watching, and it won't always be obvious from the data.

 

So the actual data that I'm going to record will only happen once everything is done moving, but the image and position displays need to be live, hence why I opted for the parallel loops in the first place. 

 

The more I look at it, the simpler it seems to just remove the "wait until Idle" function from the move VIs and add a check for movement before any processing that actually needs everything to stop... I may have forgotten why I made that early decision, but monday me was a younger and more impulsive person.


I think I understand now.

 

For me, I would probably implement the following:

  1. Move
  2. Poll if Move Complete - I would give this a FINITE amount of time to accomplish, for example, 10 seconds. If my polling function times out then go to an error state, like "Move not completed"
  3. Take Image after move complete.

For this type of scanning I would have it all in a single loop. BUT if I needed some image processing, I would send the images to a separate loop. The only reason I would not send the images to a separate loop for processing if the next move depended on the analysis of the image. For example, keep moving and taking images until you find a circle in the image, etc. (I still would probably put the processing in a separate loop, and just send a message back as to whether to continue scanning or not. But this is programmer dependent.)

 

mcduff

0 Kudos
Message 16 of 19
(1,451 Views)

Sounds similar to what I was thinking. I'll try this out. 

0 Kudos
Message 17 of 19
(1,446 Views)

Actually, this ended up not solving the issue. If the acquisition and the polling are in the same loop, anything that blocks in that loop prevents acquisition. I like that I removed the local variable by putting the acquisition into the "IDLE" state, but I think I'll need to go back to my original separation of loops.  

0 Kudos
Message 18 of 19
(1,425 Views)

If I were designing for this application, I would note that I need to position something, run a camera, and coordinate positioning and taking images.  Thus I need a "Positioning" component, a "Camera" component, and a "Main" component, and these should all be asynchronous from each other.   Regardless of the specifics of how you program, that should lead to three separate loops, with a clear role for each loop.  Displaying images while the axes are moving is trivial in this case.  

Message 19 of 19
(1,404 Views)