LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

OOP principles in the application

Hello!
I am currently working on developing an application that will interact with various devices using either serial or TCP protocols. This application will also work with DAQ devices, as well as log and monitor collected data. I'm trying to apply OOP principles while developing the application.


I. To begin with, I've created a base class called "Instrument" which includes attributes such as device's name, type, baudrate, timeout, and other relevant information. This class also includes some basic behavior such as opening and closing connections as well as sending commands to the device. There are several child classes that inherit from this base class and override certain methods to provide more specific functionality.

 

Each device will have unique identifier and is stored in a map for easy access. For each device in the map it will be necessary to create a loop in order to establish communication and perform necessary actions.

 

My question is, should there be a single subVI (possibly polymorphic) that is called asynchronously for each device, with a shared reentrant clone execution condition activated?

 

II. I'm struggling with how to approach the DAQ part of the project. There may be multiple tasks (AI, AO, DI, DO) for each device type, and I'm unsure about how to best organize this. My current idea is to create a DAQType abstract class with children. However, I'm not sure if this is the optimal approach. Could you please provide some guidance on this? I have attached a diagram to illustrate my current thoughts.

Class hierarchy exampleClass hierarchy example

 

Some commentary/questions:

 

  1. Do you think the DAQType Abstract Class needs "isRunning" attribute? Maybe a "state" attribute would be better, which the application could use to determine if a task is verified, reserved, running etc.
  2. Each task type requiers a unique set of channel parameters to be configured. For example, each AI task channel requires the following parameters: name, device, physical channel, min value, max value, terminal configuration, hasScale, slope 1 and slope 2. I believe these parameters should be cluster typeDefs stored in array as an attribute for each task class. In addition, I would like the ability to change tasks inside the application or by loading them from files. Based on my considerations, .csv file format fits because it would be convenient for the developer and user to make changes to the file.
  3. There can be a maximum of three NI DAQ devices.
  4. I would like to implement "hot plug-in" in case operator decides to add or reconfigure channels. This means I have to explicitly perform task transition, IIRC from running to unreserved state.
  5. I don't think I need to synchronize tasks with each other. Does that mean I also need a single subvi (probably polymorphic) to be called asynchronously for each task? Also, does that mean that I should store data in AI/DI classes?
  6. I'm not sure if I need a TaskManager class, maybe it would be better to have these "manager" VIs in a library. Here's how I think it could work:
  • Create a TaskManager object and call its CreateTask("AnalogInput", "ai_config.csv") method;
  • The AnalogInputTask.ConfigureFromFile will then read configuration from the file and fill array of <AIChannelConfig cluster typeDef>;
  • Then AnalogInputTask.Configure creates DAQmx task for the channels defined in the array;
  • The TaskManager will start an asynchronous call to the TaskRunner.vi for each task;
  • The TaskRunner.vi calls DAQTask.Perform independently in each loop;
  • If an error occures -> RestartOnError(). If the programm stops -> Stop() and Clear() the tasks;
  • // similar behaviour for other (AO, DI, DO) classes.

 

I feel like these is some fundamental information that I'm missing. Can you help me to put everything together?

Thank you very much in advance!

0 Kudos
Message 1 of 20
(540 Views)

Hello and welcome to the forum. 

 

Doing DAQ and I/O is what LabVIEW was made for. The DAQtype UML looks like a loose wrapper on some existing DAQmx functionality.

 

 

  1. Do you think the DAQType Abstract Class needs "isRunning" attribute? Maybe a "state" attribute would be better, which the application could use to determine if a task is verified, reserved, running etc.Maybe, you can read the task state form DAQmx methods or make a wrapper and track it yourself.
  2. Each task type requiers a unique set of channel parameters to be configured. For example, each AI task channel requires the following parameters: name, device, physical channel, min value, max value, terminal configuration, hasScale, slope 1 and slope 2. I believe these parameters should be cluster typeDefs stored in array as an attribute for each task class. In addition, I would like the ability to change tasks inside the application or by loading them from files. Based on my considerations, .csv file format fits because it would be convenient for the developer and user to make changes to the file..csv is great, its easy to open, easy to read, and ubiquitous. Also popular are .INI files and in recent years .json has gained popularity as these two have a standard unlike a raw .csv file.
  3. There can be a maximum of three NI DAQ devices.Ok?
  4. I would like to implement "hot plug-in" in case operator decides to add or reconfigure channels. This means I have to explicitly perform task transition, IIRC from running to unreserved state.Do you mean swapping out a DAQ card while the system is running?
  5. I don't think I need to synchronize tasks with each other. Does that mean I also need a single subvi (probably polymorphic) to be called asynchronously for each task? Also, does that mean that I should store data in AI/DI classes?Hmm, you should be sure of this before starting or you might end up with spaghetti in the end. Also, DAQmx handles synchronicity.
  6. I'm not sure if I need a TaskManager class, maybe it would be better to have these "manager" VIs in a library. Here's how I think it could work:This depends on the use case, are you writing a program or a library? What does the user of the program or library expect? 
  • Create a TaskManager object and call its CreateTask("AnalogInput", "ai_config.csv") method;
  • The AnalogInputTask.ConfigureFromFile will then read configuration from the file and fill array of <AIChannelConfig cluster typeDef>;
  • Then AnalogInputTask.Configure creates DAQmx task for the channels defined in the array;
  • The TaskManager will start an asynchronous call to the TaskRunner.vi for each task;
  • The TaskRunner.vi calls DAQTask.Perform independently in each loop;
  • If an error occures -> RestartOnError(). If the programm stops -> Stop() and Clear() the tasks;
  • // similar behaviour for other (AO, DI, DO) classes.

After reading your questions, you might benefit from doing a deep dive into the existing DAQmx functionality in LabVIEW, there is a lot there and it might save you a lot of time. LabVIEW is made to do I/O and the built in library is pretty amazing. Its what makes developing this kind of thing in LabVIEW super fast compared to other languages much of the stuff you are asking about is already written for you, though you might have to write you own UML : ) 


 

______________________________________________________________
Have a pleasant day and be sure to learn Python for success and prosperity.
0 Kudos
Message 2 of 20
(511 Views)

We've been using an OOP approach to hardware at my company for almost 10 years now, so I speak from experience.  And my first questions to you would be... are you ever going to use a DAQ that doesn't support DAQmx?  And, if not, why are you using LabVIEW OOP for this?

 

That might seem like a silly questions to ask, but hear me out.

 

When we started using OOP, our objectives were to:

  • Develop common methods that could be used generically across all instrument types
    • Such as "Initialize", "Shut down", "Save your configuration", "Load your configuration", and so on
  • Develop other common methods that could be used generically across all instruments of a common type
    • This would then allow easy changes from Brand X to Brand Y if we change vendors or whatever.

 

This went fine and works great for common devices like power supplies and multimeters. Things like setting max volts/amps, toggling output channels on and off, doing single measurements, all very easy to do generically and in a way that obscures the exact connection method and the commands sent.

 

However, when we got around to DAQs, it became quite sticky.  We attempted to create a common set of function calls that could handle anything we needed to do with DAQmx-compatible devices and found that if we truly wanted to be feature-complete we'd essentially have to replicate all the DAQmx calls nearly 1 to 1, and then if we ever found a 3rd party device we'd have to do a lot of creative interpretation of its commands and would likely have to rewrite a ton of things anyway.

 

As such, we eventually decided to scrap what much of what we'd created, and just create a class for DAQ devices that was essentially all the common features that all instruments had, and then a few calls to pull DAQmx data types out of the stored configuration (tasks, channels, devices, etc.), and then call it good.  We'd then just use the class as just a method of folding DAQmx into our standard model, but to go no further.  Since DAQmx is already fairly easy to change device types on (going from a CompactDAQ to a PCIe one, for instance) then we already had the functionality we were looking for.  DAQmx already works the same whether it's USB or Ethernet or whatever, and we gained nothing but headaches trying to redo it all as a LVOOP implementation.

0 Kudos
Message 3 of 20
(494 Views)

@Kyle97330 wrote:

are you ever going to use a DAQ that doesn't support DAQmx? 

 


I would stress this portion, if you can standardize on the vendor, you can eliminate the need to implement and maintain this DAQ abstraction layer.

You will be investing more into this software portion than you would save on switching between DAQ vendors unless you're purchasing 1000s of DAQs.

Santhosh
Soliton Technologies

New to the forum? Please read community guidelines and how to ask smart questions

Only two ways to appreciate someone who spent their free time to reply/answer your question - give them Kudos or mark their reply as the answer/solution.

Finding it hard to source NI hardware? Try NI Trading Post
0 Kudos
Message 4 of 20
(434 Views)

Hello, Jay14159265!

Thank you for your fast reply! 


@Jay14159265 wrote:

1. Maybe, you can read the task state form DAQmx methods or make a wrapper and track it yourself.

4. Do you mean swapping out a DAQ card while the system is running?

6. This depends on the use case, are you writing a program or a library? What does the user of the program or library expect? 

1. What concept do you mean by wrapper?

4. DAQ-card will still be the same but one group of connected signal lines may be changed to another due to a lack of channels while system is running.

6. Basically, the program should control devices via power sources and track the parameters via DAQ cards. Since the devices operate autonomously for a long period of time, the program also includes cyclograms and PID controls. User expects to be able to monitor parameters and make changes during the operation of a system. There is a possibility that the power sources may also change while peripheral devices (thermocouple, gate, vacuum gauge etc) should not be changed.

 

I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?

0 Kudos
Message 5 of 20
(420 Views)

@Shatoshi wrote:

I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?


I think

"Learn 10 Functions in NI-DAQmx and Handle 80 Percent of Your Data Acquisition Applications"

https://www.ni.com/en/support/documentation/supplemental/06/learn-10-functions-in-ni-daqmx-and-handl...

 

will be a good start followed by the "Advanced Programming" section of

 

"Getting Started with NI-DAQmx"

