Playstation 2 Controller, Arduino Uno Rev 3, Polulu Qik2s9v1

Hi all! I’m a Mechanical Engineer and so naturally writing code is not my forte but i’m learning what i can. For my senor thesis project my group is buiding a remote inspection vehicle and i’m using a Arduino Uno rev3 micro controller along with the Polulu Qik 2s9v1 motor controller to control the robot in skid steer. I would like to control the robot wirelessly with the Lynxmotion PS2 controller but i can’t seem to find the correct library online to load onto the Arduino. Any suggestions? How else do i go about doing this?

Also what are the best programs/ debugging programs to test these setups. I’m using the arduino uploading ultility to load sketches but it does provide any feedback. I have also tried the polulu serial transmitter but that program is just on another world. Any help is appreciated.

PlayStation 2 controller. The main library that most people use is by Bill porter.
billporter.info/2010/06/05/p … rary-v1-0/
I know that Lynxmotion has a fork of his code up on Github: github.com/Lynxmotion/Arduino-PS2X

As for debugging, I use a lot of Serial.print type statements. Also depending on which boards you are using, I also use LEDS on the board to indicate status. Also I use a Logic Analyzer to debug stuff (www.saleae.com)

Good Luck
KUrt

{Duplicate Kurte’s answer}

Thanks, very hupfull. Was able to integrate everything however now I’m getting an error that is shutting down the motor. I circumnavigated that and disabled the auto shutdown feature of the polulu to be able to run the motors for testing. The are running however are incredibly unresponsive. They are not responding according to joystick position however seem to max out at the values (i.e. if i hit the joystick forward the motor will stay full speed until i pull all the way back on the joystick). Only for Motor 0 (M0), Motor 1 (M1) working only for a few seconds, now however it is only moving at incredibly slow speeds even though the joystick is out putting the appropriate values, i pulled those motors and tested them to ensure they weren’t borken and they worked fine when connected directly to the battery so it must be somewhere in the programming. I’ve included my sketch below. I’ve exhausted my troubleshooting abilities. So please help if you can.

I’m only programming the joysticks for now, so the important stuff is at the bottom. The error must be somewhere in the setup but i do not know where and I don’t need to mapping for guitar hero controller and such. Is it okay to remove it to increase the programs speed?

Also the polulu is running in 7-bit (-127 to 127) for motors full speed reverse and forward. So the leftPos= and rightPos= convert the 0-255 to appropriate values.

[code]
/*
Optionally writes, then reads, the configuration parameters on the qik 2s9v1.

Please note that the memory used to store these parameters is only rated
for approximately 100,000 erase/write cycles, so you should avoid
repeatedly setting configuration parameters. It is intended that these
parameters will initially be configured as desired and then only changed
occasionally (they are saved in non-volatile memory, which means that
once set, these parameters will retain their values even if the unit is
powered off). For example, you can uncomment the appropriate calls to
setConfigShowResult() below and run this program once to initialize the
parameters. Then, you can load your final program on your Arduino, which
should assume that the parameters have already been set correctly.

Required connections between Arduino and qik 2s9v1:

Arduino qik 2s9v1

5V - VCC
GND - GND
Digital Pin 2 - TX
Digital Pin 3 - RX
Digital Pin 4 - RESET
*/

#include <SoftwareSerial.h>
#include <PololuQik.h>
#include <PS2X_lib.h> //for v1.6

PS2X ps2x; // create PS2 Controller Class

//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you conect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = 0;
byte type = 0;
byte vibrate = 0;

char* param_names] = {
“Device ID”,
“PWM Parameter”,
“Shut Down Motors on Error”,
“Serial Timeout”
};

PololuQik2s9v1 qik(2, 3, 4);

