Saturday, April 25, 2015

Accessing DualShock 4 motion sensor in Windows (ideally Unity)


I'm trying to use a DualShock 4's IMU as a motion controller in Unity, under Windows 7.


So far I've tried:



  • DS4Windows (1.5.11): reads motion sensor data, but does not expose them to Unity as axes unless I map them to the left & right sticks. This is not enough since I lose use of the sticks, I can only fit 4 of the 6 channels of data, and the values coming through are clipped into a narrow range.

  • Motioninjoy (0.7.1001): does not appear to detect the DS4 as a controller (latest docs refer only to DS3 and prior)


  • GlovePIE (0.43): after following instructions for using the DualShock 3 with LibUSB-Win32 (a long shot), SixAxis properties are all blank.


In the past I've used external programs like GlovePIE to capture Wii remote motion sensor data and pass it to Unity via OSC messages, so I'd be open to an approach like this if I can't get Unity to read the controller's sensors directly through its Input system.


Anyone had luck with this?



Answer



I've found a workable approach. I grabbed the DS4Tool source and copied the bits I needed into my Unity project so I could read the reports from the device directly.


(That's the NativeMethods class to interface with Kernel32.dll, the device enumeration from HidDevices, and reading the report from the HidDevice class. I cut out the rest to keep things as simple as possible - I've just got a thread polling for new data as fast as it can.)


This guide told me where to find the motion sensor data within the 64-byte report. A little empirical testing and it looks like this gets the data into gs and radians/sec:


accel = new Vector3(
System.BitConverter.ToInt16(_inputBuffer, 19),

System.BitConverter.ToInt16(_inputBuffer, 21),
System.BitConverter.ToInt16(_inputBuffer, 23)
)/8192f;

gyro = new Vector3(
System.BitConverter.ToInt16(_inputBuffer, 13),
System.BitConverter.ToInt16(_inputBuffer, 15),
System.BitConverter.ToInt16(_inputBuffer, 17)
)/1024f;


It's a right-handed coordinate system with x+ right, y+ up, and z+ pointing toward the player.


Fetching the data this way doesn't interfere with Unity's InputManager, which will still pick up the buttons & sticks as expected, without needing to download non-standard drivers or run extra software in the background.




Update: Wireless (Bluetooth)


I found two problems extending this to work wirelessly (and two solutions):




  1. DualShock 4s don't like to stay paired to Windows (prior to Windows 8). This silly procedure seems to work around that on Windows 7.





  2. No motion sensor data when connected via Bluetooth. I discovered you need to write an Output Report to the device (see HidDevice for the method and DS4Device for the magic numbers) in order to coax it into sending motion data. Once this is done, the input reports you get back will be shifted by 2 bytes.




No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...