Relés USB

Adquiri um módulo USB-RLY16 que permite comandar 8 relés através de uma porta USB. A ideia original é controlar as minifiguras LEGO em palco pelo que com 8 relés poderei controlar 4 micromotores LEGO de forma independente e em ambos os sentidos (os Xutos&Pontapés são 5 pelo que 2 deles terão de partilhar o mesmo motor ou terei de arranjar outra forma para controlar um quinto motor).

O módulo é baseado num circuito FT232RL que emula uma porta série através da ligação USB. Em Linux o suporte a este tipo de devices já vem incluído no kernel sendo associado um device do tipo ‘/dev/ttyUSBn’. No meu PC com Ubuntu 14.04 funcionou à primeira, tal como no EV3 com ev3dev e estou 100% convencido que com Raspberry Pi e Raspbian acontecerá o mesmo.

São necessárias duas alimentações: uma para o accionamento dos relés e outra (ou outras) para os circuitos controlados pelos relés. Teoricamente podem ser as mesmas mas optei por separá-las:

  • uma pilha PP3 com ficha de 2.1mm para o accionamento dos relés
  • uma pilha PP3 em caixa LEGO para os motores

Nota: a pseudo-documentação afirma serem necessários pelo menos 12V/500 mA para o accionamento dos relés mas dei-me bem com os 9V de uma pilha alcalina PP3.

Ligando ao EV3:

$ dmesg
(...)
usb 1-1.4: new full-speed USB device number 6 using ohci
usbcore: registered new interface driver usbserial
usbcore: registered new interface driver ftdi_sio
usbserial: USB Serial support registered for FTDI USB Serial Device
ftdi_sio 1-1.4:1.0: FTDI USB Serial Device converter detected
usb 1-1.4: Detected FT232RL
usb 1-1.4: Number of endpoints 2
usb 1-1.4: Endpoint 1 MaxPacketSize 64
usb 1-1.4: Endpoint 2 MaxPacketSize 64
usb 1-1.4: Setting MaxPacketSize 64
usb 1-1.4: FTDI USB Serial Device converter now attached to ttyUSB0

Para comunicar com a placa é necessário configurar a porta série virtual (/dev/ttyUSB0) para comunicar a 19200 baud, 8 databits, 2 stop bits, sem paridade (19200 8N2) e sem hardware nem software handshaking. No Ubuntu usei o ‘puTTy’ mas como requer ambiente gráfico no ev3dev optei pelo ‘minicom’:

$ apt-get install minicom

O minicom tem um modo de setup:

$ minicom -s

depois de configurado (19200 8N2, no flow control) se carregarmos na tecla ‘d’ accionamos todos os relés e na tecla ‘n’ desactivamos todos (confirmem numa tabela ASCII que correspondem aos códigos decimais 100 e 110). Confirmado o funcionamento podemos sair (‘Control+A’ seguido de ‘Q’), a porta virtual permanece configurada até ao próximo reboot.

Podemos agora enviar comandos directamente da shell:

$ echo d > /dev/ttyUSB0
$ echo n > /dev/ttyUSB0

