PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Roboterbau mit RPi - Tutorial



pinsel120866
20.01.2013, 11:00
Ich werde in diesem Threat (ist übrigens mein 700ster) den Aufbau meines "PinselBot" (https://www.roboternetz.de/community/threads/60619-Pinsel-s-RPi-Bot/page2?p=569354#post569354) beschreiben, um anderen die Möglichkeiten den Bot nachzubauen bzw. Anregungen für Weiterentwicklungen zu geben. Es soll dargestellt werden, dass es im Grunde nicht besonders schwer ist, Module bzw. Sensoren direkt an die GPIO Schnittstelle des Raspberri Pi anzuschliessen und damit einen autonomen Roboter aufzubauen.

ACHTUNG: Die GPIO Pins dürfen mit einer Spannung von max 3,3 Volt im Eingang (Input) betrieben werden, höhere Spannung führt im schlimmsten Fall zur Zerstörung des RPi's!!! Ich übernehme keine Verantwortung, sollte jemand meiner Anleitung folgen und durch fehlerhafte Verkabelung sein Board zerstören.

Als Buch für den Anfänger empfehle ich "Durchstarten mit Raspberry Pi" von Erik Bartmann ISBN: 978-3-86899-410-0 (dies soll keine Werbung sein, aber ich finde das Buch sehr gut). Ich gehe davon aus, dass das RPi mit Raspian "Wheezy" vorbereitet ist und eine WLAN Verbindung zum Netzwerk besteht.

Beginnen möchte ich mit dem Antrieb:

Einkaufsliste:

Neben dem Raspbery Pi benötigst du
- RP5/6 Fahrgestell (http://www.conrad.de/ce/de/product/191152/C-Control-Robot-System-Fahrgestell-Robby-RP5RP6-Roboter/SHOP_AREA_37371&promotionareaSearchDetail=005) inkl. Motoren und Batteriehalter
- Motortreiber L298N (http://www.ebay.at/itm/380520063503?ssPageName=STRK:null:IT) fertig aufgebautes Modul
- Mobiles Ladegerät (http://www.ebay.at/itm/200850595055?ssPageName=STRK:null:IT&_trksid=p3984.m1542.l2649)
- Female to Female Kabel (http://www.ebay.at/itm/261121347600?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649)
- USB Kabel Ladegerät-RPi
- 6 Stk. Akkus vom Typ AA

Weiters habe ich mir aus 2mm Plexiglas eine 220x100mm grosse "Plattform" geschnitten. Darauf kommen RPi und Motortreiber, befestigt mit z. B. Klettband. Aja, Distanzbolzen zur Besfestigung der Plattform am Fahrgestell braucht man auch noch.

Die Verkabelung ist relativ einfach, weil man in dieser Phase noch kein Steckbrett benötigt wird, siehe Fotos.
Zu beachten ist, dass das Massekabel vom RPi kommend an die Masse des L298N geklemmt wird, sonst funktioniert das Ganze nicht.

Noch die GPIO-Library installieren:
von http://pypi.python.org/pypi/RPi.GPIO herunterladen

in der Console
$ tar zxf RPi.GPIO-0.x.x.tar.gz
$ cd RPi.GPIO-0.x.x
$ sudo python setup.py install

Nachdem das erledigt ist, kann das Programm ins /pi/home Verzeichnis kopiert werden:


#Get the GPIO module
import RPi.GPIO as GPIO

#Get the time module
import time

#A routine to control a pair of pins
def ControlAPairOfPins(FirstPin,FirstState,SecondPin,S econdState):
if FirstState == "1":
GPIO.output(int(FirstPin),True)
else:
GPIO.output(int(FirstPin),False)

if SecondState == "1":
GPIO.output(int(SecondPin),True)
else:
GPIO.output(int(SecondPin),False)
#Just retur
return

####Main body of code

#Get rid of warnings
GPIO.setwarnings(False)

#Set the GPIO mode
GPIO.setmode(GPIO.BOARD)
#Set the pins to be outputs
GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)

while True:

ControlAPairOfPins("19","1","21","0")
ControlAPairOfPins("23","1","24","0")
print "Drehung nach rechts"
time.sleep(1)

ControlAPairOfPins("19","0","21","0")
ControlAPairOfPins("23","0","24","0")
print "Stop"
time.sleep(1)

ControlAPairOfPins("19","0","21","1")
ControlAPairOfPins("23","0","24","1")
print "Drehung nach Links"
time.sleep(1)

ControlAPairOfPins("19","0","21","0")
ControlAPairOfPins("23","0","24","0")
print "Stop"
time.sleep(1)

ControlAPairOfPins("19","1","21","0")
ControlAPairOfPins("23","0","24","1")
print "Geradeaus vorwaerts"
time.sleep(1)

ControlAPairOfPins("19","0","21","0")
ControlAPairOfPins("23","0","24","0")
print "Stop"
time.sleep(1)

ControlAPairOfPins("19","0","21","1")
ControlAPairOfPins("23","1","24","0")
print "Geradeaus rueckwaerts"
time.sleep(1)

ControlAPairOfPins("19","0","21","0")
ControlAPairOfPins("23","0","24","0")
print "Stop"
time.sleep(1)

Das Programm kennt nur Vollgas und Stop, die Geschwindigkeit kann nicht reguliert werden.

Gestartet wird mit dem Befehl
$sudo python motor.py

Achtung: Der Roboter bewegt sich, sofern alles richtig gemacht wurde!

pinsel120866
20.01.2013, 16:12
... und weiter geht's.

Wie man das Ultraschallmodul SRF04 anhängt, habe ich hier beschrieben:
https://www.roboternetz.de/community/threads/60468-Kosteng%C3%BCnstige-Ultraschall-Entfernungsmessung

Wenn man das Modul mit 3,3 Volt betreibt, benötigt man noch immer kein Steckbrett - allerdings ist damit eine zuverlässige Messung nur bis Entfernungen bis ca. 50 cm möglich.

Wenn man nun Antrieb und Entfernungsmessung nach meinen Vorgaben aufgebaut hat, müsste folgender Code schon funktionieren - der Bot fährt nun autonom durch die Gegend und weicht Hindernissen aus:

import time
import RPi.GPIO as GPIO
GPIO.setwarnings(False)

def ControlAPairOfPins(FirstPin,FirstState,SecondPin,S econdState):
if FirstState == "1":
GPIO.output(int(FirstPin),True)
else:
GPIO.output(int(FirstPin),False)

if SecondState == "1":
GPIO.output(int(SecondPin),True)
else:
GPIO.output(int(SecondPin),False)
return

print "Ultraschallmessung mit SRF04"

while True:

#Messung Start
GPIO.setmode(GPIO.BCM)
GPIO.setup(14,GPIO.OUT)
GPIO.setup(15,GPIO.IN)

GPIO.output(14, False)

time.sleep(0.5)

GPIO.output(14, True)
time.sleep(0.00001)
start = time.time()
GPIO.output(14, False)

while GPIO.input(15)==0:
pass

start = time.time()

while GPIO.input(15)==1:
pass

stop = time.time()
elapsed = stop-start
distance = elapsed * 17000

print "Abstand: %.1f cm" % distance
#Messung Ende

if distance < 20:

#Motor stop
GPIO.setmode(GPIO.BOARD)
GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
ControlAPairOfPins("19","0","21","0")
ControlAPairOfPins("23","0","24","0")
print "Stop"
time.sleep(1)
#Stop Ende

#Drehung rechts
GPIO.setmode(GPIO.BOARD)
GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
ControlAPairOfPins("19","1","21","0")
ControlAPairOfPins("23","1","24","0")
print "Drehung nach rechts"
time.sleep(1)

else:

#Motor vorwaerts
GPIO.setmode(GPIO.BOARD)
GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
ControlAPairOfPins("19","1","21","0")
ControlAPairOfPins("23","0","24","1")
print "Geradeaus vorwaerts"
#Vorwaerts Ende

- - - Aktualisiert - - -

Kommen wir nun zum LCD-Display:

Nicht unbedingt notwendig, macht aber schon was her...

Benötigt wird:
- Mini Steckbrett (http://www.conrad.de/ce/de/product/526819/Steckplatine-EIC-801-Steckplatine-L-x-B-x-H-84-x-54-x-85-mm-Anzahl-Polklemmen-100/SHOP_AREA_14742&promotionareaSearchDetail=005), meins hat unten ein Doppelklebeband
- LCD, möglich sind 16x1 (http://www.conrad.de/ce/de/product/183261/LCD-Punktmatrix-Modul-6H-REF-EV-Zeichenformat-16-x-1-Zeichenhoehe-66-mm/SHOP_AREA_17651&promotionareaSearchDetail=005) oder 16x2 (http://www.conrad.de/ce/de/product/183043/Alphanumerisches-LCD-Modul-Gleichmann-GE-C1602B-YYH-JTR-Zeichenformat-16-x-2-Zeichenhoehe-555-mm-Gelb-Gruen/SHOP_AREA_17651&promotionareaSearchDetail=005) oder 16x4 (braucht viel Platz) Zeichen
- Stiftleiste (http://www.conrad.de/ce/de/product/741105/Stiftleiste-RM-254-gerade-Rastermass-254-mm-Pole-1-x-20-Nennstrom-3-A-10120508-BKL-Electronic-Inhalt-1-St) zum Auflöten
- Timmerpoti 10kOhm (http://www.conrad.de/ce/de/product/425257/Vishay-Praezisions-Trimmpotentiometer-63-X-10K-10-k-05-W-10-/SHOP_AREA_17440&promotionareaSearchDetail=005)
- Male to Female Kabel (http://www.ebay.at/itm/261121345462?ssPageName=STRK:null:IT&_trksid=p3984.m1542.l2649)
- Male to Male Kabel (http://www.ebay.at/itm/261104877388?ssPageName=STRK:null:IT)

Der Aufbau ist sehr gut hier beschrieben, hat mir auch geholfen:
http://learn.adafruit.com/drive-a-16x2-lcd-directly-with-a-raspberry-pi/overview

Testcode von Adafruit:

#!/usr/bin/python

#
# based on code from lrvick and LiquidCrystal
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
#

from time import sleep

class Adafruit_CharLCD:

# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00

# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00

def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 21, 22], GPIO = None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db

self.GPIO.setmode(GPIO.BCM)
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)

for pin in self.pins_db:
self.GPIO.setup(pin, GPIO.OUT)

self.write4bits(0x33) # initialization
self.write4bits(0x32) # initialization
self.write4bits(0x28) # 2 line 5x7 matrix
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
self.write4bits(0x06) # shift cursor right

self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF

self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
self.displayfunction |= self.LCD_2LINE

""" Initialize to default text direction (for romance languages) """
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) # set the entry mode

self.clear()


def begin(self, cols, lines):

if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
self.currline = 0


def home(self):

self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!


def clear(self):

self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
self.delayMicroseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time


def setCursor(self, col, row):

self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

if ( row > self.numlines ):
row = self.numlines - 1 # we count rows starting w/0

self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))


def noDisplay(self):
""" Turn the display off (quickly) """

self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def display(self):
""" Turn the display on (quickly) """

self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noCursor(self):
""" Turns the underline cursor on/off """

self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def cursor(self):
""" Cursor On """

self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)


def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);


def leftToRight(self):
""" This is for text that flows Left to Right """

self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);


def rightToLeft(self):
""" This is for text that flows Right to Left """
self.displaymode &= ~self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def autoscroll(self):
""" This will 'right justify' text from the cursor """

self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def noAutoscroll(self):
""" This will 'left justify' text from the cursor """

self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def write4bits(self, bits, char_mode=False):
""" Send command to LCD """

self.delayMicroseconds(1000) # 1000 microsecond sleep

bits=bin(bits)[2:].zfill(8)

self.GPIO.output(self.pin_rs, char_mode)

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)

self.pulseEnable()

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4,8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)

