DoodleBorg - Controlled using a PS3 controller
This is the script we are using to control DoodleBorg using a PS3 controller.
It uses the same idea as the
To download the files click on their names above the source, they should be saved without the "
It uses the same idea as the
pbrJoystick.py example with the following modifications:- It sets up six boards to talk to
- Each board is set to drive a single motor (SetMotorsinstead ofSetMotor1andSetMotor2)
- Checking has been added to ensure the controller is in range and talking, otherwise the motors are turned off
- The communication failsafes on each board have been enabled using SetCommsFailsafe(True)
- The script waits for the controller to be attached, this way it can be started before the controller is connected
cd ~/picoborgrev./runDoodleBorg.shTo download the files click on their names above the source, they should be saved without the "
.txt" at the end of the filename.runDoodleBorg.sh
#!/bin/bash ./DoodleBorg.py > /dev/null
DoodleBorg.py
#!/usr/bin/env python
# coding: Latin-1
# Load library functions we want
import time
import os
import sys
import pygame
import PicoBorgRev
# Re-direct our output to standard error, we need to ignore standard out to hide some nasty print statements from pygame
sys.stdout = sys.stderr
# Setup the PicoBorg Reverses
PBR = []
for i in range(6):
    nextPBR = PicoBorgRev.PicoBorgRev()
    nextPBR.i2cAddress = 0x10 + i
    nextPBR.Init()
    if not nextPBR.foundChip:
        boards = PicoBorgRev.ScanForPicoBorgReverse()
        if len(boards) == 0:
            print 'No PicoBorg Reverse found, check you are attached :)'
        else:
            print 'No PicoBorg Reverse at address %02X, but we did find %d boards:' % (nextPBR.i2cAddress, len(boards))
            for board in boards:
                print '    %02X (%d)' % (board, board)
            print 'If you need to change the I²C address change the setup line so it is correct, e.g.'
            print 'PBR.i2cAddress = 0x%02X' % (boards[0])
        sys.exit()
    #nextPBR.SetEpoIgnore(True)                  # Uncomment to disable EPO latch, needed if you do not have a switch / jumper
    nextPBR.ResetEpo()
    # Ensure the communications failsafe has been enabled!
    failsafe = False
    for i in range(5):
        nextPBR.SetCommsFailsafe(True)
        failsafe = nextPBR.GetCommsFailsafe()
        if failsafe:
            break
    if not failsafe:
        print 'Board %02X failed to report in failsafe mode!' % (nextPBR.i2cAddress)
        sys.exit()
    PBR.append(nextPBR)
# Settings for the joystick
axisUpDown = 1                          # Joystick axis to read for up / down position
axisUpDownInverted = False              # Set this to True if up and down appear to be swapped
axisLeftRight = 2                       # Joystick axis to read for left / right position
axisLeftRightInverted = False           # Set this to True if left and right appear to be swapped
buttonResetEpo = 3                      # Joystick button number to perform an EPO reset (Start)
buttonSlow = 8                          # Joystick button number for driving slowly whilst held (L2)
slowFactor = 0.5                        # Speed to slow to when the drive slowly button is held, e.g. 0.5 would be half speed
buttonFastTurn = 9                      # Joystick button number for turning fast (R2)
interval = 0.02                         # Time between updates in seconds, smaller responds faster but uses more processor time
controllerLostLoops = 20                # Number of loops without any joystick events before announcing the joystick as out of range
# Setup pygame and wait for the joystick to become available
for PBRx in PBR:
    PBRx.MotorsOff()
os.environ["SDL_VIDEODRIVER"] = "dummy" # Removes the need to have a GUI window
pygame.init()
print 'Waiting for joystick... (press CTRL+C to abort)'
while True:
    try:
        try:
            pygame.joystick.init()
            # Attempt to setup the joystick
            if pygame.joystick.get_count() < 1:
                # No joystick attached, toggle the LED
                for PBRx in PBR:
                    PBRx.SetLed(not PBRx.GetLed())
                pygame.joystick.quit()
                time.sleep(0.5)
            else:
                # We have a joystick, attempt to initialise it!
                joystick = pygame.joystick.Joystick(0)
                break
        except pygame.error:
            # Failed to connect to the joystick, toggle the LED
            for PBRx in PBR:
                PBRx.SetLed(not PBRx.GetLed())
            pygame.joystick.quit()
            time.sleep(0.5)
    except KeyboardInterrupt:
        # CTRL+C exit, give up
        print '\nUser aborted'
        for PBRx in PBR:
            PBRx.SetLed(True)
        sys.exit()
print 'Joystick found'
joystick.init()
for PBRx in PBR:
    PBRx.SetLed(False)
