SBrick – controlo remoto com um gamepad

Apresento o meu script em python para controlar o SBrick com um gamepad a partir do Linux. Recorro à biblioteca PyGame para ler o gamepad (assumindo que o gamepad é suportado nativamente pelo Linux, ver também o meu artigo sobre como utiizar um gamepad com ev3dev) e ao comando gatttool do BlueZ 5.0 para comunicar via Bluetooth BLE com o SBrick (assumindo também a presença de um dongle Bluetooth 4.0).

 

Este script funciona bem com Ubuntu mas deverá também funcionar em qualquer variante de Debian incluindo Raspbian (no Raspberry Pi) e ev3dev (no LEGO Mindstorms EV3, onde utilizei uma versão inicial deste script).

#!/usr/bin/env python

# sudo apt-get install python-pygame

import sys, traceback, os
os.environ['SDL_VIDEODRIVER'] = 'dummy'
from math import log10
from subprocess import call
from time import sleep
from pygame import joystick, event, display

### buttons ###
B_TRIANG = 0
B_CIRC = 1
B_CROSS = 2
B_SQUARE = 3
B_LTRIG2 = 4
B_RTRIG2 = 5
B_LTRIG = 6
B_RTRIG = 7
B_SELECT = 8
B_LJOY = 10
B_RJOY = 11
B_START = 9


def main():
  try:
    display.init();
    joystick.init();
    js=joystick.Joystick(0);
    js.init();

    DRIVE_A="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0102"
    DRIVE_B="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0103"
    COAST_A="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=01020000"
    COAST_B="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=01030000"
    BREAK_A="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0002"
    BREAK_B="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0003"

    ### starts in Joystick mode ###
    control_by_JOYSTICK=True;

    num_axes=js.get_numaxes();
    num_buttons=js.get_numbuttons();
    num_hats=js.get_numhats();

    ### assuming 4 axes, 13 buttons and 1 hat

    flag=False;

    while True:
      x=y=motor_r=motor_l=0.0;
      event.pump();

      button_mode=js.get_button(B_SELECT);
      button_shot=js.get_button(B_SQUARE);

      if button_mode ==1:

        if control_by_JOYSTICK==True:
          control_by_JOYSTICK=False;
          print 'Control Mode=HAT';
        else:
          control_by_JOYSTICK=True;
          print 'Control Mode=JOYSTICK';


      ### joysticks axis [-1, +1]
      ### x=axis2 , y=-axis3
      ### ignore less than 0.2 (dead zone)
      ### apply log10(100x) (to reforce lower values)
      ### result is less or equal than 2 = log10(100)

      if control_by_JOYSTICK==True:

            # Control by Right Joystick, Axis 2 e 3

            axis2=js.get_axis(2);
            axis3=js.get_axis(3);

        if axis2>0:
          if axis2<0.2:
            x=0;
          else:
            x=log10(axis2*100);
        elif axis2<0:
          if axis2>-0.2:
            x=0;
          else:
            x=-log10(-axis2*100);
            else:
              x=0;

        if axis3>0:
          if axis3<0.2:
            y=0;
          else:
            y=-log10(axis3*100);
        elif axis3<0:
          if axis3>-0.2:
            y=0;
          else:
            y=log10(-axis3*100);
        else:
          y=0;

        if y<>0:
          if x<0:
            motor_r=100*y;
            # turn left => slow motor_l
               motor_l=y*(100+25*x);
          else:
            motor_el=100*y;
            # turn right => slow motor_r
            motor_r=y*(100-25*x);
        elif x<>0:
           # y=0, just turn
           motor_l=100*x;
           motor_r=-motor_l;

      else:

         # Control by HAT keys

         hat=js.get_hat(0);

         if hat==(0,1):
#            print 'FRONT';
            motor_r=100;
            motor_l=100;
          elif hat==(1,0):
#            print 'RIGHT';
            motor_l=100;
            motor_r=-100;
         elif hat==(0,-1):
#            print 'BACK';
            motor_r=-100;
            motor_l=-100;
         elif hat==(-1,0):
#            print 'LEFT';
            motor_l=-100;
            motor_r=100;
         elif hat==(1,1):
#            print 'FRONT+RIGHT';
            motor_l=100;
            motor_r=50;
         elif hat==(-1,1):
#            print 'FRONT+LEFT';
            motor_l=50;
            motor_r=100;
         elif hat==(-1,-1):
#            print 'BACK+LEFT';
            motor_l=-100;
            motor_r=-50;
         elif hat==(1,-1):