self.pulseEnable()


def delayMicroseconds(self, microseconds):
seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
sleep(seconds)


def pulseEnable(self):
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, True)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # commands need > 37us to settle


def message(self, text):
""" Send string to LCD. Newline wraps to second line"""

for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char),True)


if __name__ == '__main__':

lcd = Adafruit_CharLCD()

lcd.clear()
lcd.message("Pinsel's\n RPi Bot")

Wenn "Pinsels's RPi Bot" auf dem Diplay steht, ist alles richtig aufgebaut.

Als Goody noch ein Programm, das die US-Messwerte im Display ausgibt:


from time import sleep

class Adafruit_CharLCD:

# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00

# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00

def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 21, 22], GPIO = None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db

self.GPIO.setmode(GPIO.BCM)
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)

for pin in self.pins_db:
self.GPIO.setup(pin, GPIO.OUT)

self.write4bits(0x33) # initialization
self.write4bits(0x32) # initialization
self.write4bits(0x28) # 2 line 5x7 matrix
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
self.write4bits(0x06) # shift cursor right

self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF

self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
self.displayfunction |= self.LCD_2LINE

""" Initialize to default text direction (for romance languages) """
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) # set the entry mode

self.clear()


def begin(self, cols, lines):

if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
self.currline = 0


def home(self):