try:
    print 'Press CTRL+C to quit'
    driveLeft = 0.0
    driveRight = 0.0
    running = True
    hadEvent = False
    upDown = 0.0
    leftRight = 0.0
    loopsWithoutEvent = 0
    controllerLost = False
    # Loop indefinitely
    while running:
        # Get the latest events from the system
        hadEvent = False
        events = pygame.event.get()
        # Handle each event individually
        for event in events:
            if event.type == pygame.QUIT:
                # User exit
                running = False
            elif event.type == pygame.JOYBUTTONDOWN:
                # A button on the joystick just got pushed down
                hadEvent = True
            elif event.type == pygame.JOYAXISMOTION:
                # A joystick has been moved
                hadEvent = True
            if hadEvent:
                # Read axis positions (-1 to +1)
                if axisUpDownInverted:
                    upDown = -joystick.get_axis(axisUpDown)
                else:
                    upDown = joystick.get_axis(axisUpDown)
                if axisLeftRightInverted:
                    leftRight = -joystick.get_axis(axisLeftRight)
                else:
                    leftRight = joystick.get_axis(axisLeftRight)
                # Apply steering speeds
                if not joystick.get_button(buttonFastTurn):
                    leftRight *= 0.5
                # Determine the drive power levels
                driveLeft = -upDown
                driveRight = -upDown
                if leftRight < -0.05:
                    # Turning left
                    driveLeft *= 1.0 + (2.0 * leftRight)
                elif leftRight > 0.05:
                    # Turning right
                    driveRight *= 1.0 - (2.0 * leftRight)
                # Check for button presses
                if joystick.get_button(buttonResetEpo):
                    for PBRx in PBR:
                        PBRx.ResetEpo()
                if joystick.get_button(buttonSlow):
                    driveLeft *= slowFactor
                    driveRight *= slowFactor
                # Set the motors to the new speeds
                PBR[0].SetMotors(-driveLeft)
                PBR[1].SetMotors(-driveLeft)
                PBR[2].SetMotors(-driveLeft)
                PBR[3].SetMotors(driveRight)
                PBR[4].SetMotors(driveRight)
                PBR[5].SetMotors(driveRight)
        if hadEvent:
            # Reset the controller lost counter
            loopsWithoutEvent = 0
            if controllerLost:
                # We had lost the controller, we have now found it again
                print 'Controller re-connected, move joystick to resume operation'
                for PBRx in PBR:
                    PBRx.SetLed(False)
                controllerLost = False
        elif controllerLost:
            # Controller has been lost, pulse the LED at a regular loop count
            loopsWithoutEvent += 1
            if (loopsWithoutEvent % (controllerLostLoops / 10)) == 0:
                for PBRx in PBR:
                    PBRx.SetLed(not PBRx.GetLed())
                # Attempt to reset the joystick module
                del joystick
                pygame.joystick.quit()
                pygame.joystick.init()
                if pygame.joystick.get_count() < 1:
                    # Controller has been disconnected, poll for reconnection
                    print 'Controller disconnected!'
                    while pygame.joystick.get_count() < 1:
                        time.sleep(interval * (controllerLostLoops / 10))
                        pygame.joystick.quit()
                        pygame.joystick.init()
                        for PBRx in PBR:
                            PBRx.SetLed(not PBRx.GetLed())
                # Grab the joystick again
                joystick = pygame.joystick.Joystick(0)
                joystick.init()
                continue
            # Skip to the next loop after the interval
            time.sleep(interval)
            continue
        else:
            # No events this loop, check if it has been too long since we saw an event
            loopsWithoutEvent += 1
            if loopsWithoutEvent > controllerLostLoops:
                # It has been too long, disable control!
                print 'Controller lost!'
                for PBRx in PBR:
                    PBRx.MotorsOff()
                    PBRx.SetLed(True)
                controllerLost = True
                # Skip to the next loop after the interval
                time.sleep(interval)
                continue
        # Change the LED to reflect the status of the EPO latch
        for PBRx in PBR:
            PBRx.SetLed(PBRx.GetEpo())
        # Wait for the interval period
        time.sleep(interval)
    # Disable all drives
    for PBRx in PBR:
        PBRx.MotorsOff()
except KeyboardInterrupt:
    # CTRL+C exit, disable all drives
    print '\nUser shutdown'
    for PBRx in PBR:
        PBRx.MotorsOff()
except:
    # Unexpected error, shut down!
    e = sys.exc_info()[0]
    print
    print e
    print '\nUnexpected error, shutting down!'
    for PBRx in PBR:
        try:
            PBRx.MotorsOff()
        except:
            pass
for PBRx in PBR:
    try:
        PBRx.SetCommsFailsafe(False)
        PBRx.SetLed(True)
    except:
        pass
print
 
     
      




