Andrew R GrossJonathan Gross
Published © CC BY-SA

Controlling a Robot with a PlayStation Controller

A USB Playstation controller controls brushless motors to drive a Remotely Operated Vehicle in real time over a USB connection

IntermediateFull instructions provided8 hours15,516
Controlling a Robot with a PlayStation Controller

Things used in this project

Hardware components

Sony USB Playstation 3 Controller
SONY DualShock 3 Wireless Controller
×1
Raspberry Pi 2 Model B
Raspberry Pi 2 Model B
×1
Arduino Nano R3
Arduino Nano R3
×1
18A Speed Controller (ESC) for Brushless RC car motors
×2
Brushless motor, 800kV
×1
XT60 5V/12V Power Distribution Board w/BEC
×1
3S LiPo Battery Pack, 2200 mAh 25C
×1
SparkFun USB to micro USB cable - 6"
×1
SparkFun USB to Mini USB cable - 6"
×1
XT60 Connectors
×1
SparkFun Solder, lead-free
×1
Servos (Tower Pro MG996R)
×1

Software apps and online services

Raspbian
Raspberry Pi Raspbian
Python 2.6
Arduino IDE
Arduino IDE
jstest-gtk

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
SparkFun Third hand for soldering

Story

Read more

Schematics

PS3 controller to motor diagram

A schematic of how the PS3 controller connects to the motors via the Raspberry Pi, the Arduino, and the ESCs

Code

controller-reader.py

Python
Reads in data from joysticks and sends it out as text over serial
#############################
### controller-reader.py -- Andrew R Gross -- 2017-11-12 -- andrew@shrad.org
###
### This program will read input from a joystick or videogame controller, format it, 
### and then send it over a serial channel so an Arduino can receive it.
### Rows that should be customized are commented with '#-# '.
###

import serial
import pygame
import time

#############################
### 1: Identify the controller

pygame.init()                                     # Initiate the pygame functions
j = pygame.joystick.Joystick(0)                   # Define a joystick object to read from
j.init()                                          # Initiate the joystick or controller
print 'Detected controller : %s' % j.get_name()   # Print the name of any detected controllers

#############################
### 2: Open a Serial Channel to the Arduino

serial_is_on = False                            #-# Make 'True' to attempt a serial connection 
serial_port = '/dev/ttyUSB0'			        #-# Assign the location of the port that appears when the Arduino is plugged into the pi to a value
baud_rate = 9600					              # Assign the baudrate to a value

if serial_is_on == True:                          #Create an object that represents our open serial connection
    ser = serial.Serial(serial_port, baud_rate, timeout=1)	

#############################
### 3: Select which axes to check
   
axes_to_check = [1,3]		    		        #-# List the axes to check. Here, I want to check axis #1 and #3.
check_frequency = 5                             #~# Specify how many times a second to check for new values
breakout_button = 3                             #-# Specify which button stops the program

#############################
### 4: Begin reading the controller

while True:					                      # The program will check the button and joystick states until interrupted

    pygame.event.pump()			                  # The event.pump function refreshes knowledge of what events have changed (I think)
    recent_values = []		                      # Declare an empty list to store the values in before writing to serial
    for current_axis in axes_to_check:	          # Loop through the axes to check
        latest_value = j.get_axis(current_axis)	  # Store the current value of the axis
                                                  # If either axis isn't centered, the value will be reported
        if latest_value != 0.00: print 'Axis %i reads %.3f' % (current_axis, latest_value)
        #print(latest_value)                    #-# Uncomment to see all the raw values.  Spoiler alert: they'll mostly be zeros
                                                  # The value gets converted to an integer ranging from 0 - 200
        value_mod = int(round(latest_value*100,2)+100)
        value_mod = str(value_mod)                # The value gets converted to a string
        recent_values.append(value_mod)           # The string is added to the list of values to send over serial

    serial_output =','.join(recent_values) + ';'  # The list gets converted to a character string
    #print(serial_output)                       #-# Uncomment to see the character string that gets sent

    if serial_is_on == True:
        ser.write(serial_output)                  # The text string is sent over serial, one character at a time

    time.sleep(1/check_frequency)                 # The program waits the specified length before checking new values

    if j.get_button(breakout_button) == 1:        # If the breakout button is being held, the program ends
        break

controller-intepreter.ino

Arduino
An Arduino sketch for converting numbers contained in a text string back to numerical values and then writing them to serovs or motor controllers.
/*
  controller-intepreter -- Andrew R Gross -- 2017-11-23 -- andrew@shrad.org

  This sketch uses values sent over a serial connection to control servos or other motor controllers.
  It reads a string from serial; parses it into a list of integers; scales the inegers to the correct range
  for the motor controller, and then outputs the signal to control a motor.

*/
////////////////////////////////////
/// 1: Header

#include <Servo.h>       // Import servo libraries
Servo esc_left;          // Create a servo object named esc_left
Servo esc_right;         // Create another servo object for the right esc

String inString = "";    // define a string to hold received serial characters
int inChar = 0;          // define a variable to hold the latest character from serial
int thruster_left;       // define a variable to hold the latest signal to the left thruster
int thruster_right;      // define a variable to hold the latest signal to the right thruster
int save_as_second = false;// define a logical element that tracks if values are part of the second value in the string

////////////////////////////////////
/// 2: Setup

void setup() {
  Serial.begin(9600);    // Open a serial channel at a baudrate of 9600
  esc_left.attach(9);    // Assign a servo object to pin 9
  esc_right.attach(10);  // Assign a servo to pin 10
}

////////////////////////////////////
/// 3: Main loop

void loop() {
  /// 3.1 : Read serial data
  if (Serial.available()) {  // If serial data is available...
    inChar = Serial.read();  // Save the latest byte
    inString += char(inChar);// Join the latest character to a growing string of recent chracters
        
    /// 3.2 When a comma is detected, save the current string as a number and assign it to one of the output variables
    if (inChar == ',') {
      if (save_as_second == false) { // If the most recent chracter is a comma, confirm that the current string is the first value.
        thruster_left = inString.toInt(); // Save the string as an integer in one of our two output variables
        inString = "";               // Reset the string
        save_as_second == true;      // Indicate that the next value detected is for the second thruster
      }
    }
    /// 3.3 When a semicolon is detected, save the current string as a number and assign it to the other output variables
    if (inChar == ';') {     // If the latest chracter is the end-of-line character...
      thruster_right = inString.toInt();// Assign the most recent number string to the second thruster
      inString = "";        // Reset the string
      save_as_second = false;// Indicate that the next value detected is for the first thruster

      /// 3.4 Write out the new values to the servos and to serial
      Serial.print("Left Thruster:"); // Print the values of each thruster to serial
      Serial.println(thruster_left);
      Serial.print("Right string: ");
      Serial.println(thruster_right);
      
      esc_left.write(thruster_left);  // Write the signal value to one of the servo objects
      esc_right.write(thruster_right);
    }
  }
}

Operating a robot with USB controller files

This repository contains the latest versions of the two files used in this project.

Credits

Andrew R Gross

Andrew R Gross

7 projects • 19 followers
Biomedical engineer by profession, wanna-be roboticist on the weekends
Jonathan Gross

Jonathan Gross

2 projects • 5 followers
engineer and nerd
Thanks to Garrett Owen.

Comments