void setConfigShowResult(uint8_t parameter, uint8_t value)
{
Serial.print("Setting “);
Serial.print(param_names[parameter]);
Serial.print(” to ");
Serial.print(value);

byte result = qik.setConfigurationParameter(parameter, value);

switch (result)
{
case 0:
Serial.println(": Command OK");
break;

case 1:
Serial.println(": Bad parameter");
break;

case 2:
Serial.println(": Bad value");
break;
}
}

void setup()
{
Serial.begin(115200);
//Serial.begin(57600);
Serial.println(“qik 2s9v1 dual serial motor controller”);
Serial.println();

qik.init();

// Write configuration parameters
// Uncomment and edit the line for any parameter you want to change.

//setConfigShowResult(QIK_CONFIG_DEVICE_ID, 9);
//setConfigShowResult(QIK_CONFIG_PWM_PARAMETER, 0);
setConfigShowResult(QIK_CONFIG_SHUT_DOWN_MOTORS_ON_ERROR, 0);
//setConfigShowResult(QIK_CONFIG_SERIAL_TIMEOUT, 0);

Serial.println();

// Read configuration parameters

for (int i = QIK_CONFIG_DEVICE_ID; i <= QIK_CONFIG_SERIAL_TIMEOUT; i++)
{
Serial.print(param_names*);
Serial.print(": ");
Serial.println(qik.getConfigurationParameter(i));
}
//CHANGES for v1.6 HERE!!! *PAY ATTENTION

error = ps2x.config_gamepad(13,11,10,12, true, true); //setup pins and settings: GamePad(clock, command,

attention, data, Pressures?, Rumble?) check for error

if(error == 0){
Serial.println(“Found Controller, configured successful”);
Serial.println(“Try out all the buttons, X will vibrate the controller, faster as you press harder;”);
Serial.println(“holding L1 or R1 will print out the analog stick values.”);
Serial.println(“Go to http://www.billporter.info for updates and to report bugs.”);
}

else if(error == 1)
Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit http://www.billporter.info

for troubleshooting tips");

else if(error == 2)
Serial.println("Controller found but not accepting commands. see readme.txt to enable debug. Visit

http://www.billporter.info for troubleshooting tips");

else if(error == 3)
Serial.println("Controller refusing to enter Pressures mode, may not support it. ");

//Serial.print(ps2x.Analog(1), HEX);

type = ps2x.readType();
switch(type) {
case 0:
Serial.println(“Unknown Controller type”);
break;
case 1:
Serial.println(“DualShock Controller Found”);
break;
case 2:
Serial.println(“GuitarHero Controller Found”);
break;
}

}

void loop(){
/* You must Read Gamepad to get new values
Read GamePad and set vibration values
ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255)
if you don’t enable the rumble, use ps2x.read_gamepad(); with no values

you should call this at least once a second
*/

if(error == 1) //skip loop if no controller found
return;

if(type == 2){ //Guitar Hero Controller

ps2x.read_gamepad();          //read controller 

if(ps2x.ButtonPressed(GREEN_FRET))
  Serial.println("Green Fret Pressed");
if(ps2x.ButtonPressed(RED_FRET))
  Serial.println("Red Fret Pressed");
if(ps2x.ButtonPressed(YELLOW_FRET))
  Serial.println("Yellow Fret Pressed");
if(ps2x.ButtonPressed(BLUE_FRET))
  Serial.println("Blue Fret Pressed");
if(ps2x.ButtonPressed(ORANGE_FRET))
  Serial.println("Orange Fret Pressed");


if(ps2x.ButtonPressed(STAR_POWER))
  Serial.println("Star Power Command");

if(ps2x.Button(UP_STRUM))          //will be TRUE as long as button is pressed
  Serial.println("Up Strum");
if(ps2x.Button(DOWN_STRUM))
  Serial.println("DOWN Strum");


if(ps2x.Button(PSB_START))                   //will be TRUE as long as button is pressed
  Serial.println("Start is being held");
if(ps2x.Button(PSB_SELECT))
  Serial.println("Select is being held");


if(ps2x.Button(ORANGE_FRET)) // print stick value IF TRUE
{
  Serial.print("Wammy Bar Position:");
  Serial.println(ps2x.Analog(WHAMMY_BAR), DEC); 
} 

}

else { //DualShock Controller

ps2x.read_gamepad(false, vibrate);          //read controller and set large motor to spin at 'vibrate' speed

if(ps2x.Button(PSB_START))                   //will be TRUE as long as button is pressed
  Serial.println("Start is being held");
if(ps2x.Button(PSB_SELECT))
  Serial.println("Select is being held");


if(ps2x.Button(PSB_PAD_UP)) {         //will be TRUE as long as button is pressed
  Serial.print("Up held this hard: ");
  Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC);
}
if(ps2x.Button(PSB_PAD_RIGHT)){
  Serial.print("Right held this hard: ");
  Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC);
}
if(ps2x.Button(PSB_PAD_LEFT)){
  Serial.print("LEFT held this hard: ");
  Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC);
}
if(ps2x.Button(PSB_PAD_DOWN)){
  Serial.print("DOWN held this hard: ");
  Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC);
}   


vibrate = ps2x.Analog(PSAB_BLUE);        //this will set the large motor vibrate speed based on 
//how hard you press the blue (X) button    

if (ps2x.NewButtonState())               //will be TRUE if any button changes state (on to off, or off to on)
{



  if(ps2x.Button(PSB_L3))
    Serial.println("L3 pressed");
  if(ps2x.Button(PSB_R3))
    Serial.println("R3 pressed");
  if(ps2x.Button(PSB_L2))
    Serial.println("L2 pressed");
  if(ps2x.Button(PSB_R2))
    Serial.println("R2 pressed");
  if(ps2x.Button(PSB_GREEN))
    Serial.println("Triangle pressed");

}   


if(ps2x.ButtonPressed(PSB_RED))             //will be TRUE if button was JUST pressed
  Serial.println("Circle just pressed");

if(ps2x.ButtonReleased(PSB_PINK))             //will be TRUE if button was JUST released
  Serial.println("Square just released");     

if(ps2x.NewButtonState(PSB_BLUE))            //will be TRUE if button was JUST pressed OR released
  Serial.println("X just changed");    


if(ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) // print stick values if either is TRUE
{
  Serial.print("Stick Values:");
  Serial.print(ps2x.Analog(PSS_LY), DEC); //Left stick, Y axis. Other options: LX, RY, RX  
  Serial.print("LY,");
  Serial.print(ps2x.Analog(PSS_LX), DEC); 
  Serial.print("LX,");
  Serial.print(ps2x.Analog(PSS_RY), DEC); 
  Serial.print("RY,");
  Serial.print(ps2x.Analog(PSS_RX), DEC); 
  Serial.println("RX,");


  int leftPos = -ps2x.Analog(PSS_LY)+126;
  int rightPos = -ps2x.Analog(PSS_RY)+126;

  Serial.println(leftPos);
  Serial.println(rightPos);
  if(abs(leftPos) > 6)
  {
    qik.setM0Speed(leftPos);
  }
  else
    qik.setM0Speed(0);
  
  if(abs(rightPos) > 6)
  {
    qik.setM1Speed(rightPos);
  }
  else
    qik.setM0Speed(0);
  
} 

}

