Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Timeouts at the Priority Queue

Solved!
Go to solution

Hello again,

I am thinking of implementing a generic PID-Timer type of Actor and to do this properly I think I need a timeout on the queue and a timeout case. Is there a specific reason one was never put into the AF and any pitfalls I may be overlooking?

My other option is to just use a regular queue for the PID Timer but I want to avoid having different types of messages to send.

Here's a pre-emptive thanks for the input if you have any. Thanks!

0 Kudos
Message 1 of 9
(6,224 Views)

> Is there a specific reason one was never put into the AF and any pitfalls I may be overlooking?

Yes. The reason is mostly theoretical.

First problem with an operation based on time out is starvation. With actors, you're operating in a highly parallel, high contention system for CPU resources. So saying "I'm going to take this action if I don't receive a message for N milliseconds" suffers from the twin problems of never happening because messages pile up, or from happening right away because it takes a while for the first message to get enqueued. In general, you need much more logic than just "I haven't received a message in a while" for such systems. Usually you need logic that says, "I actually got started" and "I'm not in the middle of anything else right now". That is much better placed in your override of Actor Core.

There is also a theoretical (never empirically tested) performance problem if most of the actors had a timeout. The temptation would be to *use* it, which would turn most actors from "I'm asleep most of the time" to "I'm working most of the time", making the high parallel system also a highly contended one.

You can make the modification to your version of the AF and let me know how it works out. It might be worth adding to AF as an option in the future, but the above is the reason it isn't there now.

[EDIT] PS: Where in the code would a child specify its timeout? How do you ensure that a parent propagates the same timeout that its child asks for all the way up to the top-most Actor Core?

Message 2 of 9
(4,067 Views)

In the case I was considering, the child would specify its timeout based on the PID calculation. Say the cycle time was 1000ms and the PID commands 40% output. The first message would be to "turn the heater on" and change the timeout from -1 to 400ms. After 400ms AND If nobody has sent a command to stop heating early, the timeout would trigger a "turn off heater" and a 600ms timeout after which the cycle would begin again. It's really the only way I can figure to run a PID/Timing loop which enables me to turn the heater off in case of an emergency or a change in state.

The main reason I don't think I'll even try it is that I would have to change the connector pane for every Do.vi I have created over the past few weeks. That's probably 8 hours of work right there. I just really like the idea of being able to use queue timeouts for my PID control. The idea being that if ANY message arrives to this queue during a heating cycle, I probably want the heat to turn off before I handle it. That does create a whole new headache of having some sort of timeout message set though. Otherwise, what do you do at the timeout? I sure wouldn't want to send the exact same message any time any actor core times out.

I'm convinced it's a bad idea. I still don't have a great solution for interrupting my PID loop using the AF though. I would love to have a program that relies completely on the Do.vi except where user events are needed but how do you implement timing?

Anybody have a solution to this design challenge? Some method of sending messages, waiting for a variable period, then sending more messages. It also has to receive messages telling it when to start, stop, what the current PV is, etc... How can I do this without implementing yet another messaging system?

0 Kudos
Message 3 of 9
(4,067 Views)
Solution
Accepted by topic author Q7

I don't think I know enough about PIDs to directly answer your question. But I think I would do the following:

  1. In "Turn Heat On Msg.lvclass:Do.vi" : Turn the heater on, and in the Actor object, record a timestamp for the message. Start a Time Delayed Message with a time delay of 400ms and a repeat of 1 to deliver a "Consider Turning Off Heat Msg". Store the notifier in the Actor.
  2. In any regular message Do.vi that turns off the heat, change the timestamp in the Actor to reflect that the heat has been recently adjusted.
  3. In "Turn Heat Off Msg.lvcass:Do.vi": Disable the notifier (but remember that the message may already be in the queue, so we'll handle it in a moment). Turn the heat off.
  4. In "Consider Turning Of Heat Msg:Do.vi": Check the timestamp. If it is more than 400ms old, turn the heat off and start a new Time Delayed Message for 600 ms to consider turning the heat on. If the heat is already off, do nothing.

Maybe that helps you?

0 Kudos
Message 4 of 9
(4,067 Views)

I forgot all about that time-delayed message! Know that you mention it I remember writing a note to try and use it for this very purpose. Your answer should do it in a general way, thank you 2X!

0 Kudos
Message 5 of 9
(4,067 Views)

Just as a side note (as I've done some PID stuff in my time), I think your choosing the wrong dividing line between your actor levels.  You should be sending the heater output to a "Heater Control" actor, not "turn on" or "turn off" messages.  That way you can reuse code with alternate methods, such as software-timed duty cycle or analogue output to hardware, by making different children of "Heater Control".  Also, it is better to get the heater control logic as local as possible, to minimize the safety problem of the heater being turned on but never turned off due to a bug somewhere in a multi-actor interaction.  If I where making a "Heater Control" actor for your use case, I would put the actual heat on/off in a specialized loop in the override of Actor Core, controlled by the message-handling loop inside the parent Actor Core via queues or notifiers (with timeouts).  I would use the period of updated heater output messages to determine the period to use for heat on/off, allowing the higher-level "PID actor" to not worry about such details (and letting it be reused with different types of "Heater Control" actors.

-- James

Message 6 of 9
(4,067 Views)

I have never programmed a PID, only heard about them through customers, but what drjpowell says makes sense to my ears.

0 Kudos
Message 7 of 9
(4,067 Views)

Makes good sense, yes. Also requires me to use another messaging system...I don't know why it's such a big deal to me but I keep hearing these voices: "use whatever works best but use the same system throughout," "don't use notifiers and queues together." Since the AF uses both queues and notifiers already, plus I am forced to use User Events for HMI, why muck it up more?

I suppose I could launch a Heater Actor and then use time-delayed send messages from the PID actor. I still need some way to ensure the thing turns off if something goes wrong. Maybe I can override the Stop Core of PID to send an emergency stop to it's callees. OR, how about LabView adds an "Enable Timeout Case" to the Case Structure? Probably not too likely.

I'm going to try it both ways and post some resulting Snippets.

AQ, play around with PID a little. It would make a great training tool for LabView as it combines many functions into something that is used "real world" in almost everything. I sure wouldn't want to be in a fly-by-wire airplane that didn't implement some very robust PID loops! It is also something that simply cannot be done safely without employing a messaging system.

0 Kudos
Message 8 of 9
(4,067 Views)

Where does AF use notifiers? Oh, you mean in the time-delivered message? I consider that a separate subsystem.

You should use the same messaging protocol for messages, but there are other types of signaling, and there's a reason for each of the types. The only big rule is you never want to have any part of your code simultaneously waiting on two different kinds of signaling. Trying to write code that says "I take the next value from the queue or the next value from this notifier, which ever comes first" will make you rip your hair out because you have to continuously poll both of them with a zero timeout to make it work.

I'll put PID on my list of "things to possibly evaluate in June" -- that's when I typically have more downtime between release cycles to go explore not-directly-my-job topics.

0 Kudos
Message 9 of 9
(4,067 Views)