French FX-7 robot

From Technologia Incognita
Revision as of 20:55, 16 March 2014 by Justa (talk | contribs) (Shift-Register driving of robot)
Jump to: navigation, search
Projects
FX-7.jpg
Participants Mi1es
Skills Electronics, Soldering, Programming, Creative thinking
Status Active
Niche Electronics
Purpose World domination

"Contrôle système! Contrôle système!"

Overview

System

Direct Drive control via RaspPI

Machine has been taken apart.. blblblalbla


H-bridge board has all the transistors of the original board on it for 4 full H-bridges that can drive all of the four bi-directional motors.

Original 'direct drive' Layout was as follows , with the connectors of the motors facing you:

  • First block, gpio18, w1, gpio4, w7, Left tread
  • Second block, gpio17,w0, gpio23,w4, Right treads
  • Third block: gpio27,w2, gpio22,w3, hip
  • Fourth block: gpio24, w5, gpio25,w6, arms

'Direct Drive' Python code

import RPi.GPIO as gpio
import time
import pygame
from pygame.locals import *


gpio.setmode(gpio.BOARD)
gpio.setup(7, gpio.OUT)
gpio.setup(11, gpio.OUT)
gpio.setup(13, gpio.OUT)
gpio.setup(15, gpio.OUT)

gpio.output(7, True)
gpio.output(11, True)

 while True:
    gpio.output(13, True)
    gpio.output(15, False)
    time.sleep(2)
    gpio.output(13, False)
    gpio.output(15, True)
    time.sleep(2)
pygame.init()
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("Pygame")
pygame.mouse.set_visible(0)

done = False
enable = 0
direction = 0
while not done:
    for event in pygame.event.get():
        if(event.type==KEYDOWN):
            print event
            if(event.key==273):
                direction=1;
                enable=1;
            if(event.key==274):
                direction=-1;
                enable=1;     
        if(event.type==KEYUP):
            print event
            if(event.key==273):
                direction=0;
                enable=0;
            if(event.key==274):
                direction=0;
                enable=0;

        if(enable==1):
            if(direction==1):
                print "Forwards"
                gpio.output(13, False)
                gpio.output(15, True)
            if(direction==-1):
                print "Backwards"
                gpio.output(13, True)
                gpio.output(15, False)
        else:
            gpio.output(13, False)
            gpio.output(15, False)


