Beim erneuten Ausführen eines Widgets in Jupyter wird der Fehler „Libusb-Windows-Zugriff verweigert“ angezeigtPython

Python-Programme
Anonymous
 Beim erneuten Ausführen eines Widgets in Jupyter wird der Fehler „Libusb-Windows-Zugriff verweigert“ angezeigt

Post by Anonymous »

Zusammenfassung
Ich versuche, ein Widget zu erstellen, um Sensordaten von einem USB-Gerät in einem Jupyter-Notebook zu lesen. Ich habe sowohl matplotlib ipywidgets, Dash-plotly als auch Bokeh ausprobiert.
Beim erneuten Ausführen der Widget-Notebook-Zelle geben alle Konfigurationsanforderungen an das USB-Gerät einen Windows-Zugriff verweigert-Fehler 5 zurück. Durch einen Neustart des Kernels wird das Problem behoben.
Das Problem tritt nicht auf, wenn außerhalb eines Widgets ausgeführt wird und die Anforderungen direkt ausgeführt werden. Dies tritt auch bei der Dash-Plotly-Implementierung nicht auf, aber diese ist nicht leistungsstark genug, um mit den Sensordaten bei 20 Hz Schritt zu halten.
Bei dem Gerät handelt es sich um einen alten Drehbewegungssensor, der mit vorinstallierter Software zur Aktivierung und Steuerung geliefert wird. Durch das Aufzeichnen der Nachrichten zwischen der Software und dem Gerät kann die Steuerung blind repliziert werden.
Ich habe nicht viel Erfahrung mit USB-Geräten oder IO im Allgemeinen, habe aber versucht, usb.util.dispose_resources als Fehlerbehandler innerhalb der Klasse auszuführen. Meine aktuelle Verbindungslogik lautet:
  • Suchen Sie das Gerät, das sich beim ersten Plug-in als Bootloader registriert.
  • Konfigurieren Sie das Gerät und senden Sie Anweisungen an das Gerät, das einen Neustart in seinen Anwendungsstatus auslöst (dies kann im Geräte-Manager überprüft werden und bleibt der Fall, solange das Gerät angeschlossen ist).
  • Suchen Sie das Anwendungsgerät nach dem Zurücksetzen und konfigurieren Sie es auf die Standardkonfiguration 1.

Code: Select all

t0 = time.time()
while time.time() - t0 < timeout_s:
try:
self.__dev: usb.core.Device | None = libusb_package.find(
idVendor=ROTATION_BOOT_VID, idProduct=ROTATION_BOOT_PID
)
if self.__dev:
logging.info("Found ROTATION bootloader device.")
self.__initialize_configuration()
logging.info("Connected to ROTATION bootloader device.")
self.__write_firmware()
self.__wait_for_disconnect()
self.__dev = None  # Reset device to connect to application
except usb.core.USBError as e:
time.sleep(0.05)

try:
self.__dev: usb.core.Device = libusb_package.find(
idVendor=ROTATION_APP_VID, idProduct=ROTATION_APP_PID
)
if self.__dev:
logging.info("Found ROTATION application device.")

bConfiguration = self.__dev.get_active_configuration()
logging.info(f"Active configuration: {bConfiguration}")

self.__initialize_configuration()
logging.info("Connected to ROTATION application device.")
return
except (usb.core.USBError, NotImplementedError) as e:
if (isinstance(e, usb.core.USBError) and e.errno == 13):
logging.warning("Access Denied error here") # Taken out of handler for debug
return
self.__handle_usb_error(e)
time.sleep(0.05)

raise ValueError("No ROTATION device found within timeout period")
Die Bereinigung des Geräts wird von einem modifizierten del-Mitglied durchgeführt:

Code: Select all

def __del__(self):
"""Ensure the device is properly released"""
if self.__dev is not None:
logging.info("Cleaning up ROTATION device resources...")
usb.util.dispose_resources(self.__dev)
self.__dev = None
Diese Klasse wird in der aktuellen Bokeh-Implementierung (leistungsstärkste) des Widgets verwendet:

Code: Select all

def gyroscope_app(doc):
source = ColumnDataSource(data=dict(time=[], radial_velocity=[]))
rotation_sensor = RotationSensor()
rotation_sensor.open_device()

plot = figure(
x_axis_label='Time (s)', y_axis_label='Radial velocity (arcsec / s)',
min_width=800, min_height=400
)
plot.line('time', 'radial_velocity', source=source)