#            print 'BACK+RIGHT';
            motor_l=-50;
            motor_r=-100;


       # get direction and duty cycle

      if (motor_l<0):
     dir_l="00"
     duty_l=str(hex(int(-motor_l)))
      else:
         dir_l="01"
         duty_l=str(hex(int(motor_l)))

      if (motor_r<0):
     dir_r="01"
     duty_r=str(hex(int(-motor_r)))
      else:
         dir_r="00"
         duty_r=str(hex(int(motor_r)))

      # command+direction+dutycyle

      command_A=DRIVE_A+dir_r+duty_r[2:]
      command_B=DRIVE_B+dir_l+duty_l[2:]
      call(command_A, shell=True);
      call(command_B, shell=True);
      sleep(0.1)
#      call(BREAK_A,shell=True);
#      call(BREAK_B,shell=True);
      call(COAST_A,shell=True);
      call(COAST_B,shell=True);

    # end while

  except (KeyboardInterrupt, SystemExit):
      print "Exiting...";
  except Exception:
      traceback.print_exc(file=sys.stdout);

  js.quit();
  joystick.quit();
  display.quit();
  sys.exit(0);

if __name__ == "__main__":
    main()

SBrick – remote control with a wireless gamepad

Here is my python script for controlling SBrick with a gamepad from Linux. It uses pygame for reading the gamepad (as long as it’s supported by the kernel, see also my post about using a gamepad with ev3dev) and gatttool from BlueZ 5.x to talk to the SBrick (you need a BT 4.0 USB dongle)

It should work in Ubuntu and other Debian variants including Raspbian (Raspberry Pi) or ev3dev (LEGO Mindstorms EV3)

#!/usr/bin/env python

# sudo apt-get install python-pygame

import sys, traceback, os
os.environ['SDL_VIDEODRIVER'] = 'dummy'
from math import log10
from subprocess import call
from time import sleep
from pygame import joystick, event, display

### buttons ###
B_TRIANG = 0
B_CIRC = 1
B_CROSS = 2
B_SQUARE = 3
B_LTRIG2 = 4
B_RTRIG2 = 5
B_LTRIG = 6
B_RTRIG = 7
B_SELECT = 8
B_LJOY = 10
B_RJOY = 11
B_START = 9


def main():
  try:
    display.init();
    joystick.init();
    js=joystick.Joystick(0);
    js.init();

    DRIVE_A="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0102"
    DRIVE_B="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0103"
    COAST_A="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=01020000"
    COAST_B="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=01030000"
    BREAK_A="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0002"
    BREAK_B="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0003"

    ### starts in Joystick mode ###
    control_by_JOYSTICK=True;

    num_axes=js.get_numaxes();
    num_buttons=js.get_numbuttons();
    num_hats=js.get_numhats();

    ### assuming 4 axes, 13 buttons and 1 hat

    flag=False;

    while True:
      x=y=motor_r=motor_l=0.0;
      event.pump();

      button_mode=js.get_button(B_SELECT);
      button_shot=js.get_button(B_SQUARE);

      if button_mode ==1:

        if control_by_JOYSTICK==True:
          control_by_JOYSTICK=False;
          print 'Control Mode=HAT';
        else:
          control_by_JOYSTICK=True;
          print 'Control Mode=JOYSTICK';


      ### joysticks axis [-1, +1]
      ### x=axis2 , y=-axis3
      ### ignore less than 0.2 (dead zone)
      ### apply log10(100x) (to reforce lower values)
      ### result is less or equal than 2 = log10(100)

      if control_by_JOYSTICK==True:

            # Control by Right Joystick, Axis 2 e 3

            axis2=js.get_axis(2);
            axis3=js.get_axis(3);

        if axis2>0:
          if axis2<0.2:
            x=0;
          else:
            x=log10(axis2*100);
        elif axis2<0:
          if axis2>-0.2:
            x=0;
          else:
            x=-log10(-axis2*100);
            else:
              x=0;

        if axis3>0:
          if axis3<0.2:
            y=0;
          else:
            y=-log10(axis3*100);
        elif axis3<0:
          if axis3>-0.2:
            y=0;
          else:
            y=log10(-axis3*100);
        else:
          y=0;

        if y<>0:
          if x<0:
            motor_r=100*y;
            # turn left => slow motor_l
               motor_l=y*(100+25*x);
          else:
            motor_el=100*y;
            # turn right => slow motor_r
            motor_r=y*(100-25*x);
        elif x<>0:
           # y=0, just turn
           motor_l=100*x;
           motor_r=-motor_l;

      else:

         # Control by HAT keys

         hat=js.get_hat(0);

         if hat==(0,1):