Em python podemos comunicar directamente com a porta virtual através da biblioteca pyserial (http://pyserial.sourceforge.net/):

$ apt-get install python-serial
import serial
from time import sleep

port = serial.Serial("/dev/ttyUSB0", baudrate=19200, bytesize=8, parity='N', stopbits=2, timeout=None, xonxoff=0, rtscts=0)
port.write("d");
sleep(1);
port.write("n");
sleep(1);
port.close()

O video acima corresponde ao script python abaixo:

import serial
from time import sleep


# da esquerda para a direita:
# motores A, B, C e D
#
# motor A e/f o/p
# motor B g/h q/r
# motor C i/j s/t
# motor D k/l u/v
#

def relays_all_off():
  port.write("n");

def relays_all_on():
  port.write("d");

### Motor A ###
def motor_A_Right():
  port.write("ep");

def motor_A_Left():
  port.write("of");

def motor_A_OFF():
  port.write("op");

### Motor B ###
def motor_B_Right():
  port.write("gr");

def motor_B_Left():
  port.write("qh");

def motor_B_OFF():
  port.write("qr");

### Motor C ###
def motor_C_Right():
  port.write("it");

def motor_C_Left():
  port.write("sj");

def motor_C_OFF():
  port.write("st");

### Motor D ###
def motor_D_Right():
  port.write("kv");

def motor_D_Left():
  port.write("ul");

def motor_D_OFF():
  port.write("uv");


port = serial.Serial("/dev/ttyUSB0", baudrate=19200, bytesize=8, parity='N', stopbits=2, timeout=None, xonxoff=0, rtscts=0)

motor_A_Left();
motor_B_Left();
motor_C_Left();
motor_D_Left();
sleep(1);
motor_A_OFF();
motor_B_OFF();
motor_C_OFF();
motor_D_OFF();
sleep(1);
motor_A_Right();
motor_B_Right();
motor_C_Right();
motor_D_Right();
sleep(1);
motor_A_OFF();
motor_B_OFF();
motor_C_OFF();
motor_D_OFF();
sleep(2);

motor_A_Left();
sleep(1);
motor_A_OFF();
sleep(1);
motor_B_Left();
sleep(1);
motor_B_OFF();
sleep(1);
motor_C_Left();
sleep(1);
motor_C_OFF();
sleep(1);
motor_D_Left();
sleep(1);
motor_D_OFF();
sleep(1);

port.close();

 

Projectores LEGO

This post is part 3 of 3 of  Rede de controlo 1-wire

Alguns pormenores da montagem dos projectores LEGO para o palco do concerto dos Xutos&Pontapés:

As peças que formam o corpo do projector:

 

O LED de luz branca e a resistência para limitar a corrente (utilizei um LED SMD mas também é possível um LED convencional de 3 mm apesar de não deixar que a lente colorida feche na perfeição):

 

Nota: entretanto comprei outras resistẽncias supostamente idênticas (inclusive da mesma potência, 1/4W) mas significativamente mais pequenas e que cabem dentro do corpo do projector pelo que nos projectores mais recentes ficam escondidas.

A queda de tensão no LED é de 3 V e como usei uma resistência de 270Ω para uma alimentação de 9 V como é o caso de uma pilha PP3 temos uma corrente no LED aceso de 22 mA; se utilizar uma bateria Power Functions ou Mindstorms a tensão será um pouco menor e além disso a saída do tipo ‘open drain’ do DS2413 retira 0.4 V por isso a corrente efectiva no LED deverá ser próxima de 18 mA.

O projector com a lente colorida. Há pouca variedade de cores translúcidas desta peça (azul, laranja, vermelho claro, amarelo e transparente) por isso talvez venha a experimentar outras peças:

O cabo já entrançado e uma visão da parte traseira do projector (os cabos passam por dentro da pega, ajuda a fixar os cabos ao corpo):

 

1-wire LEGO LED stripe

This post is part 2 of 3 of  Rede de controlo 1-wire

E agora um primeira experiência com múltiplos DS2413 numa mesma microLAN…

Cada dispositivo 1-wire tem um ID distinto gravado em fábrica:

$sudo ls /mnt/1wire/
3A.4C2B13000000  81.086D33000000  settings    structure  uncached
3A.B0E216000000  bus.1          statistics  system

Vemos que temos 3 dispositivos de 2 classes diferentes.  A classe 81 é a do Master Controller (o adaptador USB DS9490R) e a classe  3A é a do DS2413. Temos portanto dois dispositivos DS2413 na rede, cada um com o seu ID:

  • 4C2B13000000
  • B0E216000000

Na forma como o owfs lida com 1-wire o par “Classe.ID” funciona como um endereço. É possível definir alias mas funcionam apenas localmente (isto é: se movermos a microLAN do meu Ubuntu para o LEGO ev3dev tẽm de ser redefinidos) e na minha primeira experiência com alias perdi o acesso aos dispositivos por isso deixo para outra altura.

Sendo da mesma classe, estes dois dispositivos partilham os mesmos atributos (PIO.A, PIO.B e PIO.ALL por exemplo). Se tiver um LED em cada PIO destes devices podemos por exemplo acender todos os LEDs percorrendo todos os dispositivos da classe 3A e escrevendo “1,1” na subpasta PIO.ALL.

O programa abaixo acende cada LED em sequência, primeiro num sentido depois no outro:

import sys, traceback
from time import sleep
from subprocess import call

# B0E216000000/PIO.A = primeiro LED
# B0E216000000/PIO.B = segundo LED
# 4C2B13000000/PIO.A = terceiro LED
# 4C2B13000000/PIO.B = quarto LED

def main():
    try:

# apagar tudo ao comecar

    call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
    call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

        while True:
        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

                call("echo 1 > /mnt/1wire/3A.B0E216000000/PIO.A", shell=True); # LED1
                sleep(0.25);

        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

                call("echo 1 > /mnt/1wire/3A.B0E216000000/PIO.B", shell=True); # LED2
                sleep(0.25);

        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

        call("echo 1 > /mnt/1wire/3A.4C2B13000000/PIO.A", shell=True); # LED3
                sleep(0.25);

        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

        call("echo 1 > /mnt/1wire/3A.4C2B13000000/PIO.B", shell=True); # LED4
                sleep(0.25);

        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

        call("echo 1 > /mnt/1wire/3A.4C2B13000000/PIO.A", shell=True); # LED3
                sleep(0.25);

        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

                call("echo 1 > /mnt/1wire/3A.B0E216000000/PIO.B", shell=True); # LED2
                sleep(0.25);


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

# apagar tudo antes de sair

    call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
    call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);
    sys.exit(0);

