RADU: Controlling Robot Movements with a Gamepad Controller using Python

The Gamepad Library

Button Configuration

import lib.Gamepad as Gamepad# Gamepad settings
gamepadType = Gamepad.PS4
# Axis
joystickSpeed = 'LEFT-Y'
joystickSteering = 'RIGHT-X'
digital_x = 'DPAD-X'
digital_y = 'DPAD-Y'
# Button
button_ps = 'PS'
button_triangle = "TRIANGLE"

Controller Connection

def wait_for_gamepad():  # Wait for a connection
if not Gamepad.available():
log_to_stdout_and_mqtt('Please connect your gamepad...')
while not Gamepad.available():
time.sleep(1.0)
gamepad = gamepadType()
return gamepad

Detecting Gamepad Button Presses

def main_loop(gamepad)
pollInterval = 0.01
gamepad.startBackgroundUpdates()
try:
while gamepad.isConnected():
if gamepad.beenPressed(button_triangle):
log_to_stdout("Triangle Button is Pressed")
# Sleep for our polling interval
time.sleep(pollInterval)
finally:
# Ensure the background thread is always terminated when we are done
gamepad.disconnect()
  • The pollInterval determines how often per second the button states will be checked
  • The complete button detection logic is enclosed in a try...catch block, mainly as a safeguard to release the gamepad if something goes wrong - alternatively you can define a custom context manager to handle the setup and teardown phases
  • A gamepads button state are checked with the beenPressed() method, which gets an argument of the earlier defined button layout. As shown here, you can use if statements to check their state, and then execute some command
  • At the end of the loop, a sleep command is issued with the defined pollInterval

Detecting the Digital and Analog Axis

def main_loop(gamepad)
#...
try:
while gamepad.isConnected():
# ...
speed = - gamepad.axis(joystickSpeed)
steering = - gamepad.axis(joystickSteering)
command = gamepad.axis(digital_x) log_to_stdout(f'Speed {speed}')
log_to_stdout(f'Steering {steering}')
engine_move(speed, steering, command) time.sleep(pollInterval)
finally:
# Ensure the background thread is always terminated when we are done
gamepad.disconnect()

Fine Tuning the Controls

def main_loop(gamepad)
#...
try:
while gamepad.isConnected():
if (mode == MOVE_MODE):
speed = -gamepad.axis(joystickSpeed)
steering = -gamepad.axis(joystickSteering)
if((speed != 0.0 or steering != 0.0) and not isStopped):
last_speed = speed
last_steeering = steering
engine_move(speed, steering)
else:
isStopped = True
time.sleep(pollInterval)
finally:
# Ensure the background thread is always terminated when we are done
gamepad.disconnect()

Controlling the Arm Movements

MOVE_MODE = 'MOVE_MODE'
ARM_MODE = 'ARM_MODE'
def main_loop(gamepad)
#...
while gamepad.isConnected():
if gamepad.beenPressed(button_ps):
if (mode == MOVE_MODE):
mode = ARM_MODE
else:
mode = MOVE_MODE
def main_loop(gamepad)
#...
try:
while gamepad.isConnected():
#...
if (mode == MOVE_MODE):
# ...
if (mode == ARM_MODE):
gripper_x = gamepad.axis(digital_x)
gripper_y = -gamepad.axis(digital_y)
if (gripper_x != 0.0):
arm.move_incr(SERVO_G, 4*int(gripper_x))
log_to_stdout_and_mqtt("X {}, Y {}".format(gripper_x, gripper_y))
if (gripper_y != -0.0):
arm.move_incr(SERVO_Z, 4*int(gripper_y ))
log_to_stdout_and_mqtt("X {}, Y {}".format(gripper_x, gripper_y ))
arm_x = gamepad.axis(joystickSteering)
arm_y = -gamepad.axis(joystickSpeed)
if (arm_x != 0.0):
arm.move_incr(SERVO_X, int(100*arm_x)/4)
log_to_stdout_and_mqtt("SERVO_X {} => {}".format(arm_x, int(100*arm_x)/4))
if (arm_y != -0.0):
arm.move_incr(SERVO_Y, int(100*arm_y)/4)
log_to_stdout_and_mqtt("SERVO_Y {} => {}".format(arm_y,int(100*arm_y)/4))
if gamepad.beenPressed(button_triangle):
arm.center()
time.sleep(pollInterval)
finally:
# Ensure the background thread is always terminated when we are done
gamepad.disconnect()

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sebastian

Sebastian

IT Project Manager & Developer