Home > Arduino, Bluetooth, TKJ Electronics, USB > PS4 controller now supported by the USB Host library

PS4 controller now supported by the USB Host library

I am very pleased to announce that I have now added support for the PS4 controller via Bluetooth. This will allow you to read all the buttons and joysticks with the same API as all the other libraries I have written for the USB Host library.

PS4 controller

To get started you should look at the provided example. It shows how to read the different buttons and joysticks. I still haven’t figured out how to control the light, rumble and read the accelerometer, gyroscope and touchpad, but hopefully I will figure that out soon.

The pairing process for the PS4 controller is a little different than the PS3 controller, as it works like a regular Bluetooth joystick, as you simply make the PS4 controller discoverable by holding down the PS and Share button at the same time. The light will then start to blink rapidly.

After that you should be able to pair with the controller, by creating the PS4BT instance like so:

PS4BT PS4(&Btd, PAIR);

You should also check out the readme which will always have the newest information available.

The PS4 Bluetooth library actually uses the BTHID library to handle all the Bluetooth communication. This is much more modular and easier to maintain. I will work on making all the Bluetooth classes like that, so it will reduce the footprint of the libraries, but also make it much easier to maintain, as all the L2CAP communication would be handled in only one class.

I still haven’t written a library to use it via USB, but I will do that in the coming weeks, when I have time.

This is all for now. Please leave a comment below if you got any questions and I will answer as quickly as possible.

Update 18. January 2014
A USB version of the library is now also available. It allows you to read the gyroscope, accelerometer and touchpad as well.

Update 22. January 2014
I now also figured out how to read the IMU and touchpad data via Bluetooth. The problem is that the controller does not send out this information via Bluetooth by default.
To enable the full output the code sends out a get feature report. For more information see this excellent Wiki: http://eleccelerator.com/wiki/index.php?title=DualShock_4 by Frank Zhao.

Update 16. February 2014
It is now also possible to control the rumble and light as well. The code was inspired by this Linux driver: https://github.com/chrippa/ds4drv.

