TheDeanLab / navigate

navigate - open source light-sheet microscope controls
https://thedeanlab.github.io/navigate/
Other
18 stars 5 forks source link

Updated ni filter wheel #908

Closed annie-xd-wang closed 2 months ago

annie-xd-wang commented 3 months ago

We can remove the commented lines after testing with devices.

codecov[bot] commented 3 months ago

Codecov Report

Attention: Patch coverage is 11.88406% with 304 lines in your changes missing coverage. Please review.

Project coverage is 51.28%. Comparing base (4fac2fb) to head (de93405). Report is 33 commits behind head on develop.

Files Patch % Lines
.../model/devices/APIs/thorlabs/kcube_steppermotor.py 0.00% 167 Missing :warning:
...odel/devices/stages/stage_tl_kcube_steppermotor.py 20.93% 68 Missing :warning:
...ate/model/devices/filter_wheel/filter_wheel_daq.py 0.00% 41 Missing :warning:
src/navigate/model/device_startup_functions.py 33.33% 16 Missing :warning:
src/navigate/model/microscope.py 65.21% 8 Missing :warning:
src/navigate/model/devices/daq/daq_ni.py 0.00% 4 Missing :warning:
Additional details and impacted files ```diff @@ Coverage Diff @@ ## develop #908 +/- ## =========================================== + Coverage 51.04% 51.28% +0.23% =========================================== Files 178 180 +2 Lines 19054 19161 +107 =========================================== + Hits 9726 9826 +100 - Misses 9328 9335 +7 ``` | [Flag](https://app.codecov.io/gh/TheDeanLab/navigate/pull/908/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheDeanLab) | Coverage Δ | | |---|---|---| | [unittests](https://app.codecov.io/gh/TheDeanLab/navigate/pull/908/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheDeanLab) | `51.28% <11.88%> (+0.23%)` | :arrow_up: | Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheDeanLab#carryforward-flags-in-the-pull-request-comment) to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

AdvancedImagingUTSW commented 2 months ago

@SJShep - have you tested this?

SJShep commented 2 months ago

@annie-xd-wang @AdvancedImagingUTSW Just tried with the new changes and I get an error recognizing "filter_wheel" in the configuration. I have validated that the filter wheel is there printing the device keys before the error is triggered.

print(configuration["configuration"]["microscopes"][microscope_name]["filter_wheel"].keys())

Here is the traceback

(ASInavigate) C:\Users\qi2lab\Documents\github\asi_navigate\navigate>C:/Users/qi2lab/miniconda3/envs/ASInavigate/python.exe c:/Users/qi2lab/Documents/github/asi_navigate/navigate/src/navigate/main.py        
['hardware', 'filter_wheel_delay', 'available_filters']
Device Not Found in Configuration.YML: ('Nanoscale', 'filter_wheel')
vvvvvvvvvvvvvvvvvvvvvvvvvvv Child Process Traceback vvvvvvvvvvvvvvvvvvvvvvvvvvv
 Traceback (most recent call last):
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\concurrency\concurrency_tools.py", line 501, in _child_loop
    obj = initializer(*initargs, **initkwargs)
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\model.py", line 129, in __init__
    self.microscopes[microscope_name] = Microscope(
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\microscope.py", line 244, in __init__
    self.load_and_start_devices(
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\microscope.py", line 877, in load_and_start_devices
    exec(
  File "<string>", line 1, in <module>
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\device_startup_functions.py", line 943, in start_filter_wheel
    device_not_found(microscope_name, "filter_wheel")
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\device_startup_functions.py", line 1359, in device_not_found
    raise RuntimeError(f"Device not found in configuration: {args}")
RuntimeError: Device not found in configuration: ('Nanoscale', 'filter_wheel')
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Child Process Traceback ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 vvvvvvvvvvvvvvvvvvvvvvvvvvv Main Process Traceback vvvvvvvvvvvvvvvvvvvvvvvvvvvv
Traceback (most recent call last):
  File "c:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\main.py", line 134, in <module>
    main()
  File "c:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\main.py", line 119, in main
    Controller(
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\controller\controller.py", line 163, in __init__
    self.model = ObjectInSubprocess(
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\concurrency\concurrency_tools.py", line 383, in __init__
    assert _get_response(self) == "Successfully initialized"
  File "C:\Users\qi2lab\Documents\github\asi_navigate\navigate\src\navigate\model\concurrency\concurrency_tools.py", line 438, in _get_response
    raise resp
RuntimeError: Device not found in configuration: ('Nanoscale', 'filter_wheel')

(ASInavigate) C:\Users\qi2lab\Documents\github\asi_navigate\navigate>
AdvancedImagingUTSW commented 2 months ago

It seems to be trying to call a nanoscale microscope object from the configuration file. What is your microscope called?

SJShep commented 2 months ago

It is called nanoscale as well, but I found where my mistake is. I do not have "device_info" configured correctly:

device_info = configuration["configuration"]["hardware"]["filter_wheel"]
SJShep commented 2 months ago

Nope, still having an issue. Here is our configuration file:

# Lasers: Controllede by NI, 2 lasers.
# Stages: ASI MS2000 Controllers
# Stage Controllers: ASI MS2000 Controller
# Cameras: Photometrics Iris15, named Cam-1
# Remote Focusing Units: Controlled by NI 
# Data Acquisition Cards: National Instruments USB 4363 name Dev2
# Galvo: Novanta CRS 4 KHz Resonant Galvo

# Zoom N/A
# Other: N/A
# Filter Wheel: N/A

# Only one microscope can be active in the GUI at a time, but all microscopes will be accessible
hardware:
  zoom: 
    type: synthetic
  filter_wheel:
    type: NI
  daq:
    type: NI
  stage:
    -
      type: KST101
      serial_number: 26001318
    -
      type: MS2000
      serial_number: 1906420147517051597
      port: COM6
      baudrate: 115200
  camera:
      type: Photometrics
      camera_connection: PMPCIECam00
      serial_number: A17K631096

microscopes:
  Nanoscale:
    daq:
      hardware:
        name: Dev2
        type: NI
      sample_rate: 100000
      sweep_time: 0.2
      # triggers
      master_trigger_out_line: Dev2/port0/line8
      camera_trigger_out_line: /Dev2/ctr0
      trigger_source: /Dev2/PFI5
      # Digital Laser Outputs
      laser_port_switcher: Dev2/port0/line0
      laser_switch_state: False

    camera:
      hardware:
        name: camera
        type: Photometrics
        camera_connection: PMPCIECam00
        serial_number: A17K631096
      subsampling: [1, 2, 4]
      readout_port: 0
      delay_percent: 5
      gain: 1
      speed_table_index: 0
      exposure_time_range:
        min: 1
        max: 1000
        step: 1
      unitforlinedelay: 10.26      

    remote_focus_device:
      hardware:
        name: daq
        type: NI
        channel: Dev2/ao2
        min: 0
        max: 10
      delay_percent: 0 
      ramp_rising_percent: 85
      ramp_falling_percent: 1.5
      amplitude: 0.7
      offset: 2.3

    galvo:
      -
        hardware:
          name: daq
          type: NI
          channel: Dev2/ao0
          min: 0
          max: 5
        frequency: 200
        amplitude: 1.5
        offset: 0
        duty_cycle: 50
        phase: 1.57079 # pi/2

    filter_wheel:
      hardware:
        type: NI  
        wheel_number: 1
      filter_wheel_delay: 0.050 # in seconds
      available_filters:
        473nm: Dev2/port0/line1
        561nm: Dev2/port0/line3
        638nm: Dev2/port0/line5
        Empty: Dev2/port0/line7

    stage:
      hardware:
        -
          name: stage
          type: MS2000
          serial_number: 1906420147517051597
          port: COM6
          baudrate: 115200
          axes: [x, y, z] # Software
          axes_mapping: [X, Y, Z] 
          feedback_alignment: [90, 90, 90, 90]
        -
          name: synthetic
          type: SyntheticStage
          serial_number: 123
          axes: [theta]
          axes_mapping: [xylophone]
          volts_per_micron: None
          axes_channels: None
          max: None
          min: None
        -
          type: KST101
          serial_number: 26001318
          axes: [f]
          axes_mapping: [1]
          feedback_alignment:
          device_units_per_mm: 2008623.6238
          volts_per_micron: 0.0
          min: 0
          max: 25000
      startfocus: -16000
      x_max: 10000 # Swapped from Z
      x_min: -10000 # Swapped from Z
      y_max: 10000
      y_min: -10000
      z_max: 10000 # Swapped from X
      z_min: -10000 # Swapped from X
      f_max: 25000 #=m
      f_min: 0 #=m
      theta_max: 0
      theta_min: 0
      #TODO: Is it because of this external_trigger ? 
      external_trigger: /Dev2/PFI0
      # joystick_axes: [x, y, z, f]
      x_rot_position: 0
      y_rot_position: 0
      z_rot_position: 0
      x_step: 50
      y_step: 50
      z_step: 50
      theta_step: 30
      f_step: 1

      position:
        x_pos: 5 # Swapped from Z initial stage position
        y_pos: 1
        z_pos: 1 # Swapped from X
        f_pos: 0
        theta_pos: 0
      velocity: 1000
      x_offset: 0
      y_offset: 0
      z_offset: 0
      f_offset: 0
      theta_offset: 0

    zoom:
      hardware:
        name: zoom
        type: SyntheticZoom
        servo_id: 1
      position:
        N/A: 0
      pixel_size:
        N/A: 0.168
    shutter: 
      hardware:
        name: daq
        type: NI
        channel: Dev2/port0/line9 
        min: 0
        max: 5

    lasers:
      # Laser 473 wavelength
      - wavelength: 473
        onoff:
          hardware:
            name: daq
            type: NI
            channel: Dev2/port0/line0
            min: 0
            max: 5
        power:
          hardware:
            name: daq
            type: NI
            channel: Dev2/ao1 
            min: 0
            max: 5
        type: LuxX
        index: 0
        delay_percent: 10
        pulse_percent: 87

      # Laser 532 wavelength
      # - wavelength: 532
      #   onoff:
      #     hardware:
      #       name: daq
      #       type: NI
      #       channel: Dev2/port0/line2 
      #       min: 0
      #       max: 5
      #   power:
      #     hardware:
      #       name: daq
      #       type: NI
      #       channel: Dev2/ao2
      #       min: 0
      #       max: 5
      #   type: Obis
      #   index: 1
      #   delay_percent: 10
      #   pulse_percent: 87

      # Laser 561 wavelength
      - wavelength: 561
        onoff:
          hardware:
            name: daq
            type: NI
            channel: Dev2/port0/line4 
            min: 0
            max: 5
        power:
          hardware:
            name: daq
            type: NI
            channel: Dev2/port0/line13
            min: 0
            max: 5
        type: Obis
        index: 1
        delay_percent: 10
        pulse_percent: 87

      # Laser 638 wavelength 
      - wavelength: 638
        onoff:
          hardware:
            name: daq
            type: NI
            channel: Dev2/port0/line6
            min: 0
            max: 5
        power:
          hardware:
            name: daq
            type: NI
            channel: Dev2/ao3
            min: 0
            max: 5
        type: Obis
        index: 1
        delay_percent: 10
        pulse_percent: 87
gui:
  channels:
    count: 5
    laser_power:
      min: 0
      max: 100
      step: 10
    exposure_time:
      min: 1
      max: 1000
      step: 5
    interval_time:
      min: 0
      max: 1000
      step: 5
  stack_acquisition:
    step_size:
      min: 0.1
      max: 1000
      step: 0.1
    start_pos:
      min: -5000
      max: 5000
      step: 1
    end_pos:
      min: -5000
      max: 10000
      step: 1
  timepoint:
    timepoints:
      min: 1
      max: 1000
      step: 1
    stack_pause:
      min: 0
      max: 1000
      step: 1
SJShep commented 2 months ago

In the filter_wheel_daq.py class, build_filter_wheel_connection() returns None which triggers a device not loaded error later on. What would be the preferred way to handle a shared device connection?

AdvancedImagingUTSW commented 2 months ago

Yeah, that makes sense...

def build_filter_wheel_connection():
    """Build DAQFilterwheel connection using the DAQ model object

    Parameters
    ----------
    daq_object : NIDAQ
        An instance of the NIDAQ class

    Returns
    -------
    tiger_controller : TigerController
        ASI Tiger Controller object.
    """
    daq_fw_controller = None
    return daq_fw_controller

Clearly the shared device is not being handled properly here.

AdvancedImagingUTSW commented 2 months ago

Try uncommenting this (line 224 in microscope.py:

                # if device_name == "filter_wheel" and device_ref_name.startswith("NI"): 
                #     device_connection = self.daq
annie-xd-wang commented 2 months ago

After the updates, we treat the ni filter wheel as an independent filter wheel just like the laser_ni.

SJShep commented 2 months ago

Uncommenting the lines in "microscope.py" worked to load the FW and it operates as expected.

AdvancedImagingUTSW commented 2 months ago

@SJShep - I checked with @annie-xd-wang, and we wanted to follow up. In retrospect, you didn't need to uncomment the lines in microscope.py, I was misinformed.

For some devices, like the Tiger Controller, we can only have one instance of communication, which we then hand to all of the necessary devices.

For the nidaqmx, we can create as many instances as we want, so long as we are not trying to write to the same port. So, handing the nidaqmx to the filter wheel class is no longer necessary. We have similar functionality in the nilaser class, where we create the NI task and interact with it in a completely local fashion.

So, if you could give us an update, it would be great if we could move forward and merge this PR.

SJShep commented 2 months ago

If the lines in microscope.py are not uncommented, it fails to load and reports no "filter_wheel" found in "nanoscale".

SJShep commented 2 months ago

The new changes load and operate the NI filter wheel correctly.