Differenze tra le versioni di "RaspiTank"

Da raspibo.
Jump to navigation Jump to search
Riga 240: Riga 240:
  
 
[http://www.youtube.com/watch?v=QB28DayPIVk Il video della prima scampagnata del RaspiTank]
 
[http://www.youtube.com/watch?v=QB28DayPIVk Il video della prima scampagnata del RaspiTank]
 +
[http://www.youtube.com/watch?v=3hHXWNNRBxU Il video della prima escursione notturna]
  
 
[[Category:Progetti]]
 
[[Category:Progetti]]

Versione delle 01:33, 17 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

La libreria usata per la gestione della GPIO è wiringpi [4]. Per l'interfaccia testuale abbiamo usato curses. Il codice accetta un argomento, il nome del file xml su cui scrivere le azioni registrate. Se non è specificato non verrà registrato nulla. Al momento esiste uno script per riprodurre le azioni salvate o scritte a mano. Purtroppo il motore del RaspiTank non è molto preciso e quindi la registrazione, al momento, non è molto affidabile.

Le frecce su e giù controllano il motore. Per fermare il RaspiTank occorre dare il controllo contrario (i.e. se sta avanzando occorre premere giù). Le frecce destra e sinistra fanno spostare l'ingranaggio del differenziale. Non è possibile cambiare la direzione mentre il RaspiTank sta muovendosi. Il tasto spazio accende e spegne le luci. Il tasto home accende la camera e fa partire lo streaming.

#!/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>")

Il rudimentale sensore della distanza

Irsensor.JPG

Questo aggeggio è composto da un LED infrarosso (a destra) e un sensore (a sinistra). Ogni intervallo di uno o più secondi uno script scrive quante volte il sensore è stato colpito. Più un oggetto è vicino più infrarossi sono riflessi e quindi il sensore dà risultati più alti. Per funzionare funziona, ma è da tarare. Inoltre i pin liberi sul RaspiTank cominciano a scarseggiare. Al momento non è ancora stato montato.

La prima escursione!

Il video della prima scampagnata del RaspiTank Il video della prima escursione notturna