self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!


def clear(self):

self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
self.delayMicroseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time


def setCursor(self, col, row):

self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

if ( row > self.numlines ):
row = self.numlines - 1 # we count rows starting w/0

self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))


def noDisplay(self):
""" Turn the display off (quickly) """

self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def display(self):
""" Turn the display on (quickly) """

self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noCursor(self):
""" Turns the underline cursor on/off """

self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def cursor(self):
""" Cursor On """

self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)


def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);


def leftToRight(self):
""" This is for text that flows Left to Right """

self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);


def rightToLeft(self):
""" This is for text that flows Right to Left """
self.displaymode &= ~self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def autoscroll(self):
""" This will 'right justify' text from the cursor """

self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def noAutoscroll(self):
""" This will 'left justify' text from the cursor """

self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def write4bits(self, bits, char_mode=False):
""" Send command to LCD """

self.delayMicroseconds(1000) # 1000 microsecond sleep

bits=bin(bits)[2:].zfill(8)

self.GPIO.output(self.pin_rs, char_mode)

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)

self.pulseEnable()

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4,8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)

self.pulseEnable()


def delayMicroseconds(self, microseconds):
seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
sleep(seconds)


def pulseEnable(self):
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, True)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # commands need > 37us to settle


def message(self, text):
""" Send string to LCD. Newline wraps to second line"""

