AzeoTech

Administrators
  • Posts

    6,418
  • Joined

Posts posted by AzeoTech

  1. Now that we finally have 20.1 out I expect we will do rapid releases, maybe once a month.  The next one should be within a week.  It will likely be numbered 20.11 and it will include access to the PID integral sum under the variable "IntSum".  It is read/write.

  2. You can use the PID's event to manage the loop.  See section 10.4 for more detail.  You can't change the actual accumulated I parameter from script.  You could, however, set the IntLimit parameter to, say, 1e-9 for an iteration or two after starting and that should essentially reset the accumulated I.  Also note that Reset on SP change will cause the accumulated I to reset whenever the SP changes.  You can just tweak the SP by a very small amount and it will reset the accumulated I.  Of course Reset on Start will do this as well whenever you start the PID loop.

     

  3. ShellExecute() creates a completely separate process, and there really aren't easy ways in Windows for processes to communicate with each other.  Windows does this for good reasons.  If you are writing your own code, it is usually best to create a DLL that DAQFactory can link to using extern() instead of an Exe it has to run.  A DLL runs in the DAQFactory process, so DAQFactory will wait for a response.  With ShellExecute() it is completely fire and forget.  Really your only alternative is to use a file or some other normal interprocess communication technique such as sockets, so while it seems it isn't very elegant, it is unfortunately the only choice.  (actually you could also search for the other processes window, but that gets into the real nitty gritty of Windows).   This limitation would be true basically with any application, not just DAQFactory.  It is why there are DLLs.

  4. If you have multiple PLC's that are on different IP addresses and not on a single RS485 chain, you can simply give all the channels of each PLC a different Timing/Offset combination.  This will cause DAQFactory to query them simultaneously, and timeouts caused by one PLC being offline won't affect the others.  So, for example, PLC1 might have its channels on Timing 1, Offset 0, while PLC2 might have Timing 1, Offset 0.25, and PLC3 might have Timing 1, Offset 0.5.

    As for device bypass, it is likely that you created circular logic and blew the stack.  I'd have to see your document to truly tell.  

  5. I asked because you should replace the endseq(S3) with just return:

      if (AutoCycleRunning == 0)
          delay(1)
          db.Close(dbase)
          return
       endif

     

    There is no reason to tell a sequence to stop itself using endseq()

     

  6. I'm sorry but I don't know Excel well enough to advise on that.  There are a lot of security implications as well for doing such a thing.  Word and Excel a long time ago started restricting running macros.

     

     

  7. Well, normally I would say put an SSR on the low voltage side and do a PWM on it with the LabJack, but 200A is a mighty big SSR and you are AC on the low voltage side, so I can see why you'd want to do the switching on the 240V side.  And of course an SSR doesn't switch AC as well because it doesn't phase align like an SCR.  Likewise PWM isn't going to work on the LabJack because it can't phase align either.    But you knew that already.  It seems like you really are just hung up on the fact that the SCR you want takes 4-20mA not 0-10V.  I'm going to let the LabJack folks chime in on possible solutions, but you can always go with a really cheap PLC that outputs 4-20mA like a Click PLC, just for that part.  The PLC is like $100 so really not a big deal, and you can use it with the LabJack for everything else.  It is available with either a serial or Ethernet connection and talks Modbus (so DAQFactory can easily talk to it).   

  8. I do not recommend opening and closing the database.  Just open it once outside the loop or in an AutoStart sequence and leave it open.  There is no reason to close the connection.  DAQFactory will do this automatically when it quits.

    Is the name of this sequence S3?

  9. Functions are standalone and can be called by as many different sequences as you want.  They are also reentrant so you can call them recursively as long as you are careful not to blow the stack (a general pitfall for recursive function calls). 

    DAQFactory script in general is thread safe, though you do have to sometimes protect against multiple threads accessing common resources.  The most common example is a comm / ethernet port.  For this there is the lockPort() function.  It is not that you will crash or hang DAQFactory, but if you don't protect the port, you could get framing overlap in your communcations (i.e. thread 1 makes a request, then thread 2 makes a request before thread 1 gets its reply.  Thread 2 still has the processor and gets the request from thread1 instead of thread 2.)

  10. Row is used to do stacked axes. If that is what you are after, then excellent! I am glad you found it.  Use the % of full to determine the size of each axis.

  11. No.  The DDE capabilities are limited largely to posting and reading data using Poke and Request only.  DDE is a very old technology and not particularly well adapted anymore.  In fact, we are largely deprecating this feature because of this.  What exactly are you trying to do?

  12. Sure.  DAQFactory supports 6 left and 6 right axes.  Just assign each trace to whatever axis you want.  The axis tab lists the axes and allows you to adjust the scaling on each one.

  13. Just another suggestion: wrap your DB calls in a function.  So, for example at a minimum (each function is a sequence):

    function dbOpen(string dbsource)
       global dbase = db.open(dbsource)
    function dbExecute(string sql)
       db.execute(dbase, sql)
    
    function dbQueryToClass(string sql)
       private ret = db.queryToClass(dbase,sql)
       return(ret)

    Then, instead of calling db.open(), db.execute() and db.queryToClass(), call the above functions.  I gave the minimum that they'd do, but you can then add error handling and debugging code to the above to further enhance it.  

    The best solution however is to create a class:

    class CDataBase
       local handle = 0
       function Open(string dbsource)
          handle = db.open(dbsource)
       endfunction
    
       function Execute(string sql)
          db.execute(handle, sql)
       endfunction
    
       function QueryToClass(string sql)
          private ret = db.queryToClass(handle,sql)
          return(ret)
       endfunction
    endclass

    Then instantiate a single instance in startup:

    global dbase = new(CDataBase)

    and call into it like this:

    dbase.open("mydatasource")

    or

    dbase.Execute("INSERT INTO mytable (field1) values (3.423)")

    Again, this allows you to eventually add features (like error handling and debugging code) as needed and encapsulates it into a single object.

     

  14. OK, three problems:

    1) "local" is the wrong declaration.  You want "private".  "local" is for class declarations and never used inside a function.
    2) while you remembered to declare all your function parameters as strings, you forgot to declare executeSTR as a string.  So you need:

    private string executeSTR = format(...)

    This is why you get NaN().  DAQFactory is trying to convert your insert string into a number so it can store it in executeSTR.

    3) I typically do not recommend constantly opening and closing a database.  Just open it once at startup and leave it open.  Close it only if you lose connectivity (which is rare).

    Two notes:

    1) db.execute() doesn't return anything so "inserts" will never have anything
    2) I typically prefer to build up my SQL strings over several lines, if only to make it clearer.  So:
     

    private string executeSTR = "INSERT INTO app01 (serialnumber, firsthigh, firstlow, secondhigh, secondlow, thirdhigh, thirdlow) values ("
    executeSTR += ER_NO 
    executeSTR += ",'" + FIRST_HIGH + "'"
    executeSTR += ",'" +FIRST_LOW+ "'"
    executeSTR += ",'" +SECOND_HIGH+ "'"
    executeSTR += ",'" +SECOND_LOW+ "'"
    executeSTR += ",'" +THIRD_HIGH+ "'"
    executeSTR += ",'" +THIRD_LOW + "'"
    executeSTR += ")"
    

     

  15. It appears you have 8 gateways, each with a unique IP address, however, all your channels are on the same Timing/Offset.  This means that DAQFactory will read Gateway1, then move to Gateway2, then to Gateway3, etc, until it gets to Gateway8, then it will repeat.  If any of those gateways are slow or timeout, it will cause the data interval to slow way down, especially since you have a timeout of 5000 (5 seconds).  I recommend two things to fix this, especially #2:
     
    1) unless you are using a radio (which it actually appears you are), set your timing to 1000.  This is a minor issue.  For radios, then a Timeout of 5000 makes sense.  But if you are connecting directly over Ethernet to a device, if it doesn't reply within a second it probably isn't going to reply at all.
     
    2) Put all the channels for each gateway on a unique Timing / Offset pair so that DAQFactory can read them concurrently.  So, for example, all your Channels for Gateway1 should be at Timing = 1, Offset = 0.  All the channels for Gateway2 should be at Timing = 1, Offset = 0.1.  Gateway 3 should be Timing = 1, Offset = 0.2, etc.  Make sure all channels on a single gateway have the same timing / offset.
     
    If you do #2 you will see a significant improvement in the timing of your data.
  16. So are you saying that you have a 4th channel from the PLC with the timestamp of the process that you want as the X axis?  You can certainly do that.  Just put that channel name as the X Expression.  Likewise, you can plot all three variables, either on the same axis, or, given your ranges, on 3 separate axes, left or right.

  17. To display delta T on the X axis you simply need to record the time of the 0 point, and then subtract that from the data time stamps.  So if you are plotting "MyChannel" vs "Time", and you create a global variable called "StartTime" which you set in, say, a button when the process starts:

    startTime = systime()

    Then, the graph would be "myChannel" vs "GetTime(myChannel) - startTime"

    As for milliseconds, when in Date/Time mode, the graph doesn't show millisecond graduations.  To do that, and especially when you are actually doing deltaT, just change the Bottom Axis from "Date/Time" to "Lin"

    The user's guide doesn't show every because some features are considered beta.  PrintPDF() for example only support generating PDFs of certain controls, namely the graph control and text controls.  It won't, for example, print a bitmap logo.  As such, we did not document it in the user's guide so it isn't really fully functional. 

    The script in DAQFactory is loosely based on C++ and Visual Basic.  It is mostly similar to C++, but with some parts (ie. endif, endwhile, etc) of Visual Basic.  The syntax was chosen to give the flexibility and power of C, while not making the syntax so strange that beginners couldn't make sense of it.  So, for example, unlike in C where you can basically create an entire program in one line, DAQFactory limits you to one statement per line.  Likewise, DAQFactory has a number of things, namely how it deals with arrays and strings, that are not easy to do in C or Visual Basic.  For example, if "x" is an array, and you want to add 1 to every element in X, in C you would have to create a loop and increment each element.  In DAQFactory it is simply x = x + 1, or even x++.

     

  18. A tree list would be used to allow the selection of any sort of organized data.  For example if you had a bunch of parts, some are nuts, some are screws, some are bolts.  Those 3 would be the top level of the tree, then under each you might have the various types of nuts, or bolts, etc.  The DAQFactory workspace is a perfect example of a Tree List.

    Every time you add an item to the tree list you get a handle.  You can then use that handle to change the name as it appears on the tree without recreating the entire tree.

    Tree lists are typically used with nested objects (classes) which is why you really can only work with it through script.    

  19. A regular query() returns a record set that you then need to traverse to read each record.  Because DAQFactory is an interpreted language this is quite slow, so we came up with QueryToClass(). This function instead returns an object with member variable arrays for each of the fields across all records.  This is much, much faster.  In addition, two member variables, classNames, and recordCount are returned.  The details of this function are described in section 9.5 of the user's guide.  With the new QueryToClass() there really are only a few use cases where the regular Query() should be used, usually ones that involve aggregate functions.

    You can telll if open() worked by whether you get 0 for a handle (failed) or another number.

    Once it is open you can't tell except that your database commands will throw an error, which you can then catch.