Thursday, August 13, 2015

Freedom!

A pretty short one today. I finally got my battery, so I can now run the Pi remotely, under its own power. Which mostly means I just sit at my computer, running it over things. I still wouldn't call it a robot, more of an R/C Tank. But it is getting there. While I don't have any real building today, I do have a bit of code. So...

Let us do this!
<!--more-->
A R/C Tank isn't any good without control, right? So how do I do it.
This is how:
import RPi.GPIO as GPIO
import time
import pygame
import sys
import pygame.camera
from pygame.locals import *

#Pin definition for drive control
in1_pin = 5 #Right back
in2_pin = 6 #Right forward
in3_pin = 12 #Left back
in4_pin = 13 #Left forward
enableA_pin = 16 #Right side
enableB_pin = 26 #Left side

#Setup pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(enableA_pin, GPIO.OUT)
GPIO.setup(enableB_pin, GPIO.OUT)
GPIO.setup(in1_pin, GPIO.OUT)
GPIO.setup(in2_pin, GPIO.OUT)
GPIO.setup(in3_pin, GPIO.OUT)
GPIO.setup(in4_pin, GPIO.OUT)

pwmA = GPIO.PWM(enableA_pin, 500) #Right side throttle
pwmB = GPIO.PWM(enableB_pin, 500) #Left side throttle
pwmA.start(0)
pwmB.start(0)


GPIO.output(in1_pin, False)
GPIO.output(in2_pin, False)
GPIO.output(in3_pin, False)
GPIO.output(in4_pin, False)

#drive commands
def forward():
    pwmA.ChangeDutyCycle(100)
    pwmB.ChangeDutyCycle(100)
    GPIO.output(in1_pin, False)
    GPIO.output(in2_pin, True)
    GPIO.output(in3_pin, False)
    GPIO.output(in4_pin, True)

def reverse():
    pwmA.ChangeDutyCycle(50)
    pwmB.ChangeDutyCycle(50)
    GPIO.output(in1_pin, True)
    GPIO.output(in2_pin, False)
    GPIO.output(in3_pin, True)
    GPIO.output(in4_pin, False)

def spinRight():
    pwmA.ChangeDutyCycle(100)
    pwmB.ChangeDutyCycle(100)
    GPIO.output(in1_pin, False)
    GPIO.output(in2_pin, True)
    GPIO.output(in3_pin, True)
    GPIO.output(in4_pin, False)

def turnRightForward():
    pwmA.ChangeDutyCycle(75)
    pwmB.ChangeDutyCycle(25)
    GPIO.output(in1_pin, False)
    GPIO.output(in2_pin, True)
    GPIO.output(in3_pin, False)
    GPIO.output(in4_pin, True)

def turnRightReverse():
    pwmA.ChangeDutyCycle(75)
    pwmB.ChangeDutyCycle(25)
    GPIO.output(in1_pin, True)
    GPIO.output(in2_pin, False)
    GPIO.output(in3_pin, True)
    GPIO.output(in4_pin, False)

def spinLeft():
    pwmA.ChangeDutyCycle(100)
    pwmB.ChangeDutyCycle(100)
    GPIO.output(in1_pin, True)
    GPIO.output(in2_pin, False)
    GPIO.output(in3_pin, False)
    GPIO.output(in4_pin, True)

def turnLeftForward():
    pwmA.ChangeDutyCycle(25)
    pwmB.ChangeDutyCycle(75)
    GPIO.output(in1_pin, False)
    GPIO.output(in2_pin, True)
    GPIO.output(in3_pin, False)
    GPIO.output(in4_pin, True)

def turnLeftReverse():
    pwmA.ChangeDutyCycle(25)
    pwmB.ChangeDutyCycle(75)
    GPIO.output(in1_pin, True)
    GPIO.output(in2_pin, False)
    GPIO.output(in3_pin, True)
    GPIO.output(in4_pin, False)

