Forum Discussion
LeeMatthewHiggi
13 years agoHonored Guest
fdti data format for the tracking data (via USB)
Hello fellow rifters..
I would like to know if a document exists with the data format /commands for the usb tracking data. It would make things easier than going through the source code in the SDK.
I would like to know if a document exists with the data format /commands for the usb tracking data. It would make things easier than going through the source code in the SDK.
3 Replies
- SignaidyHonored GuestYeah I would also like to know :D
- geekmasterProtege
"LeeMatthewHiggins" wrote:
Hello fellow rifters..
I would like to know if a document exists with the data format /commands for the usb tracking data. It would make things easier than going through the source code in the SDK.
I suppose I could do one when I get a moment. I wrote my own code to extract data from HID packets using the signal11 library. It is pretty straight-forward, but a HID packet may contain up to three samples in it (and occasionally does contain more than one sample).
Here is a modified hidtest.c module from the signal11 library, that I tested on my Win8 PC and on my Raspberry Pi. It reads and decodes Rift HID packets without requiring the OculusVR SDK:
/*******************************************************
Windows HID simplification
Alan Ott
Signal 11 Software
8/22/2009
Copyright 2009, All Rights Reserved.
This contents of this file may be used by anyone
for any reason without any conditions and may be
used as a starting point for your own applications
which use HIDAPI.
********************************************************/
//
// Geekmaster mods for Oculus Rift & Raspberry Pi support
//
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include "hidapi.h"
// Headers needed for sleeping.
#ifdef _WIN32
#include <windows.h>
typedef unsigned __int8 Uint8 ;
typedef unsigned __int16 Uint16;
typedef unsigned __int32 Uint32;
typedef __int16 Int16;
typedef __int32 Int32;
#else
#include <unistd.h>
typedef unsigned char Uint8 ;
typedef unsigned short Uint16;
typedef unsigned long Uint32;
typedef short Int16;
typedef long Int32;
#endif
int ORmX,ORmY,ORmZ; // mag
int ORgX,ORgY,ORgZ; // gyro
int ORaX,ORaY,ORaZ; // accel
int ORtime; // timestamp
int ORtemp; // temperature
Uint8 frep[5]={2,0xa0,0x0a,0,0};
Uint8 tmsg[255];
int paX=0,daX=0,pdaX=0,ddaX=0,pddaX=0,lddaX=0,ldaX=0,laX=0;vX=0,pvX=0;
int aXavg=0,aYavg=0,aZavg=0;
int gXavg=0,gYavg=0,gZavg=0,gXoff=0,gYoff=0,gZoff=0;
int mXavg=0,mYavg=0,mZavg=0,gXlow=0,gYlow=0,gZlow=0;
int prevtime=-1;
int gXcal=0,gYcal=0,gZcal=0;
int main(int argc, char* argv[])
{
int res;
unsigned char buf[256];
#define MAX_STR 255
int i, etrig=1;
hid_device *handle=0;
Uint8 *p; // byte ptr
Uint16 *pu; // unsigned int16 ptr
Int16 *pi; // int16 ptr
printf("\nGeekmaster's OculusVR Tracker DK Monitor Program\n");
// Set up command buffer.
memset(buf,0x00,sizeof(buf));
buf[0]=0x01; buf[1]=0x81;
while(1) {
#ifdef WIN32
Sleep(0);
#else
usleep(1);
#endif
if (!handle) {
handle=hid_open(0x2833,0x01,NULL); // Oculus Rift Tracker DK
hid_set_nonblocking(handle, 1); // ???
res=hid_send_feature_report(handle,frep,17); // ???
if (res<0) { hid_close(handle); handle=0; continue; } // ???
if (!handle) {
if (etrig) {
etrig=0;
printf("\nWaiting for OculusVR Tracker DK @ USB VID/PID 2833:0001 ...\n");
}
continue;
}
}
etrig=1; // allow waiting message
// Read requested state. hid_read() has been set to be
// non-blocking by call to hid_set_nonblocking() above.
// This loop demonstrates non-blocking nature of hid_read().
res=0;
while (!res) {
res=hid_read(handle,buf,sizeof(buf));
if (res>0) break;
if (res<0) { hid_close(handle); handle=0; break; }
#ifdef WIN32
Sleep(0);
#else
usleep(500*1000);
#endif
}
for (i=0;i<(buf[1]&3);i++) {
p=buf+i*16+8; // (last sample)
// Negative numbers need 1-bits shifted in anyway, so stray bits can be "more accurate"
// than masking to zero bits. No "bit hack" needed if left-justified fixed-point.
ORaX=p[0]<<24|p[1]<<16|p[2]<<8; // 8+8+5X,3Y
ORaY=p[2]<<29|p[3]<<21|p[4]<<13|p[5]<<5; // 3+8+8+2Y,6Z
ORaZ=p[5]<<26|p[6]<<18|p[7]<<10; // 6+8+7Z,1R
ORgX=p[8]<<24|p[9]<<16|p[10]<<8; // 8+8+5X,3Y
ORgY=p[10]<<29|p[11]<<21|p[12]<<13|p[13]<<5; // 3+8+8+2Y,6Z
ORgZ=p[13]<<26|p[14]<<28|p[15]<<10; // 6+8+7Z,1R
pu=pi=(Int16*)buf; ORtime=pu[1]++; ORtemp=pi[3]; ORmX=pi[28]; ORmY=pi[29]; ORmZ=pi[30];
if (!gXcal) gXoff-=(gXoff-ORgX)/256;
if (gXoff<gXlow) gXoff++;
else if (gXoff>gXlow) gXoff--;
else gXcal=1;
if (!gYcal) gYoff-=(gYoff-ORgY)/256;
if (gYoff<gYlow) gYoff++;
else if (gYoff>gYlow) gYoff--;
else gYcal=1;
if (!gZcal) gZoff-=(gZoff-ORgZ)/256;
if (gZoff<gZlow) gZoff++;
else if (gZoff>gZlow) gZoff--;
else gZcal=1;
ORgX-=gXoff; ORgY-=gYoff; ORgZ-=gZoff;
gXlow+=(ORgX-gXlow+512)/1024; // low-pass proportional correction
gYlow+=(ORgY-gYlow+512)/1024;
gZlow+=(ORgZ-gZlow+512)/1024;
aXavg+=(ORaX-aXavg)/8; // quick filter (100 Hz?)
aYavg+=(ORaY-aYavg)/8;
aZavg+=(ORaZ-aZavg)/8;
gXavg+=(ORgX-gXavg)/8;
gYavg+=(ORgY-gYavg)/8;
gZavg+=(ORgZ-gZavg)/8;
mXavg+=(ORmX-mXavg)/8;
mYavg+=(ORmY-mYavg)/8;
mZavg+=(ORmZ-mZavg)/8;
daX=aXavg-paX; ddaX=daX-pdaX;
lddaX=ddaX;
lddaX=(ddaX+pddaX*7)/8;
ldaX=(lddaX+pddaX*7)/8;
vX+=ldaX;
paX=aXavg; pdaX=daX; pddaX=lddaX; pvX=vX;
prevtime++; // expected timestamp
*tmsg=0;
if (ORtime!=prevtime && prevtime>=0) {
sprintf(tmsg," *** Missing samples @ %d ***", prevtime,sizeof(tmsg));
prevtime=ORtime;
}
printf("\n");
printf(" AccelX: %6d %6d avg\n",ORaX>>11,aXavg>>11);
printf(" AccelY: %6d %6d avg\n",ORaY>>11,aYavg>>11);
printf(" AccelZ: %6d %6d avg\n",ORaZ>>11,aZavg>>11);
printf(" GyroX: %6d %6d avg %6d low\n",ORgX>>11,gXavg>>11,gXlow>>11);
printf(" GyroY: %6d %6d avg %6d low\n",ORgY>>11,gYavg>>11,gYlow>>11);
printf(" GyroZ: %6d %6d avg %6d low\n",ORgZ>>11,gZavg>>11,gZlow>>11);
printf(" MagX: %6d %6d avg\n",ORmX,mXavg);
printf(" MagY: %6d %6d avg\n",ORmY,mYavg);
printf(" MagZ: %6d %6d avg\n",ORmZ,mZavg);
printf(" Temperature: %6d\n",ORtemp);
printf(" Timestamp: %6d %s\n",ORtime,tmsg);
printf("=====================");
}
}
hid_close(handle);
hid_exit(); // Free static HIDAPI objects.
return 0;
#ifdef WIN32
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
#endif
}
It may be a bit easier to figure out the tracking data from this small program, than from the larger OculusVR SDK.
Note that the numbers from the tracker are packed together and I do shifting and masking to extract them. I also decode up to three sets of samples per HID packet, and I interpolate for missing timestamps in the extra samples.
The key code snippet you may be interested in above is copied here:
for (i=0;i<(buf[1]&3);i++) {
p=buf+i*16+8; // (last sample)
// Negative numbers need 1-bits shifted in anyway, so stray bits can be "more accurate"
// than masking to zero bits. No "bit hack" needed if left-justified fixed-point.
ORaX=p[0]<<24|p[1]<<16|p[2]<<8; // 8+8+5X,3Y
ORaY=p[2]<<29|p[3]<<21|p[4]<<13|p[5]<<5; // 3+8+8+2Y,6Z
ORaZ=p[5]<<26|p[6]<<18|p[7]<<10; // 6+8+7Z,1R
ORgX=p[8]<<24|p[9]<<16|p[10]<<8; // 8+8+5X,3Y
ORgY=p[10]<<29|p[11]<<21|p[12]<<13|p[13]<<5; // 3+8+8+2Y,6Z
ORgZ=p[13]<<26|p[14]<<28|p[15]<<10; // 6+8+7Z,1R
pu=pi=(Int16*)buf; ORtime=pu[1]++; ORtemp=pi[3]; ORmX=pi[28]; ORmY=pi[29]; ORmZ=pi[30];
Notice that unlike the OculusVR SDK, I simply extract integer values from the buffer as integers instead of building them byte-by-byte in an endian-independent manner. We can do this because the data is little-endian and all the common devices we may use with the Rift are also little-endian (including the Raspberry Pi and common android devices). I also left-justify the numbers to avoid the "bit hack" used in the OculusVR SDK which may generate inefficient code on modern compilers (bit-hacks are awesome, but in this case it is much better to just use a simple and obvious non-hack, IMHO).
Also notice that although each HID packet may contain up to three accelerometer (ORa*) and gyro (ORg*) data points, only one magnetometer (ORm*) data point is supplied per packet. The timestamp (ORtime) value wraps periodically, and may be useful for interpolating and prediction when many consecutive samples are buffered in a large FIFO. The temperature (ORtemp) value may be useful for performing temperature compensation of the accel and gyro sensors.
The magnetometer precision may be increased with software "hard iron" and "soft iron" calibration and correction algorithms:
http://ez.analog.com/docs/DOC-2544
Here is the signal11 cross-platform USB HID library:
http://www.signal11.us/oss/hidapi/
https://github.com/signal11/hidapi - LeeMatthewHiggiHonored GuestYou are a star! exactly what I needed.
Quick Links
- Horizon Developer Support
- Quest User Forums
- Troubleshooting Forum for problems with a game or app
- Quest Support for problems with your device
Other Meta Support
Related Content
- 8 days ago
- 2 years ago
- 6 months ago