#            print 'FRONT';
            motor_r=100;
            motor_l=100;
          elif hat==(1,0):
#            print 'RIGHT';
            motor_l=100;
            motor_r=-100;
         elif hat==(0,-1):
#            print 'BACK';
            motor_r=-100;
            motor_l=-100;
         elif hat==(-1,0):
#            print 'LEFT';
            motor_l=-100;
            motor_r=100;
         elif hat==(1,1):
#            print 'FRONT+RIGHT';
            motor_l=100;
            motor_r=50;
         elif hat==(-1,1):
#            print 'FRONT+LEFT';
            motor_l=50;
            motor_r=100;
         elif hat==(-1,-1):
#            print 'BACK+LEFT';
            motor_l=-100;
            motor_r=-50;
         elif hat==(1,-1):
#            print 'BACK+RIGHT';
            motor_l=-50;
            motor_r=-100;


       # get direction and duty cycle

      if (motor_l<0):
     dir_l="00"
     duty_l=str(hex(int(-motor_l)))
      else:
         dir_l="01"
         duty_l=str(hex(int(motor_l)))

      if (motor_r<0):
     dir_r="01"
     duty_r=str(hex(int(-motor_r)))
      else:
         dir_r="00"
         duty_r=str(hex(int(motor_r)))

      # command+direction+dutycyle

      command_A=DRIVE_A+dir_r+duty_r[2:]
      command_B=DRIVE_B+dir_l+duty_l[2:]
      call(command_A, shell=True);
      call(command_B, shell=True);
      sleep(0.1)
#      call(BREAK_A,shell=True);
#      call(BREAK_B,shell=True);
      call(COAST_A,shell=True);
      call(COAST_B,shell=True);

    # end while

  except (KeyboardInterrupt, SystemExit):
      print "Exiting...";
  except Exception:
      traceback.print_exc(file=sys.stdout);

  js.quit();
  joystick.quit();
  display.quit();
  sys.exit(0);

if __name__ == "__main__":
    main()

 

 

LEGO Power Functions MOD: SuperLamp

No meu rover AD4M4ST0R estava a utilizar 3 conjuntos 8870 (LEGO Power Functions Light) para iluminar o ambiente antes de tirar uma foto com a webcam. Como os LEDs utilizados pela LEGO consomem muito pouco (entre 3 a 4 mA quando usados no EV3) foram necessários 6 para poder tirar fotos satisfatórias em ambientes escuros.

Eu acho o conjunto 8870 um pouco desajeitado com aquela peça 2×2 intermédia. E também acho caro os €6 ou mais custam avulso (os que tenho vieram com os conjuntos 8293 (LEGO Power Functions Accessory Box).

Numa conversa no fórum PLUG ocorreu aproveitar os LEDs de uma lanterna ou candeeiro baratos, ontem recuperei essa ideia ao encontrar no Leroy Merlin estas lanternas por €2.99:

A lanterna funciona com 3 pilhas AAA. A acreditar no rótulo, consome 360 mW o que a 4.5V significa 80 mA, não é exagerado para o EV3. Ligando duas em série nem precisaria preocupar-me com a tensão, pode ser ligado directamente a uma bateria Power Functions ou a uma porta NXT/EV3.

O corpo da lanterna é em alumínio. Desenroscando a parte de trás da lanterna podemos retirar o suporte das pilhas mas como a parte frontal (com os LEDs e o «vidro») não é desenroscável usei um lápis sem bico para fazer pressão por dentro e retirar:

Os seis LED estão soldados a uma placa de circuito impresso circular com duas pistas também circulares, concêntricas. Os LEDs estão montados em paralelos, todos os ânodos numa primeira pista e todos os cátodos numa segunda pista. A pista interior estava ligada ao suporte das pilhas e é o positivo, a pista exterior fazia contacto com o corpo da lanterna e é o negativo.

Não parece existir nenhuma forma de limitação de currente (numa série de lanternas «gambiarra» de origem chinesa, com 24 a 28 LEDs e também 3 pilhas AAA, encontrei sempre uma resistência de 1.5Ω de 1W).

Para testar liguei o positivo de uma conjunto de pilhas Power Functions à pista interior de uma das placas e o negativo à pista exterior da outra placa. Depois liguei as restantes pistas (pista exterior da primeira placa e pista interior da segunda placa):

E funciona!

Com um multímetro em modo Amperímetro verifica-se o consumo:

Uhmmmm… bastante mais que os 80 mA esperados. Mas aceitável à mesma para o propósito em vista (períodos curtos, controlo PWM).

Confirmadas as ligações soldei os fios e isolei com fita de electricista:

Pode-se ver na parte superior da imagem acima que usei fichas «mini-banana» junto ao terminal Power Functions de modo a poder trocar a polaridade se necessário).