for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char),True)


if __name__ == '__main__':

lcd = Adafruit_CharLCD()

GPIO_TRIGGER = 14
GPIO_ECHO = 15

adjustment = 7

print "Ultraschallmessung mit SRF04"

while True:

GPIO.setup(GPIO_TRIGGER,GPIO.OUT)
GPIO.setup(GPIO_ECHO,GPIO.IN)

GPIO.output(GPIO_TRIGGER, False)

time.sleep(0.5)

GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
start = time.time()
GPIO.output(GPIO_TRIGGER, False)

while GPIO.input(GPIO_ECHO)==0:
pass

start = time.time()

while GPIO.input(GPIO_ECHO)==1:
pass

stop = time.time()

elapsed = stop-start

distance = elapsed * 17000 + 8
distance = distance - adjustment

print "Abstand: %.1f cm" % distance
time.sleep(1)

GPIO.cleanup()



lcd.clear()
# lcd.message(" Adafruit 16x2\n Standard LCD")
lcd.message("Pinsel's\n RPi Bot")

- - - Aktualisiert - - -

Dann noch das vorerst letzte und schwierigste Modul: Der Mini Servo

Hier ist ein klein wendig Bastelarbeit notwendig um das US-Modul auf dem Servoarm zu befestigen. Aus Sperrholz oder Kunststoff habe ich mir ein passendes "U" ausgeschnitten und mit dem Servoarm verschraubt - siehe Fotos. Neben diesem Teil benötigt man noch ein