delay(50);

}[/code]*

The problems I see here are that you started off with a PS2 test program that had tons of unnecessary stuff for your usage… So it is hard to figure out what your stuff is doing and what is not working… For example I think your code is only handling one way on the joysticks and only when buttons are pressed. In addition to this, it is printing a bunch of stuff out to the serial port which also eats up time…

Note: I have a version of my Rover code for the Arduino using a Sabertooth or a Roboclaw controller up on a different thread: viewtopic.php?t=8543&p=85426#p85426

The code is a port of some code originally done by Xan. Hope that helps

Kurt

Ah okay. I did only intend to use one axis on the joysticks as it’s a skid steer robot so each joystick handles each side of the skid steer. I’ll clean up the code and see if that helps, thanks

Just use the X-Y from the joystick, and translate to skid-steer.

Motor controller can even do that for you.

Alan KM6VV

Hey, the program has been coming along great however I am having some new difficulties after attaching a few servos to the arduino. The motors are running just and proper and so are the servo, separately. However once everything is connected and I attempt to move with the motors the servos also try to move as well although I am not pressing any of the buttons mapped to the servos. I am not sure if it could be my code or could it be the fact that the two are drawing off the same power supply is the problem?

[code]
/*
Required connections between Arduino and qik 2s9v1:

Arduino qik 2s9v1

5V - VCC
GND - GND
Digital Pin 2 - TX
Digital Pin 3 - RX
Digital Pin 4 - RESET
*/
#include <SoftwareSerial.h>
#include <PololuQik.h>
#include <PS2X_lib.h>
#include <Servo.h>

