Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to connect to QDAC (USB connection) from multiple Jupyter notebooks #3862

Open
stennebroek opened this issue Jan 25, 2022 · 2 comments

Comments

@stennebroek
Copy link

Hi!

I am unable to have two instances of the QDevil QDAC (qcodes/instrument_drivers/QDevil/QDevil_QDAC.py) in two different/separate Jupyter notebooks simultaneously. Initializing the QDevil QDAC in the first Jupyter notebook works fine, but when initializing the same QDevil QDAC in the second Jupyter notebook (with a separate kernel) throws a SerialException error, probably because it is connected to the PC through USB and it doens't seem possible to connect to it from two separate notebooks.

Steps to reproduce

  1. Initialize the QDAC, e.g.
from qcodes.instrument_drivers.QDevil.QDevil_QDAC import QDac

qdac = QDac('qdac', 'ASRL3::INSTR')
  1. Initialize the QDAC in the same way in a second Jupyter notebook
  2. When running the cell in step 2, I get the following SerialException error:
---------------------------------------------------------------------------
SerialException                           Traceback (most recent call last)
Input In [1], in <module>
      1 from qcodes.instrument_drivers.QDevil.QDevil_QDAC import QDac
----> 3 qdac = QDac('qdac', 'ASRL3::INSTR')

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\qcodes\instrument_drivers\QDevil\QDevil_QDAC.py:234, in QDac.__init__(self, name, address, update_currents, **kwargs)
    215 def __init__(self,
    216              name: str,
    217              address: str,
    218              update_currents: bool = False,
    219              **kwargs: Any):
    220     """
    221     Instantiates the instrument.
    222 
   (...)
    231         QDac object
    232     """
--> 234     super().__init__(name, address, **kwargs)
    235     handle = self.visa_handle
    236     self._get_status_performed = False

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\qcodes\instrument\visa.py:89, in VisaInstrument.__init__(self, name, address, timeout, terminator, device_clear, visalib, **kwargs)
     87     self.visa_log.info(f"Could not connect at {address}")
     88     self.close()
---> 89     raise e
     91 if device_clear:
     92     self.device_clear()

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\qcodes\instrument\visa.py:85, in VisaInstrument.__init__(self, name, address, timeout, terminator, device_clear, visalib, **kwargs)
     82     self.visalib = visalib
     84 try:
---> 85     self.set_address(address)
     86 except Exception as e:
     87     self.visa_log.info(f"Could not connect at {address}")

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\qcodes\instrument\visa.py:124, in VisaInstrument.set_address(self, address)
    121     self.visabackend = 'ni'
    123 self.visa_log.info(f'Opening PyVISA resource at address: {address}')
--> 124 resource = resource_manager.open_resource(address)
    125 if not isinstance(resource, visa.resources.MessageBasedResource):
    126     raise TypeError("QCoDeS only support MessageBasedResource "
    127                     "Visa resources")

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\pyvisa\highlevel.py:3304, in ResourceManager.open_resource(self, resource_name, access_mode, open_timeout, resource_pyclass, **kwargs)
   3298     if not present:
   3299         raise ValueError(
   3300             "%r is not a valid attribute for type %s"
   3301             % (key, res.__class__.__name__)
   3302         )
-> 3304 res.open(access_mode, open_timeout)
   3306 for key, value in kwargs.items():
   3307     setattr(res, key, value)

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\pyvisa\resources\resource.py:297, in Resource.open(self, access_mode, open_timeout)
    293 logger.debug("%s - opening ...", self._resource_name, extra=self._logging_extra)
    294 with self._resource_manager.ignore_warning(
    295     constants.StatusCode.success_device_not_present
    296 ):
--> 297     self.session, status = self._resource_manager.open_bare_resource(
    298         self._resource_name, access_mode, open_timeout
    299     )
    301     if status == constants.StatusCode.success_device_not_present:
    302         # The device was not ready when we opened the session.
    303         # Now it gets five seconds more to become ready.
    304         # Every 0.1 seconds we probe it with viClear.
    305         start_time = time.time()

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\pyvisa\highlevel.py:3232, in ResourceManager.open_bare_resource(self, resource_name, access_mode, open_timeout)
   3203 def open_bare_resource(
   3204     self,
   3205     resource_name: str,
   3206     access_mode: constants.AccessModes = constants.AccessModes.no_lock,
   3207     open_timeout: int = constants.VI_TMO_IMMEDIATE,
   3208 ) -> Tuple[VISASession, StatusCode]:
   3209     """Open the specified resource without wrapping into a class.
   3210 
   3211     Parameters
   (...)
   3230 
   3231     """
-> 3232     return self.visalib.open(self.session, resource_name, access_mode, open_timeout)

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\pyvisa_py\highlevel.py:167, in PyVisaLibrary.open(self, session, resource_name, access_mode, open_timeout)
    158     return (
    159         VISASession(0),
    160         self.handle_return_value(None, StatusCode.error_invalid_resource_name),
    161     )
    163 cls = sessions.Session.get_session_class(
    164     parsed.interface_type_const, parsed.resource_class
    165 )
--> 167 sess = cls(session, resource_name, parsed, open_timeout)
    169 return self._register(sess), StatusCode.success

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\pyvisa_py\sessions.py:323, in Session.__init__(self, resource_manager_session, resource_name, parsed, open_timeout)
    320 default_timeout = attributes.AttributesByID[attr].default
    321 self.set_attribute(attr, default_timeout)
--> 323 self.after_parsing()

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\pyvisa_py\serial.py:89, in SerialSession.after_parsing(self)
     86 def after_parsing(self) -> None:
     87     cls = serial.Serial
---> 89     self.interface = cls(
     90         port=("COM" if IS_WIN else "") + self.parsed.board,
     91         timeout=self.timeout,
     92         write_timeout=self.timeout,
     93     )
     95     for name in (
     96         "ASRL_END_IN",
     97         "ASRL_END_OUT",
   (...)
    101         "SUPPRESS_END_EN",
    102     ):
    103         attribute = getattr(constants, "VI_ATTR_" + name)

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\serial\serialwin32.py:33, in Serial.__init__(self, *args, **kwargs)
     31 self._overlapped_read = None
     32 self._overlapped_write = None
---> 33 super(Serial, self).__init__(*args, **kwargs)

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\serial\serialutil.py:244, in SerialBase.__init__(self, port, baudrate, bytesize, parity, stopbits, timeout, xonxoff, rtscts, write_timeout, dsrdtr, inter_byte_timeout, exclusive, **kwargs)
    241     raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))
    243 if port is not None:
--> 244     self.open()

File ~\anaconda3\envs\pycqed39-2\lib\site-packages\serial\serialwin32.py:64, in Serial.open(self)
     62 if self._port_handle == win32.INVALID_HANDLE_VALUE:
     63     self._port_handle = None    # 'cause __del__ is called anyway
---> 64     raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
     66 try:
     67     self._overlapped_read = win32.OVERLAPPED()

SerialException: could not open port 'COM3': PermissionError(13, 'Access is denied.', None, 5)

Expected/Desired behaviour

It would be great if it's possible to initialize a QDevil QDAC in multiple Jupyter notebooks/kernels, perhaps by somehow sharing the device/sharing the USB connection in a clever way.

Actual behaviour

SerialException error is thrown when the QDevil QDAC is already initialized in another notebook on the same PC.

System

OS: Windows 10 64-bit
qcodes version: 0.31.0

Would you have any suggestions for a solution? Thank you very much in advance!

@jenshnielsen
Copy link
Collaborator

Hi

Most of the instruments qcodes supports are not designed to be remote controlled from more than one connection.
You may want to have a look at https://github.com/toolsforexperiments/instrumentserver which is an instrument server that acts as a proxy to the instruments. We may eventually implement such a feature in qcodes but we cannot commit to any promises to when that will happen

@stennebroek
Copy link
Author

stennebroek commented Mar 1, 2022

Hi @jenshnielsen, thank you for your reply and pointing out the instrument server. In the meantime we came up with a temporary "hacky" solution for our use-case, but we might invest in looking into a cleaner solution.

It would be interesting to see an implementation in qcodes someday (though I can imagine it is not a priority for you/the developers right now)!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants