2

I know that similar questions might have been asked before. But I couldn't find a solution that fits my case. Apologies for the dumb question in advance.

I am reading two voltage values from a USB-hub (connected to two sensors). The problem is that, the way that my code does it, there will be an approx. 0.8-second delay between them so I can never have both their values at the same time ( if I decrease the any of the two time.sleep(), the value of the second def will not be reported ). I was thinking that if both could run at the same time, maybe I could have values that belong to exact same time point and not shifted through time. If you have any comments that can improve this code, I appreciate it.
I thank you for your comments in advance.

            import sys
            import time
            import datetime
            from Phidget22.Devices.VoltageRatioInput import *
            from Phidget22.PhidgetException import *
            from Phidget22.Phidget import *
            from Phidget22.Net import *
            fig = plt.figure()
            ax1 = fig.add_subplot(1,1,1)
            try:
                ch = VoltageRatioInput()
            except RuntimeError as e:
                print("Runtime Exception %s" % e.details)
                print("Press Enter to Exit...\n")
                readin = sys.stdin.read(1)
                exit(1)

            a=[]
            b=[]
            try:
                start = time.time()
                while True:
                    def VoltageRatioChangeHandler(e, voltageRatio):
                        n=voltageRatio
                        a.append(n)


                    ch.setOnVoltageRatioChangeHandler(VoltageRatioChangeHandler)
                    ch.setHubPort(1)
                    ch.setIsHubPortDevice(1)
                    ch.openWaitForAttachment(5000)

                    if(ch.getChannelSubclass() == ChannelSubclass.PHIDCHSUBCLASS_VOLTAGERATIOINPUT_BRIDGE):
                        ch.setBridgeEnabled(1)

                    time.sleep(0.3)
                    ch.close()
                    end1 = time.time()
                    Elt1 = end1-start
                    print (Elt1)
                    print a
            ###    
                    def VoltageRatioChangeHandler(e, voltageRatio2):
                        m=voltageRatio2
                        if m is None:
                            b.append(0)
                        else:
                            b.append(m)

                    ch.setOnVoltageRatioChangeHandler(VoltageRatioChangeHandler)
                    ch.setHubPort(0)
                    ch.setIsHubPortDevice(0)
                    ch.openWaitForAttachment(5000)

                    if(ch.getChannelSubclass() == ChannelSubclass.PHIDCHSUBCLASS_VOLTAGERATIOINPUT_BRIDGE):
                        ch.setBridgeEnabled(1)

                    time.sleep(0.4)
                    ch.close()
                    end = time.time()
                    Elt = end - start
                    print (Elt)
                    print b


            except KeyboardInterrupt:
                print ("gracefully aborted")
                sys.exit()
user3666197
  • 1
  • 6
  • 50
  • 92

1 Answers1

0

Going parallel sounds easier than done. (... watch the [us] lost here )
Better not move in this way, but:

Long story short: costs of going "parallel" are devastating for your use-case.

Also reinventing a wheel is quite expensive, so let me offer you a concept, which is almost free of charge and works like charm.

Your measurements are so close to a multi-agent control-system, so let's re-use the framework that was developed exactly for the same reason -- the MVC ( yes, an anxious and great idea, as old as the one originated in the famous nest of smart thinkers from the XEROX Palo Alto Research Centre ).

import Tkinter as tk # YESSSS! re-using a GUI-tool ( i.e. multi-agent by-design )

The key value is in the freedom of design "under" the Controller-part of the concept, using all the exceptionally well polished tools built-in, not to bother with low-level details.


High-level idea: ( a full sensoric-network control-plan may go this way )

Let the sensors get read as often as you need ( be it driven just by a common sense, a smell of reason, or an indeed rigorous Nyquist-boundary of the theory of stability of your experiment's control-loop ).

First, we may need a way, how to passively read a value-pair ( coherently read at the same time ( well, better withing a common window-of-time, right? ) ).

SENSOR_A_Last_Voltage_Value = tk.DoubleVar()
SENSOR_B_Last_Voltage_Value = tk.DoubleVar()

SCHEDULED_EVENT_READ_A      = tk.StringVar()
SCHEDULED_EVENT_READ_B      = tk.StringVar()

SIGNAL_2_READ_Voltage_Value = tk.IntVar()

These are the MVC-Model-part smart-"registers", if you wish.

def aSensorREAD_A():
    #--------------------------------------------------
    # handle all the tricks to read a given sensor ONCE
    #--------------------------------------------------
    ...
    ch.setHubPort( 0 )
    ch.setIsHubPortDevice( 0 )
    ch.openWaitForAttachment( 5000 )
    ...
    a_just_read_value = ...

    #--------------------------------------------------
    # Let the MVC-framework store this value into MODEL
    #--------------------------------------------------
    SENSOR_A_Last_Voltage_Value.set( a_just_read_value )

    #--------------------------------------------------
    # schedule a ( self-operated ) read "next" ONCE
    #--------------------------------------------------
    SCHEDULED_EVENT_READ_A.set( root.after( 100, aSensorREAD_A ) )
    # repeat                         after  100 [ms]
    #
    # a cool way to command actually your Boss, isn't it?
    # + may,
    # if at need, root.after_cancel( SCHEDULED_EVENT_READ_A )

So, we may consider a role of a SensorREAD_*() to be one of such independent agents, responsible for doing the low-level job with the actual sensor readings.

For a passive value-consumer, there will be just a pair of "intelligent" variables, that are granted to always carry the updated ( last read )-value.

print( "[A] {0: >16.3f}[mV]".format( SENSOR_A_Last_Voltage_Value.get() )
print( "[B] {0: >16.3f}[mV]".format( SENSOR_B_Last_Voltage_Value.get() )

For a triggered-expecting value-consumer, there might be an additional tool, that will inform any such trigger-expecting-reader.

idTrA1 = SENSOR_A_Last_Voltage_Value.trace_variable( "w", aTriggerdFUN1ToCallOnA )
idTrA2 = SENSOR_A_Last_Voltage_Value.trace_variable( "w", aTriggerdFUN2ToCallOnA )
idTrA3 = SENSOR_A_Last_Voltage_Value.trace_variable( "w", aTriggerdFUN3ToCallOnA )

idTrB1 = SENSOR_B_Last_Voltage_Value.trace_variable( "w", aTriggerdFUN1ToCallOnB )
...
idTrB7 = SENSOR_B_Last_Voltage_Value.trace_variable( "w", aTriggerdFUN7ToCallOnB )
# as one may wish and need

Last, but not least, there might be another coherent-reading strategy:

SIGNAL_2_READ_Voltage_Value = tk.IntVar()                       # MVC-Model "register"

idTrSIG2R_A = SIGNAL_2_READ_Voltage_Value( "w", aSensorREAD_A ) # MVC-Controller actor
idTrSIG2R_B = SIGNAL_2_READ_Voltage_Value( "w", aSensorREAD_B )

This makes an external trigger-to-read tool, that will actually help to "fire" both reading "at the same moment", just by touching:

SIGNAL_2_READ_Voltage_Value.set( 1 + SIGNAL_2_READ_Voltage_Value.get() )

Also some final steps for graceful termination are clear and honest:

finally:
    #---------------------------------------------------
    SIGNAL_2_READ_Voltage_Value.trace_vdelete( "w", idTrSIG2R_A )
    SIGNAL_2_READ_Voltage_Value.trace_vdelete( "w", idTrSIG2R_B )
    #---------------------------------------------------
    SENSOR_A_Last_Voltage_Value.trace_vdelete( "w", idTrA1 )
    SENSOR_A_Last_Voltage_Value.trace_vdelete( "w", idTrA2 )
    SENSOR_A_Last_Voltage_Value.trace_vdelete( "w", idTrA3 )
    #---------------------------------------------------
    SENSOR_B_Last_Voltage_Value.trace_vdelete( "w", idTrB1 )
    ...
    SENSOR_B_Last_Voltage_Value.trace_vdelete( "w", idTrB7 )

For more details and mock-up case inspiration may like to read this

user3666197
  • 1
  • 6
  • 50
  • 92