With this code-shim you can test the function of your code even without having RPi.GPIO loaded (like on most PC's) Note it doesnt implement all things yet; but enough to work for this project currently. Working on a shift-register help-library


class FAKEGPIO:
  def __init__(self):
    self.BOARD=1
    self.OUT=0
    self.IN=1
  def setmode(self,variant):
    print "Call: setmode: variant -> " + str(variant)
  def setup(self,pin, type):
    print "Call: setup : pin -> " + str(pin) + ", type -> " + str(type)
  def output(self,pin,state):
    print "Out:" + str(pin) + "-> " + str(state)

gpio = FAKEGPIO()

Shift-Register driving of robot

Since the RaspPI doesnt have much IO and the robot requires 8 output-pins just for the basic motor-control already, we've started looking at driving the outputs using shift-registers instead.

The proto-board has been re-wired to have two shift-registers hosted on it, connected in series, for a total of 16 outputs.

The shift-registers in question are the 74HCT595's that has an 8-bit serial register controlled by 'data' and 'clock' lines, and an 8-bit parallel 'latch' that is controlled by a separate line; allowing you to control at which moment the 8 output pins (output A-H) should reflect the state of the internal 8-bit serial register.

By having the parallel register in between the outputs and the serially controlled register, you are able to change the contents of the serial register at your own leisure without the outputs directly following your changes.

The last control-lines on the 74HCT595 are a 'master reset' pin (active LOW; so connect to HIGH if unused) and a 'Chip enable' (active LOW, connect to GND if not used)


The motor-pins are connected to the first of the two shift-registers; this means that the last 8 bits of data shifted into the 16 bit register-space controls the motors as the first bit shifted in ends up being at the last-most position after 16 clock-cycles.


Shift-register layout
Register Bit Motor Direction
1 0 Left Tread Forwards
1 Left Tread Backwards
2 Right Tread Forwards
3 Right Tread Backwards
4 Hip Forwards
5 Hip Backwards
6 Arms Open
7 Arms Close
2 0 TBD TBD
1 TBD TBD
2 TBD TBD
3 TBD TBD
4 TBD TBD
5 TBD TBD
6 TBD TBD
7 TBD TBD

Software Side

To drive the shift-register, two approaches can be used. Either full 'software bit-banging' or using the SPI-bus on the Raspberry PI to drive (at least) the clock, enable and data-lines of the shift-register. The 'latch' pin of the register needs to be bit-banged as there seems to be no easy way to pull this off with just SPI (unless.. perhaps, doing something smart with the 'enable' line..)


The pure bit-bang approach could use any 3 or 4 GPIO pins on the PI, using the work done on https://projects.drogon.net/raspberry-pi/gpio-examples/ as already used and listed above.

The SPI approach could use the work done on http://www.100randomtasks.com/simple-spi-on-raspberry-pi.

An example snippet of code could be

import RPi.GPIO as gpio
import time
impport spidev

gpio.setmode(GPIO.BOARD)
gpio.setup(12,GPIO.OUT)
gpio.output(12,False)

spi = spidev.SpiDev()
spi.open(0,0)
while True:
  resp = spi.xfer2([0x5555])
  print resp([0])
  gpio.output(12,True)
  gpio.output(12,False)
  time.sleep(1)
  resp = spi.xfer2([0xAAAA])
  print resp([0])
  gpio.output(12,True)
  gpio.output(12,False)
  time.sleep(1)

This will import the right libs, setup pin 12 as the 'latch' pin, initialize the SPI-bus using CE0 as the chip-enable line (open(0,0)), and then write a 0x5555 value to the SPI-bus; two bytes, aka 16 bits. 0x5555 and 0xAAAA are eachothers complements; an alternating pattern of 0 and 1's, starting either with a 0 (0x5555) or a 1 (0xAAAA). The 'resp' variable will be loaded with whatever comes back in on the input at the same time; if you connect MOSI to MISO , you will normally read the same thing you are writing out. You can also connect the H' pin of register2 to MISO; this will allow you to read the PREVIOUS state of the shift-registers back... for no useful reason, however.

Toggling pin 12 up and down should trigger the parallel latch to take the contents of the serial latch and adjust the outputs and then make it safe to adjust the serial register again for the next update.

New plan with the Carambola2

The motor-driver board now has a Carambola2 device directly mounted onto it. The board gets power via an LM7805-based power-supply which regulates the power coming from the LithiumPolymer battery and makes the system fully self-contained.


Controlling the device

THe device has been configured to use Bonjour to announce itself as 'milobot.local' and be reachable on account 'root'. Password is known to the right people.

Driving the GPIO's is rather easy. It requires a few preparatory steps: For example GPIO15

- Export the pin using 'echo 15 > /sys/class/gpio/export' - This will create/enable the directory '/sys/class/gpio/gpio15' - Configure the pin direction (input/output) 'echo out > /sys/class/gpio/gpio15/direction' - Configure the pin state to 'off' 'echo 0 > /sys/class/gpi0/gpio15/value'

-Setting the pin to 'on' state involves writing a '1' to the 'value' in the last step.

Pin mapping

The motor-drivers have the following connections to the Carambola2

GPIO15/GPIO16 - Driver 1 (LED5 and LED 4, afaik) GPIO18/GPIO19 - Driver 2 GPIO20/GPIO21 - Driver 3 GPIO22/GPIO23 - Driver 4

Work to be done

It'd be good to have a python program working (in preparation to a python class) that will allow control over each motor-driver individually (forward, backward, stop) as well as perhaps some 'macros' (drive forward, drive backward, rotate left, rotate right, turn left, turn right, reverse turn left, reverse turn right.... perhaps more, as well as the arms, hinge, etc.