AzeoTech

Administrators
  • Posts

    6,432
  • Joined

Posts posted by AzeoTech

  1. I'm unclear why you would do this in the first place.  Channels are designed so that you can name them based on their purpose rather than there physical location and so should remain the same within an application.  What I mean is that you shouldn't name channels things like "AIN0", or "LabJack1_FIO4" or similar, but instead name them "BoilerTemperature", or "InletValve".  Then, the rest of your system is always referencing it by its purpose which doesn't change even if the hardware changes.  If the hardware changes, you just leave the channel name alone and adjust the Device Type, D#, I/O type and channel number (and OPC specifier for some devices).  What you are doing is just adding an extra, unnecessary layer.

    As to your original question, use [0] to get just the most recent reading from a channel (or any array really).  See the section on subsetting, 4.6 in the user's guide.

  2. Alas, despite the fact that USB stands for "Universal Serial Bus", there is very little that is universal about it other than the connector.  While some common devices, like flash drives, cameras and printers have a common, almost "Universal" interface, pretty much anything else is going to be proprietary.  And more proprietary than, say, an Ethernet or regular Serial device, where the transport layer is at least universal.  In the case of USB DAQ devices, you pretty much always have to go through the manufacturer's driver, which is definitely NOT universal.  Some companies, like LabJack, have created a Modbus wrapper to make their software somewhat universal (and their Ethernet devices are Modbus natively), but most, including the Picos, require an SDK from the manufacturer.  There are thousands if not 10's of thousands of such devices out there and as such we are unable to write drivers for them all, or for that matter most of them.  We also do not really like USB based devices except for bench top use, and since most DAQFactory users are running DAQFactory in 24x7 type operations, we typically recommend Ethernet or Serial based devices instead.

    Now, many such devices have a pretty simple SDK and you can actually use DAQFactory's Extern() function to bring in the functions in the SDK into DAQFactory and call them from there.  This works great for slower devices, but since DAQFactory cannot support a callback, it does not work for most higher speed devices that stream data and notify the parent application when new data is available.  This is, at least, one mode for the Pico.  So, while you may be able to get DAQFactory to query the Pico unit for values, probably at rates up to about 100hz, you will likely be forced to stream above that and without a custom driver, you probably won't be able to get it to work with DAQFactory.

    That all said, we can write you a driver for the Pico, but as a device that is not commonly requested, there would be development costs involved.  The actual costs would depend on which features of the Pico you needed to access.   If you are interested, please email us directly at support @.  

     

  3. I'm assuming you are creating a calculated virtual channel, i.e. you put something like:

    mean(myChannel[0,1])

    in the expression.  In this case, no, the virtual channel doesn't keep anything.  It does the calculation every time you reference it, and since the calculation doesn't result in history, neither does the V channel.  To do this, you need to use the event of myChannel to update the V channel (and you'll probably have to delete your existing V channel and create a new one).  I personally prefer using a Test D/A channel for this as regular Channels offer additional features, like events, logging, etc, but the concept is the same.

    In the event for MyChannel, put:

    v.myVChannel = mean(myChannel[0,1])

    An event in a channel is script that runs every time a new value shows up in the channel (with the exception of streaming data, where it is called once per block of data).

     

  4. The first problem I can't say without more detail, but do note that if you start/stop a sequence using beginseq() / endseq() you cannot predict when it will actually start/stop since it is running in a separate thread.  Truthfully, that applies to logging sets too, which is probably why you have the second problem.  DAQFactory keeps the file open while the logging set is active for performance reasons, and Windows has this cryptic SHARE.EXE error message that, truthfully, is left over from the old DOS days which basically means the file you are trying to manipulate is locked against manipulation, in this case, by the logging set.  You probably need a delay(1) after you update the logging set file name to junk to give it a chance to close the old file.  

  5. Just parse out the name.   But first you have to make sure the logging set isn't still attached to the file.  So:

    private string oldname = logging.BoeingData.strFileName
    logging.BoeingData.strFileName = "c:\junk"  // put something else here
    private string newname = left(oldname, getlength(oldname) - 4) + " -Reset.csv"
    file.rename(oldname, newname)

    You may prefer to search for a ".":

    private string oldname = logging.BoeingData.strFileName
    logging.BoeingData.strFileName = "c:\junk"  // put something else here
    private index = find(oldname, ".", 0)
    private string newname
    if (index != -1)
       newname = left(oldname, index) + " -Reset.csv"
    else
       newname = oldname + " -Reset"
    endif
    file.rename(oldname, newname)

     

  6. Logging sets aren't really designed to be started and stopped for short intervals to different files.  For that you probably want an export set.  But export sets have their own limitations, so I can see why you would stick with a logging set.  Really the only solution I can think of is, at start, to rename the logging set file to a junk file name, run the logging set for 0.1 seconds to dump the excess data, then rename the file to the name you want the new data to go to.

    That all said, I've added an request to our list to give you the option to clear that buffer.

  7. You are missing the include and other statements needed to bring those constants into DAQFactory.  Please see the DAQFactory - LabJack Application Guide PDF installed with your DAQFactory installation, specifically starting with chapter 8 where it talks about adding the script in an auto start sequence:

    using("device.labjack.")
    include("c:\program files\labjack\drivers\labjackud.h")

    (note that your path for the include may be different).  If you look at any of the DAQFactory UD samples you'll see something like this script included.

  8. DAQFactory will send the same value.  It doesn't look at the current value, because there are many cases where that is a bad idea.  Personally when I run into these issues I usually will create a buffer of output values to set, then go through the buffer in a separate sequence, usually the same one that is doing the input.  That way I can control it.  It also allows me to do automatic retry as I can then catch the failure (instead of Channel's quiet fail).  It is much easier if the hardware supports a readback of the output, then I can just read the readback and compare it what I think the value should be and do an update if necessary.

  9. I'd have to see how you have the U3 configured (ID, serial number) in LJControlPanel, and your .ctl document.  One possibility is that you are using D# 0 (first found) in addition to D# that matches the ID.  This will fail because you end up creating two connections to the same LabJack, which is not supported by the UD driver under USB.  The other possibility is that you configured an IP address for a particular D# and then are trying to use that same D# for the ID of the LabJack.  

  10. OK if you aren't a 4k monitor, then your DPI is just fine and you should revert those settings.

    It sounds like you may have just played with the preferences and inadvertently set them small.  The best thing is probably to just erase the settings in the registry so DAQFactory goes back to defaults.  An uninstall won't do this.  You'll need to quit DAQFactory, then fire up the Windows registry editor, and then delete the following folders and their contents:

    \HKEY_CURRENT_USER\SOFTWARE\DAQFactory\DAQFactory\BCGWorkspace2

    \HKEY_CURRENT_USER\SOFTWARE\DAQFactory\DAQFactory\RuntimeBCG2

    Then go to:

    HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\DAQFactory\Control

    and delete all the keys in that folder, while keeping the folder (to save any registry variables you might have).  You can also delete these two folders if you want:

    HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\DAQFactory\Control\ChannelTablePrefs

    HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\DAQFactory\Control\Preferences

     

     

     

  11. I'm guessing that you have a 4K monitor.  DAQFactory has been around for a long time (20+ years) and back then monitors were all pretty low res.  Only recently have 4K monitors on little 17 inch screens become the norm.  Windows added support for this, but it is a new thing and we haven't implemented it yet in the release.  It will, however, be resolved in the next, 20.1, release I expect.  Until then, the fix is super easy:

    1) open Explorer and find DAQFactory.exe in your installation folder
    2) right click on it and select Properties
    3) go to the Compatibility tab, and click on Change high DPI settings
    4) check the box towards the bottom that says "Override high DPI scaling behavior.
    5) in the drop down just below this select "System (Enhanced)"
    6) close out the properties windows and start DAQFactory.
     
  12. First, you should consider updating to 19.1 so you are running the latest. 

    Second, I see at least one, probably two applications starting up in the background that are probably not necessary.  You want to keep Windows as clean as possible if you are running 24x7.  Check your Services as well for things you don't need.

    Third, does you panel have a watchdog?  If DAQFactory crashes it shouldn't trigger a reboot unless there is a hardware issue.  If a reboot doesn't fix it, but a power restart does, then the issue is probably not DAQFactory, but a hardware issue, possibly with the hardware you are accessing from DAQFactory.  If you are using USB hardware, including a USB to serial converter, then I'm even more confident that that is the culprit.

    Otherwise, please post your .ctl document or email it to us so we can see what else you might have going on.

  13. I'm not sure what you are doing.  You have an on screen edit box?  You named the component "userInput" or do you have the edit box changing the value of userInput.  I am guessing the second, and that you have userInput declared as a number.  So, the edit box is converting 123abc to a number so it can be put into userInput, thus getting 123, then you are putting that result into your datain string variable and getting "123".

     

  14. DAQFactory follows the C / C++ standard libraries and accepts numeric values up to the first invalid character.  It will only return NaN() if the first character is invalid.  The workaround depends on what are acceptable numbers.  In most cases, you can just convert the result of strToDouble back to a string and see if it is the same as what was entered.  So:

    private string datain = "123abc"

    valid = doubleToStr(strToDouble(datain)) == datain

    The only issue with this is that if someone enters: "123.40" it will think it is incorrect, because doubleToStr() won't add the trailing 0.  

    If this is a problem, you'll probably have to write your own little script to validate the input.  Probably the easiest way then would be to use the findOneOf() function and just include every invalid character.  Something like (I'm not going to include every character):

    valid = findOneOf(datain, "abcdefghijklmnopqrstuvwxyz!@# etc...") == -1

    But that won't deal with someone entering something like "123.40.56"

    Short of you writing your own algorithm for this, I'm guessing you could use a regular expression and therefore the FindExpr() function.  I'm not sure what the regular expression would be for validating a number, but regular expressions have been around for decades so I'm guessing a quick Internet search will give you some useful ones.

  15. You'd have to combine that into a single array, then do maxcols() on it:

    private arr = temp1[0,3]
    arr[][1] = temp2[0,3]
    arr[][2] = temp3[0,3]
    private maxTemp = maxcols(arr)

    So, the max() function takes the maximum across the first (rows) dimension and is always the one with time associated.  It is the most common form since most arrays are only 1 dimensional.  MaxCols() takes the maximum across the second (column) dimension.  We build up arr as an array with 4 rows and 3 columns, one column for each channel.  By doing maxCols() we are saying we want the maximum for each row (in time), across all columns.

  16. Are you reading from your database or a file?  I'm assuming a file since you are using File. functions.  To read a date value that is stored in human readable format you have to read that column as a string then use the strToTime() function to convert it into an actual time stamp.

  17. It is important to understand that the command you send to your database has nothing to do with, nor has any access to, anything inside of DAQFactory.  This is why your first command failed.  "val" is a DAQFactory variable, not a SQL variable, and the database has no idea what val is.  You fixed it in your second post, though truthfully you did not need to use doubleToStr() as DAQFactory would do this automatically since the concatenation starts with a string.

    As for the data in your database, again, it has nothing to do with DAQFactory.  In fact, the SQL command:

    INSERT INTO public.pressure_table_01 (pressure) VALUES (3);

    which is what you would get if val was 3, should only work if the pressure field was numeric.  If the pressure field was a string in the table, you would have to put quotes around the 3:

    INSERT INTO public.pressure_table_01 (pressure) VALUES ('3');

    So, I'm not really sure what you mean by the value becoming a string?

  18. The workspace disappearing initially described has been fixed for release 20.  For now, you can just save and restart. 

    However, Kanber, I believe you are seeing something else, especially if it does it on restart, and also because you are actually seeing Connections and Pages.  In your case I believe you are opening a document with a document editing password that is forcing it into Runtime mode, and then you are managing to get DAQFactory to display the workspace.  But, since it is in runtime mode, it is not showing anything in the workspace.

  19. You can start a PID using beginPID:

    beginPID(myPID)

    Note the lack of quotes around the name of the PID loop.  

    EffectI is readonly so, no you can't edit it. However, you could use the PID event to adjust it however you wanted before applying the PID to the output.  Basically, don't provide an output channel, but instead use the event to get the three effects and calculate the output.  You can then tweak the effectI portion as needed.  EffectI is just a running sum, so you could then set it to a particular value by applying a bias in a variable that you then use in your calculation in the Event.

  20. We don't have built in support for this protocol, but it is a rather simple ASCII protocol so easy for you to implement in script.  In fact, you can manually type in commands in the command/alert window, just remember that you have to send either a carriage return, or a carriage return / line feed combo depending on what the device requires.  I would start with just a CR, which you can do at the command alert window using \013.  I found all the commands on the keysight website: 

    https://na.support.keysight.com/pxi/help/latest/Programming/GP-IB_Command_Finder/SCPI_Command_Tree.htm

    but I am not familiar with your devices so do not know exactly which commands you would want.  But as an example, it looks like if you wanted to turn the RF power on and off you would use the OUTP command, so in the command alert window you would type:

    OUTP ON\013

    to turn it on.

    To query the current state it would be:

    OUTP?\013

    I'm not quite clear what the response would be, but I am guessing it would be, say:

    1\013

    if on.

    To do this all from script requires very little more.  Instead of \013 you'd have to use chr(13), so to set the output on using script for device "myDevice" you would do:

    device.myDevice.write("OUTP ON" + chr(13))

    and to read the status you would do:

    private string in
    device.myDevice.write("OUTP?" + chr(13))
    in = device.myDevice.readUntil(13)
    global RFPower = strToDouble(in)

    This assumes that the device just returns a CR and not a CRLF.  If it returns, say:

    1\013\010

    then the readUntil() function should be readUntil(10).

    Those are the first two steps I take whenever writing protocol scripts: first I try manually reading and controlling the device from the command alert window so that I can check that I am understanding the device documentation correctly (and device documentation is often vague and even incorrect).  Then I'll write some short sequences to do one task.  

    Once I have that all figured out, I can then add functions for all the desired commands.  You can do these as separate sequences if you just have a few, or create a class to combine them into one, maybe something like:

    class CSCPI
       function RFOnOff(val)
          device.myDevice.purge()
          device.myDevice.write("OUTP " + val + chr(13))
       endfunction
    
       // etc.
    endclass
    
    global SCPI = new(CSCPI)

    Then to access a function within the class it would be, for example:

    SCPI.RFOnOff(1)

    Note that any time you modify the script you will need to rerun that sequence to update the class.

     

  21. DAQFactory uses a perturbation type autotune.  It is not necessarily the easiest autotune, but it does allow it to be used in systems that cannot be varied significantly during tuning.  What you need to do is get the system at a stable setpoint under PID control.  You can usually achieve this by setting I and D to 0 and increasing P until your PV hits your SP without significant oscillating overshoot.  Once you have this, set the auto-tune step to the amount above/below the current output you'd the autotune to adjust.  You should then let it run for several cycles of plus/minus the output. 

    That said, it is important to note that the output of the PID loop really needs to range into the negative, and for that reason I always suggest folks leave the output range to -100 to 100.  If you don't let it range negative, then whenever the PV is above the SP (in a forward PID loop), the PID loop is just going to output 0.  This makes it impossible for the PID loop to provide a maintenance output variable, i.e. providing a little heat to maintain the temperature.

    Since your output is likely only positive you will need to set the output variable of the PID loop to a Test D to A channel, then in the Event for that channel, scale the value and send it to your actual output.  So, if you name that OV Test channel PIDOut, and your actual I/O point for controlling your heater is called HeaterOut, and it ranges from 0 to 4000 you would put this in the Event for the PIDOut channel:

    HeaterOut = (PIDOut + 100) * 20

    There are other ways to do this, including using a global variable, the Event of the PID loop, a Conversion on your output channel etc, but the example I gave is the simplest.

    As to the left axis scaling, you should be able to double click on the axis to change its parameters.