- Mini Servo (http://www.conrad.de/ce/de/product/275124/Modelcraft-Mini-Servo-Gleitlager-Getriebe-Kunststoff-JR/SHOP_AREA_19788&promotionareaSearchDetail=005)
- BC548 NPN Transistor (http://www.conrad.de/ce/de/product/155020/Bipolar-Standard-Leistungstransistor-BC-548-B-NPN-Gehaeuseart-TO-92-IC-200-mA-Emitter-Sperrspannung-UCEO-30-V/SHOP_AREA_37318&promotionareaSearchDetail=005)
- 2 Stk. Kohlewiderstand 1K (http://www.conrad.de/ce/de/product/403253/14-Watt-Kohleschicht-Widerstand-5-1-k-axial-bedrahtet-Bauform-0207-025-W-5-/SHOP_AREA_17441&promotionareaSearchDetail=005)

Die Widerstände verwendet man als Spannungsteiler, weil der Servo nur mit 5 Volt betrieben werden kann. Die Verkabelung ist in der Anlage ersichtlich - hier möchte ich mich für die Handskizzen entschuldigen, ich denke dass sie ihren Zweck trotzdem erfüllen.

Hier ein Programm, um den Servo zu testen:


import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

GPIO.setup(26, GPIO.OUT)
GPIO.output(26, True)

while True:
for i in range(1, 100):
GPIO.output(26, False)
time.sleep(0.001)
GPIO.output(26, True)
time.sleep(0.02)

for i in range(1, 100):
GPIO.output(26, False)
time.sleep(0.0015)
GPIO.output(26, True)
time.sleep(0.02)

for i in range(1, 100):
GPIO.output(26, False)
time.sleep(0.002)
GPIO.output(26, True)
time.sleep(0.02)

Der Ablauf dieses Programms ist hier ersichtlich: http://www.youtube.com/watch?v=VA_2pQ9W4g4
Wenn der Servo etwas zuckt ist dies normal, ich habe keinen Weg gefunden dieses zu beseitigen. Hier wäre schon ein Ansatz mein Projekt zu verbessern.

Sind alle Komponenten und Sensoren aufgebaut, steht einem Probelauf nichts mehr im Weg.
Program dazu kann ich nicht hochladen, *.py ist eine nicht erlaubte Datei - sollte jemand den Code wollen, einfach PN mit der Emailadresse an mich senden.

Das war's vorerst, sollte jemand Anregungen, Kritik oder Verbesserungsvorschläge haben - einfach posten. Ich wünsche viel Erfolg beim Nachbau :-)

Defiant
23.01.2013, 11:43
Interessant. Ich benutz die gleiche Plattform mit dem R-Pi. Nur habe ich für die PWM-Erzeugung und Beobachtung der Spannung (Notabschaltung) noch einen 5V AVR dazwischen.Und mein R-Pi wird vom normalen Akku mitversorgt.Kann es sein, daß dir die Schutzdioden am L298 fehlen?

- - - Aktualisiert - - -

Interessant. Ich benutz die gleiche Plattform mit dem R-Pi. Nur habe ich für die PWM-Erzeugung und Beobachtung der Spannung (Notabschaltung) noch einen 5V AVR dazwischen.Und mein R-Pi wird vom normalen Akku mitversorgt.Kann es sein, daß dir die Schutzdioden am L298 fehlen?

pinsel120866
23.01.2013, 14:58
Du hast Recht, die fehlen. Wäre nett, wenn du eine Skizze/Beschreibung vom sicheren Aufbau beifügen könntest - Danke.

Defiant
24.01.2013, 07:38
Das RN wiki hat was dazu:http://www.rn-wissen.de/index.php/Getriebemotoren_Ansteuerung#Ansteuerung_mit_dem_Sc haltkreis_L298Ach ja: Dein Servo zuckt vermutlich, da deine PWM vom Timing zu ungenau ist: Ich vermute z.B. anstatt 1.5ms bekommst du mal 1.4ms/1.6ms oder schlimmer. Deswegen habe ich den AVR dazwischen.Das sollte sich mit einem Oszilloskop messen lassen.Ich bin erstaunt, daß du nur mit dem R-PI ohne RTOS den SRF auslesen kannst, welche Genauigkeit bekommst du hin?

- - - Aktualisiert - - -

Das RN wiki hat was dazu:http://www.rn-wissen.de/index.php/Getriebemotoren_Ansteuerung#Ansteuerung_mit_dem_Sc haltkreis_L298Ach ja: Dein Servo zuckt vermutlich, da deine PWM vom Timing zu ungenau ist: Ich vermute z.B. anstatt 1.5ms bekommst du mal 1.4ms/1.6ms oder schlimmer. Deswegen habe ich den AVR dazwischen.Das sollte sich mit einem Oszilloskop messen lassen.Ich bin erstaunt, daß du nur mit dem R-PI ohne RTOS den SRF auslesen kannst, welche Genauigkeit bekommst du hin?

pinsel120866
24.01.2013, 08:55
OK, Danke für die Anleitung.

Das SRF04 hat eine Genauigkeit von +/- 0,5 cm. Wobei die Ungenauigkeit mit zunehmenden Abstand grösser wird. Ist aber in diesem Fall für die Hinderniserkennung ausreichend, es wird ein Besenstiel in 1,5 Meter Entfernung erkannt.

Btw: Warum werden deine Posts doppelt angezeigt?

BastelWastel
24.01.2013, 09:07
Ich wuerde so repetitive tasks und genaue timings (z.B. Servos, Sensoren, etc..) auch eher auf einen kleinen AVR auslagern..und den PI fuer groessere Rechenaufgaben und Datenmengen (z.B. Navigation) frei halten.

pinsel120866
26.01.2013, 11:56
Als vorerst letztes Modul möchte ich euch noch meine Lösung für eine Linienverfolgung präsentieren.

Ich habe mich für eine fertig verlötete Platine mit 2 CNY70 entschieden: http://www.generationrobots.com/pob-line-sensor-robots-pob-technology,us,4,Pob-Line-Sensor.cfm
Im Lieferumfang ist noch ein Sharp Abstandsensor, diesen werde ich mich zu einem späteren Zeitpunkt zuwenden, da es nicht so einfach ist, einen analogen Sensor an die GPIO Pins anzuschliessen.

Diese Platine kann direkt an 3,3 Volt angeschlossen werden und somit wird auch für diese Anwendung kein Steckbrett benötigt. Als Input Pins werden noch die letzten verbleibenden mit der Nummer 7(links) und 12(rechts) verbunden. Damit sind mit Ausnahme der I2C Pins alle belegt, sollte jemand meinen "Vollausbau" nachgemacht haben.

Programm zum testen der Sensoren:

import RPi.GPIO as GPIO

import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BOARD)

GPIO.setup(7,GPIO.IN)
GPIO.setup(12,GPIO.IN)

while True:

input_re = GPIO.input(12)
input_li = GPIO.input(7)

print input_re
print input_li

time.sleep(1)

Ich habe natürlich ein Programm geschrieben, womit der Bot einer Linie folgt - Video hier: http://www.youtube.com/watch?v=oXrxMo1iL-8

Sollte jemand den Code verwenden wollen, PN mit Emailadresse an mich.

Video mit bessere Qualität: http://www.youtube.com/watch?v=AcXeFVIk8-w&feature=youtu.be

ex535
30.01.2013, 21:12
Hallo Pinsel,

guter Bericht zum raspberry pi.
Ich plane in Zukunft auch den Aufbau mit dem raspberry und dem Gertboard.
Zur Zeit beschäftige ich mit dem Gertboard.

Im Übrigen finde ich die ARM Serie (Cubieboard, Hackberry und Raspberry pi) sehr gut.

Schaun wir mal.
Gruß
Kurt
:)

pinsel120866
03.02.2013, 12:05
Nun kann auch die Geschwindigkeit geregelt werden!
Danke an tucow für die Unterstützung!

Lösung zum Steuern der Motoren des Pinselbots mittels Software-PWM:

Benötigt wird die Lib pizypwm.py, die sich im Anhang befindet. Einfach ins selbe Verzeichnis wie die Programmdatei legen.

Der nun angepasste Testcode für die Motoren sieht nun so aus:



import RPi.GPIO as GPIO

import time
import signal

from pizypwm import *

def endProcess(signalnum = None, handler = None):
first.stop()
second.stop()
third.stop()
fourth.stop()

GPIO.cleanup()
exit(0)

signal.signal(signal.SIGTERM, endProcess)
signal.signal(signal.SIGINT, endProcess)

first = PiZyPwm(20000, 19, GPIO.BOARD)
second = PiZyPwm(20000, 21, GPIO.BOARD)
third = PiZyPwm(20000, 23, GPIO.BOARD)
fourth = PiZyPwm(20000, 24, GPIO.BOARD)

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BOARD)

GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)

while True:

first.start(50)
second.start(0)
third.start(50)
fourth.start(0)
print "Drehung nach rechts"
time.sleep(1)

first.start(0)
second.start(0)
third.start(0)
fourth.start(0)
print "Stop"
time.sleep(1)

first.start(0)
second.start(50)
third.start(0)
fourth.start(50)
print "Drehung nach Links"
time.sleep(1)

first.start(0)
second.start(0)
third.start(0)
fourth.start(0)
print "Stop"
time.sleep(1)

first.start(50)
second.start(0)
third.start(0)
fourth.start(50)
print "Geradeaus vorwaerts"
time.sleep(1)

first.start(0)
second.start(0)
third.start(0)
fourth.start(0)
print "Stop"
time.sleep(1)

first.start(0)
second.start(50)
third.start(50)
fourth.start(0)
print "Geradeaus rueckwaerts"
time.sleep(1)

first.start(0)
second.start(0)
third.start(0)
fourth.start(0)
print "Stop"
time.sleep(1)

pinsel120866
10.02.2013, 09:33
Nun ist es auch möglich, den Servo mittels Software - PWM anzusteuern.
Danke an kampi für das Programm!

Democode:

import RPi.GPIO as GPIO
import time
import signal
import os
from pizypwm import *

def endProcess(signalnum = None, handler = None):
servo.stop()
GPIO.cleanup()
exit(0)

