推荐一本书<<金字塔原理>>,本文按照书中说提的“是什么,为什么,怎么做”,来说明如何把HMD设备接入到OSVR上。
对于我们来说,后续要制作的产品是头盔,对于头盔设备通过插件接入OSVR优点如下:
OSVR插件,为上层应用程序提供数据,包含2类插件:分析插件和设备插件
分析插件:用于把底层上报的原始数据,解析、处理成上层需要的。例如,一个手势识别的插件,可以底层上报的XYZ坐标轴的值,转换、识别成具体的手势。
设备插件:用来接入具体的物理设备,用来为上层提供各种类型的数据。例如,VR眼镜的插件可以提供显示相关的参数,以及追踪器的坐标轴数据。
如果HMD只是作为显示,则只需要修改json文件即可(json文档说明),如果需要提供追踪器数据,手势识别等功能,则需要制作插件。
以手上我们自己做得头显设备(此设备能够通过USB主动上报传感器的值即可)为例,来制作一个能够使此HMD接入OSVR-Core的插件。
CMD里运行BasicServer(此程序通过编译OSVR-core获得,这里上传一份我编译),来测试插件:
测试OK。
如果要被osvr_core加载,将此dll放入到D:\src\OSVR-Core\build_win64\bin\osvr-plugins-0\Release文件夹下,然后运行“osvr_server.exe osvr_server_config.json” 即可。
HMD与PC用USB线连接,PC通过USB来读取HMD上的所有数据(包括加速度、陀螺仪、磁力计、手势坐标等),这里我们使用一个开源库:HIDAPI库,来读取HMD的数据。
HIDAPI获取、编译点击这里。拷贝出”hidapi.h“,”hidapi.lib“,”hidapi.dll”这3个文件。
将HIDAPI库文件导入我们的工程,“com_osvr_oueh_plugin.cpp”文件添加:
同时,将”hidapi.h”、”hidapi.lib”文件拷贝到“com_osvr_oueh_plugin.cpp”文件的当前目录下。
打开“com_osvr_oueh_plugin.cpp”文件,在“HardwareDetection”类中添加,通过HID接口读取HMD设备信息的代码:
OSVR-Core会调用插件的operator方法,来检测设备是否连接。
上面hid_open参数需要替换成你的设备的VID和PID,到这步就能够读取到HMD的设备基本信息。
对于HMD设备,需要不断上报传感器数据,插件里AnalogExampleDevice类的update方法会被循环调用,我们可以在这里添加读取数据的代码:
读取函数:
如果HMD持续输出数据,这里就能读取到数据,将数据实时打出。
上面已经能够将数据读出,我们这里将进一步对读出的数据进行解析。这里手上设备是以Oculars协议来传递追踪器数据,就以这个协议做解析获取追踪器数据,Oculars协议点击这里获取。
定义数据解析结构体:
协议解析函数:
int decode_h551_hmd_data(h551_hmd_data *hmd_data, u8 *buf, int size)
{
u8 pos = 0;
int temp[2];
//for test
//buf[8] = 255;buf[9] = 251;buf[10] = 176;buf[11] = 0;buf[12] = 181;buf[13] = 0;buf[14] = 31;buf[15] = 121;
hmd_data->ReportID = buf[pos++];
hmd_data->SampleCount = buf[pos++];
hmd_data->Timestamp = buf[pos] + (buf[pos+1]<<8);
pos += 2;
//temp[0] = 0x4030201;
//memcpy(&buf[8], (u8 *)&temp[0],4);
//std::cout << "decode_h551_hmd_data: "<< "buf[8]:" <<int(buf[8])<<",buf[9]:" << int(buf[9])<<",buf[10]:" << int(buf[10]) << ",buf[11]:" << int(buf[11]) << std::endl;
hmd_data->LastCommandID = buf[pos] + (buf[pos+1] << 8);
pos += 2;
hmd_data->Temperature = buf[pos] + (buf[pos+1] << 8);
pos += 2;
//memcpy((u8 *)temp,&buf[pos],8);
//std::cout << "decode_h551_hmd_data: temp[0]=" << temp[0] << ",temp[1]:" <1]<<",pos="<<int(pos)<< std::endl;
hmd_data->accel_X = buf[pos] | (buf[pos + 1] << 8) | ((buf[pos + 2] & 0x1F) << 16);
hmd_data->accel_Y = ((buf[pos + 2] & 0xE0) >> 5) | (buf[pos + 3] << 3) | (buf[pos + 4] << 11) | ((buf[pos + 5] & 0x03) << 19);
hmd_data->accel_Z = (buf[pos + 5] & 0xFC) >> 2 | (buf[pos + 6] << 6) | (buf[pos + 7] << 14);
pos += 8;
//memcpy((u8 *)temp, &buf[pos], 8);
//hmd_data->gyro_X = temp[0] & 0x001FFFFF;
//hmd_data->gyro_Y = (temp[0] << 20) + ((temp[1] & 0x000003FF) << 11);
//hmd_data->gyro_Z = temp[1] << 9;
hmd_data->gyro_X = buf[pos] | (buf[pos + 1] << 8) | ((buf[pos + 2] & 0x1F) << 16);
hmd_data->gyro_Y = ((buf[pos + 2] & 0xE0) >> 5) | (buf[pos + 3] << 3) | (buf[pos + 4] << 11) | ((buf[pos + 5] & 0x03) << 19);
hmd_data->gyro_Z = (buf[pos + 5] & 0xFC) >> 2 | (buf[pos + 6] << 6) | (buf[pos + 7] << 14);
pos += 8;
//only use sampe[0] data,not use sample[1] sample[2]
pos += 2 * 16;
hmd_data->MagX = buf[pos] + buf[pos+1] << 8;
pos += 2;
hmd_data->MagY = buf[pos] + buf[pos+1] << 8;
pos += 2;
hmd_data->MagZ = buf[pos] + buf[pos+1] << 8;
pos += 2;
//debug
//std::cout << "decode_h551_hmd_data: pos= " << int(pos) << std::endl;
std::cout << "ReportID=" << int(hmd_data->ReportID) << ",SampleCount=" << int(hmd_data->SampleCount) << ",Timestamp=" << hmd_data->Timestamp <<",LastCommandID=" << hmd_data->LastCommandID << ",Temputure=" << hmd_data->Temperature
<< ",accel_X=" << hmd_data->accel_X << ",accel_Y=" << hmd_data->accel_Y << ",accel_Z=" << hmd_data->accel_Z
<< ",gyro_x=" << hmd_data->gyro_X << ",gyro_z=" << hmd_data->gyro_Z << ",gyro_Z=" << hmd_data->gyro_Z
<< ",MagX=" << hmd_data->MagX << ",MagY=" << hmd_data->MagY << ",MagZ=" << hmd_data->MagZ << std::endl;
return 0;
}
修改后的代码获取点击这里
编译后生成插件。
将生成的插件文件(“com_osvr_oueh_plugin.dll”),拷贝到路径“OSVR-Core\build_win64\bin\osvr-plugins-0\Release”下
将”hidapi.dll”文件,拷贝到”OSVR-Core\build_win64\bin\Release”路径下,运行”osvr_server.exe osvr_server_config.json”,可以获取到HMD的数据如下: