Differenze tra le versioni di "RaspiTank"

Da raspibo.
Jump to navigation Jump to search
Riga 1: Riga 1:
Il RaspiTank è un tentativo di integrare il Raspberry Pi con un vecchio giocattolo a motore elettrico con i cingoli. Il controllo del motore è analogo a quello della [[RaspiCar]] mentre lo sterzo è affidato a un ingranaggio che verrà mosso tramite un servo.
+
Il RaspiTank è un tentativo di integrare il Raspberry Pi con un vecchio giocattolo a motore elettrico con i cingoli. Il controllo del motore è analogo a quello della [[RaspiCar]] mentre lo sterzo è affidato a un ingranaggio tramite un servo.
 +
 
 +
== Prima versione ==
 +
 
 +
[[File:Raspitank finale.jpg]]
 +
 
 +
Al momento il RaspiTank ha le seguenti caratteristiche:
 +
* Motore alimentato da due batterie tipo D, alloggiate nel vano originale del giocattolo
 +
* Raspberry Pi modello A, con Wi-Fi dongle, alimentato da 4 pile AA; garantisce qualche ora di autonomia, a seconda dell'uso
 +
* Marcia avanti e indietro
 +
* Sterzo ottenuto facendo girare un cingolo solo alla volta, usando il differenziale originale del giocattolo mosso da un servocomando
 +
* Streaming dalla camera frontale
 +
* Luci a LED accendibili e spegnibili
 +
* Si può comandare da remoto tramite ssh con le frecce
 +
 
 +
Le caratteristiche in lavorazione sono:
 +
* Possibilità di registrare un percorso (è già possibile, ma è stato testato pochissimo)
 +
* Sensore della distanza
  
 
[[File:RaspiTank_inlavorazione.jpeg]]
 
[[File:RaspiTank_inlavorazione.jpeg]]
  
 
== Il nostro amico servocomando ==
 
== Il nostro amico servocomando ==
I servi si muovono grazie a un impulso PWM come descritto in questa pagina: [[Servo (radio control)]]. A cicli di 20ms, a seconda dell'ampiezza dell'impulso, il servo si metterà in una posizione.
+
I servi si muovono grazie a un impulso PWM come descritto in questa pagina: [[Servo (radio control)]]. A cicli di 20ms, a seconda dell'ampiezza dell'impulso, il servo si metterà in una posizione. Per il RaspiTank abbiamo usato la libreria ServoBlaster[https://github.com/richardghirst/PiBits/tree/master/ServoBlaster]. Poiché useremo (per ora) solo un servo abbiamo disabilitato tutti gli altri pin utilizzati dal demone di Servoblaster che altrimenti sarebbero stati inutilizzabili per altri scopi.
 +
 
 +
== Il groviglio di fili, ovvero la parte elettronica ==
 +
 
 +
[[File:Raspitank interior.jpg]]
 +
 
 +
Per l'azionamento del motore abbiamo riciclato i circuiti già fatti per la [[RaspiCar]] ovvero questi.
 +
 
 +
[[File:RaspiCar Schema Motor.png]]
 +
 
 +
La tensione data al motore circola in un senso o nell'altro a seconda di come scattano i due relè. Se il primo è acceso e il secondo è spento il motore girerà in un senso, vice versa se il primo è spento e il secondo è acceso il motore girerà nell'altro senso. Il motore resta spento se i due relè sono entrambi accesi o spenti.
 +
Questo è il circuito per far scattare il singolo relè.
 +
 
 +
[[File:RaspiCar Schema Relay.png]]
 +
 
 +
Per via di una interferenza che portava il servo a muoversi da solo durante la marcia, abbiamo usato un ulteriore relè che alimenta il servo solo quando si deve muovere. Il circuito per l'alimentazione del servo è lo stesso degli altri due relè.
 +
Per l'illuminazione abbiamo usato una luce alimentata da USB a due LED. Abbiamo collegato la terra alla terra della USB e il +5V al pin 15 wiringpi (pin 8 fisico). Nonostante siano solo 3,3V l'illuminazione è sufficiente per vedere diversi centimetri nell'oscurità ed evitare gli ostacoli.
  
== La webcam ==
+
== La camera ==
Il RaspiTank avrà una webcam per vedere in tempo reale dove sta andando. Al momento stiamo facendo delle prove con una micro webcam recuperata da un EeePC e unita con dei mammut a una porta USB. Lo streaming avviene tramite MjpegStreamer[http://sourceforge.net/projects/mjpg-streamer/].
+
Inizialmente il RaspiTank usava una webcam recuperata da un EeePC della ASUS collegata alla porta USB. Con il passaggio dal Raspberry Pi modello B al modello A è venuta meno una porta USB e aggiungere un HUB sarebbe stato scomodo. Abbiamo così deciso di non usare MjpegStreamer[http://sourceforge.net/projects/mjpg-streamer/] e di usare la camera da attaccare direttamente al Raspberry Pi. Questo ci ha costretti a disabilitare un pin di ServoBlaster (vedete la issue qui[https://github.com/richardghirst/PiBits/issues/11])
  
 +
== Il codice, mal scritto e mal commentato ==
 +
#!/usr/bin/python
 +
import os
 +
import wiringpi
 +
import curses
 +
import time
 +
import sys
 +
 +
#PIN da usare
 +
#11 controllo relay avanti
 +
#10 controllo relay indietro
 +
#14 controllo relay servo
 +
#7 PWM servo (servo n.0 ServoBlaster)
 +
#I relay devono essere alimentati da +5V
 +
#Il servo puo' essere alimentato da +3,3V
 +
 +
#Per registrare i comandi aggiungere il nome di un file (che sara' sovrascritto)
 +
#i comandi sono salvati in formato XML
 +
 +
def avanti():
 +
motor.digitalWrite(10,motor.HIGH)
 +
 +
def indietro():
 +
motor.digitalWrite(11,motor.HIGH)
 +
 +
def stop():
 +
motor.digitalWrite(10,motor.LOW)
 +
motor.digitalWrite(11,motor.LOW)
 +
 +
def antiorario():
 +
motor.digitalWrite(14,motor.HIGH)
 +
os.system("echo 0=240 > /dev/servoblaster")
 +
time.sleep(0.5)
 +
motor.digitalWrite(14,motor.LOW)
 +
 +
def orario():
 +
motor.digitalWrite(14,motor.HIGH)
 +
os.system("echo 0=60 > /dev/servoblaster")
 +
time.sleep(0.5)
 +
motor.digitalWrite(14,motor.LOW)
 +
 +
def dritto():
 +
motor.digitalWrite(14,motor.HIGH)
 +
os.system("echo 0=145 > /dev/servoblaster")
 +
time.sleep(0.5)
 +
motor.digitalWrite(14,motor.LOW)
 +
 +
 +
servodstart = os.system("ps -ae |grep servod >/dev/null") #controlla che servod sia stato lanciato
 +
if servodstart != 0:
 +
os.system("sudo servod >/dev/null")
 +
motor = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_PINS)
 +
motor.pinMode(10,motor.OUTPUT) #motore direzione 1
 +
motor.pinMode(11,motor.OUTPUT) #motore direzione -1
 +
motor.pinMode(14,motor.OUTPUT) #accensione servo
 +
motor.pinMode(15,motor.OUTPUT) #luci
 +
motor.digitalWrite(12,motor.LOW)
 +
stop()
 +
dritto()
 +
if __name__=="__main__":
 +
recording = False
 +
if len(sys.argv) > 2:
 +
print "troppi parametri"
 +
quit()
 +
elif len(sys.argv) == 2:
 +
filecom = open(sys.argv[1],'w')
 +
recording = True
 +
filecom.write("<listacomandi>")
 +
motion = ''
 +
direction ='straight'
 +
stdscr = curses.initscr()
 +
curses.cbreak()
 +
stdscr.keypad(1)
 +
stdscr.addstr(0,5,"Press 'q' to quit, up/down = Motion, left/right = Direct, space = Lights, home = Stream")
 +
stdscr.addstr(2,5,"Motion:")
 +
stdscr.addstr(3,5,"Direct:straight")
 +
stdscr.addstr(6,5,"Lights:off")
 +
stdscr.addstr(7,5,"Stream:off")
 +
curses.curs_set(0)
 +
stdscr.refresh()
 +
key = ''
 +
light = False
 +
timepress = 0
 +
while key != ord('q'):
 +
key = stdscr.getch()
 +
if key == ord(' '): #spazio accende e spegne le luci
 +
if light:
 +
motor.digitalWrite(15,motor.LOW)
 +
time.sleep(0.5)
 +
light = False
 +
stdscr.addstr(6,5,"Lights:off")
 +
else:
 +
motor.digitalWrite(15,motor.HIGH)
 +
time.sleep(0.5)
 +
light = True
 +
stdscr.addstr(6,5,"Lights:on ")
 +
elif key == curses.KEY_HOME:
 +
videostart = os.system("ps -ae|grep raspivid > /dev/null")
 +
if videostart !=0:
 +
stdscr.addstr(7,5,"Stream:on USE nc raspitank.local 9999 |mplayer -fps 150 -demuxer h264es -")
 +
os.system('raspivid -t 0 -fps 15 -w 640 -h 480 -rot 180 -o - |nc -l 9999 &')
 +
else:
 +
stdscr.addstr(7,5,"Stream:off                                                                ")
 +
os.system('killall raspivid >/dev/null')
 +
os.system('killall nc >/dev/null')
 +
elif key == curses.KEY_UP:
 +
if motion == 'down':
 +
if recording:
 +
filecom.write("<ordine>"+str(time.time()-timepress)+"</ordine></com>")
 +
stdscr.addstr(6,5,str(time.time() - timepress))
 +
stop()
 +
motion = ''
 +
time.sleep(0.2)
 +
elif motion == '':
 +
if recording:
 +
filecom.write("<com><ordine>bk</ordine>")
 +
timepress = time.time()
 +
avanti()
 +
motion = 'up'
 +
stdscr.addstr(2,5,"Motion:"+motion+"    ")
 +
stdscr.refresh()
 +
elif key == curses.KEY_DOWN:
 +
if motion == 'up':
 +
if recording:
 +
filecom.write("<ordine>"+str(time.time()-timepress)+"</ordine></com>")
 +
stdscr.addstr(4,5,str(time.time() - timepress))
 +
stop()
 +
motion = ''
 +
time.sleep(0.2)
 +
elif motion == '':
 +
if recording:
 +
filecom.write("<com><ordine>fd</ordine>")
 +
timepress = time.time()
 +
indietro()
 +
motion = 'down'
 +
stdscr.addstr(2,5,"Motion:"+motion+"    ")
 +
stdscr.refresh()
 +
elif key == curses.KEY_LEFT and not (motion == 'up' or motion == 'down'):
 +
stop()
 +
motion = ''
 +
if recording:
 +
filecom.write("<com><ordine>rt</ordine></com>")
 +
if direction == 'right':
 +
dritto()
 +
direction = 'straight'
 +
time.sleep(0.2)
 +
elif direction == 'straight':
 +
direction = 'left'
 +
orario()
 +
else:
 +
direction = 'left'
 +
time.sleep(0.2)
 +
stdscr.addstr(2,5,"Motion:"+motion+"    ")
 +
stdscr.addstr(3,5,"Direct:"+direction+"        ")
 +
stdscr.refresh()
 +
elif key == curses.KEY_RIGHT and not (motion == 'up' or motion == 'down'):
 +
stop()
 +
motion = ''
 +
if recording:
 +
filecom.write("<com><ordine>lt</ordine></com>")
 +
if direction == 'left':
 +
dritto()
 +
direction ='straight'
 +
time.sleep(0.2)
 +
elif direction == 'straight':
 +
direction = 'right'
 +
antiorario()
 +
else:
 +
direction = 'right'
 +
time.sleep(0.2)
 +
stdscr.addstr(2,5,"Motion:"+motion+"    ")
 +
stdscr.addstr(3,5,"Direct:"+direction+"        ")
 +
stdscr.refresh()
 +
os.system('killall raspivid >/dev/null')
 +
os.system('killall nc > /dev/null')
 +
stop()
 +
curses.endwin()
 +
if recording:
 +
filecom.write("<com><ordine>quit</ordine></com>")
 +
filecom.write("</listacomandi>")
 
[[Category:Progetti]]
 
[[Category:Progetti]]

Versione delle 22:27, 14 ago 2013

Il RaspiTank è un tentativo di integrare il Raspberry Pi con un vecchio giocattolo a motore elettrico con i cingoli. Il controllo del motore è analogo a quello della RaspiCar mentre lo sterzo è affidato a un ingranaggio tramite un servo.

Prima versione

Raspitank finale.jpg

Al momento il RaspiTank ha le seguenti caratteristiche:

  • Motore alimentato da due batterie tipo D, alloggiate nel vano originale del giocattolo
  • Raspberry Pi modello A, con Wi-Fi dongle, alimentato da 4 pile AA; garantisce qualche ora di autonomia, a seconda dell'uso
  • Marcia avanti e indietro
  • Sterzo ottenuto facendo girare un cingolo solo alla volta, usando il differenziale originale del giocattolo mosso da un servocomando
  • Streaming dalla camera frontale
  • Luci a LED accendibili e spegnibili
  • Si può comandare da remoto tramite ssh con le frecce

Le caratteristiche in lavorazione sono:

  • Possibilità di registrare un percorso (è già possibile, ma è stato testato pochissimo)
  • Sensore della distanza

RaspiTank inlavorazione.jpeg

Il nostro amico servocomando

I servi si muovono grazie a un impulso PWM come descritto in questa pagina: Servo (radio control). A cicli di 20ms, a seconda dell'ampiezza dell'impulso, il servo si metterà in una posizione. Per il RaspiTank abbiamo usato la libreria ServoBlaster[1]. Poiché useremo (per ora) solo un servo abbiamo disabilitato tutti gli altri pin utilizzati dal demone di Servoblaster che altrimenti sarebbero stati inutilizzabili per altri scopi.

Il groviglio di fili, ovvero la parte elettronica

Raspitank interior.jpg

Per l'azionamento del motore abbiamo riciclato i circuiti già fatti per la RaspiCar ovvero questi.

RaspiCar Schema Motor.png

La tensione data al motore circola in un senso o nell'altro a seconda di come scattano i due relè. Se il primo è acceso e il secondo è spento il motore girerà in un senso, vice versa se il primo è spento e il secondo è acceso il motore girerà nell'altro senso. Il motore resta spento se i due relè sono entrambi accesi o spenti. Questo è il circuito per far scattare il singolo relè.

RaspiCar Schema Relay.png

Per via di una interferenza che portava il servo a muoversi da solo durante la marcia, abbiamo usato un ulteriore relè che alimenta il servo solo quando si deve muovere. Il circuito per l'alimentazione del servo è lo stesso degli altri due relè. Per l'illuminazione abbiamo usato una luce alimentata da USB a due LED. Abbiamo collegato la terra alla terra della USB e il +5V al pin 15 wiringpi (pin 8 fisico). Nonostante siano solo 3,3V l'illuminazione è sufficiente per vedere diversi centimetri nell'oscurità ed evitare gli ostacoli.

La camera

Inizialmente il RaspiTank usava una webcam recuperata da un EeePC della ASUS collegata alla porta USB. Con il passaggio dal Raspberry Pi modello B al modello A è venuta meno una porta USB e aggiungere un HUB sarebbe stato scomodo. Abbiamo così deciso di non usare MjpegStreamer[2] e di usare la camera da attaccare direttamente al Raspberry Pi. Questo ci ha costretti a disabilitare un pin di ServoBlaster (vedete la issue qui[3])

Il codice, mal scritto e mal commentato

#!/usr/bin/python
import os
import wiringpi
import curses
import time
import sys

#PIN da usare
#11 controllo relay avanti
#10 controllo relay indietro
#14 controllo relay servo
#7 PWM servo (servo n.0 ServoBlaster)
#I relay devono essere alimentati da +5V
#Il servo puo' essere alimentato da +3,3V

#Per registrare i comandi aggiungere il nome di un file (che sara' sovrascritto)
#i comandi sono salvati in formato XML

def avanti():
	motor.digitalWrite(10,motor.HIGH)

def indietro():
	motor.digitalWrite(11,motor.HIGH)

def stop():
	motor.digitalWrite(10,motor.LOW)
	motor.digitalWrite(11,motor.LOW)
	
def antiorario():
	motor.digitalWrite(14,motor.HIGH)
	os.system("echo 0=240 > /dev/servoblaster")
	time.sleep(0.5)
	motor.digitalWrite(14,motor.LOW)

def orario():
	motor.digitalWrite(14,motor.HIGH)
	os.system("echo 0=60 > /dev/servoblaster")
	time.sleep(0.5)
	motor.digitalWrite(14,motor.LOW)

def dritto():
	motor.digitalWrite(14,motor.HIGH)
	os.system("echo 0=145 > /dev/servoblaster")
	time.sleep(0.5)
	motor.digitalWrite(14,motor.LOW)


servodstart = os.system("ps -ae |grep servod >/dev/null") #controlla che servod sia stato lanciato
if servodstart != 0:
	os.system("sudo servod >/dev/null")
motor = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_PINS)
motor.pinMode(10,motor.OUTPUT) #motore direzione 1
motor.pinMode(11,motor.OUTPUT) #motore direzione -1
motor.pinMode(14,motor.OUTPUT) #accensione servo
motor.pinMode(15,motor.OUTPUT) #luci
motor.digitalWrite(12,motor.LOW)
stop()
dritto()
if __name__=="__main__":
	recording = False
	if len(sys.argv) > 2:
		print "troppi parametri"
		quit()
	elif len(sys.argv) == 2:
		filecom = open(sys.argv[1],'w')
		recording = True
		filecom.write("<listacomandi>")
	motion = 
	direction ='straight'
	stdscr = curses.initscr()
	curses.cbreak()
	stdscr.keypad(1)
	stdscr.addstr(0,5,"Press 'q' to quit, up/down = Motion, left/right = Direct, space = Lights, home = Stream")
	stdscr.addstr(2,5,"Motion:")
	stdscr.addstr(3,5,"Direct:straight")
	stdscr.addstr(6,5,"Lights:off")
	stdscr.addstr(7,5,"Stream:off")
	curses.curs_set(0)
	stdscr.refresh()
	key = 
	light = False
	timepress = 0
	while key != ord('q'):
		key = stdscr.getch()
		if key == ord(' '): #spazio accende e spegne le luci
			if light:
				motor.digitalWrite(15,motor.LOW)
				time.sleep(0.5)
				light = False
				stdscr.addstr(6,5,"Lights:off")
			else:
				motor.digitalWrite(15,motor.HIGH)
				time.sleep(0.5)
				light = True
				stdscr.addstr(6,5,"Lights:on ")
		elif key == curses.KEY_HOME:
			videostart = os.system("ps -ae|grep raspivid > /dev/null")
			if videostart !=0:
				stdscr.addstr(7,5,"Stream:on USE nc raspitank.local 9999 |mplayer -fps 150 -demuxer h264es -")
				os.system('raspivid -t 0 -fps 15 -w 640 -h 480 -rot 180 -o - |nc -l 9999 &')
			else:
				stdscr.addstr(7,5,"Stream:off                                                                 ")
				os.system('killall raspivid >/dev/null')
				os.system('killall nc >/dev/null')
		elif key == curses.KEY_UP:
			if motion == 'down':
				if recording:
					filecom.write("<ordine>"+str(time.time()-timepress)+"</ordine></com>")
					stdscr.addstr(6,5,str(time.time() - timepress))
				stop()
				motion = 
				time.sleep(0.2)
		 	elif motion == :
				if recording:
					filecom.write("<com><ordine>bk</ordine>")
					timepress = time.time()
				avanti()
				motion = 'up'
			stdscr.addstr(2,5,"Motion:"+motion+"    ")
			stdscr.refresh()
		elif key == curses.KEY_DOWN:
			if motion == 'up':
				if recording:
					filecom.write("<ordine>"+str(time.time()-timepress)+"</ordine></com>")
					stdscr.addstr(4,5,str(time.time() - timepress))
				stop()
				motion = 
				time.sleep(0.2)
			elif motion == :
				if recording:
					filecom.write("<com><ordine>fd</ordine>")
					timepress = time.time()
				indietro()
				motion = 'down'
			stdscr.addstr(2,5,"Motion:"+motion+"    ")
			stdscr.refresh()
		elif key == curses.KEY_LEFT and not (motion == 'up' or motion == 'down'):
			stop()
			motion = 
			if recording:
				filecom.write("<com><ordine>rt</ordine></com>")
			if direction == 'right':
				dritto()
				direction = 'straight'
				time.sleep(0.2)
			elif direction == 'straight':
				direction = 'left'
				orario()
			else:
				direction = 'left'
				time.sleep(0.2)
			stdscr.addstr(2,5,"Motion:"+motion+"    ")
			stdscr.addstr(3,5,"Direct:"+direction+"         ")
			stdscr.refresh()
		elif key == curses.KEY_RIGHT and not (motion == 'up' or motion == 'down'):
			stop()
			motion = 
			if recording:
				filecom.write("<com><ordine>lt</ordine></com>")
			if direction == 'left':
				dritto()
				direction ='straight'
				time.sleep(0.2)
			elif direction == 'straight':
				direction = 'right'
				antiorario()
			else:
				direction = 'right'
				time.sleep(0.2)
			stdscr.addstr(2,5,"Motion:"+motion+"    ")
			stdscr.addstr(3,5,"Direct:"+direction+"         ")
			stdscr.refresh()
	os.system('killall raspivid >/dev/null')
	os.system('killall nc > /dev/null')
	stop()
	curses.endwin()
	if recording:
		filecom.write("<com><ordine>quit</ordine></com>")
		filecom.write("</listacomandi>")