09-30-2022 08:45 AM
Hello all
I have a list of commands that have a set priority (on bottom picture, "Home position" has highest priority and "Move Stepper 4" has lowest). While one command is executing, no other command can execute. Only one command can be executed at a time, but several can be "ordered" at the same time. Once the command is executed, it's cleared (or reset to false).
I check the state of these commands in a state machine, but unfortunately i can not share it at this time.
The solutions i thought of were these:
- a nested case structure (would require 8 levels of nested structures for the 8 commands - seems like a pain)
- the one below, a queue where i queue a priority/command and then execute it in a different loop. The dequeue loop would then have case structure where each command would be executed, unless a command is already running.
These two solutions seem kind of convoluted to me, is there a more elegant way to do this?
09-30-2022 09:07 AM - edited 09-30-2022 09:09 AM
Well you are describing and basically have pictured a Queued State Machine (QSM). I have used those lots of places where there are several individual tests, but the end user needs the ability to select which tests to run and what order to run the tests in.
But you also might also want to take a look at the Queued Message Handler and the more modern Channel Message Handler as alternatives.
09-30-2022 09:22 AM
I did not entirely get the "priority" requirement. How does that factor here?
If "Home Position" is selected by the user, it should always be executed before any other command, even if the other commands were put on the queue before that? I can imagine that such behaviour would be helfpul for a "Emergency Stop" command.
09-30-2022 09:34 AM
I have a list of commands that have a set priority (on bottom picture, "Home position" has highest priority and "Move Stepper 4" has lowest).
Your snippet looks more like an illustration of a *sequence* of commands than a set of commands with various *priorities*.
Do you need the ability to re-order your pending queue on the fly? If so, your worker loop is going to need some code that manages these priorities since queues are simply first-in first-out.
Let's say you order 4 commands with priorities 1,3,5,7 but you send them off to your worker loop in the order 3,5,1,7. Should your worker loop re-order them as 1,3,5,7 and then start executing 1? Then let's suppose that while busy executing 1 and 3,5,7 are pending, you order a new set of commands 6,4,8,2. What should the pending order be? 2,3,4,5,6,7,8? Or 3,5,7,2,4,6,8? Or something else.
-Kevin P
09-30-2022 09:53 AM
Kevin raises some very good questions. I would also ask if all commands have a unique priority are are there groups of priorities. That is, are there several high priority commands but they could execute in any order such as the order they were queued? If so, you could implement a set of queues to buffer your commands. When you enqueue an item it is placed in the appropriate priority queue. Then you dequeuer pulls from the highest priority queue first. If there are no commands yo pull from the next and so on. If you go this route you may need to have some type of logic to prevent starving the execution of lower priority commands to avoid the possibility of never executing low level commands because the higher priority queues always have some commands in them. This obviously can get messy.
Kevin's question how to add new batches of commands would have the same issue. Low priority commands could get pushed to the bottom if the commands are always reordered based on priority and therefore may never get executed. At least separate priority queues you have the ability to force execution of lower priority items even when higher priority commands are present.
With this scheme your highest priority queue could always take precedence no matter what but you would need to limit how many commands are at the highest level priority. These would be reserved for things like the emergency stop and such commands. So if you do implement a load balancer the emergency commands would always execute no matter what. Then your lower priority commands (think high, medium and low) would operate within the balancing algorithm. So it would be possible to preempt a high priority command with a medium or even low priority command.
09-30-2022 12:02 PM
@AeroSoul wrote:
Hello all
I have a list of commands that have a set priority (on bottom picture, "Home position" has highest priority and "Move Stepper 4" has lowest). While one command is executing, no other command can execute. Only one command can be executed at a time, but several can be "ordered" at the same time. Once the command is executed, it's cleared (or reset to false).
I check the state of these commands in a state machine, but unfortunately i can not share it at this time.
The solutions i thought of were these:
- a nested case structure (would require 8 levels of nested structures for the 8 commands - seems like a pain)
- the one below, a queue where i queue a priority/command and then execute it in a different loop. The dequeue loop would then have case structure where each command would be executed, unless a command is already running.
These two solutions seem kind of convoluted to me, is there a more elegant way to do this?
There are some basic convolutions aready visible in the above code. For example you can replace the index array with autoindexing and remove the 8 on N.
Can you explain how the commands are triggered? Are these controls (LEDs are typically indicators)?
How many levels of "priorities" are there? What if there are several high priority commands?
All you probably need is enqueue at the front for certain commands.
09-30-2022 12:37 PM
If there are N priorities, one for each command, I would probably replace the queue with an action engine that maintains a list of commands and re-sorts with every new entry. Should it remove duplicates?
09-30-2022 01:01 PM - edited 09-30-2022 01:10 PM
Expand the Queue to a cluster of <priority I32, Command, Data> I won't get into arguments about command, Data datatypes. Use whatever.
The queue can be flushed, sorted, and requeued at the consumer end with a trivial subvi in place of the standard dequeue. Just make sure the priority is cluster element 0.
Sneaky tip. Use larger numbers for higher priority and delete from sorted array returns the highest priority and the remaining elements naturally. Watch out for 0 iteration for loops on the reenqueue...keep the queue ref on a Shift Register.
@CA the producer does not easily know the consumer's schedule. Sorting needs to be done on dequeue to get the latest highest priority queue element when "ready for command."
09-30-2022 02:36 PM
@JÞB wrote:
Sorting needs to be done on dequeue to get the latest highest priority queue element when "ready for command."
If the AE queue is always sorted after adding any new entry, later sorting seems unnecessary.
09-30-2022 02:45 PM
@altenbach wrote:
If there are N priorities, one for each command, I would probably replace the queue with an action engine that maintains a list of commands and re-sorts with every new entry. Should it remove duplicates?
Here's what I had in mind.