Um controlo remoto simples em Snap! usando as 4 teclas cursoras:
A device extension que criei implementa 3 motores: A (canal #1), B (canal #2) e um pseudo-motor P (ambos os canais). Para movimentar o rover para trás e para a frente é usado o motor P, para rodá-lo para a esquerda ou para a direita são usados os motores A e B com direcções opostas.
Depois de uma décima de segunda de rotação dos motores é dado um comando de rotação aos motores com duty cycle de zero (COAST) mas também podia ser usado o comando stop (BREAK).
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!
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.
Para 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
(mostro o preto, foi o único que montei até agora)
O Small iBeacon é correctamente reconhecido embora como sendo um ibeacon da RF Proximity:
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.
O gamepad utilizado no AD4M4ST0R é um “Gioteck VX-2 Wireless Controller” comprado na FNAC por €19.99. Qualquer modelo compatível com PC deverá funcionar, desde que use um dongle USB (os modelos por cabo USB também funcionarão mas não servem para o caso). Quando o stack bluetooth estiver funcional no ev3dev também deverão funcionar gamepads desse tipo
O gamepad é reconhecido automaticamente como um gamepad e como um disposito de classe OHCI:
root@ev3dev:~# dmesg
(...)
usb 1-1.4: new full-speed USB device number 4 using ohci
hid-generic 0003:25F0:83C2.0001: usb_submit_urb(ctrl) failed: -1
hid-generic 0003:25F0:83C2.0001: timeout initializing reports
input: Goodbetterbest Ltd Gioteck VX2 2.4G Wireless Controller as /devices/platform/ohci.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:25F0:83C2.0001/input/input2
hid-generic 0003:25F0:83C2.0001: input: USB HID v1.10 Gamepad [Goodbetterbest Ltd Gioteck VX2 2.4G Wireless Controller] on usb-ohci.0-1.4/input0
Mas a implementação USB deixa um bocado a desejar:
root@ev3dev:~# lsusb
Bus 001 Device 004: ID 25f0:83c2
Bela porcaria, nem um descritivo? Vamos inspeccionar com mais detalhe:
root@ev3dev:~# lsusb -d 25f0:83c2 -v
Bus 001 Device 004: ID 25f0:83c2
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 16
idVendor 0x25f0
idProduct 0x83c2
bcdDevice 3.15
iManufacturer 1 Goodbetterbest Ltd
iProduct 2 Gioteck VX2 2.4G Wireless Controller
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 137
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 1
Device Status: 0x0000
(Bus Powered)
Sendo OHCI temos também:
root@ev3dev:~# ls /dev/input/by-id/ -la
total 0
drwxr-xr-x 2 root root 60 Aug 15 07:16 .
drwxr-xr-x 4 root root 140 Aug 15 07:16 ..
lrwxrwxrwx 1 root root 9 Aug 15 07:16 usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick -> ../event2
No Ubuntu consigo ver o estado dos vários botões e joysticks do gamepad com o comando ‘jstest’ do pacote ‘joystick’ por isso:
root@ev3dev:~# apt-get install joystick
root@ev3dev:~# jstest --normal /dev/input/by-id/usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick
Driver version is 0.8.0.
jstest is not fully compatible with your kernel. Unable to retrieve button map!
Joystick (Unknown) has 2 axes and 2 buttons.
Testing ... (interrupt to exit)
jstest: error reading: Invalid argument
carregar um botão apenas gerou esta sequência de caracteres estranha… pelo menos sabemos que funciona só falta entender o formato. Como sou preguiçoso fui buscar o PyGame, um módulo de python muito usado na comunidade Raspberry Pi que já faz isso – a semelhança do EV3 com o Raspberry Pi é tão impressionante que lhe podemos ir buscar ideias para quase tudo.
import traceback, os
os.environ['SDL_VIDEODRIVER'] = 'dummy'
from pygame import joystick, event, display
def main():
try:
display.init()
joystick.init()
js=joystick.Joystick(0)
js.init()
num_axes=js.get_numaxes()
num_buttons=js.get_numbuttons()
num_hats=js.get_numhats()
print 'Axes:', num_axes
print 'Buttons:', num_buttons
print 'Hats:', num_hats
while True:
event.pump()
for i in range(0, num_axes):
print 'Axis %i: %6.3f' % (i, js.get_axis(i))
for i in range(0, num_buttons):
print 'Button %i: %r' % (i, js.get_button(i))
for i in range(0, num_hats):
print 'Hat %i: %s' % (i, js.get_hat(i))
except (KeyboardInterrupt, SystemExit):
print "Exiting..."
except Exception:
traceback.print_exc(file=sys.stdout)
sys.exit(0)
if __name__ == "__main__":
main()
À custa deste script fiquei a saber que o gamepad tem 4 axes (2 por cada joystick analógico), 13 buttons e 1 hat (o hat é o conjunto de 4 teclas direccionais à esquerda do gamepad) que quando accionados devolvem:
Para cada um dos 13 botões:
gatilho esquerdo = 6
botão sobre gatilho esquerdo = 4
gatilho direito = 7
botão sobre gatilho direito = 5
select = 8
start = 9
home = 12
triangulo = 0
circulo = 1
cruz = 2
quadrado = 3
botão do joystick esquerdo = 10
botão do joystick direito = 11
(o botão “Turbo’ ao centro do gamepad parece não funcionar)
todo para cima: Eixo 3 = -1
todo para baixo: Eixo 3 = 1
todo para direita: Eixo 2 = 1
todo para esquerda: Eixo 2 = -1
=> (x,y) = (axis2,-axis3)
Para o joystick da esquerda:
todo para cima: Eixo 1 = -1
todo para baixo: Eixo 1 = 1
todo para direita: Eixo 0 = 1
todo para esquerda: Eixo 0 = -1
=> (x,y) = (axis0,-axis1)
O gamepad tem também um motor interno para vibração (force feedback?) mas que só funciona com Playstation 3. Curiosamente de vez em quando acontece-me poucos minutos depois de desligar o EV3 o gamepad desatar a vibrar.
Convém ter um cartão SD com capacidade 4 GB ou superior, categoria 4 ou superior. O cartão pode ser micro- ou mini-SD desde que se disponha de um adaptador para o formato SD.
É também necessário um computador equipado para lidar com cartões SD ou então um adaptador SD USB.
Estas indicações são para um sistema Linux (mais concretamente Ubuntu 14.04). Não é difícil adaptar para um sistema Windows mas já há muito não uso nenhum.
Preparação do cartão SD
É necessário um sistema operativo para Raspberry Pi. Eu prefiro o Raspbian por ser baseado em Debian tal como o Ubuntu que venho utilizando há já alguns anos. A versão mais recente está sempre disponível na Raspberry Pi Foundation – o ficheiro .zip contém um ficheiro único, uma imagem de um cartão inteiro pronto a usar (na versão de Junho de 2014 a imagem tem 3.0 GB pelo que um cartão de 4 GB continua a ser suficiente).
O Ubuntu tem uma aplicação gráfica “Disks” (na linha de comando “gnome-disks”) que permite entre outras coisas escrever imagens. Seleccionamos o cartão SD (qualquer coisa como “4 GB Block Device | /dev/mmcblk0”) e depois “Restore disk image” escolhendo o ficheiro .img do Raspbian.
O cartão tem agora duas partições:
BOOT
2.9 GB Volume
A primeira será usada como “/boot” e a segunda como “/” como é habitual ma maioria das instalações Linux. Não existe a habitual partição para swap porque [pelo menos no Raspbian] é utilizado um ficheiro dentro de “/”.
Antes de colocar o cartão no Raspberry é necessário alterar alguns ficheiros para ter um sistema funcional. Se montamos a segunda partição (“2.9 GB Volume”) como /X precisamos criar ou editar 2 ficheiros:
/X/etc/hostname
/etc/network/interfaces
sudo /X/etc/hostname
Este ficheiro deve conter uma única linha, com o nome pelo qual o sistema operativo vai responder:
caixademusica
sudo /X/etc/network/interfaces
Este ficheiro contém a configuração da rede Wi-Fi:
auto lo
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid "RedeWiFi"
wpa-psk "PasswordDaRedeWifi"
iface default inet dhcp
Podemos mais tarde utilizar um endereço IP estático em vez de recorrer ao cliente DHCP (deve acelerar ligeiramente o arranque e utilizar ligeiramente menos RAM). Neste exemplo defini só uma rede Wi-Fi mas é possível definir várias, ver o meu artigo “Raspberry Pi – headless + wireless” (para mim é suficientemente uma única rede já que tenho um router 3G de bolso configurado de forma semelhante à rede de casa e assim quando levo um Raspberry Pi comigo para testes ou demonstrações uso sempre a mesma configuração).
O cartão já pode ser colocado no Raspberry Pi, podemos confirmar o endereço IP na página de configuração do router (se estivermos a usar DHCP) e aceder remotamente por SSH:
ssh pi@192.168.1.67
(“pi” é o utilizador pré-configurado no Raspbian – a password é “raspberry”, convém alterar mais tarde com o comando “passwd” – e 192.168.1.67 é o endereço que no router aparece atribuido ao host “caixademusica”).
Configurações do sistema
Tendo acesso remoto à Caixa de Música é necessário expandir o file system do cartão de modo a utilizar toda a capacidade deste (como referi, até Junho de 2014 a imagem ocupa apenas 3 GB pelo que num cartão de 4 GB fica 1 GB por alocar e que pode fazer falta)
sudo raspi-config
Escolher “Expand Filesystem” e no final se não for dada opção de reboot (não recordo) dar o comando
sudo reboot
No próximo login o cartão deverá ter cerca de 1.4 GB disponíveis:
Já é bastante mas como não vou utilizar ambiente gráfico (desktop) posso libertar mais algum espaço (cerca de 1.2 GB mais) e reduzir o peso de futuros updates com os dois comandos:
Vamos agora actualizar o Raspbian para a última versão de todos os pacotes instalados:
sudo apt-get update
sudo apt-get dist-upgrade
E instalar as ferramentas necessárias:
sudo apt-get install htop mpg321 mp3gain
htop não é necessário mas gosto de utilizá-lo em vez do top nativo.
mpg321 é um player não-gráfico de ficheiros mp3 que vai servir para tocar a música que acompanha a «bailarina».
mp3gain permite ajustar o ganho dos ficheiros mp3, muito útil quando estes parecem ouvir-se pior que a maioria dos restantes
sudo apt-get install python-pip python3-pip
sudo pip install sh
sudo pip3 install sh
sh é uma library de python que permite invocar comandos da shell (do sistema operativo) e que vou usar no meu programa por isso preciso de instalar primeiro.
pip é um gestor de libraries para python (instalo duas versões – para python v2 e python v3 – provavelmente bastará a última)
Com um Rover já em condições de andar, faltava o video de demonstração da praxe (o que está no artigo de abertura desta série).
Antes de me meter à aventura com o Snap! limitei-me a transferir para o Raspberry Pi um script muito básico em python que faz o Rover por 4 vezes andar um troço a direito seguido de uma curva à esquerda (idealmente voltando ao ponto de partida mas como não usei nenhum tipo de sensores a única forma de o conseguir foi afinando os tempos à mão) e no final uma rotação em torno de si mesmo várias vezes para a direita:
import nxt
import nxt
import nxt.locator
from nxt.sensor import *
from nxt.motor import *
from time import sleep
brick = nxt.locator.find_one_brick()
left = Motor(brick, PORT_B)
right = Motor(brick, PORT_C)
both = nxt.SynchronizedMotors(left, right, 0)
leftboth = nxt.SynchronizedMotors(left, right, 100)
rightboth = nxt.SynchronizedMotors(right, left, 100)
for n in range(0,4):
both.run(100)
sleep(1.25)
both.idle()
sleep(0.25)
leftboth.run(100)
sleep(0.48)
leftboth.idle()
sleep(0.25)
rightboth.run(100)
sleep(4)
rightboth.idle()
A execução do script foi comandada manualmente (essencialmente acedi de modo wireless a partir do meu portátil por SSH e invoquei o script a partir da shell).
Não gostei da roda livre baseada num «pneu», os movimentos curvos do Rover não me pareciam consistentes.
Tinha encontrado recentemente um artigo de uma roda livre com base numa bola de um conjunto Mindstorms que eu não tenho mas a ideia pareceu-me boa e experimentei primeiro com a bola da minha trackball e depois decidi usar um «abafador» (um berlinde de vidro grande, cerca do dobro do diâmetro de um berlinde normal).
A forma como a roda livre está montada no chassis ainda é deficiente (ocorre alguma torção devido ao peso do Rover) mas os movimentos curvos são muito mais fluidos já que o eixo de rotação do Rover passou a ser a bola em vez de uma roda com o seu próprio eixo de rotação.
Entretanto ainda hei-de experimentar outra ideia bastante interessante, usar a bola de um desodorizanteroll-on, requer bastante menos peças. O autor (Philippe “Philo”Hurbain) é bastante conhecido no mundo Lego Technic e Mindstorms, com análises tecnicamente muito detalhadas aos motores e baterias da Lego. Também tem no seu site diagramas para montagem de um Rover em Lego que usa uma bola como roda livre (Spy Camera Rover).
Tentativas anteriores de ter o meu próprio site acabaram sempre mal – mais cedo ou mais tarde um palerma pirata qualquer acabava sempre por conseguir tomar conta dele e utilizar o meu domínio para fins no mínimo duvidosos. Ter um site alojado numa empresa deixa-nos dependente da qualidade dos serviços de administração de sistema dessa empresa… e a experiência ensinou-me que mais vale arregaçar as mangas e fazer eu mesmo. Mas infelizmente quando temos um site alojado numa empresa o nosso controlo sobre o servidor em si é nulo, o mais que conseguimos para lá de webadmin é o controlo sobre o file system – nunca sobre o estado dos serviços, as configurações ou as versões.
A solução passava por ter o meu próprio servidor dedicado mas os preços eram exorbitantes por isso durante algum tempo aventurei-me e tive o meu próprio servidor doméstico, ligado à net através da minha ligação ADSL. Para experiências e usos reduzidos servia perfeitamente mas as ligações ADSL na minha zona estão limitadas pela Portugal Telecom a uns míseros 4 Mbps com 512 kbps e acabei por desistir.
Mas agora existem os VPS/VDS que nos permitem utilizar apenas uma fracção de um servidor real como se fosse um servidor completo. A experiência do servidor doméstico mostrara que 200 MHz e 64 MB eram suficientes para um pequeno site por isso optei por um VDS de 256 MB com 5 GB de espaço em disco. O processador é de 3 GHz, tem de ser partilhado pelos restantes VDS mas mesmos que haja 10 servidores em simultâneo a puxar pelo processador dá 300 MHz a cada um – quanto aos outros não sei mas a mim chega-me perfeitamente.
Ah pois, e Linux porque para lidar com as parvoíces do Windows já me basta o dia-a-dia. Escolhi Ubuntu Server porque já estou familiarizado com o Ubuntu como Desktop principal mas Red Hat também seria uma boa escolha (na minha profissão também lido com uns quantos servidores RHEL embora não como webadmin).
E agora que em Portugal finalmente se deu a liberalização nos Domínios, um domínio .pt só para mim.
No próximo artigo explico como configurar o servidor VDS para funcionar como servidor Web.