通过pyusb从USB鼠标(单芯片,ADNS-2700)获取图像
我想提取单个芯片光学鼠标传感器捕捉到的实际图像,特别是ADNS-2700这个型号。与网上其他教程不同,那些教程通常使用微控制器与成像芯片的SPI接口进行通信(像这样),而我正在使用的这个芯片是内置USB接口的。
ADNS-2700 数据手册
系统:Windows 7,Python2.7,PyUSB 1.0
我已经成功提取了按键按下、速度和滚轮数据,参考了这个例子:
import usb.core
import usb.util
VENDOR_ID = 6447
PRODUCT_ID = 2326
# find the USB device
device = usb.core.find(idVendor=VENDOR_ID,
idProduct=PRODUCT_ID)
# use the first/default configuration
device.set_configuration()
# first endpoint
endpoint = device[0][(0,0)][0]
# read a data packet
attempts = 10
data = None
while attempts > 0:
try:
data = device.read(endpoint.bEndpointAddress,
endpoint.wMaxPacketSize)
print data
except usb.core.USBError as e:
data = None
if e.args == ('Operation timed out',):
attempts -= 1
continue
这段代码提取的数据如下:
array('B', [0, 0, 16, 0, 0])
array('B', [0, 0, 240, 255, 0])
array('B', [0, 0, 16, 0, 0])
array('B', [0, 0, 240, 255, 0])
我需要帮助提取原始图像数据!
我对USB不太熟悉,这可能是我遇到大部分问题的原因。
在数据手册的第18页,有一份USB命令列表。其中一个看起来很有希望:
Mnemonic Command Notes
---------------------------------------------------------------
Get_Vendor_Test C0 01 00 00 xx 00 01 00 Read register xx
然后在第28页,有一份寄存器列表,这个看起来也不错:
Address Register Name Register Type Access Reset Value
----------------------------------------------------------------------
0x0D PIX_GRAB Device Read only 0x00
然而,我尝试了:
device.write(endpoint.bEndpointAddress,'C0:01:00:00:0A:00:01:00',0)
结果是:
usb.core.USBError: [Errno None] libusb0-dll:err [_usb_setup_async] invalid endpoint 0x81
还有:
device.read(endpoint.bEndpointAddress, 0x0D)
这直接超时了。
完整解决方案:
import usb.core
import usb.util
import matplotlib.pyplot as plt
import numpy as np
VENDOR_ID = 6447
PRODUCT_ID = 2326
# find the USB device
device = usb.core.find(idVendor=VENDOR_ID,
idProduct=PRODUCT_ID)
# use the first/default configuration
device.set_configuration()
# In order to read the pixel bytes, reset PIX_GRAB by sending a write command
response = self.device.ctrl_transfer(bmRequestType = 0x40, #Write
bRequest = 0x01,
wValue = 0x0000,
wIndex = 0x0D, #PIX_GRAB register value
data_or_wLength = None
)
# Read all the pixels (360 in this chip)
pixList = []
for i in range(361):
response = self.device.ctrl_transfer(bmRequestType = 0xC0, #Read
bRequest = 0x01,
wValue = 0x0000,
wIndex = 0x0D, #PIX_GRAB register value
data_or_wLength = 1
)
pixList.append(response)
pixelArray = np.asarray(pixList)
pixelArray = pixelArray.reshape((19,19))
plt.imshow(pixelArray)
plt.show()
2 个回答
1
我刚刚自己试了一下这段代码,发现里面有一个比较大的错误。ADNS-2700的说明书上说,响应值如果没有最高有效位(最左边的那位)被设置为1,那就是无效的。所以这个循环不应该只读361次,而是应该一直读,直到得到361个有效的像素,任何没有“有效”位的字节都要丢掉。
我还做了一些小改动,比如在把返回的数组加到列表之前先解包一下,还有把返回值中的最高有效位去掉,因为它并不代表实际的像素数据。
我用一只亚马逊基础款的USB鼠标测试了这段代码,结果输出了一个有效的图像。
import usb.core
import usb.util
import matplotlib.pyplot as plt
import numpy as np
VENDOR_ID = 0x04F2
PRODUCT_ID = 0x0939
# find the USB device
device = usb.core.find(idVendor=VENDOR_ID,
idProduct=PRODUCT_ID)
# use the first/default configuration
device.set_configuration()
# In order to read the pixel bytes, reset PIX_GRAB by sending a write command
response = device.ctrl_transfer(bmRequestType = 0x40, #Write
bRequest = 0x01,
wValue = 0x0000,
wIndex = 0x0D, #PIX_GRAB register value
data_or_wLength = None
)
# Read all the pixels (360 in this chip)
pixList = []
while len(pixList) < 361:
temp = 0
response = device.ctrl_transfer(bmRequestType = 0xC0, #Read
bRequest = 0x01,
wValue = 0x0000,
wIndex = 0x0D, #PIX_GRAB register value
data_or_wLength = 1
)
if response[0] >= 0x80:
temp = response[0] & 0x7F
pixList.append(temp)
pixelArray = np.asarray(pixList)
pixelArray = pixelArray.reshape((19,19))
plt.imshow(pixelArray)
plt.show()
5
你可能需要使用 ctrl_transfer(),具体可以参考 pyUSB 教程。
你还需要把数据手册中的十六进制字节转换成 ctrl_transfer 所需的各个参数。关于格式的详细信息,可以查看 这个页面。
Get_Vendor_Test
C0 01 00 00 xx 00 01 00
可以通过 ctrl_transfer() 这样调用:
ret = dev.ctrl_transfer(bmRequestType=0xc0, # byte[0]
bRequest=0x01, # byte[1]
wValue=0x0000, # byte[2,3]
wIndex=register, # byte[4,5]
data_or_wLength = 1)# byte[6,7]