21 ottobre 2017

Creo il mio ROBOT con Raspberry Pi #001 - SMART CAR!


Benvenuti nel primo episodio della serie #Ro-Pi: creo il mio ROBOT con Raspberry Pi!

Con questa puntata si dà il via a questa nuova serie di appuntamenti con il fai-da-te smanettoso in compagnia dei single board computer della fondazione inglese raspberry pi. In particolare, oggi vedremo come costruire un piccolo robottino in grado di muoversi sul piano (es: pavimento) con l'ausilio di due ruote, due motori che ne permettono le rotazioni oraria ed antioraria, ed un bridge-motor per gestirle in modo indipendente via codice Python in esecuzione su un Raspberry Pi Zero (wireless).

Prima di entrare nel merito, vi riporto il video abbinato a questo articolo che ho pubblicato sul mio canale YouTube nel quale viene mostrato il risultato in esecuzione e spiegata a grandi linee l'idea alla base del progetto:


Il primo step di questa avventura è quello di costruire una sorta di automobile più o meno intelligente, controllabile o tramite una sequenza di passi prestabiliti (es: vai avanti, gira a destra, ruota su te stessa, etc...) oppure tramite l'input in tempo reale via radiocomando.


Componenti hardware necessarie


Per costruire il nostro robot occorreranno:
  • almeno 2 ruote e altrettanti motori per farle girare in entrambi i sensi orario ed antiorario
  • in caso di 2 ruote servirà 1 terzo ruotino di bilanciamento
  • 1 piano di appoggio a cui agganciare ruote (e ruotino) e su cui posizionare il raspberry pi e le altre componenti necessarie al progetto
  • 1 contenitore per l'alimentazione (batterie)

Esistono diversi kit economici che contengono tutto il necessario, ma attenzione che i kit di base (come quello da me utilizzato) non sono sufficienti per far sì che sia possibile controllare il movimento delle ruote via raspberry pi.
Per questo motivo è indispensabile abbinare all'acquisto del kit anche quello di uno bridge-motor (nel video erroneamente chiamato step-motor), un componente che permette di controllare via codice il senso di rotazione dei due motori che fanno poi girare le ruote. I due motori possono essere controllati indipendentemente l'uno dall'altro.


Un bridge-motor ha quattro output sui lati sinistro e destro (due per lato) che permettono di inviare i singoli segnali necessari per attivare la rotazione (oraria o antioraria) dei motori. Presenta inoltre frontalmente due input per l'alimentazione del bridge-motor stesso e per chiudere il circuito, affiancati da un output che consente di alimentare eventuali componenti esterne (si rimanda al video per maggiori informazioni). Infine, sono presenti quattro pin che vanno collegati al raspberry pi e che permettono di controllare 1:1 gli output precedentemente descritti che sono collegati ai motori (e quindi alle ruote).

Nota 1: un pin ground/terra del raspberry pi va collegato con l'input ground dello bridge-motor così da chiudere il circuito a sua volta.

Nota 2: il bridge-motor consuma molta carica e quindi è consigliato l'uso di batterie ricaricabili.

Il bridge-motor necessita alimentazione a 9V e la/le batteria/e va/vanno collegata/e al bridge-motor in modo da chiudere il circuito, ed è possibile inserire un interruttore (come mostrato nel video) che permetta di accendere o spegnere il bridge-motor stesso all'occorrenza.


Se il bridge-motor richiede un'alimentazione a 9V per funzionare, il raspberry pi ne richiede 5V. Per questo motivo è necessario alimentarlo tramite una fonte differente. Anche in questo caso il consiglio è quello di utilizzare batterie ricaricabili o un powerbank (come mostrato nel video), uno di quelli che si usano per caricare il cellulare.

Nota 3: nonostante sia scomodo e ingombrante gestire due batterie differenti, allo stesso tempo è anche la soluzione più facile da implementare, meno rischiosa e sicuramente funzionante.

