Vive Tracker – (Relatively) Maintained Documentation

Vive Tracker – (Relatively) Maintained Documentation

*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
REDDIT USER /U/MATZMANN666 HAS CREATED AN ARDUINO LIBRARY, SEE BOTTOM OF POST FOR MORE INFORMATION
*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *


Hi friends – I’m maintaining this post as I continue working with the Vive Tracker, and will be doing my best to keep up with HTC’s evolving firmware and capabilities.  I focus primarily on USB control of the Tracker, and do not go into interfacing with the pogo pins.  If this is something you all request documentation for, then I’ll take the time to add it.

Please note that if for whatever reason you need to reference my original documentation from March of 2017, it will be archived at this address.  Let’s get into it, shall we?

Below is various levels of abstraction on how I altered the Vive Tracker’s inputs.  Documentation on this page is relevant as of 26 October, 2017.  I started my programming on a breadboarded Atmel AVR (the family of microcontrollers commonly used in Arduino) AT90USB647 chip at 8 MHz and 3.3V with an external 5V power supply to the USB lines.  It should be noted that the Vive Tracker requires a 5V source in order for USB communication to work.  Later, I designed a PCB with the same chip, and now a 3.3-to-5V boost converter to control the Tracker in one condensed circuit.  Additionally worth noting, the Tracker does not externally supply power, which means accessory makers at this time will need to implement a secondary battery into their USB-driving designs.  It would appear that developers can permit the Tracker to charge off the accessory while in-communication over USB, but I have yet to confirm this feature.

1. The Feature Report

See pages 50 – 52 (.pdf file pages 60 – 62) of the USB HID Specification 1.11 for reference on HID Set_Report requests.  Referencing pages 26 – 29 (.pdf file pages 29 – 32) of the HTC Vive Tracker Developer Guidlines v1.5, this is the format for shipping out an HID Feature Report with values specific to the Vive Tracker payloads:

bmRequestType: 0b00100001      // See Page 50 of HID Spec for bit descriptions
bRequest:      0x09            // Value for SET_REPORT
wValue:        0x0300          // MSB=Report Type (0x03, value for Feature report)
                               // LSB=Report ID (0x00, report IDs not used – Page 51)
wIndex:        2               // HTC’s selected Descriptor Index (I think)
wLength:       sizeof(payload) // Size in bytes of the coming payload (Data field, next line)
Data:          {Data_Set_ADDR, Length_of_Following_Data, bData[0], bData[1], … , bData[n]}


MSB = Most Significant Byte, LSB = Least Significant Byte.

Below is an abstracted example for defining an accessory connection and sending a payload declaring the trigger held down halfway and menu button pressed (more on defining bytes below).

bmRequestType: 0b00100001
bRequest:      0x09
wValue:        0x0300
wIndex:        2
wLength:       6
Data:          {0xB3, 3, 0x03, 0x00, 0x00, 0}

 

bmRequestType: 0b00100001
bRequest:      0x09
wValue:        0x0300
wIndex:        2
wLength:       12
Data:          {0xB4, 10, 0x00, 0b00000100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00}

2. Byte Definitions

The following are HTC’s byte definitions, as outlined by their developer guidelines linked above.  I also add my own notes on the usefulness of various bytes (or lack-thereof).

ADDRESS: 0xB3
UPCOMING_DATA_COUNT (4)
0 – HOST_TYPE (1=PC, 2=PHONE, 3=ACCESSORY)
1 – RESERVED (CHARGE ENABLE, not sure if interfacing with this byte has any visible function)
2 – RESERVED (OS TYPE, TBD)
3 – LPF (Low Pass Filter configuration, 0=184Hz, 1=5Hz, 2=10Hz, 3=20Hz.  Lower frequency configurations ignore slower vibrations of the Tracker IMU, such as from accessory haptics)
{ 0xB3, 4, HOST_TYPE, RESERVED, RESERVED, LPF }

 

ADDRESS: 0xB4
UPCOMING_DATA_COUNT (10)
0 – NO VISIBLE FUNCTION (TAG INDEX)
1 – BUTTONS:
1.0 – TRIGGER (Following a SteamVR driver update, this value is independent of the analogue trigger byte)
1.1 – GRIP
1.2 – APPLICATION MENU
1.3 – SYSTEM (Yes, it will open the dashboard)
1.4 – TOUCHPAD (Following the same SteamVR driver update, this bit no longer requires TOUCHPAD_CONTACT to be high)
1.5 – TOUCHPAD_CONTACT (Does not require touchpad axis values)
1.6 – RESERVED (But whyyy?)
1.7 – RESERVED
2 – TOUCHPAD_X_LSB (LSB = Least Significant Byte)
3 – TOUCHPAD_X_MSB (MSB = Most Significant Byte)
4 – TOUCHPAD_Y_LSB (LSB)
5 – TOUCHPAD_Y_MSB (MSB)
6 – NO VISIBLE FUNCTION (Technically TRIGGER_LSB, this byte is irrelevant because SteamVR only accepts an 8-bit analogue trigger value and therefore this byte is ignored)
7 – TRIGGER (Technically TRIGGER_MSB, values remain unaffected by TRIGGER button)
8 – RESERVED (Technically BATTERY_LSB, we don’t have access to these bytes)
9 – RESERVED (Technically BATTERY_MSB)
{ 0xB4, 10, 0x00, BUTTONS, PAD_X_LSB, PAD_X_MSB, PAD_Y_LSB, PAD_Y_MSB, 0x00, TRIGGER, RESERVED, RESERVED }


