ni / nidaqmx-python

A Python API for interacting with NI-DAQmx
Other
440 stars 154 forks source link

Exception in callback done_event #51

Closed MartijnZ closed 6 years ago

MartijnZ commented 6 years ago

Hi,

First of all, thank you for sharing this module. Interacting with NI-DAQmx through Python makes life a lot easier!

When working with the nidaqmx-python, I get the following exception when using the done-event (see minimal example below):

NoneType: None
Exception ignored in: <function cb_done at 0x0000025BE34427B8>

How can I prevent this error ?

Furthermore, I noticed that the callback receives two ints and a None as arguments. Based on the C-API I assume these are the task handle, options parameter and the callback data. How can I use the object handle to recover the object that send the callback?

import nidaqmx
from nidaqmx.constants import *

def cb_done(*args):
    print('Done!')

    for a in args:
        print(a)

if __name__ == "__main__":
    devname = 'nidaq'

    # Create task:
    mytask = nidaqmx.Task('example')
    dev = nidaqmx.system.Device(devname)
    dev.reserve_network_device(True)

    # Add some signal to task:
    mod_name = 'Mod1'
    ai_index = 0
    mytask.ai_channels.add_ai_accel_chan('{0}{2}/ai{1}'.format(devname, ai_index, mod_name),
                                           name_to_assign_to_channel= 'sig1',
                                           terminal_config=TerminalConfiguration.PSEUDODIFFERENTIAL,
                                           min_val=-5.0, max_val=5.0,
                                           units=AccelUnits.METERS_PER_SECOND_SQUARED,
                                           sensitivity=100.0,
                                           sensitivity_units=AccelSensitivityUnits.M_VOLTS_PER_G,
                                           current_excit_source=ExcitationSource.INTERNAL,
                                           current_excit_val   =0.020,
                                           custom_scale_name=''
                                        )

    # Configure timing:
    mytask.timing.cfg_samp_clk_timing(1e3, source='',
                                        active_edge=Edge.RISING,
                                        sample_mode=AcquisitionType.FINITE,
                                        samps_per_chan=int(1e4)
                                     )

    mytask.register_done_event(cb_done)

    # Perform task
    print('Performing Measurement Task...')
    mytask.start()
    mytask.wait_until_done()
neilvana commented 6 years ago

For starters your callback function must return an integer (usually just returning 0 is fine).

Second, this program has a race condition since the wait_until_done can complete first and python can shut down before the callback is handled.

Finally you are not clearing the task. I made a few changes and the exception no longer occurs:

import nidaqmx
from nidaqmx.constants import *
import time

def cb_done(*args):
    print('Done!')
    for a in args:
        print(a)
    return 0

if __name__ == "__main__":
    devname = 'cDAQ2'

    # Create task:
    with nidaqmx.Task('example') as mytask:
        # dev = nidaqmx.system.Device(devname)
        # dev.reserve_network_device(True)

        # Add some signal to task:
        mod_name = 'Mod1'
        ai_index = 0
        mytask.ai_channels.add_ai_accel_chan('{0}{2}/ai{1}'.format(devname, ai_index, mod_name),
                                               name_to_assign_to_channel= 'sig1',
                                               terminal_config=TerminalConfiguration.PSEUDODIFFERENTIAL,
                                               min_val=-5.0, max_val=5.0,
                                               units=AccelUnits.METERS_PER_SECOND_SQUARED,
                                               sensitivity=100.0,
                                               sensitivity_units=AccelSensitivityUnits.M_VOLTS_PER_G,
                                               current_excit_source=ExcitationSource.INTERNAL,
                                               current_excit_val   =0.020,
                                               custom_scale_name=''
                                            )

        # Configure timing:
        mytask.timing.cfg_samp_clk_timing(1e3, source='',
                                            active_edge=Edge.RISING,
                                            sample_mode=AcquisitionType.FINITE,
                                            samps_per_chan=int(1e4)
                                         )

        mytask.register_done_event(cb_done)

        # Perform task
        print('Performing Measurement Task...')
        mytask.start()
        mytask.wait_until_done()
        print('Task is done, waiting for callback to finish')
        time.sleep(1)
MartijnZ commented 6 years ago

Thanks for the reply, the return statement indeed resolved the issue!