signal.signal(signal.SIGTERM, endProcess)
signal.signal(signal.SIGINT, endProcess)

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(26, GPIO.OUT)


while True:

Servo = PiZyPwm(500, 26, GPIO.BOARD)

user_input = raw_input("Bitte treffen Sie Ihre Wahl: ")

if(user_input == "l"):
Servo.start(90)
print "Drehung nach Links"
time.sleep(1)
Servo.stop()
GPIO.cleanup()
elif(user_input == "m"):
Servo.start(50)
print "Drehung in die Mitte"
time.sleep(1)
Servo.stop()
GPIO.cleanup()
elif(user_input == "r"):
Servo.start(10)
print "Drehung nach Rechts"
time.sleep(1)
Servo.stop()
GPIO.cleanup()
elif(user_input == "q"):
print "Programm wird beendet......"
os._exit(1)
Servo.stop()
GPIO.cleanup()
else:
print "Ungueltige Eingabe!"

pinsel120866
09.03.2013, 15:40
Endlich habe ich auch den SHARP Abstandssensor in Betrieb. Die Herausforderung hierbei war, dass der Sharp nur analoge Signale am Ausgang liefert mit denen der digitale GPIO nichts anfangen kann. Als eine Lösung bietet sich hier Kampis Vorschlag an: Ein Komparator. Dieser vergleicht 2 Eingangspannungen und schaltet durch, wenn diese erreicht sind. Nachdem der GPIO Pin im EIngang nur 3,3 Volt verträgt, muss man diese Spannung als Vergleichspannung hernehmen. Dies passt um so besser, als dass der Sharp am Ausgang maxmal 3,1 Volt liefert.

Benötigt wird:

- SHARP Abstandssensor (http://www.conrad.de/ce/de/product/504591/Distanz-Sensor-GP2Y0A21YK0F-Sharp-GP2Y0A21YK0F-Messbereiche-Erfassungsbereich-10-80-cm-5-VDC?queryFromSuggest=true)
- Trimmer Poti (http://www.conrad.de/ce/de/product/431222/Piher-Trimmer-PT-15-LH-stehend-PT-15-LH-5K-5-k-025-W-30-)
- Operationsverstärker (http://www.conrad.de/ce/de/product/175935/Linear-IC-National-Semiconductor-LM741CN-Gehaeuseart-DIL-8-Ausfuehrung-Operationsverstaerker?queryFromSuggest=true)
- Kabel

Verkabelt wird laut Skizze.
Program zum testen:

import RPi.GPIO as GPIO

import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BOARD)

GPIO.setup(26, GPIO.IN)

while True:

if GPIO.input(26) == True:
print GPIO.input(26)
time.sleep(0.5)

else:
print GPIO.input(26)
time.sleep(0.5)

Wenn man das ganze mit einer LED koppelt, sollte es so aussehen:
http://www.youtube.com/watch?v=bv1BKcY9Q24&list=UU8vzzeCkyH4y59agxNUSUew&index=2

SHARP kombiniert mit der Linienverfolgung:
http://www.youtube.com/watch?v=FUu941Vz4rI&list=UU8vzzeCkyH4y59agxNUSUew&index=1

Fazit/Epilog:

Ich habe meinen Pinselbot noch mit einem Rpi Type A (http://raspberrypi.rsdelivers.com/product/raspberry-pi/raspberry-pi-type-a/raspberry-pi-type-a-single-board-computer-256mb/7568317.aspx) ausgestattet (siehe Fotos). Der Vorteil hierbei ist, dass dieses Modell nur 200 mA Strom braucht und deswegen die Batterien etwa 3x so lange halten wie beim RPi Modell B.

Ich habe nun alle 17 GPIO Pins mit folgenden Funktionen belegt :

- Motorsteuerung 4 Pins
- LCD 6 Pins
- Servo 1 Pin
- Ultraschallmodul 2 Pins
- Liniensensor 2 Pins
- Sharp Abstandssensor 1 Pin
- LED 1 Pin

Nun warte ich auf den RPi Kamera, damit können sicher auch interessante Dinge gemacht werden (Gesichtserkennung, etc.)

Kampi
09.03.2013, 17:15
Hey,

die Motorsteuerung und die LED kannst du alternativ ja noch an einen PCF8574 packen.
Dadurch sparst du 5 GPIOs ein (nur so als Idee).
Auf die Kamera warte ich auch schon gespannt :D
Das Ding kommt an nen Servo und vielleicht noch 1-2 IR LEDs dran um eine brauchbare und schwenkbare Kamera zu haben.

pinsel120866
01.06.2013, 14:18
Gekauft bei RS: http://raspberrypi.rsdelivers.com/product/raspberry-pi/camera-module/raspberry-pi-hd-video-camera-module/7757731.aspx
Installation und Bedienung wie folgt: http://www.raspberrypi.org/archives/3890
Online Stream via VLC ist auch möglich: http://raspi.tv/2013/how-to-stream-video-from-your-raspicam-to-your-nexus-7-tablet-using-vlc

Ich habe einen Schlitz in die Plexiglasplattform gemacht und die Kamera darin fixiert (sh. Foto).

Sobald es mir möglich ist, werde ich mich mit der Objektverfolgung auseinandersetzen.

*Fortsetzung folgt*

feodor91
24.10.2013, 16:10
Prima Anleitung und Beschreibung!

Wärst du so nett die Links zu aktualisieren?

pinsel120866
17.11.2013, 14:37
Hallo,

nun eine Funktion des Bots mit Kamera: "Spionage-PiBot"

Zuerst ein Code, mit dem der Bot via Tastatur ferngesteuert werden kann:


#These are the keyboard mappings
#z = Go forward
#q = Stop going forward or back
#b = Go back
#g= Go left
#h = Go right

#Get the GPIO module
import RPi.GPIO as GPIO

#Get the time module
import time

#A routine to control a pair of pins
def ControlAPairOfPins(FirstPin,FirstState,SecondPin,S econdState):
print "Controlling them pins"
if FirstState == "1":
GPIO.output(int(FirstPin),True)
else:
GPIO.output(int(FirstPin),False)

if SecondState == "1":
GPIO.output(int(SecondPin),True)
else:
GPIO.output(int(SecondPin),False)
#Just retur
return

####Main body of code

#Get rid of warnings
GPIO.setwarnings(False)

#Set the GPIO mode
GPIO.setmode(GPIO.BOARD)
#Set the pins to be outputs
GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)

while True:
MyChar = raw_input("Press a character:")
print "You pressed: " + MyChar
if MyChar == "z":
ControlAPairOfPins("19","1","21","0")
ControlAPairOfPins("23","0","24","1")
print "Forward"
elif MyChar == "q":
ControlAPairOfPins("19","0","21","0")
ControlAPairOfPins("23","0","24","0")
print "Stop"
elif MyChar == "b":
ControlAPairOfPins("19","0","21","1")
ControlAPairOfPins("23","1","24","0")
print ("Back")
elif MyChar == "g":
ControlAPairOfPins("19","0","21","1")
ControlAPairOfPins("23","0","24","1")
print "Left"
elif MyChar == "h":
ControlAPairOfPins("19","1","21","0")
ControlAPairOfPins("23","1","24","0")
print "Right"
else:
print "Not a command"

Dann die Kamera einschalten:

raspivid -o - -t 999999 -hf -w 640 -h 360 -fps 25|cvlc -vvv stream:///dev/stdin --sout '#standard{access=http,mux=ts,dst=:8090}' :demux=h264

Und mittels VLC spionieren :-)
http://raspi.tv/2013/how-to-stream-video-from-your-raspicam-to-your-nexus-7-tablet-using-vlc

Viel Spass!

vincentp
21.08.2015, 14:23
Eine Frage ich möchte einen Pi Bot mit Tastatursteuerung WLAN und Kamera bauen dass Fahrgestell und die Brücke hab ich (genau das selbe wie Pinsel) und ich verstehe dass hier nicht wirklich kann mir jemand helfen??

morob
23.08.2015, 10:54
was verstehts du denn?