if __name__ == "__main__":
    main()

 

E o programa abaixo acende as luzes aleatoriamente, mais próprio para um concerto ou uma discoteca (com tempo hei-de estudar a forma de usar as rotinas PyAudio para medir a intensidade de uma música e controlar as luzes ao ritmo desta embora duvide que o EV3 tenha CPU para tal).

 

 

import sys, traceback
from time import sleep
from subprocess import call
from random import randrange

# B0E216000000/PIO.A = primeiro LED
# B0E216000000/PIO.B = segundo LED
# 4C2B13000000/PIO.A = terceiro LED
# 4C2B13000000/PIO.B = quarto LED


def main():
    try:

# apagar tudo ao comecar

    call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
    call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

        while True:
        # apaga tudo
        call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
        call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);

        if (randrange(2) == 1):
                    call("echo 1 > /mnt/1wire/3A.B0E216000000/PIO.A", shell=True); # LED1

        if (randrange(2) == 1):
                    call("echo 1 > /mnt/1wire/3A.B0E216000000/PIO.B", shell=True); # LED2

        if (randrange(2) == 1):
            call("echo 1 > /mnt/1wire/3A.4C2B13000000/PIO.A", shell=True); # LED3

        if (randrange(2) == 1):
            call("echo 1 > /mnt/1wire/3A.4C2B13000000/PIO.B", shell=True); # LED4
                
                sleep(0.25);


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

# apagar tudo antes de sair

    call("echo 0,0 > /mnt/1wire/3A.B0E216000000/PIO.ALL", shell=True);
    call("echo 0,0 > /mnt/1wire/3A.4C2B13000000/PIO.ALL", shell=True);
    sys.exit(0);

if __name__ == "__main__":
    main()

 

1-wire LED

This post is part 1 of 3 of  Rede de controlo 1-wire

Estou a reproduzir em LEGO um concerto dos Xutos&Pontapés. A posição dos elementos da banda em palco vai ser controlada por um controlador (ainda não decidi se um Raspberry Pi ou um LEGO EV3) e quero poder controlar também as luzes dos projectores:

Se as luzes acendessem todas em simultâneo as ligações eléctricas seriam simples e seriam necessários passar apenas 2 cabos (positivo e negativo, comuns a todos os LEDs) pela estrutura por cima do palco. Mas eu quero um controlo individual dos projectores e pelo menos 10 deles. Isso significa pelo menos 11 cabos (10 positivos e 1 negativo comum) e apesar de ser possível (consigo passar 4 ou 5 cabos de jumper por entre um furo Technic por isso bem arrumados os cabos até nem dariam muito nas vistas) obriga-me a ter pelo menos 10 portas digitais para o controlo (o que também é possível com circuitos adicionais mas não me cativa). E se quiser aumentar o número de projectores a coisa começa a complicar-se.

Comecei logo a pensar num bus de controlo e pendurar micro-circuitos de controlo ao longo do bus. O ideal mesmo seriam LEDs I2C mas não encontrei nada suficientemente pequeno ou funcional por isso optei por uma microLAN 1-wire.

O termo “1-wire” é enganador: são necessários pelo menos 2 cabos num bus 1-wire (dados e massa) e na maioria das aplicações práticas será necessário um terceiro para alimentar os dispositivos (a norma prevê um modo “parasita” em que os dispositivos retiram alimentação da ligação prevista para dados mas isso apenas se aplica a dispositivos de muito baixo consumo como sensores de temperatura). Mesmo assim 3 cabos é muito bom para controlar quantos LEDs quiser (se decidir mais 2 ou 3 projectores não preciso passar mais 2 ou 3 cabos nem desencantar mais 2 ou 3 portas digitais no controlador).

A Maxim fabrica o DS2413, um circuito extremamente reduzido que implementa 2 portas digitais bidireccionais. É um chip SMD mas a Adafruit fornece um kit com o chip já montado numa placa de circuito impresso sendo só necessário soldar 4 headers e eventualmente uma resistência (tudo fornecido com o kit) para podermos utilizar na nossa microLAN.

