SBrick remote control com Snap!

Um controlo remoto simples em Snap! usando as 4 teclas cursoras:

snap-SBrick2A 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).

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.

ev3dev – wireless gamepad

Este artigo é a parte 3 de 9 da série  AD4M4ST0R - um rover LEGO

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

gamepadO 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

“Not fully compatible with your kernel”… Oops!

Podemos sempre aceder directamente:

root@ev3dev:~# cat /dev/input/by-id/usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick
�S�z    �S�z0�S�z�S��    �S��0�S��

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.

root@ev3dev:~# apt-get install python-pygame
root@ev3dev:~# nano joystick.py
root@ev3dev:~# chmod +x joystick.py
root@ev3dev:~# python joystick.py

O script python ‘joystick.py’:

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)

Para cada um dos 4 botões do hat:

cima = (0,1)
direita = (1,0)
baixo = (0,-1)
esquerda = (-1,0)

Para o joystick da direita:

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.

Caixa de música LEGO – o software

Este artigo é a parte 2 de 2 da série  Caixa de Música LEGO

Tópicos:

  • Pré-requisitos
  • Preparação do cartão SD
  • Configurações do sistema
  • Script em python
  • Automatismo
  • Vários

Pré-requisitos

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:

df -h

Filesystem      Size  Used Avail Use% Mounted on
rootfs          3.6G  2.0G  1.4G  60% /
/dev/root       3.6G  2.0G  1.4G  60% /
devtmpfs        211M     0  211M   0% /dev
tmpfs            44M  232K   44M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            88M     0   88M   0% /run/shm
/dev/mmcblk0p1   56M   19M   38M  34% /boot

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:

sudo apt-get --purge remove cups.* xserver.* x11.*
sudo apt-get autoremove

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)

 

Script em pyhton

[por completar]

Automatismo

[por completar]

Vários

[por completar]

 

Primeiras linhas de código

Este artigo é a parte 5 de 5 da série  Crónicas do Engenheiro Maluco por Tartes de Framboesa e Lego

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).

Roda livre

Este artigo é a parte 4 de 5 da série  Crónicas do Engenheiro Maluco por Tartes de Framboesa e Lego

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).

DSC_0183-2 DSC_0185-2A 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 desodorizante roll-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).

 

Robalo no forno

Além do dito cujo, perfurado e recheado com alho:

  • abóbora da mãe aos cubos
  • cenoura da cunhada em palitos grossos
  • pomodoros do sogro aos sextos
  • manjericão da horta do 6º andar
  • chuchu às fatias
  • cebola às rodelas grossas
  • oregãos, sal fino e azeite q.b.

Forno a 180º, desligar quando as cebolas começarem a tostar ou baixar para 120º se quisermos os vegetais mais macios.

Havendo batatinhas também iam, com casca bem lavada e eventualmente previamente meio cozidas no micro-ondas (conforme o tamanho).

Não havendo grávidas nem lactentes também ia meio copo de vinho branco a meio da assadura para refrescar.

 

 

 

 

O meu próprio servidor – parte 1

Este artigo é a parte 1 de 4 da série  O meu próprio servidor

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.