Categories: Arduino, Bluetooth, TKJ Electronics, USB Tags:
  1. Sammy
    January 14th, 2014 at 02:50 | #1

    Great! Was exactly looking for this. Thanks for sharing.

  2. January 14th, 2014 at 22:48 | #2

    @Sammy
    You are welcome! It is always nice to see that people find it useful :)

  3. Raggy
    January 19th, 2014 at 20:18 | #3

    Amazing! I don’t have arduino, but do use PICAXE. Got any tips for connections? i.e. what do I need to serial out to connect? Will serial out and in work?
    Thanks a bunch

  4. January 19th, 2014 at 20:30 | #4

    @Raggy
    You will need the USB Host Shield: http://shop.tkjelectronics.dk/product_info.php?products_id=43 for it to work, but for now PICAXE is not supported by the library.

    Anyway they communicate via SPI. The relevant code is in the following file: https://github.com/felis/USB_Host_Shield_2.0/blob/master/usbhost.h.

  5. Matt
    January 20th, 2014 at 09:40 | #5

    I cant get a working dongle?!? Ive tried 3 of the cheap half mooned ebay ones and no luck. Any help?

  6. January 20th, 2014 at 12:53 | #6

    @Matt
    What errors are you getting when you plug them in?
    There is a list of working dongles here: https://github.com/felis/USB_Host_Shield_2.0/wiki/Bluetooth-dongles.

  7. Jake
    February 1st, 2014 at 04:31 | #7

    Hey ive been trying to use this library with a USB host sheild I got online but when I run the PS3BT script my serial monitor just returns random symbols. Has any one else experienced this issue and found a way to resolve it?

  8. February 2nd, 2014 at 10:21 | #8

    @Jake
    You need to set the baudrate in the serial monitor to 115200. See the dropdown menu in the bottom right.

  9. Azim
    February 23rd, 2014 at 14:41 | #9

    Hi,

    I have purchased the USB Shield and cant wait to get on with it, I really appreciate your efforts and this great work.

    I am currently planning to build a robot and was doing some research on interfacing XBOX 360 controller via BT and came across your great site, I will be going through the information provided should I require any assistance will be in touch.

    Thanks

    Azim

  10. February 23rd, 2014 at 16:31 | #10

    @Azim
    Glad to hear you like my work :) Note that the Xbox 360 wireless controller needs a special wireless receiver and is NOT using Bluetooth.
    Please see: http://blog.tkjelectronics.dk/2012/12/xbox-360-receiver-added-to-the-usb-host-library/.

  11. Joe M
    April 13th, 2014 at 21:39 | #11

    Hi guys!

    (First of all, sorry for my english level, I’m not an native english speaker…)

    So, I’m a newbie for Arduino stuff, but I’d like to start a project whit it. I want to control a very simple illumination system, you know turn on/off some lights maybe a dimmer.

    I’ve read this could be done by an Android device, but if it’s possible, i’d like to control it whit a PS controller, I dont care if PS3 or PS4.

    Does anybody think it could be possible to do whitout the USB host shield? because if I do that I’ll do it whit a BT shield and I’ll use Arduino UNO.

    Hope anyone could help me!

    Thanks for reading!

  12. April 13th, 2014 at 23:17 | #12

    @Joe M
    No you can’t use a normal Bluetooth shield, as it doesn’t support Bluetooth HID. Also the PS3 controller behaves a bit different, as you need to send a special command to it before it starts sending out data.
    If you want to know more about it, then see the PS3 wiki I wrote: https://github.com/felis/USB_Host_Shield_2.0/wiki/PS3-Information.

  13. Joe M
    May 9th, 2014 at 06:03 | #13

    @Lauszus

    Hi Lauszus! Thank you for reply!

    I’ve already bought the usb shield and BT dongle, so I could run the example!

    Then I got a bunch of doubts XD. Let me explain you and maybe (I hope) you can help me.

    The thing is, I want to use a couple of outputs to control a little DC motor, but if you could tell me how to turn on a led it’ll be more than useful!

    So, it’s posible to do? And if yes…. how can i do it?

    Thank you again, take care :)

  14. May 9th, 2014 at 11:51 | #14

    @Joe M
    It’s really simple :)

    Here is some example code:

    if (PS4.getButtonPress(CROSS))
       digitalWrite(led, HIGH);
    else
       digitalWrite(led, LOW);

    Note that if you are using an Arduino Uno, then you can not use the build in LED, as pin 13 is used by the shield for SPI communication.

  15. Joe M
    May 21st, 2014 at 23:40 | #15

    Man, you’re so kind! I found that code very helpful. But now I got a new problem ( sorry again I’m new on this :( ). When I pair de DS4 sometimes I lost the connection after 3 mins. I suppose that it ain’t normal. Haha… I tried using a new dongle (trendnet TBW 107 UB) but the arduino can’t recognise it.

    Do you think it’s a matter of the first dongle, or code…. Maybe bad luck? Hahaha

    Thank you very much for your replies and help.

    Ps. Sorry for write my feedback almost 10 days after your reply.

  16. May 22nd, 2014 at 00:03 | #16

    @Joe M
    Make sure that the dongle is getting a stable 5V also make sure that there is actually battery left on the PS4 controller? You can use the following function to read the battery level: https://github.com/felis/USB_Host_Shield_2.0/blob/2c5f5e8c0964c1639265486b6fac17739a55f1d2/PS4Parser.h#L259-L265.

    Also what is the output when it disconnects?

  17. Joe M
    June 2nd, 2014 at 02:33 | #17

    @Lauszus

    Man! Thank you very much! you was very helpful!! Seriously, you helped me a lot whit my final project!
    The trouble was the input to arduino, (wasn’t 5V stable as you said).
    Then I was able to control a RC car using DS4, USB Shield, the BT dongle and Arduino UNO!

    Again, thank you very much!

    Take care man, Cheers from Mexico!

  18. Joe M
    June 2nd, 2014 at 02:36 | #18

    @Joe M

    HAhaha I wrote “you was” I ment “You were”

    Just a little mistake XD Sorry!.

  19. June 2nd, 2014 at 11:08 | #19

    @Joe M
    Glad to hear that everything worked out for you :)

  20. Tony W
    July 26th, 2014 at 03:09 | #20

    @Lauszus,

    Awesome work first of all! I’ve used the PS4USB library without a hitch, however with the PS4BT example, it seems that I can only pair the PS4 with the dongle once…. in a while, and after that they can no longer pair (LED keeps flashing rapidly then eventually the controller shuts off). I know that in your instructions it says I only need to pair it once, and then I can just create an instance like this: PS4BT PS4(&Btd); and then simply press the PS button. But when I do that, the PS4 will just begin looking for the console (slow flashing LED) and not connect with the BT dongle…and suggestions? Thanks!

  21. July 28th, 2014 at 09:24 | #21

    @Tony W
    Please enable serial debugging: https://github.com/felis/USB_Host_Shield_2.0#enable-debugging and send me the output ;)

  22. Lee
    October 1st, 2014 at 23:40 | #22

    @Tony W Exact same problem here. Not sure if its circumstantial but I can’t connect at all if the terminal window is open.

  23. October 2nd, 2014 at 00:42 | #23

    @Lee
    Please see my reply above. If you don’t paste the output it is impossible for me to see what is going on.

  24. Lee
    October 2nd, 2014 at 04:13 | #24

    Sorry -- I completely missed that your response there was to Tony’s question… ok so I’ve enabled serial debugging and this is the only output. My computer is a mac mini and both the keyboard and mouse are connected via bluetooth. Its interesting that it shows something is connected but I have no idea what as there is no indication that the PS4 controller or anything else is actually connected.

    Serial Output
    —————
    PS4 Bluetooth Library Started
    Bluetooth Dongle Initialized
    HCI Reset complete
    Write class of device
    Local Bluetooth Address: 00:02:72:D9:E8:04
    Wait For Incoming Connection Request
    Gamepad is connecting
    Incoming Connection Request
    Remote Name: Wireles
    Connected to Device: 84:17:66:22:E7:5C
    Wait For Incoming Connection Request

    Thanks greatly for your help!

    btw the output really does say Wireles (e.g. that isn’t a retype/cut/paste error)

  25. Lee
    October 2nd, 2014 at 07:19 | #25

    I forgot to mention in my previous post that the front LED goes solid white -- so maybe it does some to be connected at some level but is not getting complete connection?

    I’m still completely unable to get a connection in non-pairing mode. In paring mode I can get it connected maybe one time in 5.

    Following output was from one of the successful connections

    PS4 Bluetooth Library Started
    Bluetooth Dongle Initialized
    HCI Reset complete
    Write class of device
    Local Bluetooth Address: 00:02:72:D9:E8:04
    Please enable discovery of your device
    Gamepad found
    HID device found
    Now just create the instance like so:
    BTHID bthid(&Btd);
    And then press any button on the device
    Connecting to HID device
    Connected to HID device
    Received Key Request
    Bluetooth pin is set too: 0000
    Pairing successful with HID device
    Send HID Control Connection Request
    Send HID Control Config Request
    Set protocol mode: 00
    Send HID Interrupt Connection Request
    Send HID Interrupt Config Request
    HID Channels Established
    Wait For Incoming Connection Request
    LeftHatX: 129 LeftHatY: 138 RightHatX: 122 RightHatY: 124
    :
    :
    in this run the BT pairing happens almost instantaneously and the front controller goes to solid blue

    Now another run… everything identical
    PS4 Bluetooth Library Started
    Bluetooth Dongle Initialized
    HCI Reset complete
    Write class of device
    Local Bluetooth Address: 00:02:72:D9:E8:04
    Please enable discovery of your device
    Gamepad found
    HID device found
    Now just create the instance like so:
    BTHID bthid(&Btd);
    And then press any button on the device
    Connecting to HID device
    Connected to HID device
    Received Key Request
    Bluetooth pin is set too: 0000

    I’ve just enabled the EXTRADEBUG in BTHID and get this output on a failed pairing connection:
    PS4 Bluetooth Library Started
    Bluetooth Dongle Initialized
    HCI Reset complete
    Write class of device
    Local Bluetooth Address: 00:02:72:D9:E8:04
    Please enable discovery of your device
    Gamepad found
    HID device found
    Now just create the instance like so:
    BTHID bthid(&Btd);
    And then press any button on the device
    Connecting to HID device
    Connected to HID device
    Received Key Request
    Bluetooth pin is set too: 0000
    Pairing successful with HID device
    Send HID Control Connection Request
    Send HID Control Config Request
    Set protocol mode: 00
    Send HID Interrupt Connection Request
    L2CAP Connection Request -- PSM: 00 11 SCID: 00 42 Identifier: 02

    this goes to solid white.

    I’m not seeing a pattern in this
    pairing mode: works occassionally
    sometimes fails (e.g. nothing more happens) after line Bluetooth pin is set too: 0000 -- light continues to blink in the pairing mode sequence
    sometimes fails to solid white following is an example of that:
    —-
    PS4 Bluetooth Library Started
    Bluetooth Dongle Initialized
    HCI Reset complete
    Write class of device
    Local Bluetooth Address: 00:02:72:D9:E8:04
    Please enable discovery of your device
    Gamepad found
    HID device found
    Now just create the instance like so:
    BTHID bthid(&Btd);
    And then press any button on the device
    Connecting to HID device
    Connected to HID device
    Received Key Request
    Bluetooth pin is set too: 0000
    Pairing successful with HID device
    Send HID Control Connection Request
    Send HID Control Config Request
    Set protocol mode: 00
    Send HID Interrupt Connection Request
    L2CAP Connection Request -- PSM: 00 11 SCID: 00 42 Identifier: 02

    in non pairing mode it sits at the waiting for connection even though it says its connected

    Ideas?

  26. Lee
    October 2nd, 2014 at 17:11 | #26

    I’m guessing there is a problem in the if condition inside the run function in BTHID where it seems that in some cases the following block never gets executed.

     if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
        pBtd->l2capConnectionClaimed = true;
        activeConnection = true;
    #ifdef DEBUG_USB_HOST
        Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
    #endif
        hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
        l2cap_event_flag = 0; // Reset flags
        identifier = 0;
        pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM);
        l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
  27. Lee
    October 2nd, 2014 at 18:47 | #27

    hmmm ok so it seems that that word “Wireles” is in fact the problem. For whatever reason it should be getting the entire phrase “Wireless Controller” to identify it in the code as a PS4 and since its not getting the entire phrase it wasn’t setting the incomingPS4 value to true which in turn was keeping the connectToHIDDevice value from getting set to true so it was never entering into the block of code I mentioned in the previous note.

    I’m not sure why its only getting this partial phrase but on the two PS4 controllers I have I’m consistently getting Wireles and not “Wireless Controller” anyway, here is a hack i’ve added to BTD.cpp as a workaround.

    replace the if block starting at line 824 with this code in BTD.cpp and it fixes my problem

    if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08) {
            if (strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {

    #ifdef DEBUG_USB_HOST
                    Notify(PSTR("\r\nPS4 controller is connecting"), 0x80);
    #endif
                    incomingPS4 = true;
            } else if (strncmp((const char*)remote_name, "Wireles", 7) == 0) {
                    // ok so here is the problem - entire phrase "Wireless Controller isn't coming through"
    #ifdef DEBUG_USB_HOST
                    Notify(PSTR("\r\nbad phrase: hack lw -> PS4 controller is connecting"), 0x80);
    #endif
                    incomingPS4 = true;

            }
    }
  28. Lee
    October 2nd, 2014 at 19:06 | #28

    sorry to be filling up your message board with comments -- I just wanted to put one of thanks in here -- this is truly a remarkable effort and your contribution is massively appreciated! Awesome work on this!

  29. VincentC
    October 4th, 2014 at 17:55 | #29

    Hello Lauszus,
    I have a problem when I want to connect my new PS4 controller by USB to my Arduino Due.
    I programmed my Due with the PS4USB.ino and I added the line #include but when I connected the controller and launched it with the button ‘PS’, the controller blinked 6 times and turned off.
    Have you a solution to connect the controller ?
    Vincent

  30. October 8th, 2014 at 01:32 | #30

    @Lee
    This is a problem with your dongle. That errors is because your dongle doesn’t not support 2.0+EDR, so the last bytes are not received.

    So unfortunately you will have to buy a new dongle. There is a list of dongles available here: https://github.com/felis/USB_Host_Shield_2.0/wiki/Bluetooth-dongles, but I recommend just buying some from a bunch of different sellers and then you will most likely get some that work.

    @VincentC
    Did you follow these instructions: https://github.com/felis/USB_Host_Shield_2.0#ps4-library?

    Also please enable serial debugging: https://github.com/felis/USB_Host_Shield_2.0#enable-debugging.

  31. VincentC
    October 8th, 2014 at 07:49 | #31

    Does it important to connect PS4 controller with Bluetooth before to connect by USB ? Else I did all instructions for USB connection.

    I have activated debugging in settings.h but I haven’t any debug on Serial port. I tested my USB cable and my Arduino Due with an Arduino example with a mouse on usb host and it worked.

    I think I haven’t any connexion problem between the Arduino Due and the PS4 controller.

    Installation problem ?

    Have you an explication ?

  32. October 8th, 2014 at 09:01 | #32

    @VincentC
    No you don’t need to connect it via Bluetooth first -- maybe that wasn’t clear.

    If nothing shows up, then it means that it does not register that you plug anything in. Please tell me what shield you are using and try to connect an external power supply to the Arduino.

  33. VincentC
    October 8th, 2014 at 17:49 | #33

    I use the USB host onboard. It must be use a shield with Max3421?

  34. October 8th, 2014 at 19:14 | #34

    @VincentC
    Yes the native USB Host is not supported. It might be supported at some point, as it is in the works ;)

  35. VincentC
    October 8th, 2014 at 19:52 | #35

    Thanks for this response :D
    So let’s go to program this ;)

  36. Lee
    October 9th, 2014 at 17:13 | #36

    hmm, just fyi, I consulted that list before I bought. The adapter in question is the gmyle with a link to amazon. I’ll try another to see if I can get different and hopefully better result.

    2nd question are there any instructions for making another arduino talk to one with the shield/usb bt combo. I think the other arduino would just need a standard ble attached -- as opposed to another host shield and usb bt but that info would be good info.

  37. October 10th, 2014 at 01:56 | #37

    @Lee
    Just order a couple of different ones from China, then you should receive a couple that will work ;)

    No not yet, as only SPP server is supported for now. I have been working on a SPP client as well, but never got the time to finish it. The code is available here: https://github.com/felis/USB_Host_Shield_2.0/tree/SPPClient.

    You will need a Bluetooth adapter that can configured into host mode in order to connect to the other Arduino.

  38. Lee
    October 10th, 2014 at 19:55 | #38

    @Lauszus -- ok, I ordered another one. btw, I’m using a standard arduino USB host shield not the Circuits@home -- could that be the issue?

    Would you mind commenting on why neither your library (nor most arduino libraries) use callback style functionality? It just makes for such a messy main loop when you have to constantly poll a function as opposed to an event getting raised back out to a callback? Is that just due to the implicit standard or is there an actual technical reason not to use callbacks?

    Also, it looks like the ds4 does not send a final message when the joysticks return to home -- if I simply look at the last received message it could indicate that the joystick location is 20% or more off of the home position. It does look possible to more/less infer when the stick is at home as the message stream stops so I can determine home by setting a timer and if there is no update in x milliseconds then it must be at home. Is there any other way to do this?

    thanks for the client code -- will try to take a look over the weekend

  39. October 15th, 2014 at 03:40 | #39

    @Lee
    Yes that can be the issue. Please use the official shield in order to support the actual developers of the hardware and software.

    The library works by each driver registers themselves -- see https://github.com/felis/USB_Host_Shield_2.0/blob/58a143b9fb1b8fc7c7b4568b74d3b9f175a2302b/BTD.cpp#L44-L45 and https://github.com/felis/USB_Host_Shield_2.0/blob/58a143b9fb1b8fc7c7b4568b74d3b9f175a2302b/UsbCore.h#L215-L223 and the different classes are then call in Usb.Task(). For instance here Poll is called: https://github.com/felis/USB_Host_Shield_2.0/blob/58a143b9fb1b8fc7c7b4568b74d3b9f175a2302b/Usb.cpp.

    The code does in fact using callback some places. Here is an example: https://github.com/felis/USB_Host_Shield_2.0/blob/58a143b9fb1b8fc7c7b4568b74d3b9f175a2302b/examples/Bluetooth/BTHID/BTHID.ino.
    The only thing that is called in the loop is Usb.Task(), but you could differently call this in an interrupt if you wanted to.

    What do you mean by home? Are you talking about when it disconnects? But yes using a timer is the proper way to do it.

  40. @Stella
    November 1st, 2014 at 11:44 | #40

    Hello,
    it could be possible to use a new BT shield (ble shield ) and Arduino UNO?

  41. November 3rd, 2014 at 22:08 | #41

    @@Stella
    No that is not possible. Shield like that normally only support SPP and I need HID host in order to talk with the PS4 controller.

  42. Donut
    November 6th, 2014 at 01:07 | #42

    @Lauszus
    Hello! I’m new here and I’m trying to use this setup to control an RC

    I’d like to ask if it’s possible to have the R2 and L2 buttons to control the motors? If so, how do I get around to doing so I’m so lost right now. Any tips?

  43. November 6th, 2014 at 08:47 | #43

    @Donut
    Simply use the analogWrite function: http://arduino.cc/en/Reference/analogWrite.

    Then you can simply do something like this:

    analogWrite(pin, PS4.getAnalogButton(L2));
  44. Donut
    December 2nd, 2014 at 08:29 | #44

    Hello @Lauszus, thank you for the help!
    Sorry for the late reply but I’ve been working on a drone for an engineering project and I’ve come across another hurdle!

    I need help with programming a 180º servo to work with the PS4, as of right now I’ve got

    if (PS4.connected()) {
    myservo.write(map(PS4.getAnalogHat(RightHatX), 0, 255, 0, 180));
    }
    else
    {
    myservo.write(90);
    }

    But this doesn’t seem to be doing anything at all, please advice

  45. December 2nd, 2014 at 08:45 | #45

    @Donut
    Did you remember to attach the servo as well: http://arduino.cc/en/Reference/ServoAttach?

  1. No trackbacks yet.