Il raspberry pi va collegato al bridge-motor tramite cavi diretti tra i pin presenti sul GPIO del pi e quelli precedentemente descritti presenti sullo bridge-motor. Vanno selezionati 4 pin programmabili tra quelli a disposizione (per dettagli sul GPIO guardare http://pinout.xyz). Una possibile scelta sono i pin 7, 11, 13 e 15, ma chiaramente non è l'unica possibile.

Nota 4: si è scelto di utilizzare il raspberry pi 0 (wireless) perché ha consumi ridotti ed è poco ingombrante, ma ovviamente è possibile utilizzare un pi 3 od un qualsiasi altro single board computer.


Il software


Per quel che riguarda il sistema operativo con cui manovrare il raspberry pi, beh, Raspbian OS è sicuramente la miglior scelta poiché è l'OS per raspberry pi 0 più ottimizzato e, soprattutto, perché contiene tutte le librerie per controllare il GPIO e le altre funzionalità utilizzate nel progetto.

Come detto, si vuole controllare il robot sia facendogli eseguire determinati spostamenti (es: percorsi predeterminati come figure geometriche) sia via input diretto. Questo secondo scenario richiede la presenza di una tastiera esterna collegata al pi stesso oppure il controllo da PC remoto.

Come funziona il bridge-motor? Ogni output è connesso ad un pin del raspberry pi (in questo esempio si è scelto di usare i pin 7, 11, 13 e 15), quindi per far muovere i motori nelle direzioni oraria ed antioraria (le quali abbinate assieme o eseguite singolarmente provocheranno lo spostamento del robot sul piano in varie direzioni) si dovrà accendere o spegnere i pin adeguatamente.

Il seguente codice permette di far disegnare un rettangolo al robot:

# import librerie GPIO e time
import RPi.GPIO as GPIO
import time

# selezione dei 4 pin per controllare il bridge-motor
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(15, GPIO.OUT)

# accendere i pin 7 e 15 per andare avanti
def backward() :
    GPIO.output(7, True)
    GPIO.output(15, True)

# accendere i pin 11 e 13 per andare indietro
def forward() :
    GPIO.output(11, True)
    GPIO.output(13, True)

# accendere gli specifici pin per girare
def backward_turnleft() :  #retro sx
    GPIO.output(7, True)
def forward_turnleft() :   #avanti sx
    GPIO.output(11, True)
def backward_turnright() : #retro dx
    GPIO.output(15, True)
def forward_turnright() :  #avanti dx
    GPIO.output(13, True)

# spegnere tutti i pin per fermare il robot
def stop() :
    GPIO.output(7, False)
    GPIO.output(11, False)
    GPIO.output(13, False)
    GPIO.output(15, False)

# passi per disegnare mezzo rettangolo
def half_square() :
    # avanti
    forward()
    time.sleep(.5)
    stop()

     # gira a destra
    forward_turnright()
    time.sleep(.3)
    stop()

     # avanti
    forward()
    time.sleep(.3)
    stop()

     # gira a destra
    forward_turnright()
    time.sleep(.3)
    stop()
 
# disegna mezzo rettangolo/quadrato
half_square()
# disegna mezzo rettangolo/quadrato
half_square()

# prima di uscire, pulizia del GPIO
GPIO.cleanup()

Nota 5: utilizzando pin differenti essi vanno impostati nel codice e, soprattutto, collegando in modo differente i cavi occorrerà verificare in ogni azione il pin corretto da attivare per muovere correttamente le ruote ed ottenere il risultato desiderato. Inoltre è possibile regolare i tempi (in secondi) di attivazione per ogni movimento.

Nota 6: potreste notare che il robottino non torni esattamente al punto di partenza. Questo dipende da diverse ragioni: tipologia del piano su cui si sta operando, bilanciamento del robot stesso, ma soprattutto perché di solito le componenti utilizzate per questo tipo di progetti fai-da-te non sono particolarmente precise.


Il seguente codice consente di comandare in tempo reale gli spostamenti:

# import librerie curses e GPIO
import curses
import RPi.GPIO as GPIO

# selezione dei 4 pin per controllare il bridge-motor
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(15, GPIO.OUT)

# definizione degli spostamenti (come da esempio precedente)
def backward() :
    GPIO.output(7, True)
    GPIO.output(15, True)
def forward() :
    GPIO.output(11, True)
    GPIO.output(13, True)
def backward_turnleft() :
    GPIO.output(7, True)
def forward_turnleft() :
    GPIO.output(11, True)
def backward_turnright() :
    GPIO.output(15, True)
def forward_turnright() :
    GPIO.output(13, True)
def stop() :
    GPIO.output(7, False)
    GPIO.output(11, False)
    GPIO.output(13, False)
    GPIO.output(15, False)

# cattura dei tasti premuti dall'utente
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)

# cicla indefinitamente per catturare i comandi
try:
    while True:
        char = screen.getch()
        # q = carattere di interruzione del programma
        if char == ord('q'):
            stop()
            break
        # su = avanza
        elif char == curses.KEY_UP:
            stop()
            forward()
        # giu = retromarcia
        elif char == curses.KEY_DOWN:
            stop()
            backward()
        # destra = ruota a destra andando avanti
        elif char == curses.KEY_RIGHT:
            stop()
            forward_turnright()
        # sinistra = ruota a sinistra andando avanti
        elif char == curses.KEY_LEFT:
            stop()
            forward_turnleft()
        # invio = ferma il robot
        elif char == 10:
            stop()

# restituisce il controllo della tastiera
finally:
    curses.nocbreak()
    screen.keypad(0)
    curses.echo()
    curses.endwin()

# prima di uscire, pulizia del GPIO
GPIO.cleanup()


Conclusioni


Bene, termina qui il primo episodio della serie!

Nelle prossime puntate si tenterà di fare riconoscere eventuali ostacoli e/o di far muovere autonomamente il robottino seguendo alcune informazioni ambientali.


A presto :-)

Nessun commento:

Posta un commento