ZeissCAN29 issue: Timeout when setting ZeissReflectedLightShutter-State=1 when it's already 1

Hello,

I have an Observer Z1 + (old) colibri connected via CAN. The microscope has three shutters:

  • ZeissReflectedLightShutter
  • ZeissTransmittedLightShutter
  • ZeissColibri

To change filters/channels, I created a group with

  • ZeissReflectorTurret-Label
  • Core-Shutter (so I can switch between colibri and transmitted light)
  • and ZeissReflectedLightShutter-State (which I set to 1 when the Colibri provides the excitation and 0 when it’s transmitted).

The issue I have as far as I can tell is that when the ReflectedLightShutter is already at 1 and one of my presets tries to set it to 1 again, a timeout occurs and the state is actually set to 0.

So we have this weird behaviour described in this thread:

http://micro-manager.3463995.n2.nabble.com/Trouble-switching-filter-cubes-Zeiss-Observer-Z1-td7590712.html

You switch from say DAPI to GFP and there’s a timeout and the preset is set to blank, and you set the preset to GFP again and it works the second time round.

If you actually set the ReflectedLightShutter state to 0 on the touchpad before changing presets in micro-manager, everything works as expected (no timeout).

In my case, moving presets from a Colibri preset to transmitted light works (ReflectedLightShutter state to 0) and moving back to a Colibri preset also works (ReflectedLightShutter state to 1). However, moving between Colibri presets (without closing the shutter first) will cause a timeout.

I can’t think of a solution for this but thought maybe someone else might :wink:

Thank you!

cfg_and_log.zip (21.8 KB)

Hi @EP.Zindy,

That is odd. Not sure what is going here, but it seems prudent to first check what the state is, and if it already is what is desired, not send the command. I made an attempt, and binaries are here: https://valelab4.ucsf.edu/~nico/images/mmgr_dal_ZeissCAN29.dll

The only function I changed is the following in ZeisCAN29.cpp:

int ZeissChanger::SetPosition(MM::Device& device, MM::Core& core, ZeissUByte devId, int position)
{
   int currentPosition;
   int ret = ZeissChanger::GetPosition(device, core, devId_, currentPosition);
   if (ret != DEVICE_OK)
      return ret;

   if (currentPosition != position)
   {
      return ZeissDevice::SetPosition(device, core, g_hub.GetCommandGroup(devId), devId, position);
   }
     std::ostringstream os;
     os << "Device " << devId_ << "was already in position " << position;
     core.LogMessage(&device, os.str().c_str(), true);
     return DEVICE_OK;
}

Let me know what you find.

Thanks Nico! I’ll brave the elements and check it out tomorrow :slight_smile:

I haven’t looked at the adapter’s code yet, so thank you for making that change. Is the currentPosition being monitored in a separate thread? What happens if I decide to change the state using the buttons on the microscope or the touchscreen?

I’ll let you know how it goes in any case.

Cheers,
Egor

Yes!

The scope sends a message to the computer that will be picked up by the monitoring thread which updates its model of the microscope, so that GetPosition will give the correct answer.

Thank you for your help Nico.

Long day today and… of course I managed to mess up your code (I had one job!).

I noticed @kbellve had this to say back in 2011:

If you set the Objector or Reflector turret on an AxioObserver Z1 to their current positions, uManager will timeout.

I found and removed Karl’s test from inside Turret::OnState() since your new test in ZeissChanger::SetPosition() also takes care of the turret, but I did not remove the GetPosition() part of the test :man_facepalming:).

Anyway, I can now switch between LEDs faster than before, but now I can’t switch from Transmitted to Reflected and back without a timeout. Was it not the other way round yesterday? I’m so confused right now…

I’ll think about this some more and come back to you with some clean code and clean logs, sorry :slight_smile:

So, I re-read Trouble switching filter cubes Zeiss Observer.Z1 thread and noticed I was actually hitting two problems at the same time:

  • The filtercube turret can only be switched to a new position, not its current one.
  • The filtercube turret is prevented from moving when the ReflectedLightShutter is open.

As Nico wrote:

Summarizing this thread:

Alina reported that - after a firmware update - the Zeiss AxioObserver Z1 had problems switching between channel configurations in Micro-Manager. Although evidence is a bit scarce (since I have been helping remotely), it seems that the new Zeiss firmware no longer allows for fluorescence turret movements while the reflected light shutter is open (a pull request on github for an upright Zeiss scope suggested the same problem.
This change was doubtlessly made to improve safety, but is quite annoying when using an LED light source that has its own “shutter” (as Alina had). Alina solved the problem by using the “multi-shutter” device in the “Utility” device adapter to combine both the LED shutter and Zeiss reflected light shutter in one “virtual” shutter. Downside of that approach is that the Zeiss reflected light shutter is much slower than the LED.

If anyone runs into this same issue again, it would be good to ask Zeiss if there is any way to go around this limitation.

I followed Nico’s advice and created a utilities multi-shutter comprising the ZeissColibri shutter and the ReflectedLightShutter.

This was done by inserting the following lines in the config:

# Preset: Startup
ConfigGroup,System,Startup,Multi Shutter,Physical Shutter 1,ZeissReflectedLightShutter
ConfigGroup,System,Startup,Multi Shutter,Physical Shutter 2,ZeissColibri

… and by setting the CoreShutter to either “Multi Shutter” for the reflected light or “TransmittedLightShutter” when using the Transmitted light position:

Group Filters
# Preset: mCherry
ConfigGroup,Filters,mCherry,ZeissReflectorTurret,Label,5-64 mPlum
ConfigGroup,Filters,mCherry,Core,Shutter,Multi Shutter

# Preset: Transmitted
ConfigGroup,Filters,Transmitted,ZeissReflectorTurret,Label,6-DIC TL
ConfigGroup,Filters,Transmitted,Core,Shutter,ZeissTransmittedLightShutter

# Preset: GFP
ConfigGroup,Filters,GFP,ZeissReflectorTurret,Label,3-38 GFP
ConfigGroup,Filters,GFP,Core,Shutter,Multi Shutter

# Preset: DAPI
ConfigGroup,Filters,DAPI,ZeissReflectorTurret,Label,1-49 DAPI
ConfigGroup,Filters,DAPI,Core,Shutter,Multi Shutter

Does this work? Sure! As long as you remember to close the “Multi Shutter” before selecting a new position from the dropdown menu. Since I’ve been experimenting with the ZeissCAN29 adapter, I’ll see if I can detect whether the reflected light shutter is open or close, close if necessary, before changing position.

… And/or like Nico suggested, ask our contact at Zeiss if there’s a way round this limitation :thinking:

That is bringing back history. Thanks for tagging me. :grinning:

Our Zeiss scope doesn’t have a ZeissColibri, so I didn’t catch that one, nor can I test the new coding changes to see if they help.

And Nico’s response to my post from 2011 seems to be prescient :

Also, I am a bit worried that other devices may behave the same behavior. Please let me know of such problems.

I did solve that Zeiss XY stage timeout issues that I left off with that 2011 post. Good Times. :grinning:

1 Like

Should I push any code changes in the ZeissCAN29 device adapter? Happy to do so, but unable to test with equipment, so rely on your judgement!

Hi Nico,

no code to push… The furthest I got yesterday was to expand on Karl’s test in Turret::OnState() to close the ReflectedLightShutter if needed:

int Turret::OnState(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      int pos;
      int ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), devId_, pos);
      if (ret != DEVICE_OK)
         return ret;
      pos_ = pos -1;
      pProp->Set(pos_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(pos_);
      int pos = pos_ + 1;
      if ((pos > 0) && (pos <= (int) numPos_)) 
      {
         // Only change position if it is different from requested
         int currentPos;
         int ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), devId_, currentPos);
         if (ret != DEVICE_OK)
            return ret;
         if (pos == currentPos)
            return DEVICE_OK;
         if (devId_ == g_ReflectorChanger)
         {
            // Close ReflectedLightShutter if needed
            ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), g_ReflectedLightShutter, currentPos);
            if (ret != DEVICE_OK)
               return ret;
            if (currentPos != 1) {
               ret = ZeissChanger::SetPosition(*this, *GetCoreCallback(), g_ReflectedLightShutter, 1);
               if (ret != DEVICE_OK)
                  return ret;
               ostringstream os;
               os << "Setting device "<< hex << (unsigned int) g_ReflectedLightShutter << " position " << dec << currentPos << " to position 1 (closed)";
               LogMessage(os.str());

            }
         }
         return ZeissChanger::SetPosition(*this, *GetCoreCallback(), devId_, pos);
      }
      else
         return ERR_INVALID_TURRET_POSITION;
   }
   return DEVICE_OK;
}

