03-19-2012 08:28 AM
1. Documentation is listed as a major component of the scoring. The scorers seem to want VI documentation, tip strips on controls, description on BD of what various parts of the code do, and a non-default icon. You have a few comments on the BD and none of the others. You do nota have anything which actually says what this VI is expected to do.
A) I should have explained myself better. I haven't gotten to documentation yet. I am only working on functionality at the moment. All the documentation tips are valid and are stuck in my mind to complete.
2. Make Typedefs of controls and clusters which get reused or which may need to be modified in the future. Your byte count cluster was the one which caught my eye. You have two copies of this outside the the upper loop. One would be enough.
A) I did not understand this point. Which one are you referring to? Just the cluster constants for bytecount?
3. Shift registers. Several of the shift registers carry data which is never changed inside the loops. Do you have a good reason for using shift registers rather than tunnels? If so, it should be documented.
A) There is a reason for doing this. I will document this.
4. The TDML_split.... VI is missing. It appears that you read on byte from the serial port and then derive three numerical values from it. I would like to know how you do that.
A) I will attach this vi here now. I thought I did in my previous post.
5. The Queue Status followed by #elements in queue = 0? seems to be redundant with Dequeue with a timeout.
A) Valid. Didn;t really pay attention because I was working on an earlier code.
6. Writing data to the Control code indicator will not trigger the Control code value change event.
A) I have modified it to a control. I so badly want to use an event structure because there are more dynamic events that will be included and hence wanted the deQing to trigger events. (Hope this makes sense)
7. The Unbundle and Bundle nodes in the event structure can be simplified and improved. The image below shows your original code in the center. Below I show wiring the cluster wire into the center terminal of Bundle. When it is wired this way, only elements which change need to be wired at the left side. At the top I show the same thing using Bundle by Name. This has the advantage of bein self-documenting.
Anyone looking at this code knows immediately what is being changed. You code works. The others can save you some time now and in the future.
A) Great GReat tip. Thanks! I will implement this.
8. You do not handle or report errors. That is one of the things which I have heard that CLD scorers look for.
A) I am looking over a webcast on handling errors. I need a better way to implement errr handling
Lynn
Also, my final executable will be running minimized in system tray "ALL THE TIME". It will sit in a wait state until staff is ready to use the device; which is when the executable will enter a working state. Now, if my exe is running 24x7, what things do I have to remember to do so that there are no memory leaks on the compter or other problems. Any suggestions would be helpful. Does, the computer allocate LabVIEW exe a fixed memory based 0on the program and just work off of that? Or will it use my my computer resources in a poor way unless I program it better? Thanks!
03-20-2012 02:08 PM
I believe this is a remarkable improvement in my programming abilities considering where I started. Thank you all for your help and advice.
I am attaching my latest version of a DEMO code for your inputs. I have cleaned it up a bit (still don't have many comments though, tried my best). It has more functionality and I would like your inputs on functionality alone.
For eg, what I could do better releasing queues and notifiers and what better way to use relay values other than locals/property nodes etc. Please review my code and let me know. I have also included a library of files that enables minimizing to tray in case someone needs help with it. I could be of assistance if need be on that (I have spent many an hour trying to figure out the means to use it with dynamic event registration 🙂 )
I value all your inputs as much as I have all these days. It has strengthened my skills and I am confident in doing well in my CLD (THis doesn't not reflect documentation etc but I am working on it as I type this message.)
Please unzip the files to a directory. All files needed are there in this demo. Please let me know if it works.
Thanks!
V
03-22-2012 09:08 AM
Any suggestions? 🙂
03-28-2012 05:47 PM
VeeJay,
I have been away for a few days.
Item 1. On comments: No comment!
Timing. In the serial port loop you have either 1 or 5 characters read from the port at 4800 baud. This takes 2.1 or 10.4 ms. The Write appears to write 1 or 5 characters, again taking 2.1 or 10.4 ms. You have a Dequeue Element function with a 2 ms timeout. You have a Wait Until Next ms Multiple with a to ms wait. You have a Wait on Notification with default timeout (-1 => Never Timeout).
So. This loop will run once and wait forever for a notification. The Send Notifier in the middle loop sends a notification on every iteration, meaning that the upper loop timing is constrained by the middle loop timing. If it receives a notification with a False value, then the timing may be set by the combination of serial reads and writes plus the Wait on Multiple. This loop could run in 10 ms, 20 ms, 30 ms, or wait forever.
The middle loop has two Dequeue Element functions with infinite timeouts. One queue is enqueued in the upper loop. The other in the bottom loop. It also has a 10 ms timeout on the event structure. This loop will wait until it gets data from both of the other loops plus up to 10 ms.
The bottom loop has Wait on Notification and Dequeue Element with infinite timeouts and a Wait Until Next ms Multiple with 10 ms wait. Both the notifier and the queue are written in the middle loop.
It is not obvious that this system will not lock up and stay in some deadlocked state forever. Even if it works now, a minor change in the future could kill it. Think about what the timing is supposed to do. Try to design each loop so that there is one dominant timing mechanism and make sure that the loops cannot lock each other.
Other things.
In the Panel Resize event case, just wire the "act" terminal directly to the case selector. Simpler code and self-documenting!
You have a question on the BD: Where is the best palce to terminate or release? I think the question refers to the queues and notifier. I like to do it the way you have done it. I place the release functions after the loop where the dequeuing is done so all the data is processed. Some people like to release the queue/notifier in the source loop and use the error in the dequeue loops to stop those loops. I dislike that method because it makes it more difficult to do an orderly shutdown. I think it also violates the philosophy of systematically and predicatble handling errors.
Typedefs. Enums used as state identifiers in state machines should be typedefs. You always change a state or add a few states. with a typedef you only need to change the typedef and all instances of the control or constants change automatically. Similarly with clusters. It seems that clusters tend to get changed during development. By making them typedefs the changes are easier. You use the speed and angle data in different clusters in different loops. One cluster might work for both places.
Lynn
03-29-2012 02:39 PM
Thank you so much Lynn for your comments. They are all valid ones. Especially your accessment with timing. This concept is lost on my and I don't quite pay attention to it much when in fact I should. Is there any document/resource that explains how these timings work (timeout, wait time in loop etc) That would be really helpful.
As you predicted, the front panel of my program gets locked up and highlight execution is useless for me to troubleshoot (BIG DISADVANTAGE OF LABVIEW because I am unable to see where I am going wrong). Looks like most of debugging is actually programming it right.
03-29-2012 03:06 PM
In this simplified version that I have attached, apart from the timing, the program seems to work sometimes. In my actual application, the thrid loop is a really really big State Machine.
WHen I run my application, the split_control_data subvi in loop1 shows an error "-1073807339" and I am not sure what this error is.
03-29-2012 04:33 PM
VeeJay,
I am not aware of any particular documentation on timing beyond what is in the help files. The Wait (ms) function is the most straightforward. It simply does not "finish" or complete its execution until the specified time has elapsed since the fucntion was called or started execution. The way it is implemented internally is efficient so that it uses very little CPU resources. While waiting, other code with no data dependency on the Wait can execute. VIs like Dequeue or Wait on Notification behave similarly if no element is available in the queue. Some other things like VISA Serial Reads and DAQmx Reads also are efficient "waiters."
Highlight execution can be a very useful tool, although locked up code may not be one of its better uses. Watching what happens right before it looks up may be useful in some cases. When working with event structures and multiple loops, sometimes breakpoints are more useful for debugging.
Error -1073807339 is a timeout error. If you context-click on the error code indicator in the error out cluster, the first item in the pop-up menu is "Explain error." You can also select Explain error from the Help menu and then type or paste the code into the panel which pops up. My guess would be that the subVI gets into one of the cases where it tries to read 4 characters from the serial port when it should not. No data shows up, or at least not 4 bytes, before the timeout period. To troubleshoot this issue run with the subVI front panel open. When the error shows up, see if the read buffer has a valid control code character.
It may also be coming from the VISA Read which preceeds the subVI. Is it present at the error in (which you have labeled "error out")? In that case the VISA Read has timed out waiting for data from the remote device. The default time out is 10 seconds. Does the upper loop pause that long just before the error shows up? Putting numeric indicators on the "i" terminals in the loops is a good way to tell which loops are running and how fast. After debugging, remove them.
Back to your more general question: How do you set up timing in a multi-loop program? Carefully!
This comes down to the design of the program. Assuming that you have determined that three loops is the right number, I would look at the tasks to be performed by each loop. Determine the range of times it can take each task to complete (neglecting waits and timeouts for now). Also determine which tasks are dependent on data from other tasks. Then try to make some kind of timing diagram which clearly represents these times and dependencies. Also look at error conditions. What should the program do if the remote device stops sending data? This can completely change the timing. Once you have everything defined, then you can look at how to implement the timing. I generally prefer to have only one timing mechanism in each loop. If it needs to change (especially in a state machine), then design specifically how and when the timing control changes.
Looking at your program (without fully understanding it), I would probably make significant changes to the middle loop. A loop with an event structure set up to handle user inputs does not need to run every 10 ms. Unless your users can push buttons 100 times per second (and the OS can keep up)! I would probably iterate that loop only when an event occurs. BUT this means that your Send Notification and Enqueues will no longer be happening every 10 ms. So that means that the other loops need changes as well. For example I would only send the Stop notification when the Stop button was pressed. The Wait on Notification functions in the other loops would need appropriate timeouts and the "timed out?" outputs would need to be tested to see if a valid notification had been received.
Lynn
03-29-2012 05:01 PM
Makes total sense. OK! I would like to pose a more general question. When dealing with so many timout and wait functions in a loop, which takes precedence? I guess I am confused by so many time functions in a loop. I assumed a Wait until 10ms function would take care of the timeout cases on the deQ and Notify function. AS you can see, I am quite confused with the whole use of timing 🙂 . I am gonna work toward understanding it better and your explanation helps.
I like the idea of adding indicators for "i" terminals so that I can see if it is stuck or not. Good tip!
I gave it a thought and I believe you are absolutely right as to why I am getting that error "-107..... " The problem is that only certain codes as shown in the subvi contain data information. I do not want data to be misrepresented as control codes ot vice versa coz that has happened before. I think I would revert back to my previous approach wherein I do not split control and data in the first loop, rrather I enQ everything and once I deQ in second loop, I will deQ the data there. Maybe that would solve the timeout error.
I have experienced the timeout error before, I did add a 1sec timeout that seemed to solve the problem, but I am not sure what the timeout on the VISA function does? The remote device that sends data shows an error on its screen because my appication has not responded back although I have disabled that option. It seems that it needs a response almost immediate (or within some ms) otherwise it times out. I will look more into this.
With respect to the number of loops, I did try combining loop 1 and 2 wherein I create an event for the VISA function as well, but it does get too complicated. I think 3 suffices for now.
Any comments on the User interaction? any bugs there I am missing???
Thanks a lot again! Like I said your comments are very valuable and helping me immensely.
03-29-2012 05:01 PM - edited 03-29-2012 05:03 PM
Makes total sense. OK! I would like to pose a more general question. When dealing with so many timout and wait functions in a loop, which takes precedence? I guess I am confused by so many time functions in a loop. I assumed a Wait until 10ms function would take care of the timeout cases on the deQ and Notify function. AS you can see, I am quite confused with the whole use of timing 🙂 . I am gonna work toward understanding it better and your explanation helps.
I like the idea of adding indicators for "i" terminals so that I can see if it is stuck or not. Good tip!
I gave it a thought and I believe you are absolutely right as to why I am getting that error "-107..... " The problem is that only certain codes as shown in the subvi contain data information. I do not want data to be misrepresented as control codes ot vice versa coz that has happened before. I think I would revert back to my previous approach wherein I do not split control and data in the first loop, rrather I enQ everything and once I deQ in second loop, I will deQ the data there. Maybe that would solve the timeout error.
I have experienced the timeout error before, I did add a 1sec timeout that seemed to solve the problem, but I am not sure what the timeout on the VISA function does? The remote device that sends data shows an error on its screen because my appication has not responded back although I have disabled that option. It seems that it needs a response almost immediate (or within some ms) otherwise it times out. I will look more into this.
With respect to the number of loops, I did try combining loop 1 and 2 wherein I create an event for the VISA function as well, but it does get too complicated. I think 3 suffices for now.
Any comments on the User interaction? any bugs there I am missing???
Thanks a lot again! Like I said your comments are very valuable and helping me immensely.
03-29-2012 07:16 PM
VeeJay,
The timing functions tend to run independently. So short times may do nothing. The Wait Until Next ms Multiple is sometimes misunderstood with results which are not what the programmer intended.
Let me discuss your upper loop (with serial port read) as an example. The Read takes about 2.1 ms per byte at 4800 baud. The function is smart enough to wait for that byte to arrive without tying up the CPU. If a byte a happens to already be there when the Read is called it will return immediately. The delay here may be negligible or up to 2.1 ms. The Dequeue has a 2 ms timeout. Like the read it will return as soon as an element is ready to dequeue or after the timeout: 0 to 2 ms. TDML_split_control_and_data.vi reads 4 bytes in some cases and does nothing in others. Delay: 0 to 8.4 ms. Wait Until Next ms Multiple with 10 ms wait. This will wait until the Tick count is a multiple of the input value. The Wait on Notification has no timeout so it uses the default (-1) or wait forever (= never timeout). The way you had the middle loop written a notification will be received at intervals no longer than 10 ms.
Functionend time
Read 10 .. 2.1
Read 20 .. 8.4+2.1*
Dequeue0 .. 2
Wait Multiple0 .. 10**
Wait Notifiy0 .. 10
* Read 2 always runs after Read 1 so the maximum Read 1 end time is added.
** Actual time depends on tick count when called on the first iteration.
How long does the loop take? If data is available at the serial port before the loop starts and the notifier and queue have already been written and the tick counter is at a multiple of 10, the first iteration could complete in a few microseconds. Later iterations will be at least 10 ms long and may be >10.5 ms if 5 bytes are received after the loop starts. If the middle loop is delayed or blocked so that the Notification is not sent, the upper loop will also wait forever.
Now, what can you do about this confused situation? First, you cannot make this loop always run in 10 ms because the 5-byte reads may take longer than that. What is the probability that the remote device will stop sending data on the serial port while this program is running? What are the consequencies when that happens? If this is unlikely and you do not care if the loop blocks until the VISA Read times out (default = 10 seconds), then use the Reads as the loop timing. Put zero timeouts on Dequeue and on Wait on Notification and remove the Wait Until Next ms Multiple. This will make the loop spin as fast as data is recieved on the serial port. If you want all iterations to be closer to 10-11 ms, put an 8 ms Wait (ms) in the no-read case in the subVI.
The VISA Read timeout sets an upper limit on how long the read will wait for the specified number of bytes or the termination character.
(Oh!) You have termination character enabled and you are specifying the number of bytes to read!!! This may be part of the reason for the timeouts. Generally you use one method or the other to terminate a read but not both. If your remote device sends a one byte control code followed by a line feed and then sends a 4-byte data set followed by a line feed, your code does this:
Reads 1 byte (command code). The subVI is set to read 4 bytes. The first byte it reads is the line feed following the command code. Because Termination Characters are Enabled, the read stops with no data available to be converted to angles and speeds. On the next iteration of the loop ther Read 1 reads the first byte of the 4-byte data set. Since this is not intended to be a control code, it will be misinterpretted by the subVI. If the remote device is sending termination characters, set the Bytes to Read inputs to a larger number than the longest message and let the termination characters do their jobs.
Back to the timeout. The timeout is intended to allow the program to recover gracefully if the remote device fails to send the expected data or the data is corrupted by noise. The default timeout is 10 seconds. If you know your device will always send data in much less time than that, you can set a shorter timeout.
Lynn