def stop():
    GPIO.output(in1_pin, False)
    GPIO.output(in2_pin, False)
    GPIO.output(in3_pin, False)
    GPIO.output(in4_pin, False)
    pwmA.ChangeDutyCycle(0)
    pwmB.ChangeDutyCycle(0)

#Setup window, set cam image to background
pygame.init()
pygame.camera.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("DaBot")
pygame.mouse.set_visible(8)
pygame.key.set_repeat(100, 100)
#cam = pygame.camera.Camera("/dev/video0", (384, 288))
#cam.start()
#background_image = cam.get_image() #pygame.image.load("eyes.jpg").convert()
#screen.blit(background_image, [0,0])
pygame.display.update()


try:
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == 273 or event.key == 278: #up arrow or Home
                    forward()
                elif event.key == pygame.K_s: #s key -> straight line test
                    forward()
                    time.sleep(3)
                    stop()
                elif event.key == pygame.K_p: #p key
                    GPIO.cleanup()
                    break
                elif event.key == 274 or event.key == 279: #down arrow or End
                    reverse()
                elif event.key == 276: #left arrow
                    spinLeft()
                elif event.key == 277: #Insert
                    turnLeftForward()
                elif event.key == 127: #Delete
                    turnLeftReverse()
                elif event.key == 275: #right arrow
                    spinRight()
                elif event.key == 280: #Page up
                    turnRightForward()
                elif event.key == 281: #Page down
                    turnRightReverse()
                else:
                    print (event.key)
#                im = get_image()
#                background_image = pygame.image.frombuffer(im.tostring(), im.size, im.mode)
                background_image = pygame.image.load("eyes.jpg").convert()
                #background_image = pygame.transform.rotate(background_image, 90)
                screen.blit(background_image, [0,0])
                pygame.display.update()
            elif event.type == pygame.KEYUP:
                stop()
     
#    speed = int(cmd[1]) * 10
#    print(speed)
#    pwm.ChangeDutyCycle(speed)

except(KeyboardInterrupt, SystemExit()):
    GPIO.cleanup()
#    cam.stop()
 I left in the camera stuff this time. Most of it is commented out, but some isn't. I just wanted to show, basically, the works there. At a leter date, when I get a camera that works with pygame, I will return to it. For now, we are just interested in the movement.
For the most part, much of this will look fairly familiar. A couple of changes you may have noticed, are the Turn functions. Spin is great, turns on a dime, gets you where you are going, and tears the tracks right off the wheels. Which, of course, leaves the bot high and dry. I found that if the robot drives forward and turns instead of just spinning, it keeps the tracks on. I also added another set of forward/reverse keys. This allows you to move your whole hand up the the "turn" keys, lowering the chance of spinning or turning when you don't want to.

Those with a keen eye may have noticed pwmA and pwmB. These are the PWM pins. Remember way back when I said leave the jumpers in place on the enable pins? Well, I removed those. I then connected them to my PWM pins. Setting the PWM pins to 100 is the same as those jumpers. However, we can now set those to lower values, basically giving us a throttle. This is what makes the Turn functions a reality. Without PWM we are stuck either all on or all off. Now we can vary it. So, 75% on one side 25% on the other, abracadabra, we turn. Without losing our tracks. I also cut the reverse power to 50%. Why? Just to test. Later, I will add input variables to adjust the speed of the functions. But for now they are proof of concept.

I now have all the tools I need to make my robot drive itself. All I need is a way for it to know where it is going. A Distance Sensor. I have a sonic one on its way, I have the code written, I even have a cable spliced with resistors waiting for a quick connect. As soon as it gets here, I will be sure to update you all.

In the meantime, I wasn't super happy with pulling my cable out of my battery pack after I shut down the Raspberry Pi. So, since I had an extra switch from the motor battery pack, I decided to add it to a USB cable to give the Pi a switch as well. I will do an aside soon to show how to set that up.

Until then, keep building!

No comments:

Post a Comment