最近有一个需求,需要检测一个物体的运动速度,经过研究我决定使用激光距离传感器来完成这个要求。在模块选择的问题上,我再次遇到了“面粉比面包贵” 的问题—–激光测距模块价格比成品要高。最终选择的是带有USB接口的优利德 UT395B。

最远可以达到150米,我选择的是可以达到70米的
他自带一个软件可以在 Windows 下获得距离,因此可以使用 USBlyzer 来抓取通讯数据数据分析协议。首先抓取Descriptor:
USB 输入设备
Connection Status |
Device connected |
Current Configuration |
1 |
Speed |
Full (12 Mbit/s) |
Device Address |
12 |
Number Of Open Pipes |
2 |
Device Descriptor SDWAY
Offset |
Field |
Size |
Value |
Description |
0 |
bLength |
1 |
12h |
|
1 |
bDescriptorType |
1 |
01h |
Device |
2 |
bcdUSB |
2 |
0200h |
USB Spec 2.0 |
4 |
bDeviceClass |
1 |
00h |
Class info in Ifc Descriptors |
5 |
bDeviceSubClass |
1 |
00h |
|
6 |
bDeviceProtocol |
1 |
00h |
|
7 |
bMaxPacketSize0 |
1 |
40h |
64 bytes |
8 |
idVendor |
2 |
0483h |
SGS Thomson Microelectronics |
10 |
idProduct |
2 |
5751h |
|
12 |
bcdDevice |
2 |
0200h |
2.00 |
14 |
iManufacturer |
1 |
01h |
“MyUSB_HID” |
15 |
iProduct |
1 |
02h |
” SDWAY “ |
16 |
iSerialNumber |
1 |
03h |
|
17 |
bNumConfigurations |
1 |
01h |
|
Configuration Descriptor 1
Offset |
Field |
Size |
Value |
Description |
0 |
bLength |
1 |
09h |
|
1 |
bDescriptorType |
1 |
02h |
Configuration |
2 |
wTotalLength |
2 |
0029h |
|
4 |
bNumInterfaces |
1 |
01h |
|
5 |
bConfigurationValue |
1 |
01h |
|
6 |
iConfiguration |
1 |
00h |
|
7 |
bmAttributes |
1 |
C0h |
Self Powered |
|
4..0: Reserved |
|
…00000 |
|
|
5: Remote Wakeup |
|
..0….. |
No |
|
6: Self Powered |
|
.1…… |
Yes |
|
7: Reserved (set to one)
(bus-powered for 1.0) |
|
1……. |
|
8 |
bMaxPower |
1 |
C0h |
384 mA |
Interface Descriptor 0/0 HID, 2 Endpoints
Offset |
Field |
Size |
Value |
Description |
0 |
bLength |
1 |
09h |
|
1 |
bDescriptorType |
1 |
04h |
Interface |
2 |
bInterfaceNumber |
1 |
00h |
|
3 |
bAlternateSetting |
1 |
00h |
|
4 |
bNumEndpoints |
1 |
02h |
|
5 |
bInterfaceClass |
1 |
03h |
HID |
6 |
bInterfaceSubClass |
1 |
00h |
|
7 |
bInterfaceProtocol |
1 |
00h |
|
8 |
iInterface |
1 |
00h |
|
HID Descriptor
Offset |
Field |
Size |
Value |
Description |
0 |
bLength |
1 |
09h |
|
1 |
bDescriptorType |
1 |
21h |
HID |
2 |
bcdHID |
2 |
0110h |
1.10 |
4 |
bCountryCode |
1 |
00h |
|
5 |
bNumDescriptors |
1 |
01h |
|
6 |
bDescriptorType |
1 |
22h |
Report |
7 |
wDescriptorLength |
2 |
0021h |
33 bytes |
Endpoint Descriptor 82 2 In, Interrupt, 10 ms
Offset |
Field |
Size |
Value |
Description |
0 |
bLength |
1 |
07h |
|
1 |
bDescriptorType |
1 |
05h |
Endpoint |
2 |
bEndpointAddress |
1 |
82h |
2 In |
3 |
bmAttributes |
1 |
03h |
Interrupt |
|
1..0: Transfer Type |
|
……11 |
Interrupt |
|
7..2: Reserved |
|
000000.. |
|
4 |
wMaxPacketSize |
2 |
0040h |
64 bytes |
6 |
bInterval |
1 |
0Ah |
10 ms |
Endpoint Descriptor 01 1 Out, Interrupt, 16 ms
Offset |
Field |
Size |
Value |
Description |
0 |
bLength |
1 |
07h |
|
1 |
bDescriptorType |
1 |
05h |
Endpoint |
2 |
bEndpointAddress |
1 |
01h |
1 Out |
3 |
bmAttributes |
1 |
03h |
Interrupt |
|
1..0: Transfer Type |
|
……11 |
Interrupt |
|
7..2: Reserved |
|
000000.. |
|
4 |
wMaxPacketSize |
2 |
0040h |
64 bytes |
6 |
bInterval |
1 |
10h |
16 ms |
Interface 0 HID Report Descriptor
Item Tag (Value) |
Raw Data |
Usage Page (Bar Code Scanner) |
05 8C |
Usage |
09 01 |
Collection (Application) |
A1 01 |
Usage |
09 03 |
Logical Minimum (0) |
15 00 |
Logical Maximum (-256) |
26 00 FF |
Report Size (8) |
75 08 |
Report Count (24) |
95 18 |
Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) |
81 02 |
Usage |
09 04 |
Logical Minimum (0) |
15 00 |
Logical Maximum (-256) |
26 00 FF |
Report Size (8) |
75 08 |
Report Count (24) |
95 18 |
Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) |
91 02 |
End Collection |
C0 |
从上面的结果可以看出这个设备是一个自定义的 HID设备,因此,需要进步一抓取通讯数据。
上面是一次完整的获得测量距离的过程,一共有8笔数据,4 笔是主机发送给设备,4笔是设备的返回值。 OUTPUT Report是主机发送给 UT395B的数据。第一个数据包: 41 54 4B 30 30 31 23 00 00 00 00 41 00 00 00 54 00 00 00 44 00 00 00 00
发送到设备之后,设备会打开激光(手册上说这是打开瞄准的功能)。第5笔数据和第1笔数据相同,设备会关闭激光。
经过研发总结: 41 54 4B 30 30 31 23 …….这个命令是打开/关闭激光。 41 54 44 30 30 31 23 …….是主机要求返回距离信息的命令。
上面8个数据的含义如下:
- 主机要求打开激光
- 设备 ECHO
- 主机要求获得上一笔数据
- 设备返回上一笔数据
- 主机要求关闭激光
- 设备 ECHO
- 主机要求获得距离数据
- 设备返回数据,就是我们需要的距离信息
一个典型的返回值:
41 54 44 00 00 3A E8 00 …… 其中的 3A E8 就是距离信息。0x3AE8=15080 对应显示在屏幕上的距离是1.508米。经过多次实验,显示小数点后3位的数值,但是实际上的数据是小数点后4位,最后一位会进行四舍五入。
最终编写 Windows 下 Console 代码如下:
//http://blog.csdn.net/xuxinhua/article/details/6329182
#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <setupapi.h>
extern "C" {
void __stdcall
HidD_GetHidGuid (
OUT LPGUID HidGuid
);
typedef struct _HIDD_ATTRIBUTES {
ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
//
// Vendor ids of this hid device
//
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
//
// Additional fields will be added to the end of this structure.
//
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
BOOLEAN __stdcall
HidD_GetAttributes (
IN HANDLE HidDeviceObject,
OUT PHIDD_ATTRIBUTES Attributes
);
BOOLEAN __stdcall
HidD_SetFeature(
_In_ HANDLE HidDeviceObject,
_In_reads_bytes_(ReportBufferLength) PVOID ReportBuffer,
_In_ ULONG ReportBufferLength
);
}
#pragma comment( lib, "hid.lib" )
#pragma comment( lib, "setupapi.lib" )
void Switch(HANDLE hUsb)
{
BOOL Result;
//Output DataµÄ»º³åÇø£¬ÒòΪÏÂÃæ·¢ËÍ HID ±¨ÎÄÐèÒª9×Ö½Ú£¬ËùÒÔÕâÀïÖ±½Ó°´ÕÕ×î´óµÄ¶¨Òå
UCHAR WriteReportBuffer[25];
WriteReportBuffer[00] = 0x00;
WriteReportBuffer[1] = 0x41;
WriteReportBuffer[2] = 0x54;
WriteReportBuffer[3] = 0x4b;
WriteReportBuffer[4] = 0x30;
WriteReportBuffer[5] = 0x30;
WriteReportBuffer[6] = 0x31;
WriteReportBuffer[7] = 0x23;
WriteReportBuffer[8] = 0x00;
WriteReportBuffer[9] = 0x00;
WriteReportBuffer[10] = 0x00;
WriteReportBuffer[11] = 0x00;
WriteReportBuffer[12] = 0x41;
WriteReportBuffer[13] = 0x00;
WriteReportBuffer[14] = 0x00;
WriteReportBuffer[15] = 0x00;
WriteReportBuffer[16] = 0x54;
WriteReportBuffer[17] = 0x00;
WriteReportBuffer[18] = 0x00;
WriteReportBuffer[19] = 0x00;
WriteReportBuffer[20] = 0x44;
WriteReportBuffer[21] = 0x00;
WriteReportBuffer[22] = 0x00;
WriteReportBuffer[23] = 0x00;
WriteReportBuffer[24] = 0x00;
DWORD lpNumberOfBytesWritten;
//µ÷ÓÃWriteFileº¯Êý·¢ËÍÊý¾Ý
//±¨Îij¤¶ÈÊÇ9×Ö½Ú
Result = WriteFile(hUsb,
WriteReportBuffer,
25,
&lpNumberOfBytesWritten,
NULL);
printf("Written %d bytes Result [%d]\n", lpNumberOfBytesWritten, Result);
}
void SendData(HANDLE hUsb)
{
BOOL Result;
//Output DataµÄ»º³åÇø£¬ÒòΪÏÂÃæ·¢ËÍ HID ±¨ÎÄÐèÒª9×Ö½Ú£¬ËùÒÔÕâÀïÖ±½Ó°´ÕÕ×î´óµÄ¶¨Òå
UCHAR WriteReportBuffer[25];
WriteReportBuffer[00] = 0x00;
WriteReportBuffer[1] = 0x41;
WriteReportBuffer[2] = 0x54;
WriteReportBuffer[3] = 0x44;
WriteReportBuffer[4] = 0x30;
WriteReportBuffer[5] = 0x30;
WriteReportBuffer[6] = 0x31;
WriteReportBuffer[7] = 0x23;
WriteReportBuffer[8] = 0x00;
WriteReportBuffer[9] = 0x00;
WriteReportBuffer[10] = 0x00;
WriteReportBuffer[11] = 0x00;
WriteReportBuffer[12] = 0x41;
WriteReportBuffer[13] = 0x00;
WriteReportBuffer[14] = 0x00;
WriteReportBuffer[15] = 0x00;
WriteReportBuffer[16] = 0x54;
WriteReportBuffer[17] = 0x00;
WriteReportBuffer[18] = 0x00;
WriteReportBuffer[19] = 0x00;
WriteReportBuffer[20] = 0x44;
WriteReportBuffer[21] = 0x00;
WriteReportBuffer[22] = 0x00;
WriteReportBuffer[23] = 0x00;
WriteReportBuffer[24] = 0x00;
DWORD lpNumberOfBytesWritten;
//µ÷ÓÃWriteFileº¯Êý·¢ËÍÊý¾Ý
//±¨Îij¤¶ÈÊÇ9×Ö½Ú
Result = WriteFile(hUsb,
WriteReportBuffer,
25,
&lpNumberOfBytesWritten,
NULL);
printf("Written %d bytes Result [%d]\n", lpNumberOfBytesWritten, Result);
}
void GetData(HANDLE hUsb)
{
//½ÓÊÕ±¨¸æµÄ»º³åÇø£¬1×Ö½Ú±¨¸æID+8×Ö½Ú±¨¸æÊý¾Ý¡£
UCHAR ReadReportBuffer[25];
DWORD lpNumberOfBytesRead;
UINT LastError;
BOOL Result;
DWORD tmp;
//µ÷ÓÃReadFile ½ÓÊÕÊý¾Ý
Result = ReadFile(
hUsb,
ReadReportBuffer,
25,
&lpNumberOfBytesRead,
NULL);
//printf("Read %d bytes\n", lpNumberOfBytesRead);
//Èç¹ûº¯Êý·µ»ØÊ§°Ü£¬Ôò¿ÉÄÜÊÇÕæµÄʧ°Ü£¬Ò²¿ÉÄÜÊÇIO¹ÒÆð
if (Result == FALSE)
{
//»ñÈ¡×îºó´íÎó´úÂë
LastError = GetLastError();
//¿´ÊÇ·ñÊÇÕæµÄIO¹Ò
if ((LastError == ERROR_IO_PENDING) || (LastError == ERROR_SUCCESS))
{
exit;
}
//·ñÔò£¬ÊǺ¯Êýµ÷ÓÃʱ·¢Éú´íÎó£¬ÏÔʾ´íÎó´úÂë
else
{
printf("Sending error£º%d \n", LastError);
//Èç¹û×îºó´íÎóΪ1£¬ËµÃ÷¸ÃÉ豸²»Ö§³Ö¸Ãº¯Êý¡£
if (LastError == 1)
{
printf("This device doesn't support WriteFile function \n");
}
}
}
else //Õý³£¶ÁÈ¡
{
for (DWORD Index = 0; Index < lpNumberOfBytesRead; Index++) {
printf("%02X ", ReadReportBuffer[Index]);
}
printf("\n");
if (0x44 == ReadReportBuffer[0x03]) {
tmp = (ReadReportBuffer[0x06] << 8) + ReadReportBuffer[0x07];
printf("%d.%d\n", tmp / 10000, (tmp - tmp /10000 * 10000 +5)/10);
}
}
printf("\n");
}
int main(array<System::String ^> ^args)
{
GUID HidGuid;
BOOL Result;
int counter=-1;
//»ñÈ¡HIDÉ豸µÄ½Ó¿ÚÀàGUDI
HidD_GetHidGuid(&HidGuid);
//Êä³öһϿ´¿´GUID
printf("HID GUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n"
, HidGuid.Data1, HidGuid.Data2, HidGuid.Data3
, HidGuid.Data4[0], HidGuid.Data4[1], HidGuid.Data4[2], HidGuid.Data4[3], HidGuid.Data4[4]
, HidGuid.Data4[5], HidGuid.Data4[6], HidGuid.Data4[7] );
//¸ù¾Ý»ñµÃµÄGUIDö¾ÙHIDÉ豸
HDEVINFO hDevInfo = SetupDiGetClassDevs( &HidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );
if( INVALID_HANDLE_VALUE != hDevInfo )
{
SP_DEVICE_INTERFACE_DATA strtInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
for( DWORD index=0; SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&HidGuid,index,&strtInterfaceData); ++index )
{
char buf[1000];
SP_DEVICE_INTERFACE_DETAIL_DATA& strtDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA&)buf[0];
strtDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )
{
printf("[%d] path: %ls\n", index, strtDetailData.DevicePath);
//ÕâÀï´ò¿ªµÄÓпÉÄÜÊÇUSB¼üÅÌÊó±êÕâÑù±È½ÏÌØ±ðµÄÉ豸£¨Ö»Äܲéѯ£©
HANDLE hUsb = CreateFile( strtDetailData.DevicePath,
NULL, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
// ²éѯÉ豸±êʶ
HIDD_ATTRIBUTES strtAttrib = { sizeof(HIDD_ATTRIBUTES) };
Result=HidD_GetAttributes(hUsb,&strtAttrib);
//ËùÒÔÕâÀïÒª¹Ø±Õһϣ¬ºóÃæÕÒµ½ÎÒÃÇ×Ô¼ºµÄÉ豸ȷ¶¨¿ÉÒÔдÈëÔÙ´ò¿ªÒ»´Î
CloseHandle( hUsb );
if(TRUE==Result)
{
if ((0x0483 == strtAttrib.VendorID) &&
(0x5751 == strtAttrib.ProductID)) //ÕÒµ½ÎÒÃÇ×Ô¼ºµÄÉ豸
{
printf("VendorID : %hX\n", strtAttrib.VendorID);
printf("ProductID: %hX\n", strtAttrib.ProductID);
printf("VerNumber: %hX\n", strtAttrib.VersionNumber);
//È·¶¨ÊÇÎÒÃÇ×Ô¼ºµÄÉ豸£¬ÔÙ´ò¿ªÒ»´Î,×¢ÒâÎÒÃÇÕâÀïʹÓõÄÊÇͬ²½·¢ËÍ
hUsb = CreateFile(strtDetailData.DevicePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
Switch(hUsb); GetData(hUsb);
//Sleep(100);
SendData(hUsb); GetData(hUsb);
Switch(hUsb); GetData(hUsb);
SendData(hUsb); GetData(hUsb);
CloseHandle( hUsb );
}//if ((0x8888==strtAttrib.VendorID) &&
} //if(TRUE==Result)
} // if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )
} //for( DWORD index=0;
if( GetLastError() != ERROR_NO_MORE_ITEMS )
{printf("No more items!\n"); }
SetupDiDestroyDeviceInfoList( hDevInfo );
} //if( INVALID_HANDLE_VALUE != hDevInfo )
system("PAUSE");
return 0;
}
运行结果:

