Jump to content

QSM-PC vs. something else in re Performance


Recommended Posts

Hello,

I am in the process of developing a control application for a prototype optical system, and I was wondering if anyone could provide a second opinion for the program architecture I have chosen, especially with regards to performance. As follows is a description of the system and the code written thus far. Please forgive me if this is a bit verbose; I figured more detail would be better,

In terms of components, there are several different types of illuminators, cameras, and motors to control the optics. Total component count is around 8 independent parts that require control. The goal of the control application is two fold. First, it must be a framework to control each component independently to allow for testing, development, and real-time testing and tweaking. Second, it must be able to control each device in a "free run" mode, which is how the system will operate as designed; such that the application must react to basic user inputs (stop, go, "look at this") as well as handle input from the various devices and adapt (e.g. camera is low light, change PWM signal on illuminator).

Each device requires a control panel of 5-15 buttons as well as 3-4 fields, numeric or enum, to handle the most used commands. Also there is a string interface for handling the esoteric command that is not often used. There is also a panel to manage device connections, and a panel for the free run mode. I assumed a tabbed interface would be best.

As for under the hood, I started basically with the QSM-PC model as discussed on the expression flow website; one loop is an event structure that handles button presses and loads them onto queues, the rest are consumer loops controlling devices. In a previous system, one of my colleagues had used this architecture to control a system of a similar level of complexity, but there were complaints of the program not being very responsive I assumed that this had to do with control-reference-variant data in the message packet, or the queue manager. To try to improve performance in this new application, I have removed the "queue manager" completely and created a message packet with a device specific "message label" and boolean value rather than a variant. To sum up the typedef and enumerated values for each device:

Hardware Module X:

-Message packet

-Message label

-Device state data cluster

-Device state list

-Device command list

plus the queue for that device, and the while-case loop that execute's that case's state machine.

Several of the components have simple state machines (with polling the UI), each standalone VIs, that already work. I attempted to reuse this code by replacing polling operations with a dequeue-and-interpret-message segment of code in each polling state. Some of these state machines have multiple polling states, especially the non eye-safe laser (IDLE, IDLE-Armed, Wait-For-Stop). The state transition mechanism is essentially:

state data + current state + (message packet if polling state) => new state + new state data

In regards to performance concerns, the application will need to decode and display two incoming video streams at 30 fps. I am assuming this will take a large amount of processor time, so I want the rest of the application to be as nimble as possible.

Any and all suggestions are welcome. If you think there may be some other bottleneck that I haven't anticipated, I'd be curious to hear your thoughts. I don't have much experience estimating the performance of control references, variants or the like.

As an aside, I've never done OOP in LabVIEW, but I'm familiar with it from C++.

Thanks,

Jon

Link to comment

Jon,

OK, I read through your description and I think you are on the right track. Everything sounds good.

I will make a couple comments:

1) Your UI and your controller should be separate applications (Model-View-Controller), not just separate loops. I'm fairly certain from your description that they are thus in your project, but it's worth emphasizing.

2) I understand most of your communication paradigm (I'm a little fuzzy on a couple points) but it sounds solid and I think it approaches something along the lines of the Object-Oriented Command Pattern. On that note, we have implemented the OO Command Pattern in LabVIEW. Messages are LabVIEW by-value objects flattened to strings and sent via a messaging system. In our case, we use networked shared variables for the communication mechanism. The advantages are that the interface is quite simple yet flexible, and that shared variables work over a network. (I personally agree that queued-statemachines--QSMs--offer an unnecessarily complex API at the application level. I think they are a step in the right direction, but there are much better solutions.) Depending on the controller's host (PC or real-time?) and design (hardware-triggered loop or not?) one can even register for shared variable events (but this requires the DSC Module) instead of polling. (We do both, depending on the application.)

3) You haven't stated what the performance requirements of the application are, but neither control references nor variants are likely to cause performance problems except in the most demanding applications. Any performance issues are more likely to result from something in the way the application handles the messages (e.g., missing messages).

4) You might consider using the OO State Pattern for statemachines still to be implemented. We've done this in LabVIEW, too. It wasn't easy for me the first time but now I love it and if you've done this in other OO languages you won't have any major troubles in LabVIEW.

Anyway, I think you're doing great! Good luck with the project!

Paul

Link to comment

Jon,

OK, I read through your description and I think you are on the right track. Everything sounds good.

I will make a couple comments:

1) Your UI and your controller should be separate applications (Model-View-Controller), not just separate loops. I'm fairly certain from your description that they are thus in your project, but it's worth emphasizing.

2) I understand most of your communication paradigm (I'm a little fuzzy on a couple points) but it sounds solid and I think it approaches something along the lines of the Object-Oriented Command Pattern. On that note, we have implemented the OO Command Pattern in LabVIEW. Messages are LabVIEW by-value objects flattened to strings and sent via a messaging system. In our case, we use networked shared variables for the communication mechanism. The advantages are that the interface is quite simple yet flexible, and that shared variables work over a network. (I personally agree that queued-statemachines--QSMs--offer an unnecessarily complex API at the application level. I think they are a step in the right direction, but there are much better solutions.) Depending on the controller's host (PC or real-time?) and design (hardware-triggered loop or not?) one can even register for shared variable events (but this requires the DSC Module) instead of polling. (We do both, depending on the application.)

3) You haven't stated what the performance requirements of the application are, but neither control references nor variants are likely to cause performance problems except in the most demanding applications. Any performance issues are more likely to result from something in the way the application handles the messages (e.g., missing messages).

4) You might consider using the OO State Pattern for statemachines still to be implemented. We've done this in LabVIEW, too. It wasn't easy for me the first time but now I love it and if you've done this in other OO languages you won't have any major troubles in LabVIEW.

Anyway, I think you're doing great! Good luck with the project!

Paul

Hi Paul

Are you able to, and do you have the time, to post up examples of your Command Pattern and State Pattern using LVOOP?

Cheers

-JG

Link to comment

Hi Paul

Are you able to, and do you have the time, to post up examples of your Command Pattern and State Pattern using LVOOP?

Cheers

-JG

Yes, I already promised to do this for the Large LabVIEW Application Development forum and I haven't forgotten about it. I will try and find a minute to post something tomorrow; if not, this weekend.

Link to comment

I worked on putting something together this afternoon. There is a lot there but it's not quite done and I need to review it.... I'll put something up soon. (It probably won't be finished but it will be something to start.)

Link to comment

Paul,

Thanks for the feedback. I'm looking into your suggestions about the OO design patterns. I also have been reading up on the LabVIEW Statechart module, but I'm not sure if that will yield any fruit. Do you (or does any one else reading) have any experience with the Statechart module?

As a more specific response

1) In regards to the Model-View-Controller, I understand it as a design paradigm. I think I could probably do a better job separating the "model" (command sets and message encode/decode) and the "controller" (state transitions and handling user interface), but I'm not entirely sure where to draw the line in terms of LabVIEW. Is this where the OO command pattern comes in? This is partially why the Statechart module piqued my interest, as it seems at a quick glance to encapsulate the controller portion of the code quite nicely.

3a) As for performance, this will be running on a PC with native windows XP 32-bit edition. There are no "real-time" requirements, per-se, but it will need to stream video (a module yet to be developed). The I/O requirements are something like 4 devices over RS-232 via PCI (PCMCIA), a video capture card (ExpressCard), USB video capture (RS-170), and a usb control device. Critical (microsecond) timing is handled by custom hardware, and does not need to be handled at the software level.

3b) After doing a little more deep reading of the previous application's code, I found another potential bottleneck or two. The code was written to dynamically load the instruction sets of each piece of hardware from a text file at start of runtime. This was loaded into a string array; in some cases, the string array was searched to lookup the particular command. For this application, that is a bit of overkill (there is no anticipation of radical changes in the command set). Also, some command sets had ~200+ commands for any device. Not so good for an O(n) search just for a button press. I'm sure there may be something else under the hood, but at this point, I don't think it is worth looking for as there are about 150 vi's, some of which are bells and whistles like this. So I guess that's the message handling quirk.

4) Considering the value of a more seamless integration, I may rewrite the existing state machines to fall in step with the eventual design paradigm. In the meanwhile, I have been encapsulating helper code, such as "Camera XYZ Build Command" and "Device ABC Interpret Response". I think it should be quite feasible to wrap these into methods, yes?

Thanks for the help,

Jon

Link to comment
  • 4 weeks later...

Jon,

Sorry for the late reply. I think I somehow missed your message while I was at the conference. Probably you've progressed well beyond this point by now! :-) Well, I will answer what I can anyway....

I haven't used the LabVIEW Statechart Module, although I did look at it on-line. I thought it was pretty cool. I've learned to do the same sort of thing manually using the Object-Oriented State Pattern easily enough, so I haven't pursued using the module. (The Statechart Module doesn't use an Object-Oriented solution--or at least didn't in its inital release.) My other concern was that I don't think theStatechart Module lets you see and edit the code it generates (understandably) but maybe this isn't really an issue. (I guess I like to see and edit my architecture code.) Anyway, the Statechart Module impressed me but I don't have any more experience with it.

I found the hardest part of M/V/C is to understand what the Model is. I look at it as the state of the system. Usually I end up encapsulating it in a classed called something like <Component>Data. It (or its member classes) comprise all the data for the component and all the behavior associated with it. The Controller figures out what to do but it delegates all the actual work to the Model, since it has all the state information and associated behaviors. In practice I initialize the Model object at the beginning of the Controller execution, and then update the Model on a shift register on the Controller's loop. The Model isn't a application itself. The Controller invokes the Model's methods.

Paul

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.