3. Library Interfacing

USB protocols are not something you can just throw together in an afternoon – you’re going to want a library to handle all that overhead (Trust me, this is coming from someone that would rather write their own scripts for basic math functions so everything is in my control – you’re going to want that library).  For the code snippet below, I used the Lightweight USB Framework for AVRs (LUFA) library by Dean Camera, building upon the GenericHIDHost demo found in …\LUFA 151115\Demos\Host\LowLevel\GenericHIDHost; coded in C++.

First I edited the makefile to reflect my chip.  This blog post by Joonas Pihlajamaa really helped me get started.  Below are the values I changed:

  MCU = at90usb647
BOARD = USER
F_CPU = 8000000

 

I then went into GenericHIDHost.h and removed any references to on-board LEDs or a serial output monitor, as my custom board did not have a definitions file for these things.  Then within GenericHIDHost.c, this was the main function to perform the same task that was described at the end of Section 1 of this post:

int main(void)
{
.   SetupHardware();
.   GlobalInterruptEnable();
.
.   for(;;)
.   {
.       uint8_t payload0xB3[6] = {0xB3, 3, 0x03, 0x00, 0x00, 0};
.       uint8_t payload0xB4[12] = {0xB4, 10, 0x00, 1 << 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00};
.
.       WriteNextReport(payload0xB3, 0x00, REPORT_TYPE_FEATURE, 6);
.       USB_USBTask();
.
.       WriteNextReport(payload0xB4, 0x00, REPORT_TYPE_FEATURE, 12);
.       USB_USBTask();
.   }
}

 

This is the bare-bones firmware I needed on my AT90USB647 to get the Tracker to work reliably.  I can assure you it is far from clean.  For example, you do not need to send the 0xB3 payload every time you update data; only once after the initial device enumeration handshake completes.

The other code I had to change was in the LUFA Library was in the function WriteNextReport at the end of GenericHIDHost.c.  Apparently wIndex was set to 0 by default, however HTC’s Vive Tracker requires wIndex to be 2 (this was the missing puzzle piece for weeks when the Tracker was first released!  Change one number and everything finally works; what a feeling)

USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = 0b00100001,
.bRequest      = 0x09,
.wValue        = 0x0300,
.wIndex        = 2,
.wLength       = ReportLength,
};

4. A Low(er)-Level Look

Solely from picking apart Dean’s library, these would seem to be the primary steps that need to be performed in order to successfully communicate with the Vive Tracker:

– Initiate USB as host
– Enumerate the attached USB device
– Read and process the device’s configuration descriptor
– Set the device to its initial configuration (Dean remarks that it’s unlikely to have more than one configuration)
>   bmRequestType: 0b10000000
>   bRequest: 0x09
>   wValue: 1
>   wIndex: 0
>   wLength: 0
>   Data: NULL
– At this stage, all the setup is now complete!
– To send a report:
>   Prepare the bus/pipe
>   Feed it the header (bmRequestType, bRequest, wValue, etc.)
>   Feed it the datastream (starting with {0xB_, etc.} )
>   Return the bus/pipe to its initial state
– Perform any other needed USB host tasks

 

This section isn’t 100% solidified for me, simply because Dean did such a great job at constructing this library that once I was able to format the payload correctly for the Tracker, I had no more need to dive into the low-level for troubleshooting.  If you’re using AVRs for your microcontroller, I highly recommend Dean’s LUFA library!

I am by no means proficient in USB HID communications, but if you run into any road blocks then feel free to reach out to me, perhaps I’ll be able to offer some advice as a result of my own troubleshooting.

I made note of this at the top – if you think that it would be valuable for me to develop this into an library for USB Host-capable Arduino boards, please comment your interest below.  It could definitely help out if you explain what you would hope to use said library to do with the Vive Tracker.

EDIT: Reddit user /u/matzmann666 has wonderfully created a library for the Arduino Due ARM-based microcontroller!  Check out their GitHub page here: github.com/matzman666/USBHost