PS2X ps2x;
int error = 0;
int leftPos = 0;
int rightPos = 0;
byte type = 0;
byte vibrate = 0;
Servo servo1;
Servo servo2;
Servo servo3;
int servo1Pos = 90;
int servo2Pos = 60;
int servo3Pos = 60;

char* param_names] = {
“Device ID”,
“PWM Parameter”,
“Shut Down Motors on Error”,
“Serial Timeout”
};

PololuQik2s9v1 qik(2, 3, 4);

void setConfigShowResult(uint8_t parameter, uint8_t value)
{
Serial.print("Setting “);
Serial.print(param_names[parameter]);
Serial.print(” to ");
Serial.print(value);

byte result = qik.setConfigurationParameter(parameter, value);

switch (result)
{
case 0:
Serial.println(": Command OK");
break;

case 1:
Serial.println(": Bad parameter");
break;

case 2:
Serial.println(": Bad value");
break;
}
}

void setup()
{
Serial.begin(115200);
Serial.println(“qik 2s9v1 dual serial motor controller”);

qik.init();

// Write configuration parameters
// Uncomment and edit the line for any parameter you want to change.

//setConfigShowResult(QIK_CONFIG_DEVICE_ID, 9);
//setConfigShowResult(QIK_CONFIG_PWM_PARAMETER, 0);
setConfigShowResult(QIK_CONFIG_SHUT_DOWN_MOTORS_ON_ERROR, 0);
//setConfigShowResult(QIK_CONFIG_SERIAL_TIMEOUT, 0);

Serial.println();

// Read configuration parameters

for (int i = QIK_CONFIG_DEVICE_ID; i <= QIK_CONFIG_SERIAL_TIMEOUT; i++)
{
Serial.print(param_names*);
Serial.print(": ");
Serial.println(qik.getConfigurationParameter(i));
}

error = ps2x.config_gamepad(13,11,10,12, true, true); //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error

if(error == 0){
Serial.println(“Found Controller, configured successful”);
Serial.println(“Try out all the buttons, X will vibrate the controller, faster as you press harder;”);
Serial.println(“holding L1 or R1 will print out the analog stick values.”);
Serial.println(“Go to http://www.billporter.info for updates and to report bugs.”);
}
type = ps2x.readType();
switch(type) {
case 0:
Serial.println(“Unknown Controller type”);
break;
case 1:
Serial.println(“DualShock Controller Found”);
break;
case 2:
Serial.println(“GuitarHero Controller Found”);
break;
}
servo1.attach(6);
servo2.attach(7);
servo3.attach(8);
}

void loop()
{
if(error == 1) //skip loop if no controller found
return;
ps2x.read_gamepad(); //read controller and set large motor to spin at ‘vibrate’ speed

ps2x.read_gamepad(ps2x.Analog(PSS_LY), DEC);

ps2x.read_gamepad(ps2x.Analog(PSS_RY), DEC);
leftPos = -ps2x.Analog(PSS_LY)+127.5;
rightPos = -ps2x.Analog(PSS_RY)+127.5;

qik.setM0Speed(leftPos);
qik.setM1Speed(-rightPos);

if(ps2x.Button(PSB_L1))
{
if (servo1Pos > 0)
{
servo1Pos -= 1;
servo1.write(servo1Pos);

}

}
if(ps2x.Button(PSB_L2))
{
if (servo1Pos <= 160)
{
servo1Pos += 1;
servo1.write(servo1Pos);

}

}
if(ps2x.Button(PSB_R1))
{
if (servo2Pos > 0)
{
servo2Pos -= 1;
servo2.write(servo2Pos);

}

}
if(ps2x.Button(PSB_R2))
{
if (servo2Pos <= 120)
{
servo2Pos += 1;
servo2.write(servo2Pos);

}

}
if(ps2x.Button(PSB_GREEN))
{
if (servo3Pos > 0)
{
servo3Pos -= 1;
servo3.write(servo3Pos);

}

}
if(ps2x.Button(PSB_RED))
{
if (servo3Pos <= 120)
{
servo3Pos += 1;
servo3.write(servo3Pos);

}

}
}[/code]*

The problem is soft-of complex and no real simple solution. The issue is, the servo library relies on interrupts that need to be processed in a very timely manner. In simple terms it acts like: it gets a timer interrupt, it changes the IO line associated with a servo high, it sets up to be interrupted again, and then when that interrupt happens it puts the IO line back down. The amount of CPU cycles between the time the system requests the interrupt to the time the actual interrupt handling code is hopefully pretty consistent, such that you can get consistent pulse widths. If the width is not the correct width the servos will move.

The issue is that your Qik2s use a serial interface, that I believe is using the SoftwareSerial library. When you output a character using Software Serial it disables interrupts for the complete time it takes to output one byte, likewise if it starts to receive a character back from the serial port, it leaves interrupts disabled for the time it takes to receive the character.

So suppose the servo library is outputting a simple 1500us pulse to a servo (center), and suppose your are communicating with your servo controller at the maximum baud rate 38400. It takes about (1000000/(38400/10) or about 260us to output one character. So now suppose the servo driver had started the pulse and just before the interrupt came in to bring the servo low, you started an output which disabled the interrupt, the interrupt will then be processed after interrupts are reenabled. So that 1500us pulse may turn into something like 1500+260 or 1760us, which will cause that servo to jerk some.

Hope that makes sense.
Kurt

Okay. It makes sense some, but only in the sense that I understand what your trying to say but not the meaning. Do you have any idea how I may fix it? Or is it even possible to fix it with the current set up and it is simply the code? Or may it be that I can’t run both the motors and the servos at the same time with the current set up.

The meaning is: if you do not get consistent servo pulses the servos will often jump around a little or a lot depending on what else is happening on the processor, for the reasons I mentioned.
if you google something like: software serial and servo library
You will see lots of discussions about this.

Obviously fixing it with additional hardware would the easiest. Things like use an SSC-32 to control the servos. Or if you were using an Arduino Mega, you could probably run the Qik2 off of one of the additional hardware uarts. Or you could use something like an Arduino Servo Shield…

Software wise, one could try some mucking with a couple of the Arduino Libraries, to make them work better with each other. Like try to add some form of handshake between the servo library and SoftwareSerial, that it will only output a character when it knows it has time, that will not interfere with a servo pulse… Not sure if anyone has actually tried doing this or not, but could be interesting.

If you had only 2 servos, I would suggest going with a PWM servo library, like you find different versions of up on the web, like: orionrobotics.com/FireAnt-He … p_248.html, which also has more things like timed moves…

But these only support 2 servos on the Arduino Uno and must be on pins 9, and 10. Why these pins? Because they are connected to the only 16 bit timer on an Arduino Uno. One could also try to use one of the other 2 8 bit timers to try to drive servos the same way, but the resolution would not be very good. It probably would not be hard to hack up the pwmservo to halfway support it.

Hope that helps
Kurt