From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Newbie questions about AF

Hi,

I'm new to the actor framework. I've worked through the hands-on tutorial and looked at various examples.

I'm now trying to build my first small application and was hoping for a nodge in the right direction with two main questions. Before going into those I will outline the software.

The application is used to calibrate a device. As such it has analogue inputs/outputs but is also using I2C via FTDI.

The whole calibration process is strictly scripted.

As all of this can be functionally described as the process I wanted launch a process actor. The process actor is then starting a state machine actor as well as an IO management actor which subsequently starts the DAQ and the I2C actors.

The top level application is also going to start an error handler as well as a GUI actor.

Now for my first question. I only want to show the GUI actor and not the launcher. What is the most elegant way of causing the top level app to shut down from within the GUI actor?

I had two approaches:

1. generate a user event which gets written into the private class data of the GUI before the actor gets launched. The "send stop" vi is then put into an event structure which waits for the GUI to fire the user event (which is done in the GUI actor from a "panel close?" filter event). I disbanded this approach as I didn't like the fact that I had to pre-initialise the actor with data member access vis before the launch actor vi had even been started. I got the impression that all necessary initialisation should be done from the "pre launch init" as everything else would mean that the actor isn't self contained anymore which is one of the big strengths of the actor framework.

2. I've attached screenshots of this approach. As you can see I am now using the actor queue of the top level app. As no other actor is using this queue I use it to signal the shut down by acquiring the caller queue in the GUI and enqueuing a message from within the gui. This seems slightly better than the first attempt as it is self contained but I still don't like it as it feels like a hack, abusing the top level actor queue for a purpose it was not intended for.

top level AF.png

GUI AF.png

Now for my second question. This is about implementing the state machine. To me it seems that the most intuitive way of implementing this is by creating a FGV in the state machine class and have authorised actors enqueue commands by using the appropriate message class (third screenshot). Is there a better way of doing this?

state machine.png

Thanks a lot

Mathis

Download All
0 Kudos
Message 1 of 22
(10,935 Views)

Hi Mathis,

Welcome to AF!

1. I have a top level actor (not a launcher) that controls the communication between the modules and launches/closes them (I call mine Controller ). My launcher launches the controller, and the controller launches the GUI and measurement actors. Therefore, it makes perfect sense for the GUI to notify the controller when panel close event and the controller proceeds to shut down everyone. In your case, your launcher is also your controller, which seems a bit odd to me. I also personally prefer that my modules communicate through the controller and not directly between them, but that's a personal preference, you can argue either way.

2. I didn't really understand. Why create a FGV in the state machine actor? What do you mean state machine actor? If you mean an actor that holds a state machine, I'm not sure that makes sense, as actors need to be able to handle any message at any time and state machines inherently can't. If the process is strictly scripted, then I think it might be better to create a message such as "Goto Next State", or" Task done", that signals the state machine actor to move to the next task in the script. If it needs data it should hold it in its class data (if it's a HW connection) or get it through the message as a flattened string or variant etc. In any case, using an FGV to hold class data is pointless as you have the class data for that, and using an FGV for communication between actors is also pointless, you have messages for that. Maybe you can explain a bit more?

Good luck!

Danielle

"Wisdom comes from experience. Experience is often a result of lack of wisdom.”
― Terry Pratchett
0 Kudos
Message 2 of 22
(6,069 Views)

Hi Danielle,

thank you very much for your feedback. I'm quite glad that I wasn't going totally wrong though there are still many things to improve in my code. The launcher being the controller is something that I probably wrongly learned from the hands-on tutorial as that is doing exactly that: launching the two main actors and exchanging the queue references. Those two actors then launch the cascade of child actors.

I kind of get the feeling that I have to free my mind of being stuck in thinking in queued message handlers when working with AF. Technically AF is exactly that (a queued message handler) only that it's easy to overlook that layer when developing as it is so encapsulated.

I do now realise that your approach in creating a message for each state is the intended one. FWIW I'll try to explain what I meant to do.

Rather that having one vi/message which deals which each state I was going to have one vi/message which dealt with all states using the typical cluster with a command string or enum and a variant which contained the data. This could obviously not run as a loop but would have to store data ... therefore FGV to store that data. To summarise I hadn't had a full grasp of how to best use the AF for my case.

0 Kudos
Message 3 of 22
(6,069 Views)

I have one question. If you launch your controller from the top level diagram, what mechanism do you use in the launcher to find out that the controller has shut everything and itself down so that it can proceed to dispose of the queue reference?

0 Kudos
Message 4 of 22
(6,069 Views)

At the beginning, I didn'tuse any mechanism and let the launcher end. However, as that sometimes causes library locking problems (you can read all about it here), I use the last ack of the controller:

Controller Launcher.png

So far it's working great.

"Wisdom comes from experience. Experience is often a result of lack of wisdom.”
― Terry Pratchett
0 Kudos
Message 5 of 22
(6,069 Views)

Hi Danielle,

thank you very much for the code snippet. I found out about the last acknowledge by looking through the AF source code yesterday and started using that as well but simply wasn't sure if it was good practive. It's very reassuring that you're using the same mechanism

Mathis

0 Kudos
Message 6 of 22
(6,069 Views)

Hi,

I'm a bit stuck and wondered if someone could give me some feedback. I've decided to practice AF on a little project which has the following structure:

actor framework.jpg

I do now want to send a message from my GUI to a DAQ output. This seems very complicated to me as to my understanding I need to create a vi in the controller class and generate the matching message to this, the repeat this for the process class, IO management class and DAQ class to daisy chain the message through (all in green). To display any input from the DAQ I then seem to have to repeat this in reverse order until my data reaches the GUI (all in red).

My basic question is: Am I missing something or is it really that complicated to get a message from point A to point B in the software?

You can obviously have everything being controlled by the controller, that way you reduce the number of vis+message classes to two for any message but that is obviously at the cost of functional structuring as e.g. the DAQ is supposed to talk most heavily to the state machine meaning that the controller queue doesn't need to get clogged up by that.

Looking forward to some feedback of how I can get this more efficient

thanks a lot

best regards

Mathis

0 Kudos
Message 7 of 22
(6,069 Views)

Mathis,

This is a typical problem people have with AFand there are various solutions, each with varying degrees of complexity and trade off's.

The obvious answer is that you can share the actor queues by either putting them all in functional globals or initiating the actors with a reference to any queue you would like.

I've written a few iOS apps and modeled some of this communication based on some of the architecture they provide, it's a bit complicated but I will give you an idea and if you are interested you can follow up with further questions.

The idea is that you create a "Notification Center", this is a singleton object that is created as soon as your application runs.  The queue of this object can be shared as a functional global encapsulated in a "Register For Notification" or "Post Notification" vi.

When you register for a notification, you pass along your queue and the message you want sent to you when the notification occurs.  These messages all inherit from a "Notification Message Class" that has a variant to carry data as a dictionary using the variants set attributes.

Actors can then register or post notifications and it's all very loosely coupled because you only need to know about the notifications you care about, not anything about the actual actor posting them.

Just a thought to share with the community, you can read more about it, in apple's documentation if you search for NSNotificationCenter.

Hope this helps at all.

Message 8 of 22
(6,069 Views)

Mathis,

I think the design looks good, but in order to leverage the layers you need to not just relay a message from the bottom of one branch up to the top and then down the other branch. More likely you would send the DAQ data messafe to the IO manager. The IO manager would do something to all of the data it is receiving (DAQ and 12C) and send a different type of message to the Process. The Process would do something with the SM and IO Mgmt and send another type of message to the Controller.

I think you might want to think about why you made the different layers in your design and think about the interface (messages) between them. Do you have these layers so you can do a plug-in architecture? What messages are you going to send?

UI elements can be a bit tricky if you really want to display everything. I aggregate my data and send a message with the aggregate.

Now, to make it even more reuseable you will want to learn about "zero coupling" and make it so that the DAQ send a message to its "caller" without knowing who that is:

https://decibel.ni.com/content/message/41428

Good luck.

Casey

Casey Lamers


Phoenix, LLC


casey.lamers@phoenixwi.com


CLA, LabVIEW Champion


Check Out the Software Engineering Processes, Architecture, and Design track at NIWeek. 2018 I guarantee you will learn things you can use daily! I will be presenting!

0 Kudos
Message 9 of 22
(6,069 Views)

What is the meaning of the process layer? Does a process have general "init","run","close" etc. that each process implements separately?

If you have an IO management layer, shouldn't the message go only to there? If your message is part of a "get data" function of the process, the message should only go to the process.

While it is extremely complex, did you look at Elijah Kerry's measurement utility? There the actors are the measurements (the process in your case?). The HW a measurement uses are regular classes. So each measurement actor uses a class of type hardware to perform the basic "init", "run", "show data" etc.

As a general answer, all my classes inherit from a parent actor. If there is a message that should pass through or can be acceptable to all actors (e.g. change state) I implement the change state VI as dynamic dispatch in the parent actor, implement the message on the parent actor, and override the Change State vi in the children. That helps a bit with the number of VIs (this concept is explained in greater detail here).

I hope that this helps.

Danielle

"Wisdom comes from experience. Experience is often a result of lack of wisdom.”
― Terry Pratchett
0 Kudos
Message 10 of 22
(6,069 Views)