I have one last thing I want to try on Thursday (maybe I need to close both the ReflectedLightShutter and the TransmittedLightShutter before moving to a new position) but I’m furiously clutching at straws here.

If that doesn’t help, I suggest that the ZeissCAN29 adapter is just fine the way it is. We’ll see! :slight_smile:

Hi folks,

I’m done beating this dead horse… the fix eludes me. I’ve attached my latest try with the following two changes in ZeissCAN29.cpp and the resulting CoreLog. With or without these changes, we can switch filters with the shutters closed, and as long as people remember to use autoshutter on when doing their MDA acquisition, it’s a small inconvenience (a.k.a. the “you’re holding it wrong” excuse).

If anyone wants to look into this: With these two changes below, I can switch between reflected light positions with autoshutter off and the combined (colibri + reflected light) shutter open. I can also switch from a reflected light position to transmitted light. However, switching from transmitted light to reflected light still times out… Why??

@nicost, since I can’t guarantee these changes bring anything to the table, we probably should leave the ZeissCAN29 code as is for now.

Still, if anyone has a solution or wants me to try something, I’m all ears :wink:

Cheers,
Egor

First change:

int ZeissChanger::SetPosition(MM::Device& device, MM::Core& core, ZeissUByte devId, int position)
{
   int currentPosition;
   int ret = ZeissChanger::GetPosition(device, core, devId_, currentPosition);
   if (ret != DEVICE_OK)
      return ret;

   if (currentPosition != position)
   {
      return ZeissDevice::SetPosition(device, core, g_hub.GetCommandGroup(devId), devId, position);
   }

   std::ostringstream os;
   os << "Device " << hex << (unsigned int) devId << " was already in position " << position;
   core.LogMessage(&device, os.str().c_str(), true);
   return DEVICE_OK;
}

Second change:

int Turret::OnState(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      int pos;
      int ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), devId_, pos);
      if (ret != DEVICE_OK)
         return ret;
      pos_ = pos -1;
      pProp->Set(pos_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(pos_);
      int pos = pos_ + 1;
      if ((pos > 0) && (pos <= (int) numPos_)) 
      {
         // Only change position if it is different from requested
         int currentPos;
         int ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), devId_, currentPos);
         if (ret != DEVICE_OK)
            return ret;
         if (pos == currentPos)
            return DEVICE_OK;
         if (devId_ == g_ReflectorChanger)
         {
            // Close ReflectedLightShutter if needed
            ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), g_ReflectedLightShutter, currentPos);
            if (ret != DEVICE_OK)
               return ret;
            if (currentPos != 1) {
               ret = ZeissChanger::SetPosition(*this, *GetCoreCallback(), g_ReflectedLightShutter, 1);
               if (ret != DEVICE_OK)
                  return ret;
               ostringstream os;
               os << "Setting device "<< hex << (unsigned int) g_ReflectedLightShutter << " position " << dec << currentPos << " to position 1 (closed)";
               LogMessage(os.str());
            }

            // Close TransmittedLightShutter if needed
            ret = ZeissChanger::GetPosition(*this, *GetCoreCallback(), g_TransmittedLightShutter, currentPos);
            if (ret != DEVICE_OK)
               return ret;
            if (currentPos != 1) {
               ret = ZeissChanger::SetPosition(*this, *GetCoreCallback(), g_TransmittedLightShutter, 1);
               if (ret != DEVICE_OK)
                  return ret;
               ostringstream os;
               os << "Setting device "<< hex << (unsigned int) g_TransmittedLightShutter << " position " << dec << currentPos << " to position 1 (closed)";
               LogMessage(os.str());
            }
         }
         return ZeissChanger::SetPosition(*this, *GetCoreCallback(), devId_, pos);
      }
      else
         return ERR_INVALID_TURRET_POSITION;
   }
   return DEVICE_OK;
}

ZeissCAN29.zip (15.2 KB) CoreLog20210318T171329_pid1120.zip (97.9 KB)