Close

PS3 controller I2C concerns

A project log for Building the Thor robot

Building a 6-axis robot based on the Thor robot. When size DOES matter!

olaf-baeyensOlaf Baeyens 04/02/2017 at 01:005 Comments

When testing the PS3-controller USB 2.4 Host I discovered 2 concerns in using to control a robot that could mess up the safety

http://www.hobbytronics.co.uk/ps3-controller-bluetooth

I originally thought that my Ultratronics board (Arduino due) was freezing when I was reading in variable from the PS3-controller USB 2.4 Host.

But it turns out that the the firmware for the I2C may be freezing and not return data anymore when I2C is being used.

The code to retrieve the data is below.

void get_ps3()
{
  int bytesToRead=28;
  
  // Get data from PS3 DualShock Controller
  // We only want single byte values (0 to 255)
  // We use a pointer to the ps3 struct we defined so we can populate the data in sequence

  uint8_t *ps3Ptr = (uint8_t *)&ps3;    // Create pointer to ps3 struct
  
  unsigned char data_values_rcvd=0;     // keep track of how many characters received    
  Wire.beginTransmission(I2C_ADDRESS);  // transmit to device
  Wire.write(0);                        // Start receiving data from register 0
  Wire.endTransmission();               // end transmission
  
  // To retrieve all data we need 35 bytes, but restriction in Arduino means
  // we can only get 32 bytes at one go, so we split it into 2 reads
  
  Wire.requestFrom(I2C_ADDRESS, bytesToRead);    // request 28 bytes from PS3 
  data_values_rcvd=0; 
  while(Wire.available())
  { 
    *ps3Ptr++ = Wire.read();            // receive a byte and increment pointer address
    data_values_rcvd++;
  }

  Wire.beginTransmission(I2C_ADDRESS);  // transmit to device
  Wire.write(28);                       // Start receiving data from register 28
  Wire.endTransmission();               // end transmission  
  Wire.requestFrom(I2C_ADDRESS, PS3_DATA_SIZE-bytesToRead);    // request outstanding bytes from PS3 
  while(Wire.available())
  { 
    *ps3Ptr++ = Wire.read();            // receive a byte and increment pointer address
    data_values_rcvd++;
  }  
  
}

It is split into 2 parts.

Using that code I starts to fail receiving correct data when I have to read the second 7 bytes.

The number of bytes received is still correct, but the contents of the data coming from the PS3 controlled does not change anymore and returns the last known values.

Now when I modify the code that I only read in 28 bytes

void get_ps3()
{
  int bytesToRead=28;
  
  // Get data from PS3 DualShock Controller
  // We only want single byte values (0 to 255)
  // We use a pointer to the ps3 struct we defined so we can populate the data in sequence

  uint8_t *ps3Ptr = (uint8_t *)&ps3;    // Create pointer to ps3 struct
  
  unsigned char data_values_rcvd=0;     // keep track of how many characters received    
  Wire.beginTransmission(I2C_ADDRESS);  // transmit to device
  Wire.write(0);                        // Start receiving data from register 0
  Wire.endTransmission();               // end transmission
  
  // To retrieve all data we need 35 bytes, but restriction in Arduino means
  // we can only get 32 bytes at one go, so we split it into 2 reads
  
  Wire.requestFrom(I2C_ADDRESS, bytesToRead);    // request 28 bytes from PS3 
  data_values_rcvd=0; 
  while(Wire.available())
  { 
    *ps3Ptr++ = Wire.read();            // receive a byte and increment pointer address
    data_values_rcvd++;
  }
 return ;
...
}

I now get more stability but the locking still happens at random. Less likely but unacceptable on a robot in regard of safety.

I revert the change to read 35 bytes but now slow down the number of times per second I read in the p3 settings.

void loop()
{
  unsigned char i;

  currentTime = millis();
    
  if(currentTime >= (ps3ReadTime + 50)){  
    // Get data from PS3 Controller every 50ms
    get_ps3(); 
    if (ps3.btn_up) {
      digitalWrite(LED_BUILTIN, HIGH);   
    } else { 
      digitalWrite(LED_BUILTIN, LOW);   
    }
    ps3ReadTime = currentTime;  // Updates ps3ReadTime
  }
  
  if(currentTime >= (ps3PrintTime + 200))
  { 
    // Print out our data to serial port every 200ms
    //print_ps3();
    ps3PrintTime = currentTime;  // Updates ps3PrintTime
  }
delay(200);
}
This delay(200) appears to make the ps3 controller also stable but still the issue persists if you try long enough..

My direct guess is that we have an firmware "locking" issue.


There is another thing that gives a clue that there is a bug in the firmware. When you power on the Ultratronics board but do not pair yet the USB host controller to a PS3. I receive random values. (I notice these values clearly when I connect one button to the debug LED).

The debug LED finally comes to rest once paired to a PS3 controller never giving any random value anymore.


The danger here is that the robot may come into action when the controller freezes or when the robot receives random commands. This cannot be accepted.

Discussions

Olaf Baeyens wrote 02/21/2018 at 21:41 point

Hello Sepio, I used all I2C's I found.

What I did was connect a button to the debug LED, and tested a loop to see the lag. After many presses the I2C communication somehow messed up.

I propose you to do this kind of test before you put a live robot behind it :-)

  Are you sure? yes | no

Sepio wrote 02/23/2018 at 12:19 point

If you look at your photo at the right side of your LAN connector and go about 1 cm Up there is a 2x4 pin connector. According to the documentation that are the 2 I2C ports.

  Are you sure? yes | no

dannyvandenheuvel wrote 02/21/2018 at 21:27 point

Hi Sepio,

Did you make use of crc check? I don't mark any issues so far at my remote movements.
It could be that there will be a bad package but it won't be accepted and thrown away in my program.

Where did you take the I2C pins? mine are taken from another place, look at my drawing sheet.
From my place you have to put some additional resistors.

Greetz..

  Are you sure? yes | no

Sepio wrote 02/21/2018 at 01:30 point

Hi Olaf,

Why are you using the analog pin header and not 1 of the 2 dedicated I2C ports on the right? 

I already used resistors to pull the line to 3.3v.

  Are you sure? yes | no

Olaf Baeyens wrote 02/23/2018 at 23:32 point

There is a 3rd I2C. I tried the other 2 before. The picture I took was the last trial if I remember correctly.

  Are you sure? yes | no