Jump to content

PaulL

Members
  • Posts

    544
  • Joined

  • Last visited

  • Days Won

    17

Everything posted by PaulL

  1. OK, I'm intrigued. What data does each of these methods need to operate? If there is no special data needed or if it comes from the caller (which is very likely the case), then you can just write three methods (e.g., start, logIfError, stop) for a single class (e.g., EventLogger). (Note that the class input terminal does not have to be required!) I'm guessing the start and stop methods need to know a logFilename and a queueName, and the logIfError method additionally has an error input. Paul
  2. I was just pointing out that the use of objects doesn't always require wires. (So such an argument, alone, is not a reason not to use objects.) There are times (for sharing data between concurrent, legitimately independent components running in parallel, in particular) when wires won't work and so some kind of communication mechanism is necessary for the components to share data. There are various methods (queues, TCP/IP messaging, shared variables, functional global variables, even global variables) that one can apply for this purpose. There are a couple points I have been pondering on this topic. Here is what I think: 1) We should use unwired communication when it is appropriate (which means when it is necessary--i.e., for interfaces between concurrent components) and not otherwise (not to avoid using a wire where we should have one--that just makes the code harder to read). 2) I am talking about methods of communication. In particular, we are talking about sharing data. We have to be careful when we start adding in other things. I like networked shared variables for data communication because they work over a network, they follow a publish-subscribe paradigm, I (generally) like the API (there is room for improvement here), and I don't have to worry about the details of implementation (whether functionality or performance) but I still get things like logging and alarming (optionally). I do think other communication methods are fine for use when appropriate. I will confess I don't use functional global variables anymore, not because I think they are bad (they have their place--in fact, I'll bet they are part of the shared variable implementation), but because I like the APIs of other available solutions better. It is easier for me to read my code (or someone else's), in my experience, if it uses shared variables and object methods than if it uses functional global variables. There is probably some aspect of how well one uses each technology that impacts this, but still I think shared variables and classes are, used properly, more readable, more flexible, and more powerful.
  3. Also, earlier in the thread: (Black Pearl) (neBulus)First, it is possible to transmit objects "wirelessly." We do this here when we implement the Command Pattern. We flatten the (by-value!) objects to strings, send them using a String-typed networked shared variable (you could use the communications protocol of your choice), and unflatten them on the other end. This works quite well. [Technical note: In our designs to date we don't have to worry about race conditions. Each shared variable has a single writer, and the recipient responds to the data received in the fashion appropriate for its current state. I don't think we will ever have a case here when we will need to do otherwise.] Within a single loop, however, yes, we typically pass around a single wire of the Model class (and wire this to a shift register). This results in code that is both efficient and in our assessment easy to read. Just extract the data you need when you need it.
  4. Ben, Thanks much for the link! Now I know exactly what you mean by an action engine. By way of understanding, I would say in my language, I do much the same thing with an object-oriented controller (usually a statemachine) that invokes methods on a model object that is rather similar to the functional global variable that forms your action engine. I handle sharing data between parallel loops with messaging--in my case networked shared variables that can publish data of any type, including object data, and I suppose that may be the biggest difference between the two methods. That is for another topic, however. I now understand what you mean by the term action item. Thanks for the clear explanation. Paul
  5. This is somewhat of a tangent, but I have a question about the term "action engine." This term appears frequently on LAVA but I admit I haven't paid that much attention to it. In this thread the acronym "AE" appears before anyone uses the term "action engine," which is confusing enough, but what concerns me more is that I'm not sure what the term means. In particular, I did a search on action engine with Google and didn't find anything relevant before I hit this LAVA link (Action Engine), where at least one participant equates it with a statemachine. Is this the case? If so, can we please use the term statemachine, given that it has much broader (and well-defined) usage not only with NI but also with UML and general software design? If there is a difference, can someone please clarify for the benefit of those (including myself) who might be confused? Paul
  6. The constraints for the project might not allow this, but with LabVIEW DSC it is possible (and straightforward) to handle networked shared variable value change events. (This only helps if you can update the clients in your application to write to shared variables, of course.) Networked shared variables use a publish-subscribe paradigm, so if you just want to share broadcast data between clients this is a simple solution to implement. It might be possible to simplify this even further depending on the messages you are sending. For instance, if every client can send and receive the same message set you might consider using a single shared variable and the object-oriented Command Pattern, passing along inside the particular command object an object as a data element that represents the particular client that is the source or destination of the message (if needed). I can explain further if this is of interest to you.
  7. I'm confused. Where would I find this? (I have the OpenG libraries, but I'm not sure what I'm seeking here. I'm hoping you will help me out.) Thanks!
  8. You can't. I independently tried this just the other day and the "To .NET Object" method always returns an error method such as the following: "Error 1199 occurred at Invoke Node in To .NET Object.vi->Untitled 37 Possible reason(s): LabVIEW: Cannot convert the specified LabVIEW type to .NET object. Method Name: .NET:Convert To .NET Type" This is most unfortunate.
  9. We use JIRA and love it. We can access it with via a browser, it is easy to do searches, and it does pretty much everything we need. Our contractor and team have had very positive things to say their experience with the tool as we have moved along in the project. Of additional interest to us is that FishEye automatically updates JIRA issues when we reference them in our Subversion update comments (fantastic!) and a new product we are using (Enterprise Tester) links JIRA and Enterprise Architect, which we use to do our modeling. Paul
  10. I don't know if this will be a suitable solution for your case, but you might also consider using RT-FIFO enabled networked shared variables. We have used these quite successfully on multiple projects with cRIOs and have not encountered the difficulties you describe.
  11. I, too, advocate what is really the Model-View-Controller separation principle. The UI should just handle UI actions and send messages to the controller, which determines how to handle the requests from the UI. A quite elegant way to do this is with the (object-oriented) Command Pattern. In our case we send objects flattened to strings via a single shared variable. (We have implemented this as an asynchronous message system.) This works great! Other approaches already suggested will work fine, too. If it fits your plan at all it really is worth it to separate the UI from the controller!
  12. Sharon, I think (as Frank said) there are more elegant solutions using native LabVIEW coding approaches than resorting to scripting. Consider sending your timer values in an array and performing the calculations on the array. If it gets more complex than that then I'd suggest you consider the Command pattern (an object-oriented solution), but I think for your current problem a solution using an array will be sufficient and much simpler. Paul
  13. Two more notes: 1) We use the name to do a search and replace on the XML output. 2) The code I wrote works with JKI's EasyXML VIs, but one could easily change the search and replace to work with LabVIEW's native XML VIs. Paul
  14. OK, I have now implemented a workaround (that takes off from an idea offered by NI support) that I think is at least fairly robust. The essentials are: 1) When flattening data with units to XML, wire the data twice to the workaround subVIs we create. The first input is really for the data and allows us to create polymorphic VIs so that we can only wire, say, a Double array with a compatible unit to the workaround subVI. The second input is a variant. We use the VIs in the VariantDataType Utilities library to verify the type is correct and, more importantly, to extract the name of the data. A third input is a typedef of the units for the particular type of unit to specify which unit we want in the XML representation. 2) Unflattening data works the same way except that the first data input is solely for type information. I created polymorphic VIs for Double scalars and arrays for a subset of units (currently planeAngle, Time, Pressure, Force, TemperatureAbs, Length, Velocity, Acceleration, Frequency, and Mass). Adding to this is straightforward but beyond our current scope. I can make the code available if anyone is interested. Some further thoughts: 1) While I consider this to be a reasonably robust workaround, I don't consider this to be a final solution. In particular: a) Having to wire up a node to two inputs on a subVI, while relatively robust in this instance, is quite inelegant. It always begs the question. b) Creating instances to handle new variations (different data types or different units), while straightforward, is time-consuming and should not be necessary at the developer level. 2) I would encourage NI to consider the following: a) Why can't the developer get name and type information from a data item from a LabVIEW object reference in the same way they can get this information from a reference for any other type of LabVIEW data? There may be an issue with security here, but this is quite an important issue that keeps recurring, I find. NI should really figure out a way to allow this if it is in any way possible. b) NI should modify the Convert Unit function so that the data name out (at the various levels) is the same as the data name in. In fact, that is by far the simplest resolution to the current issue. c) Again, NI should make an implementation of XML that conforms to some common schema (a standard, if possible). The XML schema LabVIEW currently implements is useful within the LabVIEW environment, but useless in communicating with an external development environment (e.g., Java). There are immensely powerful possibilities that open up when we use a truly interchangeable schema. Paul
  15. Congratulations, Jim!
  16. A few things: 1) Why not strict typedefs? If we use a typedef, we pretty much always make it a strict typedef! 2) If you can use a wire to pass the data (usually best within a software layer) you can use a strict typedef'd cluster or a LabVIEW object. This works very well. 3) If you can't use wires to pass the data (for instance, you want to separate the View from the Controller--highly recommended!), that is, you want to know what the current value of a control is at some other layer in the application, there are several approaches to resolve what is essentially now a communications issue. Hence there were the suggestions for queues, notifiers, and functional globals. One simple approach (and the one I would use) is to bind the control (strictly typedef'd, of course) to a shared variable and then read the shared variable on demand. Shared variables also have the advantage that they work across a network.
  17. Just to add some detail to my previous statement: So my workaround is currently to wire the control to the Convert Unit function, then wire the control and the output of the Convert Unit function to a subVI with variant inputs. From one input (wired from the Convert Unit output) the subVI gets the pure number and from the other input the subVI (wired from the control itself) it gets the name. It then sets the name of the variant with the pure number based on the name from the control. (I'm using OpenG VIs for all this.) Then it writes the result to XML using an Easy XML VI. (Whew!) This process essentially works but now I need a Convert Unit function, two To Var functions (because of the bug) and a subVI to do this. I can't put the Convert Unit functions or the To Var functions inside the subVI. It's not the end of the world, but I think there should be a much better way! That's an awful lot of complexity I need to repeat in a lot of VIs I have to do a fairly simply thing. (I don't know if there is a better way in the current version of LabVIEW, actually, but I'd like to see this change. OK, there are a lot of design issues involved here: units handling most of all, XML secondly, but also LabVIEW object design. I was hoping I was wrong and somebody had a clever way to do this without too much trouble!) Paul
  18. Scott, Yes, to get the original units we have to know something about the control, not the wire. This is what the Convert Unit function does. What I was trying to do was use the Convert Unit function to get a pure number in the desired units. The Convert Unit output doesn't retain the name, however, so I need that from the variant. I'm not exactly sure what all the constraints are on the bug, but basically what I did was the following: Create a numeric (DBL) control with units in deg on the front panel of VI A. Wire it up to a Convert Unit function with units deg to get a pure number. Wire the output of the Convert Unit function to a subVI (create VI B for this purpose) that has a variant input. (A coercion dot will appear, of course.) Run VI A. The variant control in the subVI (VI B) correctly shows the value with no units. So far so good. Now replace the numeric control (VI A) with an array of these numerics with units. Run VI A. The variant control in the subVI (VI B) correctly shows an array of values with no units. Still good. Now make a copy of VI B (make this VI C--it needs to be a separate VI) and wire the numeric array in VI A directly to the variant input of VI C. (Note that this is before stripping the Convert Unit function.) Run VI A. The VI C control has an array with units (the base units, as expected). The VI B control has an array with units, instead of a pure number. This is unexpected! A workaround is to use To Var functions outside the subVIs instead of having the coercion dots. (This is not ideal, of course, since it means we can't just do a search and replace on a subVI when we find a better method.) A huge deal? Maybe not. It does make me wonder just what exactly the rules are. For the record, the CAR # is 186761. Paul
  19. Scott, The first method (with variants) in your VI bears some similarities to the method on which I have been working. When I wire up a control ('angle', with a value of 10 deg) we get the Base Units (rad) in your VI. We want the value in deg. Nonetheless, a version of the this approach really does work (although a LabVIEW bug requires a To Variant outside the subVI to make it work all the time.) The second method (with Refnums) is actually more desirable in some respects, especially since it is a reference to a control and therefore can obtain the original unit (which is one of my requirements). Unfortunately we don't have a reference to the control in our case since we are extracting the values as data members from LabVIEW objects. Paul
  20. I have a support case open with NI on this issue (OK, it's been open a while) but I thought it deserved its own topic. Suppose I have a control (named "angle") that is a type DBL and has an associated unit (deg). Suppose the value is 10 deg. Now suppose we want to write this to an XML string. We might want something like: <angle>10</angle>. OK, ideally we want to write the unit as an attribute but I'll settle for getting the correct value and the correct name. Note that the format of the XML string follows the schema used in SimpleXML in Java or in JKI's EasyXML Toolkit (which we like). LabVIEW's internal Write To XML method has a different (uncommon!) format but the issues we describe here apply equally with that method. Well, if we just wire the control to, for example, JKI's EasyGenerate XML VI, the output actually is: <angle>0.174533</angle> Yes, the value is the radian equivalent, simply because the value on the wire in LabVIEW is always in the SI unit. Now, say we really actually want to represent the value in the XML output in the original units. (There a couple reasons why this is desirable: first, we might be using XML as a message passing tool so that converting on one end and reconverting on the other is quite silly extra work, and second--and more importantly, writing values as finite ASCII strings and doing the conversions will result in round-off errors--of course!) Well, then, it seems we need to strip the unit--but retain the value--before writing to XML. Accordingly, we might use LabVIEW's Convert Unit function, which will, if the convert unit matches the source unit, produce a pure number. This sounds logical, but we have a problem. Since the Convert Unit function is really just a subVI, the output value doesn't retain the original name, so when we wire it to JKI's EasyGenerate XML VI the output is: <unnamed_numeric>10</unnamed_numeric> This is not exactly what we wanted, either! Does anybody have a way to write a value with units (any valid unit!) to XML 1) with the value corresponding to the desired unit 2) with the correct name that also must a) work as a subVI? ____ OK, I do have a workaround to do this using variants (which helps with the subVI constraint) to read the name before the Convert Unit and then write the name to the Convert Unit output. This works but 1) a LabVIEW bug necessitates putting To Variants outside the subVI, making this a little messier than I'd like in order to work with arrays as well as single values 2) it's a pretty inelegant solution (the subVI requires two inputs, actually!) that requires the use of some fairly complex OpenG VIs that seem like overkill (and an extra maintenance challenge) for the purpose. Hence I'm hoping one of the LAVA folks has a better solution! Thanks! Paul
  21. Well, first I will mention that for full details you will want to check out the classic GoF Design Patterns book and the more conversational Head First Design Patterns book for all the details and more insight than I could ever offer. Nonetheless, the heart of the Command Pattern involves making commands into objects. So, for instance, we might have the following. The top-level Command class is an abstract class. (Really, it would be an interface but the closest thing in LabVIEW currently is an abstract class. The important thing is that we never instantiate a Command object.) It has a single method, execute(). The actual commands are concrete classes that inherit from Command. Each concrete command class implements the execute() method. Note that a particular command can contain attributes (i.e., command parameters, or more abstractly, state). I don't show in the diagram the Client (e.g., a UI, but multiple Clients can invoke the same command, so that we could have a UI Client and a Command Line Client), a Receiver (a component that knows what to do with the commands; again the Receiver is decoupled from the Command classes so the framework can support different Receivers), and an Invoker (determines when--may be immediately--to call the Command::execute() method). Note that the Invoker calls Command::execute; dynamic dispatching determines which execute() method actually, um, well, executes. Notes: One can assemble commands into composite commands (with the Composite Pattern) to implement macros. (Essentially a MacroCommand executes a sequence of Commands.) One can combine the Command and Memento patterns to support undo. One can easily log Commands (and read back the log!) simply by writing and reading the objects (e.g., as flattened strings) in a file, all by thinking of them at the code-level as instances of Command. Most importantly, again, the Command pattern decouples the Invoker and the Receiver! An example from our experience: The Command Pattern is precisely a pattern so many variations are possible. In one of our subsystems we send Commands from a UI or external subsystem. The Invoker is really just a message passing system (we send objects flattened to strings over a CommandSharedVariable) combined with a an event structure that fires upon receipt of a message and calls Command::execute. The Receiver is simply the Controller and it knows what to do with each Command. (Note that in our case how the Receiver responds to a particular command depends on its current state, so it implements the State Pattern as well.)
  22. Tom, I'm not too clear yet on exactly what you are trying to do. You mentioned a statemachine so at first I thought we should use the State Pattern (which we have done and is quite straightforward), but after rereading your description a few times it seems to me that you are executing a series of steps (basically a macro), choosing the macro based on user input. Is that correct? Then the problem you are trying to solve is how to send the proper macro to the controller. If that is the case, we can do that quite efficiently using the Command Pattern (we have done this with simple commands and it is even more straightforward; the pattern does support macros). Let me know if this is on the right track. If so, I think I can help you with this. Paul
  23. First, thanks for the ATML information. I hadn't heard of that before. I just started to look at it now. What I was thinking about in units came from this: LabVIEW and XML. I certainly agree that this should be standards-based! On that note (and departing a bit from the conversation) I would really like to see a reusable, standards-based, XML parser for LabVIEW. For instance, I was talking to an AE about an issue a couple weeks ago and he commented that he writes his own XML parsing code when he needs it. While the basics of this are not particularly difficult, getting everything correct does take some time. Ideally LabVIEW developers would have a reusable, common, library we can all share, rather than each reimplementing something (with lots of variations!) ourselves. Ideally we can spend time working on code relevant to our project domain rather than on infrastructure. (That's the dream!) This is one reason why I separately advocate using a commonly available publish-subscribe framework such as shared variables. While I don't want to ignore existing issues with SVs, I am not fond of the frequent suggestion to posters to write a communications framework using TCP/IP primitives. The latter solution is not particularly difficult, but it does require a finite amount of time and the resulting infrastructure is quite customized. Where this is necessary, this is great, but I think most often SVs fit the bill (and they have features one is not likely to take the time to develop oneself!) and they are something that is common at least within LabVIEW--and NI will presumably do the work of maintaining the infrastructure into the future. Again, I want to focus on code in my application domain. (If I am trying to sell infrastructure tools, that is another story.) I'd really like to see XML become something that LabVIEW developers just use, rather than develop. I'm not sure anyone besides NI can create a framework to handle objects currently, so I'd really like to see NI do this. Paul
  24. We use XML extensively here. On the other hand, TDM files are readable with any of the tools you mention. They are ideal for LabVIEW and DIAdem, of course, but there are plug-ins for Excel and MATLAB (Integrating TDMS in Third-Party Products) and the TDM format is publicly available, I'm pretty sure. We use XML largely to share data with other applications. There are a couple challenges: 1) No complete XML tool exists for LabVIEW yet to my knowledge, although some tools offer a very good start. We use JKI's EasyXML and like it. A complete tool would handle LabVIEW objects, for instance, and I'm not sure that a truly appropriate solution is possible without having access to the LabVIEW internals. My opinion is that NI should release a suitable XML framework, but I have no reason to believe that NI is working on such a thing. (Yes, there is the LabVIEW internal XML definition, but that is not useful for sharing data with nonLabVIEW applications. In particular, if a LabVIEW object has default data the XML representation just indicates this rather than detailing the data.) 2) An issue we have encountered recently is handling units. If a control has units in say, degrees, the value on the wire is always in SI units (radians in this example), and this can create issues when writing to XML. For instance, EasyXML just writes the value on the wire to the XML output and ignores the unit (quite reasonably) but this means the value is the value in radians, not degrees. (We are developing a work-around here, but there are some pitfalls just because of the way LabVIEW handles unit information. It's more trouble than you might think.) Again, I think a "complete" XML framework for LabVIEW would handle units correctly. (This ideally would probably mean writing units and dimensions as attributes, but even writing the value in the desired unit would be a great start!) Nonetheless, XML is a great way to share structured data between applications. Its universality makes it very appealing (and hence why I would like to see a complete implementation in LabVIEW). Paul
×
×
  • Create New...

Important Information

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