Uhmmm… qual microLAN?

É possível implementar uma microLAN com o Raspberry Pi como master utilizando uma porta GPIO e uma resistência de pull-up. Mas é algo específico para o Raspberry, prefiro algo que possa replicar no meu PC ou no LEGO EV3. Por isso encomendei à RS Online um Maxim DS9490R que é um dispositivo USB que funciona como master controller numa microLAN e é suportado pelo Linux.

No meu portátil (Ubuntu 14.04) foi só ligar:

$ dmesg
(...)
[18011.890734] usb 2-1.3: new full-speed USB device number 7 using ehci-pci
[18011.983566] usb 2-1.3: New USB device found, idVendor=04fa, idProduct=2490
[18011.983576] usb 2-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[18012.021996] Driver for 1-wire Dallas network protocol.
[18012.026144] usbcore: registered new interface driver DS9490R

Não fui ver que módulos foram carregados na altura mas penso que foram ‘ds2490’ e ‘wire’ (existe também um módulo ‘ds9490r’ mas não está presente no meu Ubuntu).

Após detectar uma microLAN o kernel cria uma pasta ‘/sys/bus/w1’ para dispositivos 1-wire:

$ ls /sys/bus/w1/devices
 81-000000336d08  w1_bus_master1

“81-” identifica o DS9490

A ligação do DS2413 à microLAN é muito simples: o DS9490R tem uma ficha RJ12, idêntica às RJ11 dos telefones mas com 6 contactos. Felizmente dos 6 contactos apenas os 2 centrais são necessários pelo que podemos usar um cabo normal de telefone só com dois condutores:

  • 3 – OW (OW 1-Wire Data)
  • 4 – GND_OW (1-Wire Return)
Wire D

Apesar da datasheet da MAXIM indicar o pinout achei esta foto menos dada a confusões:

Sheepwalk Electronics: Pinout DS9490R

A Sheepwalk Electronics vende alguns produtos 1-wire (inclusive o DS9490R) e publica no seu site alguma informação útil relacionada com 1-wire.

Depois de soldar o header à placa da Adafruit foi só fazer as ligações (com cabos de jumper ou crocodilos, o que houver à mão):

1wire-led

Com 3 baterias AA NiMH (cerca de 3.8V) e um LED branco de alto brilho (cerca de 3.2V) temos 0.6V na resistência por isso se esta for de 1KΩ o consumo do LED será de 0.6 mA de corrente, bastante abaixo dos 20 mA tolerados por cada porta e suficiente para um teste (no palco LEGO irei puxar mais por cada LED, pelo menos 10 mA cada e alimentação será de outro tipo).

NOTA: com o kit da Adafruit vem uma resistência de 4.7KΩ para pull-up da linha ‘1-Wire Data’. Deveria ligar esta resistência ao pino 1 da ficha RJ12 (+5V vindos do bus USB do host onde estiver ligado o controlador, neste caso o PC) mas não me agradou muito a ideia e como suspeito que internamente o controlador já preveja isso optei deliberadamente por não usar o pull-up… aparentemente sem consequências.

Pouco depois de ligar o cabo telefónico ao controlador USB o nosso circuito é imediatamente reconhecido:

 [  706.356777] 0x81: count=17, status: 01 00 20 40 05 04 04 00 20 53 00 00 00 01 00 00 a5
 [  706.356800]
 [  706.356808]                                   enable flag:        1
 [  706.356812]                                  1-wire speed:        0
 [  706.356816]                        strong pullup duration:       20
 [  706.356819]                    programming pulse duration:       40
 [  706.356822]                    pulldown slew rate control:        5
 [  706.356825]                              write-1 low time:        4
 [  706.356829]      data sample offset/write-0 recovery time:        4
 [  706.356832]                      reserved (test register):        0
 [  706.356835]                           device status flags:       20
 [  706.356839]                  communication command byte 1:       53
 [  706.356842]                  communication command byte 2:        0
 [  706.356845]           communication command buffer status:        0
 [  706.356848]              1-wire data output buffer status:        0
 [  706.356852]               1-wire data input buffer status:        1
 [  706.356855]                                      reserved:        0
 [  706.356858]                                      reserved:        0
 [  706.356861]                             new device detect:       a5
 [  707.897674] w1_master_driver w1_bus_master1: Family 3a for 3a.00000012fdf4.44 is not registered.