callback_id = {'value': None}

@count()
def update(t):
reading = rotation_sensor.read()

if reading is None or len(reading) != 4:
print("Invalid reading received, skipping update.")
return

reading_data = reading[0] if reading[1] >  0 else -reading[0]

new_data = dict(time=[t], radial_velocity=[reading_data])

source.stream(new_data, rollover=30)

def start():
if callback_id['value'] is None:
rotation_sensor.start_sensor_reading()
callback_id['value'] = doc.add_periodic_callback(update, 100)

def stop():
cid = callback_id['value']
if cid is not None:
doc.remove_periodic_callback(cid)
callback_id['value'] = None
rotation_sensor.stop_sensor_reading()

def reset():
stop()
source.data = dict(time=[], radial_velocity=[])

start_button = Button(label="Start", button_type="success")
start_button.on_click(start)

stop_button = Button(label="Stop", button_type="danger")
stop_button.on_click(stop)

reset_button = Button(label="Reset", button_type="warning")
reset_button.on_click(reset)

doc.add_root(
column(
row(start_button, stop_button, reset_button),
plot
)
)
show(gyroscope_app)
Hinweise
  • Der Benutzer verfügt über die entsprechenden Berechtigungen und Verbindungsfunktionen ohne Probleme, wenn er nicht in einem Widget ausgeführt wird.
  • Keine mit dem Gerät verknüpften Python-Seitenobjekte bleiben nach der Zellenausführung und dem Löschen der Ausgabe im Debugger-Stack-Trace sichtbar. Das Problem besteht jedoch weiterhin.
  • Die Konfiguration bei einem Fehler kann nicht überprüft werden, da der Aufruf von usb.core.Device.get_active_configuration() zur gleichen Zugriffsverweigerung führt. Während die Überprüfung, ob der Kernel-Treiber aktiv ist, in Windows nicht implementiert ist.
Lösungsversuche
  • Nach der Zellenausführung bleiben für die Bokeh-Implementierung keine Jupyter-Objekte übrig. Für das matplotlib ipywidget hatte ihre Entfernung jedoch keine Auswirkungen.
  • Protokollierung für libusb zeigt:

Code: Select all

[1898.785734] [000103bc] libusb: debug [libusb_open] open 2.2
[1898.785900] [000103bc] libusb: error [winusbx_open] could not open device \\?\USB#VID_0945&PID_0002#6&2F625D12&0&1#{A5DCBF10-6530-11D2-901F-00C04FB951ED} (interface 0): [5] Access is denied.
[1898.785973] [000103bc] libusb: debug [libusb_open] open 2.2 returns -3
  • Jupyter-Zellenausgabe ist:

Code: Select all

2025-08-20 15:46:56,447 DEBUG:usb.backend.libusb1:_LibUSB.get_device_descriptor()
DEBUG:usb.backend.libusb1:_LibUSB.get_device_descriptor()
2025-08-20 15:46:56,447 DEBUG:usb.backend.libusb1:_Device._finalize_object()
DEBUG:usb.backend.libusb1:_Device._finalize_object()
INFO:root:Found ROTATION application device.
2025-08-20 15:46:56,448 DEBUG:usb.backend.libusb1:_LibUSB.open_device()
DEBUG:usb.backend.libusb1:_LibUSB.open_device()

WARNING:root:Device already configured /* Issue caught here but prevents reading */

INFO:tornado.access:200 GET /autoload.js?bokeh-autoload-element=e97c48c3-168f-4e7c-9b22-33e50eb6464d&bokeh-absolute-url=http://localhost:53080&resources=none (127.0.0.1) 89.15ms
INFO:tornado.access:101 GET /ws (127.0.0.1) 1.00ms
INFO:bokeh.server.views.ws:WebSocket connection opened
INFO:bokeh.server.views.ws:ServerConnection created
  • Beim Lesen von Paketen mit Wireshark und Usbpcan werden nur USB_INTERRUPT-Meldungen angezeigt. Zeigt keine verbleibenden Nachrichten an, wenn die Zelle nicht erneut ausgeführt wird, sodass die Kommunikation nicht aktiv ist.

Code: Select all

No.      Time           Source                Destination           Protocol Length Info
52 7.472741       host                  2.4.1                 USB      27     URB_INTERRUPT in