A «LEGOlização» foi mais uma vez conseguida à custa do famigerado Kragle (cola de contacto transparente)

E finalmente a montagem no AD4M4ST0R:

Com o ev3dev utilizei o segunte comando para comparar consumos:

cat /sys/class/power_supply/legoev3-battery/current_now

Para cada cenário medi 10 vezes e calculei a média (sempre com o EV3 com bateria ligada ao carregador):

  • Em repouso: 317 mA
  • Com 6 LEDs Power Functions @100%: 340 mA
  • Com SuperLamps @100%:  579 mA

Portanto os 6 LEDs Power Functions consomem 23 mA e as minhas SuperLamps consomem 262 mA (onze vezes mais!). É um valor bastante superior aos 181 mA medidos com o multímetro e o suporte de pilhas Power Functions e que já faz considerar a hipótese de adicionar um díodo do tipo 1N400x para reduzir um pouco a tensão aplicada aos LEDs e com isso reduzir a corrente.

 

 

 

AD4M4ST0R – controlando LEDs

This post is part 5 of 9 of  AD4M4ST0R - um rover LEGO

A qualidade das fotos tiradas pela webcam Logitech C170 não é má… desde que haja suficiente luz ambiente. Por isso lembrei-me de ligar LED’s Power Functions a uma das portas de saída ainda disponíveis para funcionar como «flashes» ao tirar a fotografia.

Infelizmente a versão actual do ev3dev ainda não permite o controlo individual das portas (foi aberto hoje um issue, depois de uma troca de ideias) por isso a única maneira é enganar o ev3dev fazendo-o acreditar que tem um motor.

Os motores e os sensores EV3 têm uma funcionalidade «Auto-ID» que permite ao EV3 identificar que dispositivo foi ligado a cada porta (género “Plug and Play”). Nos videos do utilizador “TecnicRobot” ele utiliza um par de resistências para que os seus dispositivos de saída pareçam ser motores EV3.

Para isso fiz um cabo semelhante a este (não tinha resistências de 1KΩ e 10 KΩ à mão mas como o que interessa é a proporção usei de 2.2KΩ e 22KΩ) e funciona.

(o pinout do cabo EV3 foi baseado neste)

    EV3 Cable                             PF Cable
                                           - 9V
White    Pin 1 (M1)     -------------------- C2 (middle)
Black    Pin 2 (M2)     -------------------- C1 (middle)
Red      Pin 3 (GND)    ----[R1]---x       - GND
Green    Pin 4 (POWER)  ----[R2]---x
Yellow   Pin 5 (TACHO0) -----------x
Blue     Pin 6 (TACHO1) -------- Pin 3 (GND)

R2 ~10xR1
R1 = 1K, 2K2, 3K3...
R2 = 10K, 22K, 33K...
dmesg:
tacho-motor tacho-motor2: Tacho motor registered.
ev3-tacho-motor outC:motor: A Tacho Motor connected to port outC gpio 93 irq 194

Para acender os LEDs a meia intensidade:

echo 50 > /sys/class/tacho-motor/tacho-motor2/duty_cycle_sp
echo 1 > /sys/class/tacho-motor/tacho-motor2/run

Para acender na máxima intensidade:

echo 100 > /sys/class/tacho-motor/tacho-motor2/duty_cycle_sp
echo 1 > /sys/class/tacho-motor/tacho-motor2/run

ad4m4st0r-02 (parece-me que é altura de fazer um cabo decente e dar uma arrumação aos cabos do AD4M4ST0R).

Durante a noite, numa sala com pouca iluminação (halogéneo)

ad4m4st0r-03Durante a manhã, no mesmo local com iluminação média (natural mas indirecta):

ad4m4st0r-04A terceira imagem foi tirada com um segundo par de LED’s Power Functions o que me levou na noite seguinte a acrescentar um terceiro par:

ad4m4st0r-06As 4 imagens correspondem a Duty Cycles de 0%, 33%, 67% e 100% (ou seja os LED’s apagados, o equivalente a um par aceso, o equivalente a dois pares acesos e os três pares acesos).

Assim que me for possível vou tentar medir a luminosidade ambiente com um EV3 Color Sensor (45506) para determinar automaticamente o Duty Cycle a aplicar aos LEDs antes de cada fotografia.

SmartBrick – em breve num LEGO perto de si

A campanha KickStarter atingiu o primeiro objectivo, 7 dias antes da deadline e posso orgulhar-me de ter dado o meu contributo. Espero poder ajudar ainda mais nos próximos meses, vamos a ver.

To everyone who has made this possible,

We want to thank you from the bottom of our hearts for all the help you have given us over the last three weeks. All the support you have given has led this project to success. We know the hard part only begins now, as we have just placed our order for the first shipment of BLE chips 🙂

We want to thank you for the all the work you have put into spreading the news about the project. You are responsible for the wonderful karma that has been with us all along the way!

Dear Friends,  and we think we can call you that by now, we have worked really hard over the last 8 months in building SBrick for you. Now that we have reached our funding goal, our common dream will become a reality,  and you will be there with us to enjoy all the fun that this project will bring!

Thank you again for all your support, and keep on supporting the SBrick!

Estou ansioso por poder testar um bichinho destes com o Raspberry Pi e com o LEGO Mindstorms EV3. Acho que é desta que vou aprender a programar decentemente em Python 😉

Pitágoras e Base Jumping

Com 2 sensores de toque (é o que tenho neste momento) e um motor ocorreu-me um elevador automático, capaz de desligar ou reverter o motor cada vez que a cabina atinja um dos extremos do percurso:

pitagoras-elevator

O elevador em si não é muito diferente do de elevador de Linda Hamilton e a ideia da sua utilização com um Raspberry Pi e um PiFace Digital também não é original (Reinoud de Lange recorreu a microswitches em vez de sensores LEGO).

O código (um loop infinito que desloca a cabina para cima e para baixo)

#!/usr/bin/python3

import sys
from time import sleep
import pifacedigitalio

pifacedigital = pifacedigitalio.PiFaceDigital()
led7=pifacedigital.leds[7]
led6=pifacedigital.leds[6]
led7.turn_off()
led6.turn_off()
in0=pifacedigital.input_pins[0]
in1=pifacedigital.input_pins[1]

subir=True

sleep(2.0)

while(True):
 if(in1.value != 0):
   print("EM BAIXO!")
   led6.turn_on()
   sleep(0.025)
   led6.turn_off()
   subir=True

 if(in0.value != 0):
  print("NO ALTO!")
  led7.turn_on()
  sleep(0.025)
  led7.turn_off()
  subir=False

 if((in0.value ==0) and (in1.value ==0)):
   if (subir):
     print("PARA CIMA!")
     led6.turn_on()
     sleep(0.025)
     led6.turn_off()
   else:
     print("PARA BAIXO!")
     led7.turn_on()
     sleep(0.025)
     led7.turn_off()

Alguns pormenores da montagem:

elevator-bottom-sensor
O sensor no fundo do «poço» do elevador
elevator-winch
O mecanismo que puxa o elevador
elevator-top-sensor
O sensor no topo do «poço» do elevador
elevator-cabin-basejumper
A cabina do elevador levando um assustado base jumper

Pitagoras e a Esfinge

Faltava ainda um tipo qualquer de sensor para ter um sistema verdadeiramente autónomo por isso liguei um sensor de toque LEGO Mindstorms (ainda estilo RCX) a uma das entradas digitais PiFace.

O PiFace tem 8 entradas digitais com pull-ups internos (li algures que se podem desligar, deixando as entradas «flutuantes»). Como o sensor de toque RCX é um mero interruptor basta ligar um dos cabos a uma das entradas e o outro à massa. Com o sensor em repouso (interruptor aberto) a entrada do PiFace vai ler um “1” e quando ocorrer contacto (interruptor fechado) a entrada vai ficar ligada à massa e é lido um “0”.

bricklink.com: Lego Touch Sensor (879)

É muito fácil acompanhar o estado do sensor, basta ler continuamente o estado da entrada. No script abixo usei a entrada #0 e acrescentei um atraso de 200 ms entre cada leitura para não inundar o terminal com mensagens “ON!” ou “OFF!”

#!/usr/bin/python3

import sys
from time import sleep
import pifacedigitalio