And lastly, I’d like to send a thousand thanks to Dario Laverde from HTC.  He was a great help in troubleshooting a lot of the feature report content, and I wouldn’t have Vive Trackers to work with if it weren’t for him.  Thank you, Dario!

Alright, that’s all I’ve got for this documentation.  Like I said at the top, let me know if there’s aspects about the Tracker that the community needs documentation on, and I’ll look into what I can learn.  I hope some folks out there find this information useful :)

38
Leave a Reply

avatar
15 Comment threads
23 Thread replies
8 Followers
 
Most reacted comment
Hottest comment thread
17 Comment authors
Daniel ClayChrisJackStevenaZUR Recent comment authors
  Subscribe  
newest oldest
Notify of
Ryan Mott
Guest
Ryan Mott

yes, would love a Vive Tracker Arduino library! found your blog looking for more details on the Tracker USB protocol exactly because I want to make a custom controller this way.

Simon Heath
Guest

Great to see you working on tracking , I haven’t checked back in a while. So want to see this get to market. I’m launching a VRcade , theVRhub.co.uk this weekend and would love it to feature for our customers to use. Don’t like treadmills, foot tracking is the future. Keep on tracking. :)

Simon

adam
Guest
adam

+1 for an arduino lib!

Dennis Kehrig
Guest
Dennis Kehrig

Thank you for documenting this! It helped me create an Android app that can use the tracker to pretend its trigger has been activated for as long as I press a button on the touch screen.

It looks like you need to send the host report only once, and pretty quickly after the tracker is connected via USB – otherwise SteamVR will show the tracker as connected, but not tracking. Both host types seem to be working for me, not sure what the difference is.

The activity report seems to be completely independent.

Thanks again!

Dan
Guest
Dan

I would also be interested in an Arduino Vive Tracker library! Looking forward to your updates, I am about to venture down this road as well. Hopefully I can contribute to the cause as well. Thanks again for your work on this!

Mike
Guest

Arduino Library for interfacing with the tracker would be extremely useful and appreciated. Thanks!

Matt
Guest
Matt

Peter, how did you figure out that 0x0F was a half-press for the trigger?

I tried testing this today using existing code that outputs analog values (between 0-1.0) for a regular Vive controller but sending 0x0F for TRIGGER_MSB caused Unity to output a value of 1.

James
Guest
James

Peter, thanks for this writeup. I thought I saw somewhere that it’s not possible to send data via a serial COM port using the pogo pins, is that true? I have an accessory that I’m making which needs to emulate a specific USB HID device (with a specific HID descriptor), and right now I can pretty easily achieve that using a Teensy — except that I have to have the tracker mounted to my accessory as well as have my accessory wired to my PC via a USB cable. Also, the Teensy is receiving data over USB, as well as… Read more »

Luke
Guest
Luke

As I understand correctly that new Library in arduino to support vive tracker is only for accessory makers? So you can’t get position of sensor?

Michael Varner
Guest
Michael Varner

First off, thank you so much for posting this. It’s been kind of difficult finding this kind of information so far regarding building a custom controller.

That said, do you have any recommendations on which particular Arduino board to use?

I’m thinking the Gemma or the Micro would probably be most appropriate for the use case, but this would be my first Arduino board, so I defer to your experience.

Michael Varner
Guest
Michael Varner

Just noticed you mention that /u/matzmann666 created the Arduino library off of the Due. Is that a requirement or just what they happened to use?

Michael Varner
Guest
Michael Varner

Looks like on the Arduino site it’s says it’s required to use the Due for the project that was forked to create the Vive Tracker USB Library:
https://www.arduino.cc/en/Reference/USBHost

“USBHost

Compatible with Arduino Due only”

Glenn
Guest
Glenn

Thanks for the write up.

Have you had any success sending to a peripheral from the game engine via the trackers USB? For instance, telling an LED to illuminate from in game.

aZUR
Member
aZUR

hello, Im little bit disapointed because i made an hid joystick with a pic18 and so i assume that he is working as a device not a host. It work really well on my pc and now I want to get the value of all axis through my vive tracker. how can I do ?
should I just put an external battery to my device ?

Steven
Guest

Hello,

Thanks for this detailed documentation. With it, I was able to write an Android app that communicates different button presses to the Vive tracker via USB.

I made a post about it. Hopefully, it can help some people out:
http://www.brightdevelopers.com/communication-htc-vive-tracker-android/

trackback

[…] Hollander’s documentation about the Vive tracker is what inspired me to write an Android app to work with the tracker. The […]

Chris
Guest
Chris

Thank you for your documentation, it has been very helpful.

However, I am wondering if it is possible to poll the sensor data from the tracker via the arduino usb interface.
The USB host library disables polling.
Is it possible to enable it, and is there some documentation on it? Or rather has somebody already done it?