Diddyborg PS3 Control

Hi,

I've successfully built the Diddyborg and I'm using the ps3DiddyJoy.sh/DiddyJoy.sh (with a few modifications) script to control it with my PS3 controller. It all works flawlessly and it's awesome! Now I want to add some modifications to it to make it look cooler.
Is it possible to add in a line into the script (Using Python) to control an led with a button on the PS3 controller? I'm struggling to understand how to map a PS3 button to do things..

Thanks,
Sam

piborg's picture

It is reasonably easy to add a new button to the diddyJoy.py script.
I will walk through adding some code to the cross button as an example for you.

First we need the button index for the new button we are going to use.
Go to our PlayStation 3 controller help sheet page and scroll down until you see the table.
Find the button you want in the list and note the value in the "Button index" column.
For cross the value we need is 14.

Second open up the diddyJoy.py script in a text editor and add a new variable to the "Settings for the joystick" section.
We will call this variable buttonLed in our example, and assign it the value of our button, 14:

# Settings for the joystick
axisUpDown = 1                 # Joystick ax...
axisUpDownInverted = False     # Set this to...
axisLeftRight = 2              # Joystick ax...
axisLeftRightInverted = False  # Set this to...
buttonResetEpo = 3             # Joystick bu...
buttonSlow = 8                 # Joystick bu...
slowFactor = 0.5               # Speed to sl...
buttonFastTurn = 9             # Joystick bu...
buttonLed = 14                 # Joystick bu...
interval = 0.00                # Time betwee...

Third we need to add some code to the "Check for button presses" section.
This code will check if the joystick button is held, and run some code:

                # Check for button presses
                if joystick.get_button(buttonResetEpo):
                    PBR.ResetEpo()
                if joystick.get_button(buttonSlow):
                    driveLeft *= slowFactor
                    driveRight *= slowFactor
                if joystick.get_button(buttonLed):
                    print "LED button pressed"
                # Set the motors to the new speeds

In this example it will just print a message on the terminal screen.
You can insert your own code to control an LED instead of the print statement.
Remember your code should be indented so that it is to the right of the if line.

You can repeat this as many times as you need to add new buttons to the script.

Hi,

Thank you very much, that fully explained what I needed to know to add a new button to control things, awesome!

So I've built a robotic arm and I'm using a python script (robotic-arm-ps3.py) to use the PS3 controller to control it. I'm going to attach it to the diddyborg and I want to be able to use the arm at the same time as driving. Unfortunately I need to use the analog sticks to control both devices, which causes a problem. Is there a way I can assign a PS3 button within diddyJoy.py to run this robotic-arm-ps3.py script? And then to stop running this script so I can again drive diddyborg? Or I can somehow integrate both scripts somehow.
I've attached my script for the arm if it helps.

Thanks!

Attachments: 
piborg's picture

It should be possible to do either, but we will start with trying to run the script as a separate file.

Firstly we need to take a copy of a 'clean' python environment to keep the scripts isolated.
We will do this before any other code has run:

#!/usr/bin/env python
# coding: Latin-1

cleanGlobals = globals().copy()
cleanLocals = locals().copy()

# Load library functions we want

Next we want to setup our button variable like last time.
I will use 16 this time, which should correspond to the PS logo button:

# Settings for the joystick
axisUpDown = 1                 # Joystick axis ...
axisUpDownInverted = False     # Set this to Tr...
axisLeftRight = 2              # Joystick axis ...
axisLeftRightInverted = False  # Set this to Tr...
buttonResetEpo = 3             # Joystick butto...
buttonSlow = 8                 # Joystick butto...
slowFactor = 0.5               # Speed to slow ...
buttonFastTurn = 9             # Joystick butto...
buttonArmScript = 16           # Joystick butto...
interval = 0.00                # Time between u...