pifacedigital = pifacedigitalio.PiFaceDigital()
led7=pifacedigital.leds[7]
led6=pifacedigital.leds[6]
led7.turn_off()
led6.turn_off()
in0=pifacedigital.input_pins[0]

while(True):
 if(in0.value != 0):
   print("ON!")
 else:
   print("OFF!)
 sleep(0.2)

E se quisermos usar o sensor para controlar o leão basta juntar tudo:

#!/usr/bin/python3

import sys
from time import sleep
import pifacedigitalio

DELAY_UP = 0.17
DELAY_DOWN = 0.14
DELAY_WAIT = 0.75

pifacedigital = pifacedigitalio.PiFaceDigital()
led7=pifacedigital.leds[7]
led6=pifacedigital.leds[6]
led7.turn_off()
led6.turn_off()
in0=pifacedigital.input_pins[0]

while(True):
 if(in0.value != 0):
   print("Para cima!")
   led7.turn_on()
   sleep(DELAY_UP)
   led7.turn_off()
   print("Espera!")
   sleep(DELAY_WAIT)
   print("Para baixo!")
   led6.turn_on()
   sleep(DELAY_DOWN)
   led6.turn_off()

Para ligar o sensor à entrada #0 do Piface Digital cortei um cabo RCX a meio:

rcx-cableO diagrama abaixo ilustra a configuração final, no que diz respeito às ligações eléctricas:

pitagoras-e-a-esfinge

Controlo de motores Lego

Quero utilizar o Raspberry Pi para controlar directamente construções em Lego, um pouco à maneiro do Lego Education WeDo Robotics.

Encomenda à PTRobotics:

Já tinha:

  • Lego Power Functions Rechargeable Battery Box (8878) ou AA Battery Box (8881)
  • Lego Power Functions XL Motor (8882)
  • fio eléctrico
  • carregador com ficha micro-USB
  • SD Card 4 GB com Raspbian instalado e pré-configurado para wi-fi para evitar ter de usar um teclado e um monitor
  • 2 resistências entre 220 Ω e 2.2 KΩ (usei duas de 1 KΩ)

A montagem do PiFace é simples: encaixar o módulo sobre o Raspberry Pi, inserir o SD Card e o Wi-Pi e fornecer energia através do cabo micro-USB.

O PiFace faz uso da interface SPI pelo que é necessário activá-la:

$sudo raspi-config

Escolher no menu “8 Advanced Options” e depois “A5 SPI”, responder “yes” e finalmente “finish”. Não é necessário reboot.

É também necessário instalar o módulo python para o PiFace, que já faz parte do repositório do Raspbian:

$sudo apt-get install python3-pifacedigitalio

Para testar, basta correr o script que vem com o módulo:

$python3 /usr/share/doc/python3-pifacedigitalio/examples/blink.py

O LED #7 acende e apaga segundo a segundo, tudo OK podemos passar ao controlo do motor.

As saídas do PiFace são Open Collector pelo que é necessário um pull up (ligar aos +5 V através de um resistência) para obter algo compatível com as entradas da bridge.

A bridge é alimentada pela bateria Lego Power Functions (usei um cabo Power Functions cortado a meio, aproveitando apenas os 2 condutores exteriores – um para GND e o outro para PWR).

powerfunctions-hbridge-powerUtilizei um voltímetro para confirmar qual o positivo e qual o negativo – no caso do modelo 8878 da foto acima o selector de velocidade ficou rodado até ao extremo no sentido dos ponteiros do relógio; no modelo 8881 é necessário deslocar o selector no sentido da ficha.

O motor é ligado à H-bridge com a outra metade do cabo anterior, desta vez utilizando apenas os 2 condutores interiores.

O script blinky.py anterior serve para testar mas para controlo manual a partir da shell do python optei por usar estes comandos:

$python3
>>>import pifacedigitalio
>>>pifacedigital = pifacedigitalio.PiFaceDigital()
>>>led7=pifacedigital.leds[7]
>>>led6=pifacedigital.leds[6]
>>>led7.turn_off()
>>>led6.turn_off()

Para acender apenas o LED #7 e fazer o motor rodar num sentido:

>>>led7.turn_off()
>>>led6.turn_on()

Para acender apenas o LED #6 e fazer o motor rodar no sentido oposto:

>>>led7.turn_on()
>>>led6.turn_off()

Se acender ambos os LED o motor permanece parado:

>>>led7.turn_on()
>>>led6.turn_on(

E para sair da shell de python:

>>>exit()