Frame 52: 27 bytes on wire (216 bits), 27 bytes captured (216 bits) on interface \\.\USBPcap2, id 0
Section number: 1
Interface id: 0 (\\.\USBPcap2)
Interface name: \\.\USBPcap2
Interface description: USBPcap2
Encapsulation type: USB packets with USBPcap header (152)
Arrival Time: Aug 20, 2025 15:46:51.434821000 GMT Daylight Time
UTC Arrival Time: Aug 20, 2025 14:46:51.434821000 UTC
Epoch Arrival Time: 1755701211.434821000
[Time shift for this packet: 0.000000000 seconds]
[Time delta from previous captured frame: 0.000037000 seconds]
[Time delta from previous displayed frame: 0.000037000 seconds]
[Time since reference or first frame: 7.472741000 seconds]
Frame Number: 52
Frame Length: 27 bytes (216 bits)
Capture Length: 27 bytes (216 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: usb]
USB URB
[Source: host]
[Destination: 2.4.1]
USBPcap pseudoheader length: 27
IRP ID: 0xffffe48f6a499820
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (0x0009)
IRP information: 0x00, Direction: FDO -> PDO
0000 000. = Reserved: 0x00
.... ...0 = Direction: FDO -> PDO (0x0)
URB bus id: 2
Device address: 4
Endpoint: 0x81, Direction: IN
1... .... = Direction: IN (1)
.... 0001 = Endpoint number: 1
URB transfer type: URB_INTERRUPT (0x01)
Packet Data Length: 0
[Response in: 55]
[bInterfaceClass: HID (0x03)]

No.     Time           Source                Destination           Protocol Length Info
53 12.032803      2.4.1                 host                  USB      35     URB_INTERRUPT in

Frame 53: 35 bytes on wire (280 bits), 35 bytes captured (280 bits) on interface \\.\USBPcap2, id 0
Section number: 1
Interface id: 0 (\\.\USBPcap2)
Interface name: \\.\USBPcap2
Interface description: USBPcap2
Encapsulation type: USB packets with USBPcap header (152)
Arrival Time: Aug 20, 2025 15:46:55.994883000 GMT Daylight Time
UTC Arrival Time: Aug 20, 2025 14:46:55.994883000 UTC
Epoch Arrival Time: 1755701215.994883000
[Time shift for this packet: 0.000000000 seconds]
[Time delta from previous captured frame: 4.560062000 seconds]
[Time delta from previous displayed frame: 4.560062000 seconds]
[Time since reference or first frame: 12.032803000 seconds]
Frame Number: 53
Frame Length: 35 bytes (280 bits)
Capture Length: 35 bytes (280 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: usb:usbhid]
USB URB
[Source: 2.4.1]
[Destination: host]
USBPcap pseudoheader length: 27
IRP ID: 0xffffe48f6a4b2010
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (0x0009)
IRP information: 0x01, Direction: PDO -> FDO
0000 000. = Reserved: 0x00
.... ...1 = Direction: PDO -> FDO (0x1)
URB bus id: 2
Device address: 4
Endpoint: 0x81, Direction: IN
1... .... = Direction: IN (1)
....  0001 = Endpoint number: 1
URB transfer type: URB_INTERRUPT (0x01)
Packet Data Length: 8
[Request in: 50]
[Time from request: 4.928069000 seconds]
[bInterfaceClass: HID (0x03)]
HID Data: 0200000000000000
Fahrerinformationen

Code: Select all

;
; MyDriver.inf
;
; Installs WinUsb
;

[Version]
Signature   = "$Windows NT$"
Class       = "NAME Interface"
ClassGUID   = {4CCE036B-4B8C-40c9-9606-A2F6E54202D1}
Provider    = %ManufacturerName%
CatalogFile = NAMEUSB.cat
PnpLockDown = 1
DriverVer = 08/26/2024,12.3.18.533

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%ManufacturerName% = Standard,NTamd64

[Standard.NTamd64]
%DeviceName0001% = USB_Install, USB\VID_0945&PID_0001
%DeviceName0002% = USB_Install, USB\VID_0945&PID_0002

; =================== Installation ===================

[ClassInstall32.NTamd64]
AddReg=Class_Addreg

[Class_Addreg]
HKR,,,,"NAME Interface Class"
HKR,,Icon,,"-20"

[USB_Install]
Include = winusb.inf
Needs = WINUSB.NT

