10
\$\begingroup\$

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?

\$\endgroup\$
8
\$\begingroup\$

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.

\$\endgroup\$
7
  • \$\begingroup\$ Is it possible for you to clarify this answer per this post? \$\endgroup\$ – user1430 May 12 '16 at 20:29
  • \$\begingroup\$ I'm travelling right now, but I'll take that on when I've got some downtime with wifi. Thanks @JoshPetrie! \$\endgroup\$ – DMGregory May 13 '16 at 9:25
  • \$\begingroup\$ Digging into this, I no longer have the source code for the motion sensing project I was working on, and going back to DS4Tool reminded me why I ripped out only the bits I need! This gets super verbose and might go beyond a reasonable length for a StackExchange answer. I'll try to simplify as much as I can but it will take some time. \$\endgroup\$ – DMGregory May 15 '16 at 5:57
  • 1
    \$\begingroup\$ @DMGregory -- This data sheet is, I think, for the IMU the DualShock 4 uses: mouser.com/ds/2/783/BST-BMI055-DS000-08-786482.pdf -- and it says Short.MaxValue corresponds to 2000 degrees per second. By my calculation, you're getting about 1833 degrees per second, which is close (and reasonable for the result of testing), but perhaps adjusting your calculation accordingly will give you a bit more accuracy? \$\endgroup\$ – Jibb Smart Mar 22 '18 at 3:48
  • \$\begingroup\$ (I'm doing gyro stuff myself right now, and was going to try figure out the standard unit conversions by testing myself, and then a friend found that link for me) \$\endgroup\$ – Jibb Smart Mar 22 '18 at 3:56
2
\$\begingroup\$

I've created a solution to this myself. It's called JoyShockLibrary, and reads from DualShock 4, Switch Pro Controller, and Joy-Cons. It's open source, MIT license, and works well, although Bluetooth support for the DS4 was only added recently and is still improving.

It's used in JoyShockMapper, which is an input-mapping tool, and JoyShockOverlay, which isn't public yet, but you can see it in action here (Gfycat) and here (YouTube).

JoyShockLibrary complements XInput nicely -- besides its IMU reports, it looks very similar to XInput -- so you can cover all current gen console controllers easily, with the benefit of gyro and accelerometer input from those that support it.

It's pretty easy to use with Unity, though I should put up a .cs file to make it easier for others.

\$\endgroup\$
0
\$\begingroup\$

Those appear to all be tools that wrap DirectInput to XInput. Unity has support for DirectInput and so you should be looking at getting it work without 3rd party tools. The key is if the IMU is mapped to anything in DirectInput and if it is already in a usable state. If not, you might have to write your own DirectInput handler to deal with the raw data.

You can thank the xbox for all these controller woes.

\$\endgroup\$
1
  • \$\begingroup\$ Unfortunately the IMU does not appear to be mapped to any of the 20 "joystick axes" Unity reads, nor to Input.gyro etc. I ended up digging into the raw data; added an answer with details of the solution. \$\endgroup\$ – DMGregory Nov 12 '14 at 16:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.