Controlling a robotic car with a PS2 Controller (Joystick)
Rick Price
Posts: 36
I am new, so I don't know if this has been discussed in detail already, if so, sorry, and please point me at the relevant thread.
I am controlling a three wheeled (two driven wheels with an idler, in a triangle shape) robotic car with a PS2 controller joystick.
I have it working as far as it goes, but want some ideas on how to translate the position of the joystick to the PWM duty to the wheels.
One thing I noticed while watching the numbers coming back from the controller is that the joystick rarely if ever actually centers, so the reading can be off by at least 15 points from 128 (0-255 value for each axis on the joysticks with 128 being the center). I am also using a PWM Drive duty from -100%-0-100%, with negative generally meaning to go in reverse.
Because I don't want to waste battery power *almost* driving the motors all the time, I create a dead-zone in the joystick values when the value is between 154 and 101 (basically I use the 100 lowest and highest values and directly map them to the PWM signal).
Now maybe I am making things more complicated than they should be, but I am trying to find the best way to map the left/right -100-0-100 signal and the forward/back -100-0-100 signal.
I would like the car to remain easy to drive in a straight line, but also be able to do a spin about it's axis by turning one motor forward and the other backward if the controller is hard to the left or right (?maybe this should be a separate mode when the car is being driven slowly?).
I find that the method I am using now is too sensitive/awkward (probably because the joystick is so small, and the large dead zone), and perhaps I need to increase my sampling rate on the joystick (4 updates per second currently).
I was wondering if there were any ideas for better solutions than what I have so far?
UpdatePWM is run in a hard loop from the main cog.
PWM frequency is 40khz
The wheels are driven by a plastic gearmotor drivetrain which includes the small motor that runs on about 3v.
+++ CURRENT JOYSTICK ALGORITHM HERE +++
PUB Main
Serial.init(31, 30, 19200) 'Use the USB connection that is used to progam the Propeller.
LeftWheel.Start(LW_enable,LW_forward,LW_forwardInverse,PWM_frequency)
RightWheel.Start(RW_enable,RW_forward,RW_forwardInverse,PWM_frequency)
PS2.Start(PS2_pinBlockStart, PS2_pollFrequency)
Repeat
UpdatePWM
PUB UpdatePWM | LeftMotorDuty, RightMotorDuty
waitcnt(clkfreq/4 + cnt)
LeftMotorDuty:=NormalizeJoystickValue(PS2.get_LeftY)
RightMotorDuty:=NormalizeJoystickValue(PS2.get_LeftY)
LeftMotorDuty -=NormalizeJoystickValue(PS2.get_LeftX)
RightMotorDuty +=NormalizeJoystickValue(PS2.get_LeftX)
LeftWheel.SetDuty(LeftMotorDuty)
RightWheel.SetDuty(RightMotorDuty)
' LeftWheel.SetDuty(NormalizeJoystickValue(PS2.get_LeftY))
' RightWheel.SetDuty(NormalizeJoystickValue(PS2.get_RightY))
'Serial.str(Num.dec(Pulse_High_Ticks))
'Serial.str(Num.dec(Pulse_Low_Ticks))
'Serial.str(Num.dec(Delay_Ticks))
Serial.str(Num.ihex(PS2.get_Data1,8))
Serial.str(Num.ihex(PS2.get_Data2,8))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_RightX),4))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_RightY),4))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_LeftX),4))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_LeftY),4))
Serial.str(string(" "))
'Send carriage return so no new line is created and data is overwritten in the same line
Serial.tx(13)
PUB NormalizeJoystickValue(joystickValue) : normalizedValue
joystickValue := joystickValue-128
if (||joystickValue > 28)
if (joystickValue > 0)
return joystickValue-27
else
return (||joystickValue-28)*-1
else
return 0
return joystickValue
I am controlling a three wheeled (two driven wheels with an idler, in a triangle shape) robotic car with a PS2 controller joystick.
I have it working as far as it goes, but want some ideas on how to translate the position of the joystick to the PWM duty to the wheels.
One thing I noticed while watching the numbers coming back from the controller is that the joystick rarely if ever actually centers, so the reading can be off by at least 15 points from 128 (0-255 value for each axis on the joysticks with 128 being the center). I am also using a PWM Drive duty from -100%-0-100%, with negative generally meaning to go in reverse.
Because I don't want to waste battery power *almost* driving the motors all the time, I create a dead-zone in the joystick values when the value is between 154 and 101 (basically I use the 100 lowest and highest values and directly map them to the PWM signal).
Now maybe I am making things more complicated than they should be, but I am trying to find the best way to map the left/right -100-0-100 signal and the forward/back -100-0-100 signal.
I would like the car to remain easy to drive in a straight line, but also be able to do a spin about it's axis by turning one motor forward and the other backward if the controller is hard to the left or right (?maybe this should be a separate mode when the car is being driven slowly?).
I find that the method I am using now is too sensitive/awkward (probably because the joystick is so small, and the large dead zone), and perhaps I need to increase my sampling rate on the joystick (4 updates per second currently).
I was wondering if there were any ideas for better solutions than what I have so far?
UpdatePWM is run in a hard loop from the main cog.
PWM frequency is 40khz
The wheels are driven by a plastic gearmotor drivetrain which includes the small motor that runs on about 3v.
+++ CURRENT JOYSTICK ALGORITHM HERE +++
PUB Main
Serial.init(31, 30, 19200) 'Use the USB connection that is used to progam the Propeller.
LeftWheel.Start(LW_enable,LW_forward,LW_forwardInverse,PWM_frequency)
RightWheel.Start(RW_enable,RW_forward,RW_forwardInverse,PWM_frequency)
PS2.Start(PS2_pinBlockStart, PS2_pollFrequency)
Repeat
UpdatePWM
PUB UpdatePWM | LeftMotorDuty, RightMotorDuty
waitcnt(clkfreq/4 + cnt)
LeftMotorDuty:=NormalizeJoystickValue(PS2.get_LeftY)
RightMotorDuty:=NormalizeJoystickValue(PS2.get_LeftY)
LeftMotorDuty -=NormalizeJoystickValue(PS2.get_LeftX)
RightMotorDuty +=NormalizeJoystickValue(PS2.get_LeftX)
LeftWheel.SetDuty(LeftMotorDuty)
RightWheel.SetDuty(RightMotorDuty)
' LeftWheel.SetDuty(NormalizeJoystickValue(PS2.get_LeftY))
' RightWheel.SetDuty(NormalizeJoystickValue(PS2.get_RightY))
'Serial.str(Num.dec(Pulse_High_Ticks))
'Serial.str(Num.dec(Pulse_Low_Ticks))
'Serial.str(Num.dec(Delay_Ticks))
Serial.str(Num.ihex(PS2.get_Data1,8))
Serial.str(Num.ihex(PS2.get_Data2,8))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_RightX),4))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_RightY),4))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_LeftX),4))
Serial.str(Num.decf(NormalizeJoystickValue(PS2.get_LeftY),4))
Serial.str(string(" "))
'Send carriage return so no new line is created and data is overwritten in the same line
Serial.tx(13)
PUB NormalizeJoystickValue(joystickValue) : normalizedValue
joystickValue := joystickValue-128
if (||joystickValue > 28)
if (joystickValue > 0)
return joystickValue-27
else
return (||joystickValue-28)*-1
else
return 0
return joystickValue