Now in the event code we will grab the button down event:

            elif event.type == pygame.JOYBUTTONDOWN:
                # A button on the joystick just got pushed down
                hadEvent = True
                if event.button == buttonArmScript:
                    # Stop moving
                    driveLeft = 0.0
                    driveRight = 0.0
                    PBR.MotorsOff()
                    # Run the arm control script
                    execfile('robotic-arm-ps3.py', cleanGlobals.copy(), cleanLocals.copy())
                    # Jump to the next control input
                    break
            elif event.type == pygame.JOYAXISMOTION:

We do this in here to make sure we only see the event once.

There are three commented sections in this code block which do the following:

  1. Stop the motors moving
    Remove this if you want him to carry on driving when moving the arm
  2. Run the other script
    You may need a ./ or path to the script
    This script will stay on this line until the other script has finished
    By passing a 'clean' copy of the environment we stop the other script affecting the variables in this script
  3. Skip to next event
    We do this to avoid interpreting the last state of the controller when the other script ends
    Hopefully pygame.event,get() will not get any events from when the other script was running

The only other thing you need to do is make a button (can be the same one) stop the other script from running.
You can do this by using a global variable to terminate the loop:

global running
running = True
...
def processArm(event):
      global ..., running
      if event.type == pygame.JOYBUTTONDOWN:
          if event.button == ...:
              running = False
              return
    ...
...
try:
    while running:
        ...
    j.quit()    
except KeyboardInterrupt:
    j.quit()

Hopefully that will be enough to allow you to switch between control scripts.

Hi,

Thanks for your reply and help again. So I added a button in the diddyJoy script to call the script for the arm like you showed above and that seems to be working ok, but when the script for the arm begins to start-up i get this error:
Traceback (most recent call last):
File "/home/pi/diddyborg/diddyJoy.py", line 109, in
execfile('./robotic-arm-ps3.py', cleanGlobals.copy(), cleanLocals.copy())
File "./robotic-arm-ps3.py", line 158, in
processArm(event)
File "./robotic-arm-ps3.py", line 89, in processArm
if event.type == pygame.JOYBUTTONDOWN:
NameError: global name 'pygame' is not defined

I've tried to fix the problem but have no idea why this is happening. The script for the arm works fine when i just run it by itself and diddyJoy.py seems to be working fine when i press the button to call the arm script. Do you have any idea what this error means?
I've attached my 2 modified scripts

Thanks!

piborg's picture

It seems that execfile is not the best way to do this then.
I did some reading and there is a module called runpy that seems to work well.

I tried your code (with the USB bits commented out) and had the same issue.
I then changed to this new method and it appears to work well.

First we remove the old globals / locals copying and import the runpy module:

#!/usr/bin/env python
# coding: Latin-1

# Load library functions we want
import time
import os
import sys
import pygame
import PicoBorgRev
import runpy

The button number is still needed like the previous method:

# Settings for the joystick
axisUpDown = 1                 # Joystick axis ...
axisUpDownInverted = False     # Set this to Tr...
axisLeftRight = 2              # Joystick axis ...
axisLeftRightInverted = False  # Set this to Tr...
buttonResetEpo = 3             # Joystick butto...
buttonSlow = 8                 # Joystick butto...
slowFactor = 0.5               # Speed to slow ...
buttonFastTurn = 9             # Joystick butto...
buttonArmScript = 16           # Joystick butto...
interval = 0.00                # Time between u...

Now in the event code where we grab the button down event we use the runpy module instead:

            elif event.type == pygame.JOYBUTTONDOWN:
                # A button on the joystick just got pushed down
                hadEvent = True
                if event.button == buttonArmScript:
                   # stop moving
                   driveLeft = 0.0
                   driveRight = 0.0
                   PBR.MotorsOff()
                   # Run the arm control script
                   runpy.run_path('./robotic-arm-ps3.py')
                   # Re-initialise the joystick after the script change
                   joystick = pygame.joystick.Joystick(0)
                   joystick.init()
                   # Jump to the next control input
                   break                   
            elif event.type == pygame.JOYAXISMOTION:

Notice I have also added a re-initialisation of the joystick.
When testing this new version it turns out the joystick is no longer running when it returns control.
This way the joystick is started again, allowing the script to continue properly.

This all works fine on my DiddyBorg, except I did not use the USB code.
I also tried with another script which drives an LedBorg from the controller, that worked fine this way.

piborg's picture

I forgot to mention that I had to make a slight correction to the loop at the end of your script.

Instead of the while running: being inside the while True:, it needs to replace it.

This is how the loop looks in the version I had running:

try:
    # Run until we receive the quit command
    while running:
        	# Sleep so we don't eat up all the CPU time
        	time.sleep(0.1)
        
        	# read in events
        	events = pygame.event.get()
        
        	# and process them
        	for event in events:
            		processArm(event) 
        
    j.quit()    
except KeyboardInterrupt:
    j.quit()

Hey there!

I was wondering, can I use those same commands when using the wiringPi library to do this in C?
I'm very new to the raspberry pi world but I'm familiar with C so I'm looking for the simplest way I can do this.

Any help will be appreciated (possibly some sample code, if you could!) Thanks!

piborg's picture

In order to control a DiddyBorg using C/C++ you will need to use different code.

The code required is not too difficult, it should be fairly easy to understand if you are familiar with C already.

First you will need to setup the PS3 controller in the same way we do for the Python scripts.
This should get the joystick driver setup ready to go.

In order to use the joystick we want to use the sys/ioctl and linux/joystick headers.
The API documentation can be found here:
https://www.kernel.org/doc/Documentation/input/joystick-api.txt
There is an example of reading the joystick states using this API here:
http://archives.seul.org/linuxgames/Aug-1999/msg00107.html

We do not have a library for controlling PicoBorg Reverse from C/C++, but you should be able to get the same functionality as the Python library using the I2C libraries.
Take a look at this post for a detailed explanation of how this can be done:
C/C++ library for PicoBorg Reverse

I purchased a used PS3 Sixaxis controller for my DiddyBorg. I installed all the drivers and at first it worked extremely well but recently it has started to have problems, as follows:

Originally when I pressed the PS button the 4 leds on the controller would flash (whether or not robot was turned on. Now I have to plug it in to the robot (Pi 2) before I can get any active leds at all.

Once I have a Bluetooth connection established with a single led showing on the controller it seems to be a matter of luck as to how long the connection will last, it may be minutes or seconds but then the single led goes off and control is lost. Pressing the PS button elicits no response and I have to go through the USB connection routine again.

I realise that strictly speaking this is not a DiddyBorg problem but I would welcome any help or advice to try and sort this out.
Thanks
Il Diavolo

piborg's picture

It sounds like the PS3 controller has run out of battery power and needs to be charged.

Connecting the USB will provide some power, this is what is allowing it to make the connection when attached with a cable.
It will not get very much charge from a few minutes though, hence it runs out of battery fairly quickly when turned on.

If you leave the PS3 remote plugged in to a USB port overnight it should charge up and be ready to go again.
The Raspberry Pi may not have enough power available to charge the remote so I would recommend attaching it to a powered hub or a PC to charge.

You can also attach the controller to a PS3 to charge it, but you may need to re-run the pairing routine afterwards as the PS3 will likely pair the controller to itself.

Great, thanks.
I thought I had been charging it by plugging it into a wall socket USB adaptor but your reply prompted a "Googling" session. It seems that using a wall adaptor (the same one that I power the Pi with when not running on batteries) will not work. Apparently the controller needs to "handshake" with its charging source which it can't do with an adaptor.
I left it plugged into a USB port on my laptop for a couple of hours until the 4 leds stopped flashing (which never flashed at all when using the adaptor, should have been a clue!) and it's now working properly.
Many thanks for your help.
Il Diavolo

Subscribe to Comments for "Diddyborg PS3 Control"