Search code examples
pythonxmllabview

Read XML to LabVIEW as task / Cluster using Python to configure DAQ


I am trying to load an XML file that will be used to configure my DAQ in LabVIEW.

So when looking at the options I have:

  1. my XML channel configuration is dynamic - meaning one XML may have 3 channels the other may have >100 channels.
  2. would be much easier for me to pars the xml in Python and pass the data as structure/task to LabVIEW.

e.g. for XML channel

<Channels>
        <Channel name="CH_PH1" enable="True" visible="False" virtual="False" units="A" physical_channel="PXI1Slot2/ai0" b_factor="0" m_factor="1033.221069" measurement_type="VOLTAGE" type="D" max_value="0.1" min_value="-0.1">
          <RollingAvg do_rolling_avg="False" rolling_avg_frame_sec="0" />
        </Channel>
        <Channel name="CH_PH2" enable="True" visible="False" virtual="False" units="A" physical_channel="PXI1Slot2/ai1" b_factor="0" m_factor="1073.772766" measurement_type="VOLTAGE" type="D" max_value="0.1" min_value="-0.1">
          <RollingAvg do_rolling_avg="False" rolling_avg_frame_sec="0" />
        </Channel>
        <Channel name="P_CH" enable="True" visible="False" virtual="True" units="V" formula="CH_PH1*CH_PH2" doTotalEnergy="False">
          <RollingAvg do_rolling_avg="False" rolling_avg_frame_sec="0" />
        </Channel>
        <Channel name="P_PH_Total" enable="True" visible="False" virtual="True" units="V" formula="CH_PH1+CH_PH2" doTotalEnergy="False">
          <RollingAvg do_rolling_avg="False" rolling_avg_frame_sec="0" />
        </Channel>
</Channels>

My code in Python to parse the xml:

def xml():
    import xml.etree.ElementTree as ET
    tree = ET.parse(r'C:\Users\LAB_PTG\Desktop\Cosmo_v0.93.6\nidaq.xml')
    root = tree.getroot()
    P={}
    C={}
    for Channel in root.iter('Channel'):
        z=(Channel.attrib)
        if z['virtual']=='False':
            P.update({z['name']:(z['physical_channel'],z['enable'],z['m_factor'],z['max_value'])})
        else:
            C.update({z['name']:(z['formula'])})
    print(P,C)

Help needed:

  1. how to execute the code in LabVIEW?
  2. how to handle DICT in LabVIEW? or is there a better solution to pass the data?
  3. use the paras data to dynamically configure the DAQmx channels

I didn't manage creating a xml parser in LabVIEW as it enforces more hard coding and having a fixed stricture.

I am targeting the LV DAQmx continues sampling example and replace the configuration with the parsed xml.

enter image description here

Thanks for every one supporting Assaf Baker


Solution

  • Parsing XML in Labview

    Parsing XML in LV is a bit tricky, but not that difficult. Maybe, you give it a try?

    This code loops over all channels, extracts attributes name and virtual, and from their children RollingAvg, it extracts the attribute do_rolling_avg.

    enter image description here

    May be, it is more handy to get a list of all attributes / values of a node first, and then work on the generated array:

    enter image description here

    Now, it is important to close all references at the end to avoid a memory leak, which is done quick and dirty, here.

    Further more, if something is not found, the search VIs will throw an error. (Your Python will do so, too). Some error handling should be added if necessary.


    If you insist on using Python

    Today, there's an option to run Python directly from LV. I don't know this, my LV is from 2017. There, it is possible to use the System Exec.vi to run any command on the commandline, and read its output back into LV:

    enter image description here

    Finally, what Python prints, will be returned as string. I'd work with JSON, which easily converts a dict to JSON:

    import json
    
    a=[]
    a.append({'name':'CH_PH1', 'virtual':False, 'RollingAvgFrame':3.141})
    a.append({'name':'CH_PH2', 'virtual':True, 'RollingAvgFrame':42.0})
    print(json.dumps(a))
    

    Output:

    [{"name": "CH_PH1", "virtual": false, "RollingAvgFrame": 3.141}, 
    {"name": "CH_PH2", "virtual": true, "RollingAvgFrame": 42.0}]
    

    In LV, define a cluster according to the JSON structure, and use the Unflatten from JSONVI to fill it. The names of the cluster elements must match those in the JSON code.

    enter image description here

    However, JSON knows only simple data types. There is no way to transfer time or any other more complex datatype, unless it can be packed as something more simple like a string containing a timestamp.