SBrick beta testing

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.

SBrick Remote Control

A fast incursion in Python and Tkinter (a very easy GUI library for those like me who abuse from Google-Copy-Paste) so I can play with SBrick from my Ubuntu laptop without the command line:

SBrick-RemoteControl

#!/usr/bin/env python 

from Tkinter import *
from time import sleep
from subprocess import call

def quit():
  global Window
  Window.destroy()

  return;

def STOP():

  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0002",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0003",shell=True)
  return

def NORTH():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010301FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010200FF",shell=True)
  sleep(time)
  STOP()
  return

def SOUTH():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010300FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010201FF",shell=True)
  print("Backward")
  sleep(time)
  STOP()
  return

def EAST():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010301FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010201FF",shell=True)
  print("RIGHT")
  sleep(time)
  STOP()
  return

def WEST():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010200FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010300FF",shell=True)
  sleep(time)
  STOP()
  return


Window = Tk()
Window.title("SBrick Remote Control v0.1")

B_North = Button(text = "N", command = NORTH)
B_North.grid(row=0, column=1)

B_West = Button(text = "W", command = WEST)
B_West.grid(row=1, column=0)

B_STOP = Button(text = "STOP", command = STOP)
B_STOP.grid(row=1, column=1)

B_East = Button(text = "E", command = EAST)
B_East.grid(row=1, column=2)

B_South = Button(text = "S", command = SOUTH)
B_South.grid(row=2, column=1)

scale = Scale(Window, from_=0.125, to=2.5, digits=3, resolution=0.125, orient=HORIZONTAL, length=250, label="Time")
scale.grid(row=3,column=0,columnspan=3)

B_QUIT = Button(text = "QUIT", command = quit)
B_QUIT.grid(row=4, column=1, )

mainloop()

 

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

 

 

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

SBrick + Snap!

A linguagem Snap! (antes designada BYOB) é uma linguagem de programação visual baseada na experiência “drag-and-drop”, uma reimplementação extendida da linguagem Scratch que tem ganho alguma notoriedade por ter sido incluída no ambiente gráfico dos Raspberry Pi.

Eis um exemplo de um programa muito simples, que faz um rover andar às voltas:

snap-SBrick1De há um par de anos para cá que alimento a ideia de utilizar Snap! para ensinar à miudagem [e não só] conceitos básicos de robótica. A forma como o Snap! está a ser desenvolvido permite criar «device extensions» para interagir com dispositivos físicos (descobri o Snap! justamente por ter uma extensão para Mindstorms NXT, a Snap-NXT by Technoboy10) e hoje criei a minha primeira extensão, para o Sbrick.

Basicamente editei a extensão para Mindstorms NXT, deitei fora a parte específica do NXT e acrescentei os meus comandos que invocam o comando gatttool do BlueZ (do que resulta a minha extensão apenas funcionar em Linux, lamento).

A device extension consiste em dois ficheiros:

O primeiro é um programa em Python que corre um servidor http muito básico que aceita comandos http. O segundo é uma definição XML das funcionalidades implementadas (dois comandos apenas: ‘move motor’ e ‘stop motor’, sendo possível controlar 3 «motores»: A = channel#1, B=channel#2 e P = channel#1+channel#2). Estando o programa ‘snap-sbrick.py’ a correr, lançamos o Snap! com a device extension quando acedemos por browser ao endereço:

http://snap.berkeley.edu/snapsource/snap.html#open:http://localhost:1330/snap-sbrick

Ou seja o Snap! em si é carregado da Universidade de Berkeley e apontado para o nosso PC de onde carrega as definições das funcionalidades adicionais. É possível carregar o Snap! a partir do nosso próprio PC para trabalhar em modo offline mas isso já é outra história.

A definição dos comandos pode também ser feita graficamente, sendo depois gerado um ficheiro XML semelhante ao acima referido:

  • comando ‘move motor’

snap-movemotor-def

  • comando ‘stop motor’

snap-stopmotor-defPodemos ver que a definição de ‘move motor’ está bem melhor que a de ‘stop motor’ – é feita uma validação dos parâmetros, se speed não pertencer ao intervalo [-100,100] ou se motor não for A/B/P é gerada uma excepção.

SBrick Remote Control

Uma incursão rápida em Python e Tkinter (uma library para aplicações GUI muito fácil de usar no modo Google-Copy-Paste) para poder comunicar com o SBrick a partir do meu laptop Ubuntu sem usar a linha de comando:

SBrick-RemoteControl

#!/usr/bin/env python 

from Tkinter import *
from time import sleep
from subprocess import call

def quit():
  global Window
  Window.destroy()

  return;

def STOP():

  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0002",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=0003",shell=True)
  return

def NORTH():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010301FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010200FF",shell=True)
  sleep(time)
  STOP()
  return

def SOUTH():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010300FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010201FF",shell=True)
  print("Backward")
  sleep(time)
  STOP()
  return

def EAST():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010301FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010201FF",shell=True)
  print("RIGHT")
  sleep(time)
  STOP()
  return

def WEST():

  time=scale.get()
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010200FF",shell=True)
  call("gatttool -b 00:07:80:7F:28:E1 -i hci0 --char-write --handle=0x0025 --value=010300FF",shell=True)
  sleep(time)
  STOP()
  return


Window = Tk()
Window.title("SBrick Remote Control v0.1")

B_North = Button(text = "N", command = NORTH)
B_North.grid(row=0, column=1)

B_West = Button(text = "W", command = WEST)
B_West.grid(row=1, column=0)

B_STOP = Button(text = "STOP", command = STOP)
B_STOP.grid(row=1, column=1)

B_East = Button(text = "E", command = EAST)
B_East.grid(row=1, column=2)

B_South = Button(text = "S", command = SOUTH)
B_South.grid(row=2, column=1)

scale = Scale(Window, from_=0.125, to=2.5, digits=3, resolution=0.125, orient=HORIZONTAL, length=250, label="Time")
scale.grid(row=3,column=0,columnspan=3)

B_QUIT = Button(text = "QUIT", command = quit)
B_QUIT.grid(row=4, column=1, )

mainloop()

 

 

LEGO MOC: Xutos & Pontapés ao vivo no Braga BRInCKa 2014

Longe de estar terminado mas já suficientemente funcional para supreender alguns visitantes:

[actualização] com mais algumas minifigs e um backstage a disfarçar a electrónica [ideia da mulher, claro 😉 ]