LEGO Dimensions + EV3: reading tags

I started fiddling with LEGO Dimensions Toy Pad and the Mindstorms EV3. Later I’ll post better and more organized information but for now here is the script I used with the following video – it shows how to read the NGC tags and change the RGB color of each pad.

All my code is based on woodenphone work.

#!/usr/bin/python

import usb.core
import usb.util
from time import sleep

import lego_dimensions_gateway

# UIDs can be retrieved with Android App (probably in hexadecimal)
uidDarthVader = (4, 161, 158, 210, 227, 64 , 128)

pad1_red = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:red right:off

pad1_green = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:green

pad2_red = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:red center:off right:off

pad2_green = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:green center:off right:off

pad3_red = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:off right:red

pad3_green = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:off right:green

pads_off = [0x55, 0x06, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x00, 29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # Switch all pads off


def init_usb():
    global dev
    # find our device
    dev = usb.core.find(idVendor=0x0e6f)# 0x0e6f Logic3 (made lego dimensions portal hardware)

    # was it found?
    if dev is None:
        raise ValueError('Device not found')

    reattach = False
    if dev.is_kernel_driver_active(0):
        reattach = True
        dev.detach_kernel_driver(0)

    # set the active configuration. With no arguments, the first
    # configuration will be the active one
    dev.set_configuration()

    # Initialise portal
    dev.write(1, [0x55, 0x0f, 0xb0, 0x01, 0x28, 0x63, 0x29, 0x20, 0x4c, 0x45, 0x47, 0x4f, 0x20, 0x32, 0x30, 0x31, 0x34, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])# Startup
    return dev

def uid_compare(uid1, uid2):
  match = True
  for i in range(0,7):
    if (uid1[i] != uid2[i]) :
       match = False
  return match 

def demo():
    while True:
        try:
            inwards_packet = dev.read(0x81, 32, timeout = 10)
            bytelist = list(inwards_packet)

            if not bytelist:# We need a packet
                pass
            elif bytelist[0] != 0x56: # Only listen to NFC packets
                pass
            else:
                pad_num = bytelist[2]
                uid_bytes = bytelist[6:13]
                match = uid_compare(uid_bytes, uidDarthVader)
                action = bytelist[5]
                if action == 0 : #IN
                  if match:
                  # Darth Vader IN
                      if pad_num ==1 :
                          command = pad1_red
                      elif pad_num == 2 :
                          command = pad2_red
                      elif pad_num == 3 :
                          command = pad3_red
                      else :
                          pass
                  else:
                  # some other tag IN
                      if pad_num ==1 :
                          command = pad1_green
                      elif pad_num == 2 :
                          command = pad2_green
                      elif pad_num == 3 :
                          command = pad3_green
                      else :
                          pass                      
                  dev.write(1, command)
                elif action == 1 : # OUT
                  dev.write(1, pads_off)

        except usb.USBError, err:
            pass

def main():
    init_usb()
    demo()
    return

if __name__ == '__main__':
    main()

WeDo 2.0 LED Button Service

This post is part 3 of 6 of  WeDo 2.0 - reverse engineering

And we continue digging into the  WeDo 2.0 Hub primary services, now with the “Nordic LED Button Service”

WeDo 2.0 Hub BLE services

[A0:E6:F8:1E:58:57][LE]> primary
...
attr handle: 0x000c, end grp handle: 0x002f uuid: 00001523-1212-efde-1523-785feabcd123
...

So this Primary service uses handles from 0x000c to 0x002f. Let’s look deeper:

[A0:E6:F8:1E:58:57][LE]> characteristics 000c 002f
handle: 0x000d, char properties: 0x0a, char value handle: 0x000e, uuid: 00001524-1212-efde-1523-785feabcd123
handle: 0x0010, char properties: 0x12, char value handle: 0x0011, uuid: 00001526-1212-efde-1523-785feabcd123
handle: 0x0014, char properties: 0x10, char value handle: 0x0015, uuid: 00001527-1212-efde-1523-785feabcd123
handle: 0x0018, char properties: 0x12, char value handle: 0x0019, uuid: 00001528-1212-efde-1523-785feabcd123
handle: 0x001c, char properties: 0x12, char value handle: 0x001d, uuid: 00001529-1212-efde-1523-785feabcd123
handle: 0x0020, char properties: 0x12, char value handle: 0x0021, uuid: 0000152a-1212-efde-1523-785feabcd123
handle: 0x0024, char properties: 0x08, char value handle: 0x0025, uuid: 0000152b-1212-efde-1523-785feabcd123
handle: 0x0027, char properties: 0x0a, char value handle: 0x0028, uuid: 0000152c-1212-efde-1523-785feabcd123
handle: 0x002a, char properties: 0x02, char value handle: 0x002b, uuid: 0000152d-1212-efde-1523-785feabcd123
handle: 0x002d, char properties: 0x08, char value handle: 0x002e, uuid: 0000152e-1212-efde-1523-785feabcd123

[A0:E6:F8:1E:58:57][LE]> char-desc 000c 002f
handle: 0x000c, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000e, uuid: 00001524-1212-efde-1523-785feabcd123
handle: 0x000f, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0010, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0011, uuid: 00001526-1212-efde-1523-785feabcd123
handle: 0x0012, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0013, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0014, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0015, uuid: 00001527-1212-efde-1523-785feabcd123
handle: 0x0016, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0017, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0018, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00001528-1212-efde-1523-785feabcd123
handle: 0x001a, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x001b, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x001c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001d, uuid: 00001529-1212-efde-1523-785feabcd123
handle: 0x001e, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x001f, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0020, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0021, uuid: 0000152a-1212-efde-1523-785feabcd123
handle: 0x0022, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0023, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0024, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0025, uuid: 0000152b-1212-efde-1523-785feabcd123
handle: 0x0026, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0027, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0028, uuid: 0000152c-1212-efde-1523-785feabcd123
handle: 0x0029, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x002a, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002b, uuid: 0000152d-1212-efde-1523-785feabcd123
handle: 0x002c, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x002d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002e, uuid: 0000152e-1212-efde-1523-785feabcd123
handle: 0x002f, uuid: 00002901-0000-1000-8000-00805f9b34fb

Lot of things here: 10 characteristics and 36 handles!

The first handle (0x000c) just marks the begin of the service (UUID 2800).

Then we see that there are 10 handles with UUID 2803 (Characteristic Declaration Attribute) and also 10 handles with UUID 2901 (Characteristic User Description) – these handles mark the begin of each characteristic and also defines its properties, so let’s read them all  (char-read-hnd) and translate it:

Name Char               0x000e  read+write
Button Char             0x0011  notify+read
Port Type Char          0x0015  notify
Low Voltage alert       0x0019  notify+read
High Current alert      0x001d  notify+read
Low Signal alert        0x0021  notify+read
Turn off device         0x0025  write
Vcc port control        0x0028  read+write
Battery type Indicator  0x002b  read
Disconnect Char         0x002e  write

Some characteristics also have an handle with UUID 2902 (Client Characteristic Configuration). That’s used for Notifications – the 5 characteristics that support this feature use this extra handle to activate or deactivate it.

So let’s read the 7 handles that are readable:

Name Char               75 30 30 30 31 = u0001
Button Char             00
Low Voltage alert       00
High Current alert      00
Low Signal alert        00
Vcc port control        01
Battery type Indicator  00

So ‘Name char’ contains the friendly name of my Hub. And it is writable, so what happens if I change it?

[A0:E6:F8:1E:58:57][LE]> char-write-cmd 0x000e 4d616a6f72
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x00e
Characteristic value/descriptor: 4d 61 6a 6f 72

Well it retains what I wrote.

And if I now read the ‘Device Name’ it is no longer ‘u0001’:

[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A00
handle: 0x0003      value: 4d 61 6a 6f 72

So now my Hub announces a new name:

$ sudo hcitool -i hci0 lescan
LE Scan ...
A0:E6:F8:1E:58:57 (unknown)
A0:E6:F8:1E:58:57 Major

Changing 'Device Name' attribute

Cool, isn’t it?

Now the ‘Button Char’ just reads zero. But if I press the Hub’s button while I read it:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0011
Characteristic value/descriptor: 01

it reads ‘1’.

And what about ‘Port Type Char’? It’s not defined as readable (just ‘notify’) but I can try to read it anyway:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor:

Hmm… null value.

But I have nothing connected to the Hub. Let’s try it again with a motor at port 1:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 01 01 00 01 01 00 00 00 01 00 00 00

And removing the motor again:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 01 00

Interesting – it’s not null now.

Let’s do the same again but on port 2:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 02 01 01 01 01 00 00 00 01 00 00 00

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 02 00

So the first byte seems to identify the Port (’01’ or ’02’) and the second byte the action (’01’ might be ‘device plugged’ and ’00’ might be ‘device removed’). I have no explanation for the third byte and the other 8 bytes bytes seem to be some kind of identification of the motor.

Now let’s connect a tilt sensor in port 1 (and nothing in port 2):

01 01 00 22 00 00 00 10 00 00 00 10

and then move it to port 2:

02 01 01 22 00 00 00 10 00 00 00 10

Now just a distance sensor in port 1:

01 01 00 23 00 00 00 10 00 00 00 10

and move it to port 2:

02 01 01 23 00 00 00 10 00 00 00 10

Now just the motor again in port 1 and then the tilt sensor in port 2 (two readings):

01 01 00 01 01 00 00 00 01 00 00 00
02 01 01 22 00 00 00 10 00 00 00 10

So ‘Port Type Char’ doesn’t describe the ports state, it just shows the last action detected at ports. I think that’s the reason it’s not defined as ‘notify + read’, it’s purpose is just to notify that a change ocurred on ports.

Now we have 3 characteristics named “Alert”: Low Voltage Alert, High Current Alert and Low Signal Alert. Their names seem clear enough to understand their purpose and since all read zero everything seems to be OK. But let’s try to force an “High Current Alert” – make the motor run, block it and read the handle:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 01 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 01 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 01 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00

When I block the motor with my hand, the Hub beeps and flashes the LED twice (in yellow). And sometimes the Alert reads ’01’.

But instead of reading several times the handler, we can activate ‘Notifications’ by turning ON the ‘notification’ flag in the ‘Client Characteristic Configuration’ and then just wait for the Hub to send the notification when the High Current Alert changes it’s state:

[A0:E6:F8:1E:58:57][LE]> char-write-req 001e 0100 -listen
Characteristic value was written successfully
[A0:E6:F8:1E:58:57][LE]> char-write-cmd 003d 01010164
Notification handle = 0x001d value: 01 
Notification handle = 0x001d value: 00

We used a different write command: ‘char-write-req’ instead of ‘char-write-cmd’ expects an answer from the device and ‘-listen’ keeps listening for future ‘answers’.

Now the ‘Vcc port control’ name isn’t much clear about it’s purpose. It reads ‘1’ but it’s also writable… does it allows us to control power in the ports? No matter what I write to 0x003d it seems to retain only ‘0’ or ‘1’ and when I write ‘0’ to it while the motor is running it keeps running.

‘Battery type indicator’ reads zero, I guess that it identifies the kind of battery being used. I’m using 2 AA alcaline batteries, will try again with the LiPo battery when I get it.

And finally the 2 writable-only characteristics: ‘Disconnect Char’ and ‘Turn off device’. They also seem quite clear about their purpose:

[A0:E6:F8:1E:58:57][LE]> char-write-cmd 002e 01
[A0:E6:F8:1E:58:57][LE]> 
(gatttool:8257): GLib-WARNING **: Invalid file descriptor.

[A0:E6:F8:1E:58:57][LE]> connect
Attempting to connect to A0:E6:F8:1E:58:57
Connection successful

Writing to ‘Disconnect Char’ makes the Hub disconnects but keeps it in discovery mode so I cpuld reconnect to it.

[A0:E6:F8:1E:58:57][LE]> char-write-cmd 0025 01
[A0:E6:F8:1E:58:57][LE]> 
(gatttool:8257): GLib-WARNING **: Invalid file descriptor.

[A0:E6:F8:1E:58:57][LE]> connect
Attempting to connect to A0:E6:F8:1E:58:57
[A0:E6:F8:1E:58:57][LE]> 
Error: connect error: Connection refused (111)

Writing to ‘Turn off device’ really turns it off.

So that’s it for ‘Nordic LED button service’. What LED, you ask? Well, the Android App is from Nordic and they have some examples on the Net with this UUID so my explanation is that LEGO used part of their code for the ‘button’ part without changing the UUID so the App recognizes it this way.

Next post: Motors and LED.

WeDo 2.0 Battery Service

This post is part 2 of 6 of  WeDo 2.0 - reverse engineering

In first post we have seen that the WeDo 2.0 Hub offers a “Battery Service” Primary Service:

[A0:E6:F8:1E:58:57][LE]> primary
...
attr handle: 0x0046, end grp handle: 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb
...

‘180F’ is defined in the Bluetooth Standard as a ‘Battery Service‘. LEGO assigned all handles from 0x0046 to 0xFFFF to this service (not quite true: since there is no other Primary Service, gatttool assumes 0xFFFF as the last handle).

What handles and characteristics?

[A0:E6:F8:1E:58:57][LE]> characteristics 0x0046 0xffff
handle: 0x0047, char properties: 0x12, char value handle: 0x0048, uuid: 00002a19-0000-1000-8000-00805f9b34fb
[A0:E6:F8:1E:58:57][LE]> char-desc 0x0046 0xffff
handle: 0x0046, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0047, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0048, uuid: 00002a19-0000-1000-8000-00805f9b34fb
handle: 0x0049, uuid: 00002902-0000-1000-8000-00805f9b34fb

So there is  just one useful characterist, the one with UUID ‘00002a19-0000-1000-8000-00805f9b34fb’ or just ‘2a19’ assigned to handle 0x0048.

There are 3 other characteristics (‘2800’, ‘2803’ and ‘2902’) each one assigned to one handle (‘0x0046’, ‘0x0048’ and ‘0x49’). What’s their purpose?

The first characteristic (‘2800’) contains the UUID of the Primary Service (we already know that it is ‘180F’):

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x046
Characteristic value/descriptor: 0f 18

The second characteristic (‘2803’) describes the Service – something we already know from the ‘characteristics’ command:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x047
Characteristic value/descriptor: 12 48 00 19 2a

The first byte is the ‘characteristic properties’. Each bit has a meaning:

Broadcast: 01h
Read: 02h
Write without response: 04h
Write: 08h
Notify:10h
Indicate: 20h
Authenticated Signed Writes:40h
Extended Properties: 80h

So ’12h’ means ‘notify’ + ‘read’ so we can read and the battery level and we can also ask for notifications.

The second and third bytes specify the handle associated to the battery level: ‘0048h’.

The fourth and fifth bytes specify the characteristic UUID of the battery level: ‘2a19’.

Now the last characteristic (‘2902’) is used for notification and indication control.

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x049
Characteristic value/descriptor: 00 00

Since it’s value is ‘0’ it means ‘Notifications and indications disabled’

Now let’s read the battery level, at the third characteristic (UUID: ‘2a19’/ Handle: 0x0048)

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x048
Characteristic value/descriptor: 64

64h = 100d so battery level is 100%

We can also use this other command:

[A0:E6:F8:1E:58:57][LE]> char-read-uuid 2a19
handle: 0x0048      value: 64

Now let’s check with Android nRF Connect App:

WeDo 2.0 Battery Service

Seems ok once again.

Until now we just accessed information defined in the Bluetooth standard. Maybe in the future the Bluetooth SIG decide to include motors, lights and other devices in the standard but for now each vendor (like LEGO) decides how to communicate with its gadgets and if it doesn’t release that information to the public it’s almost impossible to develop third-party applications for it.

LEGO promised to release a SDK in the first half of 2016. That’s a good decision, everyone (including LEGO) will benefit if everyone can create it’s own application and even integrate it with other tools or systems. But we are already in the second half of 2016 and no SDK…

Luckily there are already a few pieces of information scattered around the Web…

Next post: the WeDo 2.0 Hub button.

WeDo 2.0 with EV3 – an ev3dev tutorial

What a great weekend:

  • at Paredes de Coura FAN Weekend with almost 200 AFOL’s from allover the world
  • finally got the LEGO Education WeDo 2.0 App working with my Android phone – thanks Fernando for being such a good PITA 😉
  • github notified me that my ev3dev tutorial got merged so it’s now available in the ev3dev site on the Tutorials section: Controlling a WeDo 2.0 motor

Controlling WeDo 2.0 motor from Linux

LEGO Education released the WeDO 2.0 some months ago and I bought a kit. I returned to LEGO thanks to WeDO 1.0 and since I’m already using BLE with the SBrick, using the WeDo 2.0 seemed natural.

But LEGO Education made the Android app very restrictive and only a few Android devices are allowed to install it – I have two different BLE enabled Android phones and none complies with LEGO Education definitions. Although LEGO Education promised a SDK for the new WeDO 2.0, there’s still nothing available and since I don’t own a Windows computer or an Apple device, my WeDO 2.0 kit was rusting on the shelf, waiting for better days.

Then yesterday I found a Microsoft guy’ with some bluetooth code samples with references for the WeDO 2.0 – how ironic!

So it took me only a few hours to achieve what I think is a world premiere: a linux system controlling a LEGO WeDO 2.0 motor. And what better linux system than a LEGO Mindstorms EV3?

Next post will I’ll give more details.

How to remote control a LEGO DUPLO Train

Some weeks ago, a fellow from my LEGO User Group reached me for some Infrared electronics insights. He was trying to remote control his LEGO DUPLO Train with an infrared remote.

I never played with IR before but got curious. I love the idea of remote controlling something. But not manually, it has to be programmatically so one can use it for automation or robotic purposes. So after some weeks I found the LIRC definitions for LEGO Power Functions IR and used it to remote control LEGO from my laptop via the audio output.

Then it was the anniversary of one the kids and he asked granny for a major upgrade of their DUPLO train track:

LEGO® DUPLO® Deluxe Train Set

So I thought it would be great if they could control the train back and forth… and ordered a used DUPLO Train Locomotive Base (5135c01) from BrickLink.

Opening it was difficult but I managed to do it without breaking anything, thanks to these two previous brave pioneers:

(their locomotives are from a different set but the idea is the same)

The locomotive has a pair of free wheels at front and another pair drived by a motor and some gears at back where there is also a piezo buzzer, a printed circuit board and a pair of wires comming from the batteries holder. There are also two rubber buttons that press some small metal rings against the surface of the PCB to act as switches – the smaller one, hidden in a small hole, makes the sound of fuel being pumped into the tank when the fuel hose is inserted, the bigger one controls starts/stops the train but also indirectly controls the sound of the locomotive (when in movement) and the sound of the breaks (when stopping).

The PCB has 6 wires soldered at points labeled J1 to J6:

  • J1 and J3 – buzzer
  • J2 and J4 – batteries
  • J5 and J6 – motor

As the batteries holder is for just 3 AA batteries, the board works with 4.5V. Not much but enough for a LEGO Power Functions IR receiver or a Vengit SBrick.

We could just dessolder the wires at J2/J4 (power) and J5/J6 (motor), get a LEGO Power Functions cable, cut it in half and solder the tips from one half to J2/J4 and the tips from the other half to J5/J6. But that will make the buzzer useless.

As the buzzer is controlled by an IC on the PCB, I choose to keep the power lines going to the PCB (J2/J4) and deriving from there to the Power Functions cable (but still dessoldering J5/J6). This way, when the batteries are inserted, both the remote and the PCB are ON so the two buttons maintain their functionality. This gives us as an unexpected possibility: we can also use the PF cable to power the train instead of using 3 AA batteries – with special caution because LEGO PF batteries or LEGO 9V batteries give more than 4.5V so some reduction has to be done, like adding some 1N4001 diodes or a voltage regulator… but a USB 5.0V battery pack will be perfect.

Since I didn’t want to drill or cut the plastic, I managed to pass the PF cables through the start/stop button hole (before soldering it) but later found out that it was to tight for the rubber button – so no more «tchoo-tchoo!» nor breaks (some may consider this a feature, not a bug).

Some more photos are available at this Brickshelf folder.

The final result is a LEGO DUPLO train that:

  • can be remotely controlled by Infrared or Bluetooth, manually or programatically
  • can move forward AND backward
  • can use LEGO batteries (PF or 9V) with a special cable or a USB battery pack

Raspberry Pi + SBrick

Finally got time to return to the Pi.

Yes, the Raspberry Pi can talk to the SBrick. It’s only necessary to install Bluez 5.

But as the standard Raspbian is based on Debian Wheezy, if you install bluez from the repositories

sudo apt-get install bluez

you will get Bluez 4 (today, 1 December 2014, it’s version 4.99). I can make a Low Energy Scan (lescan) and find the SBrick but my gatttool commands fail with

Host is down (112)

So we need Bluez 5. There are at least two ways:

  • get Bluez 5 source code and compile as in RPi Bluetooth LE
  • update Raspbian to Debian Jessiea as it already includes Bluez 5

I’m lazy, I don’t like to compile anything. I’m also afraid that any update might brake compatibility and forces me to recompile again. And my laptop (Unbuntu) and my EV3 (ev3dev) are already running a version of Jessie so let’s update.

Warning: Raspbian update from Wheezy to Jessie takes almost a day – so compiling Bluez might appeal to those in a hurry.

We need enough free space on the SD card. I used a 4 GB card and my first try failed miserable after a long night. So the second time I removed some things to assure an happy end.

First I transfered the most recent image available (2014-09-09) to the 4 GB card and edited networking to get wi-fi (I only use SSH with the Raspberry, like I do with the LEGO Mindstorms EV3).

After first boot with the fresh card run rasp-config to expand the file system with all free space available.

sudo rasp-config

after next boot remove some heavy things and clean:

sudo apt-get remove x11-common midori lxde
rm /opt/vc/src/hello_pi/hello_video/test.h264
rm -rf python_games
sudo apt-get clean
df -h

there are now 2.0 GB available on the 4.0 GB card. That’s enough, let’s change the source of our packages:

sudo nano /etc/apt/sources.list

replace ‘wheezy’ with ‘jessie’ and save.

sudo apt-get update
sudo apt-get upgrade
sudo reboot
By now we have near 1.8G available.

sudo dist-upgrade
sudo reboot

Now we are already using a Debian Jessie version of Raspbian.

sudo apt-get install bluez

As of 1 December 2014, Debian Jessie for Raspberry Pi uses bluez 5.23-1. Now remove all garbage and check space again:

apt-get autoremove

df -h

807 MB avaliable, not bad.

My bluetooth BT 4.0 USB dongle is recognized (it already was) but is not active by default so before using it

sudo hciconfig hci0 up

now gatttool commands work with the SBrick, and so all my scripts from Ubuntu and EV3.

 

 

 

 

 

 

LEGO WeDO – Temperature Sensor

As the WeDo USB Hub uses some kind of ADC (Analog to Digital Converter) to read the tilt sensor values, we can use this ADC for our own analog sensors.

So let’s start with  a Temperature Sensor.

The most simple/easy temperature sensor is just a NTC thermistor: every regular resistor has some minor variations when the operating temperature changes and a thermistor is just a resistor designed to have a significant and well-known variation. A NTC (negative temperature coefficient) thermistor has a decrease in it’s value proportional to the temperature increase.

We can buy a cheap (less than €1) 10 kΩ NTC thermistor and use it as a temperature sensor knowing that at 25°C (average ambient temperature) it has a 10 kΩ value – we also need to know its temperature coefficient from the manufacturer datasheet or from our own calibration tests. Just solder two wires and provide some insulation and we’re done:

Or we can just use an old LEGO Mindstorms (RCX) Temperature Sensor 🙂

To use this sensor we can make our own cable with just one 3.9 kΩ resistor between C1 and 0 to makes the WeDo think we have a tilt sensor connected to it. Then we connect our sensor between C2 and 0 or between C2 and 9V.

Our we can piggyback a real tilt sensor with a modded cable and just connect our sensor to it:

In this scenario we must assure that the tilt sensor always stays flat so it doesn’t get in our way when we’re reading the temperature sensor and since the tilt sensor already has a 10 kΩ resistor between C2 and 0 I prefer to connect the sensor between C2 an 9V.

Early first readings, room temperature compared to the readings from a SensorTag :

RAW Temp (°C)
159 20
158 20
165 36.5
157 19.8
157 19.5
157 19.6
156 18.8
157 19
156 18.9