Jump to content

OpenGOOP - how to use?


Recommended Posts

I want to use OPENGOOP to develop my program,but I have not any experience to use oop in LABVIEW。

I try to do a small program to test how to use OPENGOOP like this

class Circle{

private:

int x,y;

int r;

public:

float area(int i);

};

float Circle:area(int i)

{

float A;

A=i*i*3.1415;

return A;

}

When I use "Make New OpenGOOP Class" ,I get some vi . I don,t know how to start,maybe someone can help me.

The examples in "OPENG" are hard to me,and I open it in LV 7.0 have something wrong.

Thanks for the help

Link to comment

Hi

I try to explain it as far as I know how to use it.

1. First you have to create a new OpenGOOP class, as you already mentioned. A dialog appears, where you have to give a name and the location for your new class (let's call it car). If you select ok, the source is being generated.

2. Browse to your class location. You have a directory with the same name as your class. Inside there are three subdirectories (Core, Datastructures and Templates).

3. To create attributes of you class (let's say length, hp, number of doors, brand, model) browse into the directory datastructures and open the file Classname Data.ctl (in this case Car Data.ctl). This file contains a structure with some controls. Change these to meet your requirements. (In this case add three numeric and two string controls).

4. The class is now defined and you may want to creat constructors and accessor-method. So now you need the templates. There are four types: Create, Destroy, Modify Data and Read Data. Open one of these, add you functionality and save them in a new directory.

5. There's maybe a broken arrow if you open one of these templates the first time. To fix this, open the vi Classname Object Data Store VI Ref Type.vi (in this case Car Object Data Store VI Ref Type.vi) which is located in the core directory. Right-click on the refnum-control, select "select vi server class >> browse". Select the vi Classname Object Data Store.vi (in this case Car Object Data Store.vi). Save this vi and there should not be any broken arrow now.

I hope this helps you.

Thomas

Link to comment
I want to use OPENGOOP to develop my program,but I have not any  experience to use oop in LABVIEW。

I try to do a small program to test how to use OPENGOOP like this

When I use  "Make New OpenGOOP Class" ,I get some vi . I don,t know how to start,maybe someone can help me.

The examples in "OPENG" are hard to me,and I open it in LV 7.0 have something wrong. 

4355[/snapback]

First of all you should know what oo is... :thumbup:

The openGoop is a form of static classes. For each class (NOT the instances) in your project define an unique name. Each class is then organized in a directory structure. The structure holds the subdirectories:

core: all the vi's needed so the opengoop works properly

data structure: the controls (typedefs) so the opengoop works properly

template: templates of the public methods

create by your own:

public: place where you will put your public methods

private: place where you will put your private methods, create if needed.

In the data structure you get a typedef <class name> data.ctl: edit it at your whish so it holds all the properties of your class. After editing it go to core, open <class name> Object Data Store VI Ref Type.vi and drag-n-drop the sub-vi from the block diagram onto the "VI Refnum" on the frontpanel.

Also in data structure open <class name> Object Refnum - Enum.ctl and edit the text in the enum with e.g. the class name. That will give you a reference typedef that is unique to your class.

In core" you'll fine the vi's <class name> Get Data.vi, <class name> Get Data to Modify.vi and <class name> Set Modified Data.vi These are primitives that give you access to the INSTANCE properties. You'll have to handle the properties in a whole (organized in the cluster you saw in the <class name> Data.ctl)!

With Get Data just read the properties, with Get Data to Modify read the data an lock them (to make modifications) and with Set Modified Data write the modified data-cluster back and release the lock.

:nono: NEVER try to access the properties in any other way, you'll run into race conditions and probably loose data.

At the end open <class name> - VI Tree.vi and close it to save all changes. Also put your created public/private methods in this vi.

The intention of this vi is to be the "central class management point".

When implementing an instance, use <class name> Create.vi (derived from the template). You get a reference that is (this time) unique to your OBJECT! When you want to call any other method or the properties ALWAYS wire this reference or you get errors.

Implement your methods based on <class name> Read Data.vit template when you don't have to write back something to your properties.

Implement based on <class name> Modify Data.vit when you modify properties.

At the end, when the Instance isn't used anymore release the memory with <class name> Destroy.vi.

To find an implementation look at my version of the pop-up menu in Popup menu.

Also have a look at OpenG.org: OpenGOOP. It hold's further descriptions.

Didier

Link to comment
:oops: sorry Thomas, if I repeated what you already said. Seems as we just got into a "race condition": you sent your answer while I was still typing....

4366[/snapback]

Hi Didier

No Problem. I think both of us have to give such answers as long as our brains are fresh and free of any confusing workday thoughts :laugh: .

Thomas

Link to comment
  • 11 months later...

:question: Hey all, I've got a question that I'm pretty confused about. So I have created multiple classes for my system. This system basically reads a serial port, parses the data, saves the data, creates a directory, and display's the data. So I have multiple classes for each of these functions (open serial port, parse data, save data, gui). I'm having lots of problems when I try to transfer information between these classes. For example, in the user interface, the user enteres their name and batch ID. These two values go into the data of the userinterface class. From here, the name and batch ID are used by the createpath class to make a directory if the user is new, or welcome back the user if they have previously used the system. The problem I'm having is that in my user interface I'm not sure how to call the createpath class and transfer these values to it so it can perform its function.

Thanks a lot in advance!

Link to comment
I'm having lots of problems when I try to transfer information between these classes.

The problem I'm having is that in my user interface I'm not sure how to call the createpath class and transfer these values to it so it can perform its function.

Thanks a lot in advance!

My solution to this challenge is to create a Master class that contains all of the other classes.

Here is the Data Cluster of a Class that I am currently working with. It represents a Test Bay.

post-584-1142142636.png?width=400

All of the class objects for this class are created in the Master create vi.

post-584-1142143074.png?width=400

When 2 or more separate classes need to work together their referenced are easily accessible inside a public function.

post-584-1142144067.png?width=400

Hope this helps.

Link to comment

post-584-1142142636.png?width=400

  1. I'm impressed by the graphics used in the refnums. It never did occur to me to customize the controls with pictures.
  2. You are the first person I've found (besides me) who is using Galil motion controllers with LabVIEW.
    I've always found that to be a bit odd because IMHO they are very nice controllers to use.

Link to comment
  1. I'm impressed by the graphics used in the refnums. It never did occur to me to customize the controls with pictures.
I think they add a definite cool factor to the Goop vis :thumbup:
Although sometimes the graphic creation takes more time than it should.

  1. You are the first person I've found (besides me) who is using Galil motion controllers with LabVIEW.
    I've always found that to be a bit odd because IMHO they are very nice controllers to use.

I'm very fond of Galil.

They have great Products

Excellent Support

And like NI the people at the top are very technical minded.

Link to comment
I want to use OPENGOOP to develop my program,but I have not any experience to use oop in LABVIEW. I don't know how to start,maybe someone can help me.

I too have just started to try to understand GOOP. There's a lot of good information scattered around in this and other web sites but it's sort of like putting together two old jigsaw puzzles that have had their pieces mixed together; there's a lot of sorting going on and you are not sure whether or not a few pieces are missing.

One of the more integrated and documented** implementations of GOOP that I have found is dataACT's dqGOOP.

(**The one place where I missed good documentation in the dqGOOP system (and OpenG is no better in this respect) was for the class templates. They do not come with an explanation of their purpose. In most cases you can figure out why they are included and what they do from their name, but in a couple of cases I was left scratching my head wondering "why the heck is that VI here?")

I had examined the OpenG implementation and had seen how its data store made use of a functional global and, in fact I had done similar things with functional globals in the past on my own, but after reading a post over on the NI forums here that in essence said "a single element queue is faster than a functional global and it comes with a built-in mutex mechanism" then I decided to focus my attention on the dqGOOP.

In my case I arrived at the conclusion of "I need GOOP" when I decided that I needed a common or generic motion control interface that I can use with my projects. This would allow me hide the details of operating a particular brand of controller from whatever higher-level code needed motion control functions. I am hoping that I too can get a little insight into the way GOOP should be used.

In the case of my motion control, I think I can divide my data structures (classes?) into two general groups.

  1. The first is static data that represents how the (motion) controller is to be configured and it is rarely changed once the proper configuration has been determined. Certain elements of the structure (attributes?) such as motor steps per physical unit can be frequently read however.
  2. The second data group is dynamic data such as axis positions or speeds and that data is both read and updated quite often.

The motion control system consists of multiple axes and each axis will have its own (mostly) unique set of data that falls into these two classes.

In the past I have used arrays of clusters of data with each (cluster) element of the array being the data for a different axis in the system. But, as I am looking at GOOP, I am wondering "should my class also be an array of clusters of either the static or the dynamic data or should the class be just the cluster itself and I end up with a different class for each axis?" I'm leaning toward the array but perhaps there's a reason why I shouldn't?

I'm also a bit confused by the various template VI's that are made available after either the dqGOOP or OpenGOOP wizards are run. I believe these are intended to be the starting point for the public methods for accessing the data so in my naivet

Link to comment
In my case I arrived at the conclusion of "I need GOOP" when I decided that I needed a common or generic motion control interface that I can use with my projects. This would allow me hide the details of operating a particular brand of controller from whatever higher-level code needed motion control functions. I am hoping that I too can get a little insight into the way GOOP should be used.

:thumbup: I'm always using GOOP-Classes for my datastore (even that my co-programmes shake their heads). In my opinion you can structure your program further than with just sub-vi's. At least you will have to think of how to build up your program BEFORE you begin to wire.

In the past I have used arrays of clusters of data with each (cluster) element of the array being the data for a different axis in the system. But, as I am looking at GOOP, I am wondering "should my class also be an array of clusters of either the static or the dynamic data or should the class be just the cluster itself and I end up with a different class for each axis?" I'm leaning toward the array but perhaps there's a reason why I shouldn't?

In the context of OO-programming you would most probably end up with a "instrument"-class, a "axis"-class that you instanciate n-times as you have n-axes. It might also be that the "axis"-class is just a virtual class that you use a parent class for the different "x"- "y"- "z"-classes. But since OpenGOOP/dqGoop doesn't know inheritance forget the last sentense.

I'm also a bit confused by the various template VI's that are made available after either the dqGOOP or OpenGOOP wizards are run. I believe these are intended to be the starting point for the public methods for accessing the data so in my naivet
Link to comment

Thanks for the reply!

In the context of OO-programming you would most probably end up with a "instrument"-class, a "axis"-class that you instanciate n-times as you have n-axes.
If I create a subclass of axis to the instrument class (which is the only class I was previously envisioning) then it seems like I'd be adding a lot of extra GOOP overhead to the access of the axis data. I would be replacing simple INDEX ARRAY and REPLACE ARRAY ELEMENT functions (which would otherwise be buried in the public methods of an instrument-only class) with more complex GOOP public & private methods to do exactly the same thing. Is this really good thing? Why would it make sense?

If we assume it is a good thing and I do decide to use both an axis and instrument class then from a purely-LabVIEW perspective I would still use a cluster of items to characterize an axis and an array of those clusters to characterize the system of axes. From a GOOP perspective then the cluster of items for an axis would become the class for a generic axis. Then would I use an array of those clusters for the instrument class or should I instead use an array of references to the axis class?

The templates are prototypes for methods that work with the attributes you have stored in the class. You can use them to either get data from the specific object (instanciated class), update attributes of the object or to perform further operations/mathematics with the attributes of the object.

Try always to use the templates to perform operations with the attributes. They prevent that race conditions occure on daily work. The primitives (in the "Core" and "Data Structure" folders) are meant to use only in class methods. Do not use them outside, you might end up with strange behaviours. I would even restrict the use to the three primitives "Get data", "Get data to modify" and "set modified data".

...

The read template is intended for reading out attributes that has to be used once and doesn't need writing back to the class-attributes. For this purpose use the read/write template. Otherwise you might end with race conditions.

Update as much attributes in one read/write method as you have place on your connector pane.

But is it considered acceptable to just read/update the entire class (typedef'd cluster) rather than individual attributes? If my class (cluster) has 10 attributes (items) in it, then why bother with 10 connector pane connections when I can just use one for the cluster? Am I supposed to be keeping the cluster hidden/private?

I agree with you that for a beginner, ore informations of the different templates would be nice. But from the moment you frequently use the templates as a base of your class methods it get annoying alway having to delete this "put you code here".
I know what you are saying but there has to be some way of educating the new user, be it through added text, added example code, included examples or included documentation. The experienced user, if he gets annoyed enough, would probably know how to find and modify the wizard templates to remove the explanations. As an example of what I am talking about, dataACTS' dqGOOP comes with the best documentation I've seen outside NI, yet the templates themselves only have documentation for the controls and indicators. The only clue about what a template is for comes from its name and block diagram and in some cases the block diagram is rather cryptic. I'm still left wondering under what circumstances I'm supposed to be using a few of these templates:

post-2800-1142257471.png?width=400

like this nonModifying.vit:

post-2800-1142257535.png?width=400

Link to comment
If I create a subclass of axis to the instrument class (which is the only class I was previously envisioning) then it seems like I'd be adding a lot of extra GOOP overhead to the access of the axis data. I would be replacing simple INDEX ARRAY and REPLACE ARRAY ELEMENT functions (which would otherwise be buried in the public methods of an instrument-only class) with more complex GOOP public & private methods to do exactly the same thing. Is this really good thing? Why would it make sense?

I said: "in the context of OO programming". Since LV doesn't include classes/inheritance/... for custom use in itself, some things can be done here easier. If you right-click on a property node and select "class" you get the class hierarchy that NI uses for the usable LV-objects (controls, decorations,...). With a different programming language (e.g. Delphi) such stuff (e.g. graph) are a bunch of hierarchically organized classes/subclasses. Even the data of such an graph is not organized in a array but in a "List"-class that includes methods to set/move a pointer to navigate through your data (like a database), methods to read the data as string, double, integer,..., methods to add/remove elements, methods to... :wacko:

Using OO-methods doesn't end with ONE best solution. In your case I agree with you it is easier to just implement the instrument class.

But is it considered acceptable to just read/update the entire class (typedef'd cluster) rather than individual attributes? If my class (cluster) has 10 attributes (items) in it, then why bother with 10 connector pane connections when I can just use one for the cluster? Am I supposed to be keeping the cluster hidden/private?
I wouldn't try to write to the cluster itself (by plopping the cluster onto the block diagram). Since you can instanciate several objects from the same class your data isn't stored in the typedef cluster, but somewhere behind a reference. The primitives "get data to modify" and "set modified data" allows you to read/write from/to the data without suffering race conditions. after calling "get data to modify" your data is locked until you call "set modified data". a second "get data to modify" will wait until the lock is released .
I know what you are saying but there has to be some way of educating the new user, be it through added text, added example code, included examples or included documentation. The experienced user, if he gets annoyed enough, would probably know how to find and modify the wizard templates to remove the explanations. As an example of what I am talking about, dataACTS' dqGOOP comes with the best documentation I've seen outside NI, yet the templates themselves only have documentation for the controls and indicators. The only clue about what a template is for comes from its name and block diagram and in some cases the block diagram is rather cryptic. I'm still left wondering under what circumstances I'm supposed to be using a few of these templates:

Agree, I also guessed what was the purpose for few templates.

The one your refer to, is probably intended for some operations that belongs to the class, but doesn't use any class-attributes. As you group methods and attributes that belong together into a class, it can happen, that e.g. acquired data seometime (but not always) need further arithmethics, but doesn't need attributes of the class (which will typically be "VISA", meas-range, timeouts, for an instrument driver).

Working with classes ends up with overhead of code (and resource use), but gaining readability of your code if you correctly group your stuff into the classes.

How deep you create your class-hierarchy is your problem. C# as example, dives quite far, since every variable (you define) is a class itself, allowing to create inherted classes of it, having properties,... :blink:

Didier

Link to comment
Thanks for the reply!

If I create a subclass of axis to the instrument class (which is the only class I was previously envisioning) then it seems like I'd be adding a lot of extra GOOP overhead to the access of the axis data. I would be replacing simple INDEX ARRAY and REPLACE ARRAY ELEMENT functions (which would otherwise be buried in the public methods of an instrument-only class) with more complex GOOP public & private methods to do exactly the same thing. Is this really good thing? Why would it make sense?

If we assume it is a good thing and I do decide to use both an axis and instrument class then from a purely-LabVIEW perspective I would still use a cluster of items to characterize an axis and an array of those clusters to characterize the system of axes. From a GOOP perspective then the cluster of items for an axis would become the class for a generic axis. Then would I use an array of those clusters for the instrument class or should I instead use an array of references to the axis class?

But is it considered acceptable to just read/update the entire class (typedef'd cluster) rather than individual attributes? If my class (cluster) has 10 attributes (items) in it, then why bother with 10 connector pane connections when I can just use one for the cluster? Am I supposed to be keeping the cluster hidden/private?

It sounds like you are thinking of a class as more of a global variable.

In a class data is manipulated only by its public and private functions.

If you hold to the strict class rules, programs out side of the class can only access the class through public functions. Only public or private functions may access or change the data cluster.

Any function that manipulates the data cluster should be a part of the private or public class functions.

This allows you to encapsulate the class and makes for easier debugging.

So every time you want to add more functionality to the class you would create another public vi to do so.

Yes it does create more overhead but I think you will gain flexibility and robustness.

like this nonModifying.vit:

post-2800-1142257535.png?width=400

I have a similar template in my goop structure. It is used when I need to combine two or more public vis together. An example would be a standard motion profile that calls a public single move vi several different times with pauses in between.

Link to comment
It sounds like you are thinking of a class as more of a global variable.
I guess I was thinking of it as a protected data store or as a data library that allowed reading or updating (check-out, modify, check-in). It would only be global to the motion control module.

Do you use your classes for something different?

In a class data is manipulated only by its public and private functions.

If you hold to the strict class rules, programs out side of the class can only access the class through public functions. Only public or private functions may access or change the data cluster.

So, if for example I need a GUI to update some aspect of the static data like maximum-allowed axis acceleration, then that GUI needs to be one of the functions built into the class rather than checking data out, allowing the user to modify it and then checking it back into the class?

Isn't it reasonable for a more global motion control module (that makes use of the static axis data class) to be responsible for communicating those changes to the motion controller rather than trying to do it in the static axis data storage class? I would think it would be the job of the more-global module because IMHO it doesn't make sense to me to stuff controller communications down into something that is primarily a container for data. That would seem to me to argue for the GUI being in the upper-level module so that it can coordinate the updating of the controller as well as the data store.

Any function that manipulates the data cluster should be a part of the private or public class functions.

This allows you to encapsulate the class and makes for easier debugging.

So every time you want to add more functionality to the class you would create another public vi to do so.

Yes it does create more overhead but I think you will gain flexibility and robustness.

Surely the data cluster and the class can be subordinate to a more all-encompassing function that does cause changes to occur in the data. Sticking with the motion control example, why can't an upper level module (beyond these static & dynamic axis data classes) include a GUI which provides the user the necessary information and means to move an axis and in doing so the upper-level module would access the static class data to determine the bounds of movement and it would access the dynamic class data to determine the current axis state? IMHO, it wouldn't be reasonable to try and shove the GUI and the running of the motion controller down into either the static or the dynamic classes because they are both needed to get the job done (so which one do you pick if you are intent on shoving the GUI down into one?) and neither one really has anything to do with RUNNING a motion controller; they are just there to hold data about some specific aspects of it.

In an overall sense, I agree that I want to end up with something that will provide a uniform motion control interface wherever I might need it and it should definitely hide most of the details of that motion control from the system that is using it. I just don't think I want to try to do it all in one bottom-level class.

Link to comment
I just don't think I want to try to do it all in one bottom-level class.

Seems you are at the point, where you'll have to decide how to structure your program, aka "how will my class hierarchy look like". As I stated there is not ONE AND ONLY best solution. It all depends on the purposes, desired and needed complexity of your application/instrument driver.

An Instrument driver, typically I would build it up in the following manner:

- the create.vi gets standard parameters from its calling vi, like port, baudrate,... (things that might change from application to application and would be stored in the application-ini-file.

- Have a method that pop-ups its frontpanel to change the class attributes. In this vi you can freely use the "get data" "get data to modify" and "set modified data" primitives since you are already in the class. Usually I store the FP-values into the class attributes only after pressing <OK> or (if you have one) <TEST Instrument>.

- Have various methods which only purposes are to get the parameters from a higher-lever vi (e.g. a global configuration-vi) and store them into the class attributes. such methods include just "get data to modify", "bundle by name" tied to the conn-pane-controls and the "set modified data".

- Have various methods that gives the data to a higher-level vi. These methods consists of "get data", "unbundle by name", and the conn-pane-indicators.

- Various methods with further code to accomplish the whole work. Divide the work into pieces that are self-contained (this is one method) but allow to be combined depending on the purpose.

If you divide your instrument into sub-classes (e.g. instr-class & axis-classes) it is up to you to, either supply the instrument-top-class with all the parameters and then it hands them on to the sub-classes, or to get the sub-class-references from the top-class and then pass the parameters directly to the sub-classes.

Both are valid approaches.

To have methods with the contols on their fp and then plop them as sub-panels isn't correctly. On "OO-languages" the fp-elements always belong to the fp-class which will seldom be the instrument class. Passing the value from the fp-element to the class-attributes is done on a event (e.g. "on value change" or "on <OK>").

Didier

Link to comment
I guess I was thinking of it as a protected data store or as a data library that allowed reading or updating (check-out, modify, check-in). It would only be global to the motion control module.

Do you use your classes for something different?

I think of them as dynamic objects. What they do is as important as what data they hold. Checking in and out (which implies some external object takes control of the data) is not allowed. However Requesting changes and viewing data is permitted through public functions only.

Inside a change public function the object is locked.

The data is tested, changed and written in to the cluster

and them unlocked.

The data never leaves the class.

So, if for example I need a GUI to update some aspect of the static data like maximum-allowed axis acceleration, then that GUI needs to be one of the functions built into the class rather than checking data out, allowing the user to modify it and then checking it back into the class?

How about this instead.

The GUI would like to increase the maximum acceleration. It calls the public function "Change Acceleration.vi" and the function makes sure it is capable and then changes the acceleration value. It then returns the values that was actually set.

Sticking with the motion control example, why can't an upper level module (beyond these static & dynamic axis data classes) include a GUI which provides the user the necessary information and means to move an axis and in doing so the upper-level module would access the static class data to determine the bounds of movement and it would access the dynamic class data to determine the current axis state? IMHO, it wouldn't be reasonable to try and shove the GUI and the running of the motion controller down into either the static or the dynamic classes because they are both needed to get the job done (so which one do you pick if you are intent on shoving the GUI down into one?)

If you think of a class as a group of functions that manipulate data and not a global variable that needs help, then

I think there isn't a valid reason to separate static data from dynamic data.

How often a data object changes doesn't make the functionality less dependant on its values.

Since we are using motion as an example here is how I would frame the solution.

I would create an Axis class

Its data cluster contain thing like acceleration, velocity, position, tuning constants, motor com reference, rotary encoder count/rev, gearbox ratio......

The private vis manage things like communication, syntax, conversion of counts to degrees, maybe even plug-ins for different controllers.......

The public vis are the interface to the class. their inputs use real world units like Degrees and seconds.

All the public function are tested to make sure they work as expected. Even unexpected data is used to insure the class is robust and can adapt to bad inputs.

When I'm finished I have a stand alone class that can be used by any program that wants to use an axis. A program that uses the class doesn't need to know how to communicate with the motion controller or how to convert degrees/sec to counts/sec. It only has to know where it wants to go and how fast it wants to get there.

If I find I need more functionality I create a new public function and it is automatically usable by all axes.

If multiple axes are needed then I would create a multi axis class to do the coordination. This class would have an array of axis class references inside the data cluster.

Now the GUI is much simpler to write because it only has to be concerned with the user and the multi axis public functions.

If the axis class is written well I could even change the motor controller brand without affecting the GUI.

Robustness, flexibility and modularity that

Link to comment
I think of them as dynamic objects. What they do is as important as what data they hold. Checking in and out (which implies some external object takes control of the data) is not allowed. However Requesting changes and viewing data is permitted through public functions only.

Inside a change public function the object is locked.

The data is tested, changed and written in to the cluster

and them unlocked.

The data never leaves the class.

I guess this locking business is one point that caused me to think that the data would be leaving the class. Inside the class is a small protected environment that I would expect to be single-threaded. Outside the class no assumptions about how or when the data is accessed can be made. Why bother with the locks if the environment where the data is used is well defined and protected?
If you think of a class as a group of functions that manipulate data and not a global variable that needs help, then

I think there isn't a valid reason to separate static data from dynamic data.

How often a data object changes doesn't make the functionality less dependent on its values.

Since we are using motion as an example here is how I would frame the solution.

I would create an Axis class

Its data cluster contain thing like acceleration, velocity, position, tuning constants, motor com reference, rotary encoder count/rev, gearbox ratio......

The private vis manage things like communication, syntax, conversion of counts to degrees, maybe even plug-ins for different controllers.......

The public vis are the interface to the class. their inputs use real world units like Degrees and seconds.

All the public function are tested to make sure they work as expected. Even unexpected data is used to insure the class is robust and can adapt to bad inputs.

When I'm finished I have a stand alone class that can be used by any program that wants to use an axis. A program that uses the class doesn't need to know how to communicate with the motion controller or how to convert degrees/sec to counts/sec. It only has to know where it wants to go and how fast it wants to get there.

You know this is beginning to sound a lot like what I already had for motion control before I allowed it to get polluted with other non-motion control functions. It started out with someone saying "I need to control these axes" and after that was done, "Gee, that works great! Now we need to run this camera too" followed by "oh, by the way, we need to control this illumination source" and so forth. Fortunately the added functions are very much standalone (built on a client/server model) and were just added to the existing motion control code. I can probably just strip out those functions and tweak a few of the routine interfaces and be right where you are suggesting I should be (though it won't have data locks 'cause it doesn't need them). Then it's just a matter of building an upper-level VI to re-integrate all the functions again...
Link to comment
I guess this locking business is one point that caused me to think that the data would be leaving the class. Inside the class is a small protected environment that I would expect to be single-threaded. Outside the class no assumptions about how or when the data is accessed can be made. Why bother with the locks if the environment where the data is used is well defined and protected?

For a decent size class there will be many public function using the same data cluster. The locking insures that only one public vi at a time may change the data. This is more apparent when using classes or even functional globals in multiple while loops.

The locks will prevent the following situation.

PulblicOne.vi reads data cluster (A)

PublicTwo.vi reads data cluster (A)

PublicOne.vi unbundles STR data, changes it and bundles it and writes back the data cluster (A & STR).

PublicTwo.vi unbundles NUM data, changes it and bundles it and writes back the data cluster (A & NUM) not (A & STR & NUM).

PublicOne's change is lost because PublicTwo did not read the STR changes.

Its the changing of one data item and assuming that none of the other item in the cluster have changed that causes the problem.

The locking of the data cluster would have forced PublicTwo to wait until PublicOne had completed its change.

Tracking down a lost data problem is very difficult.

Timming is a major factor and when you try to find the problem you change the timming.

Here is an example showing why locks are important.

the counts of each loop should follow the itteration number

Download File:post-584-1142554592.llb

To do the same thing with out locks you have to keep all of data change functionality inside a single Functional global to insure no other

vi has access to the data while it is being changed.

There are probably other ways but the dqGOOP locking method to me is the eaisest way to keep the data safe.

"Gee, that works great! Now we need to run this camera too" followed by "oh, by the way, we need to control this illumination source" and so forth.

It sound like you too have fallen victim to the dreaded "SCOPE CREEP" :ninja:>>>>>>>>>> :o

Link to comment
The locking insures that only one public vi at a time may change the data. This is more apparent when using classes or even functional globals in multiple while loops.
Right, wrong or otherwise I try to stay away from multiple loops running at the same time within a given VI hierarchy. I've seen it taken way too far by others and have come to hate it, especially when trying to debug with execution highlighting on. Give me a good old linear state machine any day. If have I needed a system to do two things at once, so far I've always been able to build separate processes (VI hierarchys) to take care of it and I communicate between the processes with queues. The data and hardware used by the different processes remain separate and distinct.
To do the same thing with out locks you have to keep all of data change functionality inside a single Functional global to insure no other

vi has access to the data while it is being changed.

And guess what I use to initialize/read/write/update my data? A single functional global (which also looks a lot like a simple state machine).
It sounds like you too have fallen victim to the dreaded "SCOPE CREEP" :ninja: >>>>>>>>>> :o
Boy that's an understatement!

And sometimes our scopes don't even have the courtesy to creep; some of those suckers positively jog along. :laugh:

Link to comment

Ok guys,

Thanks for your posts. Even if it's sometimes a little bit hard to follow... it clearly illustrates OO programmers questionning ! :worship:

I'm beginning to use OpenGOOP with lv8 on mac OS X. Everything works. However, I'm surprised because OpenGOOP creates each class in one ".llb" file. I read in many posts and docs that it should create "core", "Private", "Methods" folders and a "Tree" vi but it doesn't on my mac. Is it a new feature of openGOOP for lv8 or something like that ?

I built a large application, without any OO programming. I'd like to "clean" all the stuff and make it simple to update (some people will join us soon for that) using GOOP. Is it "reasonable" to change a whole application (approx. 100 vis) from classical labview to GOOP ? (:clock: and :headbang: ?)

Last question, I'm trying to find the "best" GOOP toolkit (remember I use macs) : dqGOOP seems to be Windows only, and NI GOOP not updated anymore. OpenGOOP seems perfect ? Am I wrong ? :book:

Thanks, :beer: !

Boris

Link to comment
dqGOOP seems to be Windows only

Hi Boris,

The installer is Windows only, but dqGOOP uses the native LabVIEW queue functions so it is multi platform. The only other issue is that the help is compiled into a *.chm file so it won't be available. However, the help is just HTML and I could try and put something together that should work (I can not test). I will see if I can get something together this afternoon and post back. Here is the link to Zip archive of dqGOOP (Extract this archive into the ..\LabVIEW X.X\project directory of LabVIEW version 7.0 or greater.)

Brian

PS If the wizard doesn't work in LV 8, you can always use the OpenG "Rename Folder of VIs" utility to create a new class. A modified version that also copies the source directory is here.

Link to comment
Everything works. However, I'm surprised because OpenGOOP creates each class in one ".llb" file.

To me it seems you are referencing to the NI/Endevo-Goop tool. This builds a neat packed llb. If the internal primitive "<something> object repository" is password protected, or you installed the tool from a file called "goop6i.exe" (or similar), then it's NI/Endeve-GOOP.

To create a new openGoop class select in the menu "Tools\Make new OpenGOOP class...". You'll have to download/install it with OpenG-Commander.

Didier

Link to comment

Hi Brian and Didier,

Thanks for the link, I began to use dqgoop and it's fine (under lv8.0.1 and OS X 10.4.5). It would be great to have html help ! :worship:

Thanks Didier too, you're right... I wasn't using opengoop but labview goop (I tried to install it, and thought it hadn't worked...) :oops: .

I'll try to make openGOOP work... :book:

I hope I would post something in a few weeks after turning my whole app into OOP.

Boris

Link to comment
Snip... It would be great to have html help ! :worship:

...Snip

I was hoping that I could just create a directory called "dqGOOP.chm" and use the existing help tags with the uncompiled help in the "dqGOOP.chm" directory, but it won't work on my Windows PC. Does anyone know if this will work on a Mac?

For example, the Help path is:

&lt;helpdir&gt;:\dqGOOP.chm

and the Help tag is:

dqGOOP_Help\VI_TREE\dqClass_getData.htm

where "dqGOOP.chm" is a compile help file on Windows

In the mean time the help is also available online at http://dataact.com/dqGOOP.htm.

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.