[USB_Install.Services]
Include = winusb.inf
Needs = WINUSB.NT.Services

[USB_Install.HW]
AddReg = Dev_AddReg
Include = winusb.inf
Needs = WINUSB.NT.HW

[Dev_AddReg]
; By default, USBDevice class uses iProduct descriptor to name the device in
; device manager.  Uncomment for this device to use %DeviceName%:
;HKR,,FriendlyName,,%DeviceName%
HKR,,DeviceInterfaceGUIDs,0x10000,"{9A9A65EE-A425-482d-AE44-80DA1A1210C6}"

; =================== Strings ===================

[Strings]
ManufacturerName = "NAME"
DiskName = "NAME Installation Disk"
DeviceName0001 = "NAME USBLink Bootloader"
DeviceName0002 = "NAME Device"

Code: Select all

[Version]
Signature = "$Windows NT$"
Class = "NAME Interface"
ClassGuid={4CCE036B-4B8C-40c9-9606-A2F6E54202D1}
Provider = %NAME%
DriverVer=08/14/2008,1.0.0.0
CatalogFile=NAMEUSB.cat

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%NAME% = NAME_WinUSB,NTx86,NTamd64

[NAME_WinUSB.NTx86]
%USB\NAME.DeviceDesc.0001% = USB_Install, USB\VID_0945&PID_0001
%USB\NAME.DeviceDesc.0002% = USB_Install, USB\VID_0945&PID_0002

[NAME_WinUSB.NTamd64]
%USB\NAME.DeviceDesc.0001% = USB_Install, USB\VID_0945&PID_0001
%USB\NAME.DeviceDesc.0002% = USB_Install, USB\VID_0945&PID_0002

; =================== Installation ===================

[ClassInstall32.nt]
AddReg=Class_Addreg

[Class_Addreg]
HKR,,,,"NAME Interface Class"
HKR,,Icon,,"-20"

;[1]
[USB_Install]
Include=winusb.inf
Needs=WINUSB.NT

;[2]
[USB_Install.Services]
Include=winusb.inf
AddService=WinUSB,0x00000002,WinUSB_ServiceInstall

;[3]
[WinUSB_ServiceInstall]
DisplayName     = %WinUSB_SvcDesc%
ServiceType     = 1
StartType       = 3
ErrorControl    = 1
ServiceBinary   = %12%\WinUSB.sys

;[4]
[USB_Install.Wdf]
KmdfService=WINUSB, WinUsb_Install

[WinUSB_Install]
KmdfLibraryVersion=1.5

;[5]
[USB_Install.HW]
AddReg=Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{9A9A65EE-A425-482d-AE44-80DA1A1210C6}"

;[6]
[USB_Install.CoInstallers]
AddReg=CoInstallers_AddReg
CopyFiles=CoInstallers_CopyFiles

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01005.dll,WdfCoInstaller","WinUSBCoInstaller.dll"

[CoInstallers_CopyFiles]
WinUSBCoInstaller.dll
WdfCoInstaller01005.dll

[DestinationDirs]
CoInstallers_CopyFiles=11

; ================= Source Media Section =====================
;[7]

[SourceDisksNames]
1 = %DISK_NAME%,,,\x86
2 = %DISK_NAME%,,,\amd64

[SourceDisksFiles.x86]
WinUSBCoInstaller.dll=1
WdfCoInstaller01005.dll=1

[SourceDisksFiles.amd64]
WinUSBCoInstaller.dll=2
WdfCoInstaller01005.dll=2

; =================== Strings ===================

[Strings]
NAME="NAME"
USB\NAME.DeviceDesc.0001="NAME USBLink Bootloader"
USB\NAME.DeviceDesc.0002="NAME USBLink"
WinUSB_SvcDesc="NAME WinUSB"
DISK_NAME="NAME Install Disk"

Einschränkungen
Meine Aufgabe erfordert, dass das Endprodukt auf einem Windows 10-Computer als Jupyter-Notebook mit allen über Conda oder PyPi verfügbaren Abhängigkeiten ausgeführt wird
Gibt es eine Möglichkeit, dies auf der js-Seite zu debuggen, die mir fehlt?
(Ich schaue mir an, wie ich Hintergrundprozesse entfernen kann, die Probleme verursachen)
Nein Klar, wie ich das mit Jupyter machen würde.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post