https://www.ni.com/en/support/documentation/supplemental/06/getting-started-with-ni-daqmx--main-page... 

Message 6 of 20
(410 Views)

Hello, !

Thank you so much for such a detailed answer!


@Kyle97330 wrote:

And my first questions to you would be... are you ever going to use a DAQ that doesn't support DAQmx?  And, if not, why are you using LabVIEW OOP for this?


There is one device available that does not support DAQmx. I assumed it would be a good idea to use LVOOP if this device is going to be used. In fact, the system can do without this "custom" device. Another reason is that I want to make a scalable application, and based on my Java development experience, I'm trying to apply similar development patterns. It seems like I should change my mindset. 

 

Your answer has cleared up the confusion in my head. I would appreciate it if you could at least give me an approximate idea of what the class for DAQ devices you are using is. Also, based on your experience, can you recommend any sources of information that I could start with?

 

In the first part of my post, there was also a question about I/O equipment:

 

Each device will have unique identifier and is stored in a map for easy access. For each device in the map it will be necessary to create a loop in order to establish communication and perform necessary actions.

My question is, should there be a single subVI (possibly polymorphic) that is called asynchronously for each device, with a shared reentrant clone execution condition activated?

 Am I thinking in the right way, or am I fundamentally wrong?

0 Kudos
Message 7 of 20
(408 Views)

@UliB wrote:

@Shatoshi wrote:

I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?


I think

"Learn 10 Functions in NI-DAQmx and Handle 80 Percent of Your Data Acquisition Applications"

https://www.ni.com/en/support/documentation/supplemental/06/learn-10-functions-in-ni-daqmx-and-handl...

 

will be a good start followed by the "Advanced Programming" section of

 

"Getting Started with NI-DAQmx"

https://www.ni.com/en/support/documentation/supplemental/06/getting-started-with-ni-daqmx--main-page... 


Cheers!

0 Kudos
Message 8 of 20
(404 Views)

@Shatoshi wrote:

...

1. What concept do you mean by wrapper?

4. DAQ-card will still be the same but one group of connected signal lines may be changed to another due to a lack of channels while system is running.

6. Basically, the program should control devices via power sources and track the parameters via DAQ cards. Since the devices operate autonomously for a long period of time, the program also includes cyclograms and PID controls. User expects to be able to monitor parameters and make changes during the operation of a system. There is a possibility that the power sources may also change while peripheral devices (thermocouple, gate, vacuum gauge etc) should not be changed.

 

I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?


1. From Wikipedia: 

 A wrapper function is a function (another word for a subroutine) in a software library or a computer program whose main purpose is to call a second subroutine[1] or a system call with little or no additional computation. Wrapper functions simplify writing computer programs by abstracting the details of a subroutine's implementation.

 

4. Good, this is the easier case. DAQmx can handle this. 

 

6. So this is an application, you need to provide object interfaces that can be utilized by the UI in a way that makes interacting with each I/O channel homogenous. 

 

Yes, I understand that you are using primarily NI hardware so in your application you can have DAQmx as your base class for tasks and extend the class for instruments that do not use DAQmx. The only bummer is that the DAQmx VIs are not written in LVOOP, maybe someone has a library that has created the wrappers already to make them LVOOP style. 

______________________________________________________________
Have a pleasant day and be sure to learn Python for success and prosperity.
0 Kudos
Message 9 of 20
(354 Views)

@Shatoshi wrote:

Hello, !

Thank you so much for such a detailed answer!


@Kyle97330 wrote:

And my first questions to you would be... are you ever going to use a DAQ that doesn't support DAQmx?  And, if not, why are you using LabVIEW OOP for this?


There is one device available that does not support DAQmx. I assumed it would be a good idea to use LVOOP if this device is going to be used. In fact, the system can do without this "custom" device. Another reason is that I want to make a scalable application, and based on my Java development experience, I'm trying to apply similar development patterns. It seems like I should change my mindset. 

 

Your answer has cleared up the confusion in my head. I would appreciate it if you could at least give me an approximate idea of what the class for DAQ devices you are using is. Also, based on your experience, can you recommend any sources of information that I could start with?

 

In the first part of my post, there was also a question about I/O equipment:

 

Each device will have unique identifier and is stored in a map for easy access. For each device in the map it will be necessary to create a loop in order to establish communication and perform necessary actions.

My question is, should there be a single subVI (possibly polymorphic) that is called asynchronously for each device, with a shared reentrant clone execution condition activated?

 Am I thinking in the right way, or am I fundamentally wrong?


That is what I do. I have one non-reentrant part that scans for all instruments and makes a map of device information, model, sampling rate, etc. I use the instrument alias as the key. The user enters the parameters for an Analog Input acquisition, and this non-entrant VI configures all the task parameters in the map. Once the task is configured and committed, it is sent to a reentrant VI that starts the task. This reentrant VI allows one to change the display, analysis, etc of the running task. Thus multiple devices can run at once.

 

I do not know if this is the correct way, but it works.

0 Kudos
Message 10 of 20
(335 Views)