Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Integrating AF & LVOOP with hardware

Solved!
Go to solution

Hi All,

 

I've got a question (might be simple...)

 

I've got a project where I'll be interacting with many pieces of automated test equipment. Let's call each of them ATE1, ATE2...ATEN etc. An example of ATE1 might be an optical power meter while ATE2 might be an optical spectrum analyzer. A test software might integrate N of such devices.

 

My familiarity LVOOP & ATE hardware is that I frequently have multiple brands of ATEs  and so I create general class where each brand gets its own child that inherits the general class. All physical optical power meters inherit from one general optical power meter class. I think this is "good practice" but let me know if it's otherwise.

 

My question is how to match up these ATE1, ATE2...ATEN to actors and integrate them into a AF project. I have a few questions:

  1. Does each type of ATE get an actor? 
  2. Does the ATE general class (or child class?) go into the private data of the actor? 
  3. If I have a software controlled test with many synchronous steps, does this get handled by the root actor sending messages and waiting for responses?

 

Sorry, I'm at the stage where I am first learning about AF and therefore am a bit stuck in the mud. I don't have source code to share at the moment - don't know what to wire.


------------------------------------------------------------------------------------

Please join the conversation to keep LabVIEW relevant for future engineers. Price hikes plus SaaS model has many current engineers seriously concerned...

Read the Conversation Here, LabVIEW-subscription-model-for-2022
0 Kudos
Message 1 of 88
(4,804 Views)
Solution
Accepted by topic author WavePacket

Use Composition.

 

What I would do is take your parent class, your power meter class and create an actor for it. Call it power meter actor. Inside its private data, put a power meter class object. Make an accessor to set the exact type of powermeter. Then  create a message for each of the methods on the power meter class. The actor class simply delegates to the power meter class.

 

So to spin up a specific power meter, you take a power meter actor, pass it the specific power meter you want to use and launch it.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
Message 2 of 88
(4,776 Views)
Solution
Accepted by topic author WavePacket

Your exact use case will depend on what exactly your test is and what its timing requirements are. For me, I do lots of DAQmx sampling, so I have a DAQmx generic actor set up that I can override with different sub-types of DAQmx components.

 

When that actor launches, it generates data constantly and sends it upstream to my main actor. When it receives a "new data" message, it acts on it. In this way, the DAQmx device itself controls all of my timing and it works great. I've run tests for many weeks with DAQmx units outputting 1 MS/s data continually with no issues by processing each new batch of data on the fly. (I didn't save all of it, of course, I was just looking for very short events).

 

If you have more of a "Set a value, take a value" type of test, and your data isn't particularly time-sensitive, you could have your sub-actors constantly send data to your parent actor. The parent actor then maintains the current value of each instrument. When the parent actor runs a test, it just grabs the current values. You could even write in a timestamp or a "Read?" flag so you don't duplicate measurements. For example, say you need data from 5 measurement devices, you can clear the "Read?" flags from each one. As each device sends back a new measurement, you can set the Read? flag. Your reading is done when you AND all flags together and get True.

 

A couple points to consider.

1- Interfaces are new but they are the recommended way to go for HAL's. Imagine you have a multimeter that you use to take voltage and a current meter you use for current. You would make a "Multimeter" parent class and a "Current meter" parent class and implement each one as a manufacturer-specific child class. Great, right? Well, now say one day you get yourself a fancy power meter that can measure both. Unfortunately, you can't make two classes, so what to do? Maybe make a "Power meter" class? It gets nasty quick. If you use Interfaces, you can have each device implement each interface it's able to implement, and you get multiple inheritance.

 

2- Don't fall into the trap of wanting synchronous messages- i.e., messages that block until they get a response (like "Step 4: Measure voltage: Ask device to measure voltage, then wait in the message for a reply.") Blocking actor messages is a bad idea. What if your user wants to cancel? What if the unit locks up? Blocking an Actor message should be done with the utmost care. Anything that blocks should be handled in a helper loop, leaving the main Actor Core free to do its own thing. Try to consider the data as "pushed" rather than "queried". Messages should ask an actor to do something, not demand it. Ask your actor to send data, then wait until it does so- but don't block until it does so. Simply idle until it sends the "New data" message.

 

3- It's easy to want your actors to live forever, but really actors can be very short-lived. Maybe you need to take a quick measurement. Is there any reason that actor can't start up when you call it, take a measurement, send back data, then die? For that matter, if you don't need a constant interface, don't feel like everything has to be an actor. If you can implement things as a regular object, go for it. Use Actors when you need an independent state machine to sit there looking at something.

 

4- Consider when to spawn actors. Do it when you need one, not when you think you need one. I got into a trap with my DAQmx actor trying to make it start up when the program did. I was planning on giving it a few states, so it could start sampling, go idle, reconfigure settings, etc. It then occurred to me, if it's not talking to an instrument, why is it alive? Now I configure my DAQ in Pre Launch Init. If it fails (like if the hardware is reserved), then Launch Actor fails and my parent actor knows immediately. If it succeeds, it starts sending data back. When I'm done with it I tell it to stop, and the actor shuts down. WAY easier than trying to maintain state all the time!

 

5- Don't try to bite off an enormous HAL for your first AF project. AF is great, but there's a learning curve. I'd recommend starting smaller and trying to get one solid application done with it. You'll learn a lot that way and will be WAY quicker than trying to get it perfect out of the gate. Abstract what you need to but don't try to implement any and all actors you could ever implement. I originally wanted my DAQmx actor to work with any voltage source. That was like 4 years ago and it's never come up. I'm super glad I didn't waste time trying to make it 100% universal.

 

Good luck!

Message 3 of 88
(4,768 Views)

@Taggart wrote:

Use Composition.

 

What I would do is take your parent class, your power meter class and create an actor for it. Call it power meter actor. Inside its private data, put a power meter class object. Make an accessor to set the exact type of powermeter. Then  create a message for each of the methods on the power meter class. The actor class simply delegates to the power meter class.

 

So to spin up a specific power meter, you take a power meter actor, pass it the specific power meter you want to use and launch it.


Ok, thanks. I think I understand that enough to start laying wires.


------------------------------------------------------------------------------------

Please join the conversation to keep LabVIEW relevant for future engineers. Price hikes plus SaaS model has many current engineers seriously concerned...

Read the Conversation Here, LabVIEW-subscription-model-for-2022
Message 4 of 88
(4,748 Views)

@BertMcMahan wrote:

...

Good luck!


Wow, what a response. I'll need a bit of luck!

 


@BertMcMahan wrote:

...

If you have more of a "Set a value, take a value" type of test, and your data isn't particularly time-sensitive, you could have your sub-actors constantly send data to your parent actor. The parent actor then maintains the current value of each instrument. When the parent actor runs a test, it just grabs the current values. You could even write in a timestamp or a "Read?" flag so you don't duplicate measurements. For example, say you need data from 5 measurement devices, you can clear the "Read?" flags from each one. As each device sends back a new measurement, you can set the Read? flag. Your reading is done when you AND all flags together and get True.

...

Good luck!


That's helpful, I definitely do these kinds of tests.

 


@BertMcMahan wrote:

...

A couple points to consider.

1- Interfaces are new but they are the recommended way to go for HAL's. Imagine you have a multimeter that you use to take voltage and a current meter you use for current. You would make a "Multimeter" parent class and a "Current meter" parent class and implement each one as a manufacturer-specific child class. Great, right? Well, now say one day you get yourself a fancy power meter that can measure both. Unfortunately, you can't make two classes, so what to do? Maybe make a "Power meter" class? It gets nasty quick. If you use Interfaces, you can have each device implement each interface it's able to implement, and you get multiple inheritance.

...

Good luck!


Thanks, I think I understand point #1. Cross-functional equipment seems well handled by interfaces. 

 


@BertMcMahan wrote:

...

2- Don't fall into the trap of wanting synchronous messages- i.e., messages that block until they get a response (like "Step 4: Measure voltage: Ask device to measure voltage, then wait in the message for a reply.") Blocking actor messages is a bad idea. What if your user wants to cancel? What if the unit locks up? Blocking an Actor message should be done with the utmost care. Anything that blocks should be handled in a helper loop, leaving the main Actor Core free to do its own thing. Try to consider the data as "pushed" rather than "queried". Messages should ask an actor to do something, not demand it. Ask your actor to send data, then wait until it does so- but don't block until it does so. Simply idle until it sends the "New data" message.

...

Good luck!


I'm not sure I understand your suggestion with #2. Let's say I turn on a light source, and I'd like to measure the optical power after the light source is emitting. Don't I want to enforce an order to the messages? -- or am I not understanding something. In non-actor framework, I'd have the error wire setting the timing. That is to say, the error wire would first go into an on method the lightsource class, and then I'd run the measure power method of the general power meter class. Mind if I ask how to achieve this in AF?

 


@BertMcMahan wrote:

...

3- It's easy to want your actors to live forever, but really actors can be very short-lived. Maybe you need to take a quick measurement. Is there any reason that actor can't start up when you call it, take a measurement, send back data, then die? For that matter, if you don't need a constant interface, don't feel like everything has to be an actor. If you can implement things as a regular object, go for it. Use Actors when you need an independent state machine to sit there looking at something.

...

Good luck!



Thanks, this is one of my main confusions right now. When is it desired to implement a separate actor vs when should I just use a "regular object?" I realize you gave me some advice there, but I'm still a little stuck on this. I'm familiar with QMH, statemachine, OOQMH. Learning AF for the first time and I'm not sure when the complexity is justified.

 


@BertMcMahan wrote:

...

4- Consider when to spawn actors. Do it when you need one, not when you think you need one. I got into a trap with my DAQmx actor trying to make it start up when the program did. I was planning on giving it a few states, so it could start sampling, go idle, reconfigure settings, etc. It then occurred to me, if it's not talking to an instrument, why is it alive? Now I configure my DAQ in Pre Launch Init. If it fails (like if the hardware is reserved), then Launch Actor fails and my parent actor knows immediately. If it succeeds, it starts sending data back. When I'm done with it I tell it to stop, and the actor shuts down. WAY easier than trying to maintain state all the time!