Infelizmente diz que a famíla 3A não está registrada – o suporte nativo do kernel a dispositivos 1-wire não se extende [ainda?] ao DS2413. É pena, assim não temos nada útil dentro de ‘/sys/bus/w1/devices/3a-00000012fdf4’. Mas tudo bem, já esperava isso, existe o projecto owfs dedicado especificamente ao 1-wire:

sudo apt-get install owfs
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  libow-2.8-15 owfs-common owfs-fuse owftpd owhttpd owserver
Suggested packages:
  owfs-doc
The following NEW packages will be installed:
  libow-2.8-15 owfs owfs-common owfs-fuse owftpd owhttpd owserver
0 upgraded, 7 newly installed, 0 to remove and 0 not upgraded.
Need to get 296 kB of archives.
After this operation, 1,364 kB of additional disk space will be used.
Do you want to continue? [Y/n]

Após a instalação descobrimos que temos 3 serviços a correr:

  • owserver
  • owhttpd
  • owftpd

Embora não me pareçam necessários, nesta fase vou deixá-los a correr. Descobrimos também que o owfs impede o kernel de carregar os drivers que referi acima de modo a não ocorrerem conflitos:

$ cat /etc/modprobe.d/libow-2.8-15.conf
blacklist ds9490r
blacklist ds2490
blacklist wire

Para aceder à microLAN usamos o comando ‘owfs’ mas primeiro é necessário definir um mountpoint onde o owfs vai criar uma estrutura de pastas virtuais que mapeiam cada dispositivo (escolhi ‘/mnt/1wire’):

sudo mkdir /mnt/1wire
sudo owfs -u -m /mnt/1wire

Para confirmar que funciona:

$ sudo ls /mnt/1wire
81.086D33000000 bus.1 settings statistics structure system uncached

temos 1 dispositivo na microLAN (o master controller DS9490R). Vamos agora ligar o DS2413 à microLAN – passadas algumas dezenas de segundos temos:

$ sudo ls /mnt/1wire
3A.F4FD12000000  bus.1       statistics  system
81.086D33000000  settings  structure   uncached

agora já temos algo útil dentro do device ‘3A.F4FD12000000’:

$ sudo ls /mnt/1wire/3A.F4FD12000000
address  family   PIO.A    PIO.BYTE   r_locator   sensed.B
alias     id      PIO.ALL  r_address  sensed.A      sensed.BYTE
crc8     locator  PIO.B    r_id       sensed.ALL  type

Ligando um LED a PIO.A podemos acendê-lo:

$ sudo sh -c  "echo 1 > /mnt/1wire/3A.F4FD12000000/PIO.A"

e voltar a apagá-lo:

$ sudo sh -c  "echo 0 > /mnt/1wire/3A.F4FD12000000/PIO.A"

(os comandos são muito feios porque o owfs tem de correr com previlégios de root e eu não sou root no meu Ubuntu; em Raspberry Pi ou ev3dev bastaria:

echo 1 > /mnt/1wire/3A.F4FD12000000/PIO.A
echo 0 > /mnt/1wire/3A.F4FD12000000/PIO.A

)

E agora um script python para piscar o LED a cada meio segundo:

import sys, traceback
from time import sleep
from subprocess import call

def main():
    try:
        while True:
                call("echo 1 > /mnt/1wire/3A.F4FD12000000/PIO.A", shell=True);
                sleep(0.5);
                call("echo 0 > /mnt/1wire/3A.F4FD12000000/PIO.A", shell=True);
                sleep(0.5);

    except (KeyboardInterrupt, SystemExit):
        print "Exiting...";
    except Exception:
        traceback.print_exc(file=sys.stdout);
    call("echo 0 > /mnt/1wire/3A.F4FD12000000/PIO.A", shell=True);
    sys.exit(0);

if __name__ == "__main__":
    main()

Os meus agradecimentos à PTRobotics por incluírem o Adafruit DS2413 na sua lista de produtos a meu pedido.

 

 

 

 

Small iBeacons da myBeacon

Recebi finalmente os meus primeiros iBeacons, dois Small iBeacons da myBeacon (um preto e outro vermelho). A encomenda demorou 12 longos dias a chegar, a acreditar na data do carimbo Royal Post 10 deles foram passados nos serviços postais.

A encomenda chegou num envelope almofadado pequeno, sem remetente. Dentro apenas 2 saquinhos ziplock – nada de instruções ou sequer um papel com a ordem de encomenda!

mybeacon-small-01
Small iBeacon da myBeacon (vermelho)

Dentro de cada saco outros dois saquinhos, um adesivo redondo 3M e 3 peças pretas que formam a caixa do dispositivo; um dos sacos tem uma pilha CR2032, o outro a placa de circuito impresso do beacon propriamente dito.

mybeacon-small-02mybeacon-small-03Para montar é simples: insere-se a pilha CR2032 com a face “+” para cima e a face “-” virada para o circuito impresso. Como não existe qualquer interruptor, assim que inserimos a pilha o beacon liga-se e assim permanece até retirarmos a pilha ou ela se descarregar (é suposto durar entre 6 a 12 meses).

Das 3 peças que forma caixa só 2 são necessárias, permitindo montar:

  • – um cilindro
  • – um cilindro com aba furada para porta-chaves

mybeacon-small-04

(mostro o preto, foi o único que montei até agora)

O Small iBeacon é correctamente reconhecido embora como sendo um ibeacon da RF Proximity:

RFProximity
 MAC:...
 Updated: ...
 RSSI: -79.0 db/-79.0 db
 UUID: ....
 Major: 0    Minor: 0
 TX Power: -58    Distance: 8.65m
 Descriptor: FAR

Mais uma vez a precisão deixa muito a desejar: não eram 8.65m mas 30cm!!! O que só prova:

  • a implementação do LEGO B3AC0N até está bastante boa;
  • a precisão da maioria das aplicações disponíveis no Google Play é uma desgraça!

Infelizmente a myBeacon apenas fornece software para iOS pelo que não sei ainda como configurá-lo (alterar os valores de Major e Minor, eventualmente também o UUID) mas para o que pretendo por agora serve perfeitamente.

A RF Proximity tem aplicações para Android, incluido uma para encontrarmos o carro quando nos esquecemos onde o estacionámos (assumindo que deixámos o iBeacon dentro do carro e tínhamos o telemóvel a segui-lo quando saímos do carro). Mas infelizmente também não parece ter nenhuma para configurar os seus beacons.

Logitech c170 – MOD

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

A câmara utilizada no AD4MAST0R, uma webcam Logitech c170, não foi prevista para montagem em robots autónomos. Dois pontos que poderão ser vistos como vantajosos para o seu propósito original acabam por atrapalhar:

  • O clip é pouco útil, demasiado grande e não foi previsto como amovível
  • O cabo USB é longo (cerca de 1.2m) quando se podia ter colocado uma ficha no corpo da webcam para ser utilizada com um cabo USB do tamanho que se pretendesse

Felizmente não é difícil contornar estas limitações:

_________________________________________________________________________

ATENÇÃO!

A execução dos procedimentos abaixo VIOLA a garantia do produto. Além disso estes procedimentos estão descritos para um género de leitores que os compreende – se não for esse o caso NÂO tente proceder a estas modificações sob risco de danificar de foram definitiva a sua webcam e o bus USB do seu EV3 ou PC.

_________________________________________________________________________

1. Remoção do clip

Para remover o clip é necessária uma chave de relojoeiro (fenda ou Philips, desde que pequena). Também é conveniente uma chave de fendas maior (género busca-pólos) ou um canivete de lâmina fina mas forte.

  1. desapertar o parafuso da metade do clip junto à webcam e remover a tampa
  2. desapertar os 2 parafusos do corpo da webcam e destapar
  3. desapertar os 2 parafusos que fixam o cabo e os 2 parafusos da placa de circuito impresso
  4. soltar a placa de circuito impresso
  5. por baixo desta há um parafuso que fixa o eixo de plástico que mantém o clip agarrado ao corpo da webcam: desaparafusar
  6. através do furo deixado vago, tentar empurrar o eixo para fora até ser possível enfiar uma chave de fendas ou uma lâmina na ranhura entre a ponta do eixo e o corpo da webcam para poder puxar o parafuso para fora
  7. voltar a montar a placa de circuito impresso, apertar os restantes parafusos, alinhar o microfone, tapar a webcam e apertar os parafusos
  8. confirmar que a webcam ainda funciona 🙂

No final deste processo sobram o clip, a tampa do clip, o eixo e 2 parafusos

2. Redução do cabo

Bastou seguir o artigo “Connect USB with other devices by short Wire” do autor Indiana67 no site “Instructables”. A única diferença foi não ter tubo termoretráctil suficientemente largo, o que utilizei não consegui puxar para cima da zona cortada e por isso acabei enrolando fita de electricista preta. Feio mas igualmente funcional.

E confirmei novamente que ainda funciona 🙂

 

3. LEGO-lização da webcam

No lugar deixado vago pelo eixo de fixação ao clip pode-se montar um eixo LEGO Technic, basta alargar um pouco [e com cuidado] o furo e colar com uma cola resistente:

O eixo permite inúmeras possibilidades de montagem, comecei por esta:

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.

 

 

 

LEGO EV3 + TI SensorTag

Chegou hoje o SensorTag da Texas Instruments.

É um dispositivo BLE (Bluetooth 4.0 Low Energy) com vários sensores (temperatura, humidade, aceleração/orientação e pressão atmosférica, bem como 2 botões de pressão).

Com o ev3dev foi facílimo ler a temperatura ambiente, bastou consultar dois links:

Partindo de um dongle BT4.0 funcional em hci0 (ver o meu artigo anterior, LEGO B3AC0N)

Carregar no botão de discovery do SensorTag e fazer um scan BLE:

root@ev3dev:~# hcitool -i hci0 lescan
BC:6A:29:AB:83:4D SensorTag
BC:6A:29:AB:83:4D (unknown)
BC:6A:29:AB:83:4D SensorTag
BC:6A:29:AB:83:4D (unknown)
BC:6A:29:AB:83:4D SensorTag
...
^C

 

root@ev3dev:~# gatttool -b BC:6A:29:AB:83:4D -I
[BC:6A:29:AB:83:4D][LE]> connect
Attempting to connect to BC:6A:29:AB:83:4D
Connection successful
[BC:6A:29:AB:83:4D][LE]> char-read-hnd 0x25
Characteristic value/descriptor: 00 00 00 00
[BC:6A:29:AB:83:4D][LE]> char-write-cmd 0x29 01
[BC:6A:29:AB:83:4D][LE]> char-read-hnd 0x25
Characteristic value/descriptor: ae fe 74 0c
[BC:6A:29:AB:83:4D][LE]>

 

Os quatro bytes do valor medido (ae fe 74 0c) correspondem a duas temperaturas: a do objecto em frente e a ambiente, no formato

ObjLSB ObjMSB AmbLSB AmbMSB

Assim:

Temp Amb = 0c74 = 3188

O valor real é obtido dividindo por 120:

3188/128 = 24.90625 = 25ºC

 (Valor confirmado pela aplicação Android BLE SensorTag da TI)

Nota: ocasionalmente a conexão BLE falha. Nessas situações pode-se reiniciar o dongle com os comandos:

hciconfig hci0 down
hciconfig hci0 up

(em casos extremos será necessário remover fisicamente o dongle e voltar a inseri-lo ou na sua impossibilidade o velho reboot resolve tudo)

 

 

 

LEGO B3AC0N

Com os updates recentes ao kernel do ev3dev e a inclusão do módulo btusb [a meu pedido, modéstia à parte] já é possível utilizar dongles Bluetooth 4.0 com o LEGO EV3.

Enquanto não me chegam às mãos beacons e outros dispositivos BT 4.0 para testar, o único aparelho que tenho é um telemóvel Android que infelizmente apenas “consome” serviços. Bem, demos-lhe qualquer coisa para consumir: um beacon – não posso dizer iBeacon porque é trademark da Apple… mas é a mesma coisa: um «farol» que pode servir para marcar presença, orientação, medição de distâncias, fornecimento personalizado de informação…

A implementação é muito fácil, está quase tudo no post “piBeacon – DIY Beacon with a Raspberry Pi” da Adafruit.

Claro que primeiro é necessário um dongle Bluetooth 4.0 como este (qualquer um que funcione num Raspberry Pi a correr Raspbian deverá funcionar também com o EV3 a correr ev3dev).

É necessário também uma versão recente do ev3dev (baseado em Debian jessie, com kernel  3.16.1-1 ou superior, neste momento estou a usar a 3.16.1-2). Quem já tiver instalado a versão pre-release (ev3dev-jessie-2014-07-12) que à data é a mais recente disponível para download, basta

apt-get update
apt-get dist-upgrade
apt-get install linux-image-3.16.1-2

Para confirmar que temos o dongle a funcionar usamos o comando hciconfig:

root@ev3dev:~# hciconfig -a
hci1:    Type: BR/EDR  Bus: UART
    BD Address: 00:17:EC:02:91:B7  ACL MTU: 1021:4  SCO MTU: 180:4
    UP RUNNING PSCAN
    RX bytes:563 acl:0 sco:0 events:27 errors:0
    TX bytes:879 acl:0 sco:0 commands:27 errors:0
    Features: 0xff 0xff 0x2d 0xfe 0x9b 0xff 0x79 0x83
    Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
    Link policy: RSWITCH HOLD SNIFF PARK
    Link mode: SLAVE ACCEPT
    Name: 'ev3dev-0'
    Class: 0x000000
    Service Classes: Unspecified
    Device Class: Miscellaneous,
    HCI Version: 2.1 (0x4)  Revision: 0x0
    LMP Version: 2.1 (0x4)  Subversion: 0x191f
    Manufacturer: Texas Instruments Inc. (13)

hci0:    Type: BR/EDR  Bus: USB
    BD Address: 00:1A:7D:DA:71:13  ACL MTU: 310:10  SCO MTU: 64:8
    UP RUNNING PSCAN
    RX bytes:25008 acl:0 sco:0 events:1215 errors:0
    TX bytes:2486 acl:0 sco:0 commands:159 errors:0
    Features: 0xff 0xff 0x8f 0xfe 0xdb 0xff 0x5b 0x87
    Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
    Link policy: RSWITCH HOLD SNIFF PARK
    Link mode: SLAVE ACCEPT
    Name: 'ev3dev #1'
    Class: 0x000000
    Service Classes: Unspecified
    Device Class: Miscellaneous,
    HCI Version: 4.0 (0x6)  Revision: 0x22bb
    LMP Version: 4.0 (0x6)  Subversion: 0x22bb
    Manufacturer: Cambridge Silicon Radio (10)

Temos 2 dispositivos Bluetooth: hci1 (UART) que é o nativo (interno) do EV3, ainda 2.0 e que por isso de pouco serve; e hci0 (USB) que é o nosso.

Podemos ver na informação acima que hci0 já está em estado “UP RUNNING” apesar de na maioria dos artigos que encontrei referirem sempre ser necessário activá-lo

hciconfig hci0 up

Inicialmente hci0 não está a anunciar-se em modo Low Energy pelo que é necessário ativar esse modo. Além disso o artigo em que me inspirei refer ser conveniente desactivar a procura de outros dispositivos por poder interferir e apesar de achar isso estranho para este exemplo mal não faz por isso

hciconfig hci0 leadv
hciconfig hci0 noscan

Resta apenas configurar hci0 para funcionar se anunciar como beacon e fingir ser da Apple:

root@ev3dev:~# hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00 00 00 00 C8 00
< HCI Command: ogf 0x08, ocf 0x0008, plen 32
  1E 02 01 1A 1A FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F
  17 D1 AD 07 A9 61 00 00 00 00 C8 00
> HCI Event: 0x0e plen 4
  01 08 20 00

Se no nosso Android instalarmos uma aplicação como a “Bluetooth LE Scan” (e o telemóvel/tablet tiver BT 4.0 e Android 4.3 ou superior) após um SCAN encontramos o nosso Beacon:

ev3dev #1
MAC: 00:1A:7D:DA:71:13
Updated: 2014-09-12 17:46:50
RSSI: -60.0db / -60.0 dB
UUID: ....
Major:   0     Minor:  0
Tx Power: -56  Distance: 1.64m
Descriptor: NEAR

A precisão deixa um pouco a desejar: vários SCAN consecutivos deram valores entre 1m [NEAR] e 7m [FAR] quando o telemóvel estava a cerca de 1m40 do dongle.

Podemos ajustar um pouco mudando um valor de referência Tx Power enviado pelo Beacon no penúltimo byte do comando hcitool (“C8” acima) que corresponde ao valor RSSI medido em laboratória a distâncias de um metro, escrito em complemento para 2 (C8 = -56 portanto corresponde a uma medição de RSSI de -56 dB a um metro)

Seguem algures valores próximos de -56 dB:

-54 dB = CA
-55 dB = C9
-56 dB = C8
-57 dB = C7
-58 dB = C6
-59 dB = C5

Portanto se colocarmos o dispositivo Android a exactamente um metro do dongle USB, o valor RSSI medido será o nosso valor ideal de Tx Power.

Infelizmente obtive valores entre -55 e -63 dB (com o EV3 alimentado por carregador para garantir uma alimentação constante) por isso fiquei na mesma. Após algumas experiências com algumas medições a várias distâncias fiquei-me por -57 dB = C7, pareceu-me o menos flutuante.

hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00 00 00 00 C7 00

Quando tiver um Beacon a sério vou poder calibrar melhor este meu EV3 B3AC0N (e até pode ser que a flutuação seja do software, vou procurar outras aplicações semelhantes).

Falta agora o inverso: utilizar hci0 para encontrar outros Beacons. Ou talvez outros B3AC0Ns.

Nota: podemos não fingir ser Apple, substituindo 4C 00 pelo Company ID de outro fabricante (infelizmente a LEGO não aparece) como por exemplo ​FE 00 (reserved)… só que deixa de ser reconhecido como um Beacon.