Na campanha Kickstarter do SBrick (ou SmartBrick) inscrevi-me como beta tester. O meu SBrick chegou finalmente esta semana, vindo da Hungria numa encomenda verdadeiramente espartana, sem qualquer folheto ou instruções:
É ainda uma versão muito tosca e com alguns defeitos (um dos quatro canais parece estar avariado e a ficha de outro não encaixa com firmeza nos cabos Power Functions) mas já permite ensaiar a conectividade com o Linux e em especial com o ev3dev – o meu propósito como beta tester é sobretudo ajudar na ligação entre o Mindstorms EV3 e o Sbrick.
O SBrick expõe 6 serviços Bluetooth BT4.0/BLE: Generic Access, Device Information e mais 4 específicos do fabricante. Os 2 primeiros expõem esta informação:
Device Name = SBrick
Appearance = Generic Remote Control
Model Number = 4.0
Firmware Revision = 4.1
Hardware Revision = 4.0
Software Revision = 4.1
Manufacturer Name String = Vengit Ltd.
Os outros 4 serviços são específicos da Vengit e expõem ao todo 8 campos:
– 5 Read Only
– 1 Write Only
– 1 Read/Write
– 1 Unknown
Entretanto recebi de um dos engenheiros da Vengit a informação mínima mas suficiente para controlar um motor ligado a um dos 4 canais: o UUID do serviço de controlo remoto é ‘4dc591b0-857c-41de-b5f1-15abda665b0c’, sendo a caracteristica do controlo remoto ‘2b8cbcc-0e25-4bda-8790-a15f53e6010f’.
Isso em termos práticos, utilizando o comando gatttool que vem com o BlueZ 5 (o stack de Bluetooth para Linux) corresponde a escrever no handle 0x0025 os comandos reconhecidos pelo firmware.
Até agora apenas me foram apresentados dois comandos (00h = BRAKE e 01h = DRIVE)
- BRAKE Channel
- DRIVE Channel Direction DutyCycle
Channel corresponde a uma das 4 portas disponíveis, podendo ser 00h, 01h, 02h ou 03h.
Direction corresponde ao sentido da rotação, podendo ser clokwise (00h) ou anticlockwise (01h).
DutyCycle corresponde à potência transmitida ao motor, variando entre 00h (“Coast”) e FFh (full power).
Assim para enviar um comando a partir de um sistema Linux (PC com Ubuntu, Raspberry Pi com Raspbian ou Mindstorms EV3 com ev3dev) equipado com dongle USB BT4.0/BLE basta invocar o comando gatttool:
$ gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010000FF
No exemplo acima é enviado para o dispositivo BT com identificativo 00:07:80:7F:28:E1 (o meu SBrick) a partir do device hci0 (o meu dongle BT4.0/BLE) o comando
DRIVE Channel#0 Clockwise 100%
Como este comando não mantém a sessão bluetooth aberta, ao fim de cerca de 3 segundos ela fecha e os canais deixam de comandar os motores (se invocarmos o comando gatttool em modo interactivo com a opção “-I” ou “–interactive” e dermos a partir daí os comandos equivalentes a sessão persiste e os motores continuam activos indefinidamente).
No video abaixo são mostrados dois motores a rodar em sentidos diferentes:
- DRIVE Channel#0 Clockwise 22%
- DRIVE Channel#2 Anticlockwise 17%
No próximo video é mostrado um motor EV3 a servir de referência a um motor Servo Power Functions:
E finalmente uma versão um pouco mais refinada do mesmo exemplo com introdução de um factor de escala de modo a que os movimentos sejam equiparáveis e ainda uma limitação ao intervalo [-90º,+90º]
Para este último video foi usado o script abaixo, em python:
import traceback from sys import exit from time import sleep from subprocess import call from subprocess import check_output from math import trunc def reset_ev3motor(): call ("echo 0 > /sys/class/tacho-motor/motor0/position", shell=True); return; def rd_ev3motor(): v=check_output("cat /sys/class/tacho-motor/motor0/position",shell=True); return(trunc(float(v))); def sbrick_drive(channel,direction,dutycycle): " calls gatttool command from BlueZ, the official Linux Bluetooth protocol stack" if(dutycycle > 255): dt_hexa="0xFF"; else: dt_hexa=str(hex(int(dutycycle))); command="gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=01"+channel+direction+dt_hexa[2:]; # print(command); call (command, shell=True); return; def main(): try: pos=0.0; SCALE=255.0/90.0; reset_ev3motor(); while(True): pos=rd_ev3motor()*SCALE; if(pos>0): sbrick_drive("02","00",pos); else: sbrick_drive("02","01",-pos) sleep(0.1); except (KeyboardInterrupt, SystemExit): print "Exiting..."; except Exception: traceback.print_exc(file=sys.stdout); exit(0); if __name__ == "__main__": main()
Recorro à função ‘call’ da library ‘subprocess’ para invocar o comando gatttool. É feio mas funciona, ainda não tive tempo de procurar uma library específica para bluetooth BLE.