Interfacing a PS3 controller to the joystick partner port

This thread only applies to college teams.

There was lots of discussion earlier this year about the partner joystick port and alternative devices that could be interfaced to it.

magicode had asked about using this port and had received this answer.

There had also been posts about the communications protocol in threads such as this and this. I had posted some code that could be used on a PC to communicate with the partner port but what was/is really needed is an embedded solution.

To address this I have put together a technology demo that interfaces a playstation Dualshock 3 controller (although it should also work with other PS3 controllers as well). The only reason I chose to use this device is that I have them laying around at home, the principle used for interfacing this would be the same for many other USB controllers, in particular I know there was interest in using the Logitech 3D Pro, it would take some extra work but I see no reason why college students could not handle that.

Most devices like the PS3 controller implement a class of USB communications know as HID (Human interface device). There is lots of existing firmware available that shows how to interface to HID devices and many different micro-controllers that have the capability to implement a USB host interface. For this project I chose to use an arduino, mostly because I have them available but also because there has been some useful development already done in interfacing HID controllers.

Hardware

The small embedded system I put together consisted of an arduino pro and a USB shield both from sparkfun.

[ATTACH]6358[/ATTACH]

http://www.sparkfun.com/products/10914
http://www.sparkfun.com/products/9947

In addition to these I used a small breakout board to turn the logic level serial data into appropriate RS232 levels.

http://www.sparkfun.com/products/11189

And some headers for connecting the two boards.

http://www.sparkfun.com/products/10007

Total investment about $55 not including various wire and connectors I already had.

Edit: I should add that if you are starting from scratch you would need a programming adapter such as this one. check the voltage depending on which board you go with.

http://www.sparkfun.com/products/9873

Firmware

The arduino development environment is free and available for Mac, PC and Linux. You can download it from the arduino home page.

The firmware is simple, the PS3 controller is initialized, the values of its joysticks and buttons are read and placed into a data structure suitable for sending to the VEX joystick, the packet is then sent to the serial port on the arduino.

The USB communications are handled by code developed by a gentleman know as Oleg, his home page is here.

The library can be downloaded from github.

https://github.com/felis/USB_Host_Shield_2.0

Oleg developed the original version of the USB shield (as far as I know) but his version is a little different from the sparkfun version. Specifically, reset to the USB controller is handled a little differently between the two boards, this means that the examples included with the library do not work out of the box as reset on the sparkfun system is held low by default. To rectify this a couple of lines of code need to be added to the arduino setup function.

    // reset USB shield - this is needed for the sparkfun version
    pinMode( 7,  OUTPUT); 
    digitalWrite( 7, 0 );
    digitalWrite( 7, 1 );
    digitalWrite( 7, 0 );
    digitalWrite( 7, 1 );

This simply toggles the reset line, which is connected to output 7 on the sparkfun board, and then holds it high.

The arduino pro uses an Atmel Atmega328P running at 8MHz (although there is also a 16MHz version for the same price). This micro-controller only has one serial port, as we wish to use the serial port for interfacing to the VEX joystick we need to be careful as it is often also used for debugging purposes. The arduino development system also provides a “software serial” library but I find this does not work well at the 115200 baud rate the VEX partner port needs. The PS3USB class has some debugging turned on by default and this needs to be turned off, the file PS3USB.cpp needs to be edited and the definitions for debugging commented out.

//#define DEBUG // Uncomment to print data for debugging
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers

I have attached the sketch (the arduino guys call programs sketches) for this project but the key parts are as follows.

Definition of the vex communications data.

// Storage for the vex communications data
typedef union _vexdata { 
    struct {
      unsigned char  header_aa;
      unsigned char  header_55;
      unsigned char  reply_type;
      unsigned char  datalen;
      unsigned char  js_1;
      unsigned char  js_2;
      unsigned char  js_3;
      unsigned char  js_4;
      unsigned char  button_56;
      unsigned char  button_78;
      unsigned char  accel_y;
      unsigned char  accel_x;
      unsigned char  accel_z;
      unsigned char  checksum;
     } data;
     
   unsigned char    buffer[16];  
  } vexdata;

The main loop that the arduino code constantly calls.

void loop()
{
    static  uint32_t  timer = 0;
    
    // Run every 50mS
    if(millis() - timer < 50)
      return;     
    timer =  millis();
    
    // Call the USB task
    Usb.Task();

    // If we are connected then gather all the data
    if(PS3.PS3Connected || PS3.PS3NavigationConnected)
      {
      // Get analog joystick data
      MyVexData.data.js_1 = PS3.getAnalogHat(RightHatX); 
      MyVexData.data.js_2 = PS3.getAnalogHat(RightHatY); 
      MyVexData.data.js_3 = PS3.getAnalogHat(LeftHatY); 
      MyVexData.data.js_4 = PS3.getAnalogHat(LeftHatX); 
    
      // Any buttons changed from last time ?      
      if(PS3.buttonChanged)
        {     
        MyVexData.data.button_78 = 0;
         
        if( PS3.getButton(DOWN) )
          MyVexData.data.button_78 |= 0x01;
        if( PS3.getButton(LEFT) )
          MyVexData.data.button_78 |= 0x02;
        if( PS3.getButton(UP) )
          MyVexData.data.button_78 |= 0x04;
        if( PS3.getButton(RIGHT) )
          MyVexData.data.button_78 |= 0x08;
          
        if( PS3.getButton(CROSS) )
          MyVexData.data.button_78 |= 0x10;
        if( PS3.getButton(SQUARE) )
          MyVexData.data.button_78 |= 0x20;
        if( PS3.getButton(TRIANGLE) )
          MyVexData.data.button_78 |= 0x40;
        if( PS3.getButton(CIRCLE) )
          MyVexData.data.button_78 |= 0x80;
        
        MyVexData.data.button_56 = 0;
      
        if( PS3.getButton(L2) )
          MyVexData.data.button_56 |= 0x01;
        if( PS3.getButton(L1) )
          MyVexData.data.button_56 |= 0x02;
          
        if( PS3.getButton(R2) )
          MyVexData.data.button_56 |= 0x04;
        if( PS3.getButton(R1) )
          MyVexData.data.button_56 |= 0x08;
        }
      
      // Accelerometer data  
      MyVexData.data.accel_y = PS3.getSensor(aY);
      MyVexData.data.accel_x = PS3.getSensor(aX);
      MyVexData.data.accel_z = 0x7f;
      }
   
   VexDataChecksum();
#ifdef  DEBUG
   VexDataPrint();
#else
   VexDataTransmit();
#endif
}

I’m not going to explain all of this but the essence of this code is to copy the PS3 control values into the VEX data structure and then send it to the serial port. As this is demo code I did not bother to receive messages back from the VEX joystick, doesn’t seem to matter but this should be improved in production code.

The code was checked by using a simple ROBOTC program to display values from the partner joystick on the LCD.

Here is a photo of the system thrown together on my desk, remember it’s only a prototype to prove that it can work.

[ATTACH]6349[/ATTACH]

For competition use this would obviously need to be packaged, a standard VEX battery would easily be able to power it.

The USB shield library also supports an interface to the PS3 controller using bluetooth, a bluetooth dongle is connected to the USB port in place of the cable to the joystick.

I will create a block diagram showing how all this is connected together in another post.

Enjoy.
PS3ToVex.zip (2.97 KB)
arduino_usb_shield.jpg

4 Likes

Here’s the block diagram, don’t worry about the arduino to USB shield connections if you stack the boards as they are obviously made for you. I am showing the sparkfun part numbers but these or similar parts are available from a number of sources.

There is a small variation on this that uses the prolific PL2303 serial adapter that most of us already have (it’s the VEX programming cable) in conjunction with a USB hub, I will post details of that and some updated code later on.

[ATTACH]6376[/ATTACH]

4 Likes

So here is a variation that does not use the built in arduino serial port but instead uses a USB to RS232 adapter. As we now have two USB devices plugged into the USB Shield this requires the use of a USB Hub, everything could be housed together in one enclosure and the hub does not need additional power. The advantage of this configuration is that the normal arduino serial port is available for debugging and download without affecting the communications to the VEX joystick.

The USB Host Shield V2.0 library supports hubs but I had trouble getting an older model to work, a more recent model I had would initially only recognize every other port, I had to instantiate two instances of the USBHUB class to solve this and presume that inside my 7 port hub there are two daisy chained 4 port devices.

The serial adapter I used was the orange cable supplied as part of the VEX programming kit. The orange interface box should not be used, the 9 pin connector on the cable is adapted to the partner port cable directly. I made a cable from the 4P4C connector to a female 9 pin that could be plugged into the prolific adapter, this was just an old telephone handset cable where I cut one end off and soldered on the 9 pin connector.

I had to make one small change to the header file for the PL2303 class to get my adapter to work correctly, uncomment the line

#define PL2303_COMPAT //uncomment it if you have compatibility problems

in the cdcprolific.h file.

Here is the revised block diagram
[ATTACH]6379[/ATTACH]

The revised sketch is attached

.


PS3ToVex2.zip (3.43 KB)

4 Likes

This is some beautiful work! I haven’t done anything with USB on Arduino yet, so I’ll make sure and have a look through this project to see what I can pick up.

An addition that would probably be very popular is using a spare digital input as a PPM decoder, so that an old-style VEX R/C remote can be used as the partner joystick. I know a lot of people like the fine control allowed by the larger joysticks. Should be pretty straightforward, since it is just a matter of timing the pulse spacing.

Again, very well done. I’ll study this in detail next week when I have more time.

Cheers,

  • Dean
1 Like

Thanks Dean, the real credit should go to Oleg and the others who did most of the work by creating the USB library, I simply added a little glue code.

The real potential here is not using a PS3 controller but adapting other devices. In the most simple terms there is the ability to send 7 bytes of information (the 4 joystick axis and 3 accelerometer channels) along with 12 additional bits (the 12 buttons) that could be used in many different ways. One extreme would be hundreds of buttons, another perhaps more variable controls but with reduced bit depth, say 14 four bit rotary devices. It’s a shame that there is not a back channel that had several arbitrary bytes that could be sent back from the cortex for feedback and display purposes. Now we could use the programming port for such things but I’m not sure as the the legality of this.

This would be quite trivial but I don’t have an old style remote, we do have one at school so perhaps I can do this in the fall when everyone returns.

3 Likes

James,

When I tried to compile the attached file I get a number of compiler errors, I’m using Arduino 1.01, is there something I also need to download and install to get this to compile? I saw very similar errors trying to compile the SNtoVex sample.

Thanks in advance. Kb

Here’s the output from the compiler error window:

PS3ToVex2:59: error: expected class-name before ‘{’ token
PS3ToVex2:61: error: ‘ACM’ has not been declared
PS3ToVex2:65: error: ‘uint8_t PLAsyncOper::OnInit’ is not a static member of ‘class PLAsyncOper’
PS3ToVex2:65: error: ‘ACM’ was not declared in this scope
PS3ToVex2:65: error: ‘pacm’ was not declared in this scope
PS3ToVex2:66: error: expected ‘,’ or ‘;’ before ‘{’ token
PS3ToVex2:96: error: ‘USB’ does not name a type
PS3ToVex2:97: error: ‘USBHub’ does not name a type
PS3ToVex2:98: error: ‘USBHub’ does not name a type
PS3ToVex2:101: error: ‘PS3USB’ does not name a type
PS3ToVex2:105: error: ‘PL2303’ does not name a type
PS3ToVex2.cpp: In function ‘void setup()’:
PS3ToVex2:155: error: ‘Usb’ was not declared in this scope
PS3ToVex2.cpp: In function ‘void loop()’:
PS3ToVex2:184: error: ‘Usb’ was not declared in this scope
PS3ToVex2:187: error: ‘PS3’ was not declared in this scope
PS3ToVex2:190: error: ‘RightHatX’ was not declared in this scope
PS3ToVex2:191: error: ‘RightHatY’ was not declared in this scope
PS3ToVex2:192: error: ‘LeftHatY’ was not declared in this scope
PS3ToVex2:193: error: ‘LeftHatX’ was not declared in this scope
PS3ToVex2:200: error: ‘DOWN’ was not declared in this scope
PS3ToVex2:202: error: ‘LEFT’ was not declared in this scope
PS3ToVex2:204: error: ‘UP’ was not declared in this scope
PS3ToVex2:206: error: ‘RIGHT’ was not declared in this scope
PS3ToVex2:209: error: ‘CROSS’ was not declared in this scope
PS3ToVex2:211: error: ‘SQUARE’ was not declared in this scope
PS3ToVex2:213: error: ‘TRIANGLE’ was not declared in this scope
PS3ToVex2:215: error: ‘CIRCLE’ was not declared in this scope
PS3ToVex2:220: error: ‘L2’ was not declared in this scope
PS3ToVex2:222: error: ‘L1’ was not declared in this scope
PS3ToVex2:225: error: ‘R2’ was not declared in this scope
PS3ToVex2:227: error: ‘R1’ was not declared in this scope
PS3ToVex2:232: error: ‘aY’ was not declared in this scope
PS3ToVex2:233: error: ‘aX’ was not declared in this scope
PS3ToVex2.cpp: In function ‘void VexDataTransmit()’:
PS3ToVex2:320: error: ‘Pl’ was not declared in this scope

Kevin

Looks like you did not install the USB library, it needs to be in the “libraries” folder of the Arduino documents folder.

Also, don’t forget this if you are using the PL2303 adapter.

1 Like

well oops I forgot to install it with the new version of Arduino I installed.
so now I get a new set of errors.

PS3ToVex2.cpp: In function ‘void loop()’:
PS3ToVex2:196: error: ‘class PS3USB’ has no member named ‘buttonChanged’
PS3ToVex2:200: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:202: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:204: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:206: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:209: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:211: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:213: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:215: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:220: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:222: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:225: error: ‘class PS3USB’ has no member named ‘getButton’
PS3ToVex2:227: error: ‘class PS3USB’ has no member named ‘getButton’

Any advice? I’ll keep looking and post any updates

Cheers Kb

I was able to successfully compile the example PS3USB.ino in Oleg’s library example directory

1 Like

Kevin

Well, the USB library has changed since I posted the code. getButton has been replaced with getButtonPress, buttonChanged has been removed altogether. Modify the code as follows;

    // If we are connected then gather all the data
    if(PS3.PS3Connected || PS3.PS3NavigationConnected)
      {
      // Get analog joystick data
      MyVexData.data.js_1 = PS3.getAnalogHat(RightHatX); 
      MyVexData.data.js_2 = PS3.getAnalogHat(RightHatY); 
      MyVexData.data.js_3 = PS3.getAnalogHat(LeftHatY); 
      MyVexData.data.js_4 = PS3.getAnalogHat(LeftHatX); 
    
      // Any buttons changed from last time ?      
//      if(PS3.buttonChanged)
//        {     
        MyVexData.data.button_78 = 0;
         
        if( PS3.getButtonPress(DOWN) )
          MyVexData.data.button_78 |= 0x01;
        if( PS3.getButtonPress(LEFT) )
          MyVexData.data.button_78 |= 0x02;
        if( PS3.getButtonPress(UP) )
          MyVexData.data.button_78 |= 0x04;
        if( PS3.getButtonPress(RIGHT) )
          MyVexData.data.button_78 |= 0x08;
          
        if( PS3.getButtonPress(CROSS) )
          MyVexData.data.button_78 |= 0x10;
        if( PS3.getButtonPress(SQUARE) )
          MyVexData.data.button_78 |= 0x20;
        if( PS3.getButtonPress(TRIANGLE) )
          MyVexData.data.button_78 |= 0x40;
        if( PS3.getButtonPress(CIRCLE) )
          MyVexData.data.button_78 |= 0x80;
        
        MyVexData.data.button_56 = 0;
      
        if( PS3.getButtonPress(L2) )
          MyVexData.data.button_56 |= 0x01;
        if( PS3.getButtonPress(L1) )
          MyVexData.data.button_56 |= 0x02;
          
        if( PS3.getButtonPress(R2) )
          MyVexData.data.button_56 |= 0x04;
        if( PS3.getButtonPress(R1) )
          MyVexData.data.button_56 |= 0x08;
 //       }
      
      // Accelerometer data  
      MyVexData.data.accel_y = PS3.getSensor(aY);
      MyVexData.data.accel_x = PS3.getSensor(aX);
      MyVexData.data.accel_z = 0x7f;
      }

I cannot try this as the PS3 went with my son to Berkeley, at some point I will pickup another controller and retest everything. Open source code is always a moving target, they should have changed the version number to 2.01 or something, perhaps they did and I missed it.

1 Like

It seems as though the PS3USB module is the one which changed and it is included as an example vs integral to the USB library so I think that’s why the USB library version didn’t change.

Well you bring up a good point, my son just came home for the holiday and took his PS3 back with him as well. The only USB based gamepad I can find is the Logitech f310. I see for your SNtoVex project you have a parser for the Space Navigator module. Is it that difficult to get information to build a parser for say the Logitech F310? I’d be interested in tackling that. You can email me directly if you want.
Thanks Kb

1 Like

Difficult is relative, all you need to do is find (or reverse engineer) the HID report details for the Logitech and then create a new class in the same way as I created a class for the space navigator. So is it hard? Not really, but if you have never done this type of thing then perhaps it is.

1 Like

Very interesting work with usb host and arduino. thanks for sharing the information.