...

Good luck!

Thanks, I think this makes sense to me. No need for actor to be ready until you are actually going to start sending messages to it.


@BertMcMahan wrote:

...

 

5- Don't try to bite off an enormous HAL for your first AF project. AF is great, but there's a learning curve. I'd recommend starting smaller and trying to get one solid application done with it. You'll learn a lot that way and will be WAY quicker than trying to get it perfect out of the gate. Abstract what you need to but don't try to implement any and all actors you could ever implement. I originally wanted my DAQmx actor to work with any voltage source. That was like 4 years ago and it's never come up. I'm super glad I didn't waste time trying to make it 100% universal.

 

Good luck!


Yeah, I'm getting that feeling.

 

Thanks for all your help.

 


------------------------------------------------------------------------------------

Please join the conversation to keep LabVIEW relevant for future engineers. Price hikes plus SaaS model has many current engineers seriously concerned...

Read the Conversation Here, LabVIEW-subscription-model-for-2022
0 Kudos
Message 5 of 88
(4,736 Views)

@WavePacket wrote:
I'm not sure I understand your suggestion with #2. Let's say I turn on a light source, and I'd like to measure the optical power after the light source is emitting. Don't I want to enforce an order to the messages? -- or am I not understanding something. In non-actor framework, I'd have the error wire setting the timing. That is to say, the error wire would first go into an on method the lightsource class, and then I'd run the measure power method of the general power meter class. Mind if I ask how to achieve this in AF?

There are synchronous messages in AF. They are discouraged for a reason in that you can end up with deadlocks. If your message is simply for the hardware actor to return some values and it's not sending off messages anywhere else and you use a reasonable timeout, you should be ok.

I forget how to do the response messages off the top of my head. if they are on the palettes they are hidden in one of the subpallettes. They intentionally made them hard to find. IIRC they are just a class that your message inherits from.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 6 of 88
(4,732 Views)
Solution
Accepted by topic author WavePacket

Under the advanced subpallete look for Send Message and Wait for Response.vi

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 7 of 88
(4,731 Views)

@Taggart wrote:

@WavePacket wrote:
I'm not sure I understand your suggestion with #2. Let's say I turn on a light source, and I'd like to measure the optical power after the light source is emitting. Don't I want to enforce an order to the messages? -- or am I not understanding something. In non-actor framework, I'd have the error wire setting the timing. That is to say, the error wire would first go into an on method the lightsource class, and then I'd run the measure power method of the general power meter class. Mind if I ask how to achieve this in AF?

There are synchronous messages in AF. They are discouraged for a reason in that you can end up with deadlocks. If your message is simply for the hardware actor to return some values and it's not sending off messages anywhere else and you use a reasonable timeout, you should be ok.

I forget how to do the response messages off the top of my head. if they are on the palettes they are hidden in one of the subpallettes. They intentionally made them hard to find. IIRC they are just a class that your message inherits from.


I'm sure I said this before, but as an outside observer into the Actor Framework I really think you suffer from not having a standard implementation of an Asynchronous Request-Reply pattern.  "Do something after the light is turned on" is not something that should require you to hold your nose and compromise on your "Asynchronous" architectural principle.  Develop it to the multiple address version, called Async Scatter-Gather, and you can avoid those tiresome "Read?" flags too.

Message 8 of 88
(4,724 Views)
Solution
Accepted by topic author WavePacket

I'd say use an actor when you need a separate QMH for some task. If you're just reading a simple value from something, just use a regular actor. At its core, the AF is just a QMH, so if you don't need message handling or separate loops then just use a "regular" object.

 

For example, my DAQmx actor needed to constantly monitor data across three different types of inputs. It made sense to use an actor here, as something needed to repeatedly call DAQmx Read when data was available. I had to use a loop anyway. If I just need to, say, read a volt meter, then there's no need to maintain a separate state machine. I just initialize the object at the beginning of my test, then ask it for the current voltage when I need it.

 

Remember that Actors are not "super objects"; they're more like "super message handlers".

Message 9 of 88
(4,722 Views)

@BertMcMahan wrote:

I'd say use an actor when you need a separate QMH for some task. If you're just reading a simple value from something, just use a regular actor. At its core, the AF is just a QMH, so if you don't need message handling or separate loops then just use a "regular" object.

 

For example, my DAQmx actor needed to constantly monitor data across three different types of inputs. It made sense to use an actor here, as something needed to repeatedly call DAQmx Read when data was available. I had to use a loop anyway. If I just need to, say, read a volt meter, then there's no need to maintain a separate state machine. I just initialize the object at the beginning of my test, then ask it for the current voltage when I need it.

 

Remember that Actors are not "super objects"; they're more like "super message handlers".


This.

And it's easy to turn any object into an Actor if you later need asynchronous behavior.

But please use composition instead of inheritance (ie instead of your class inheriting from actor, make a seperate actor that "owns" a copy of your class in its private data, and create messages that delegate each method). You'll thank me later.

 

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
Message 10 of 88
(4,718 Views)