Broadcom-based USB BLE dongle

Found my BT BLE dongle with the Broadcom chipset.

It’s a “Targus Bluetooth v4.0 Dual-mode Dongle ACB75A” that is sold at Staples.

dmesg:

usb 1-1: new full-speed USB device number 9 using xhci_hcd
usb 1-1: New USB device found, idVendor=0a5c, idProduct=21e8
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: BCM20702A0
usb 1-1: Manufacturer: Broadcom Corp
usb 1-1: SerialNumber: 5CF370878D54
Bluetooth: hci1: BCM: chip id 63
Bluetooth: hci1: BCM: features 0x07
Bluetooth: hci1: BCM20702A
Bluetooth: hci1: BCM20702A1 (001.002.014) build 0000
bluetooth hci1: Direct firmware load for brcm/BCM20702A1-0a5c-21e8.hcd failed with error -2
Bluetooth: hci1: BCM: Patch brcm/BCM20702A1-0a5c-21e8.hcd not found

hciconfig:

hci1:	Type: Primary  Bus: USB
	BD Address: 5C:F3:70:87:8D:54  ACL MTU: 1021:8  SCO MTU: 64:1
	UP RUNNING 
	RX bytes:1052 acl:0 sco:0 events:63 errors:0
	TX bytes:4898 acl:0 sco:0 commands:63 errors:0
	Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
	Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 
	Link policy: RSWITCH SNIFF 
	Link mode: SLAVE ACCEPT 
	Name: 'xxxx'
	Class: 0x1c010c
	Service Classes: Rendering, Capturing, Object Transfer
	Device Class: Computer, Laptop
	HCI Version: 4.0 (0x6)  Revision: 0x1000
	LMP Version: 4.0 (0x6)  Subversion: 0x220e
	Manufacturer: Broadcom Corporation (15)

so it’s a Broadcom BCM20702A chipset and my Ubuntu doesn’t find the firmware needed. It still works without firmware but I went after it.

This site helped:

wget https://s3.amazonaws.com/plugable/bin/fw-0a5c_21e8.hcd
sudo cp fw-0a5c_21e8.hcd /lib/firmware/brcm/BCM20702A1-0a5c-21e8.hcd

I got my script working with 6 LEGO BLE devices. And 7. And even 8:

But latency isn’t great (with 8 I had to decrease the loop period from 1 second to 0.25 to prevent connection drops and even send the initial command twice to the Handset to hold the session) so even if it supports 14 sessions I doubt that we can make good use of 14 LEGO LPF2 hubs with just one dongle.

To reduce latency we can add more dongles. But even so, when a command takes 0.2 to 0.3 seconds to complete before we can send the next one, it’s hardly interesting for robotics. A Powered Up based robot will require a real autonomous device, able to read its own sensors and react on the fly, not with half a second round trip delay to the “brain”.

Also tried the script without the firmware. It works but with a few “connect error: Function not implemented (38)”.

And also re-tried the Cambridge CSR 4.0. It clearly states that it can’t handle the sixth: “connect error: Too many links (31)”

Controlling several LEGO BLE devices at same time

Yeap. CSR 4.0 on Ubuntu can control 5 different BLE devices:

Bash script:

#!/usr/bin/env bash

#usage: ./rgbled.sh hci0

HCI=$1

#DELAY=0.03
DELAY=0

#colors
OFF=0
PINK=1
PURPLE=2
BLUE=3
LIGHTBLUE=4
LIGHTGREEN=5
GREEN=6
YELLOW=7
ORANGE=9
RED=9
WHITE=A

#hubs
PUPA="90:84:2B:06:AB:5D"
PUPB="90:84:2B:03:CA:6E"
BOOSTA="00:16:53:A3:47:EA"
HANDSETA="A4:34:F1:CE:DC:A2"
WEDOA="A0:E6:F8:1B:FF:9B"

function remoteLED () {
    gatttool -i $HCI -b $PUPA --char-write-req --handle 0x0e --value 080081321151000$1
    sleep $DELAY
    gatttool -i $HCI -b $PUPB --char-write-req --handle 0x0e --value 080081321151000$1
    sleep $DELAY
    gatttool -i $HCI -b $BOOSTA --char-write-req --handle 0x0e --value 080081321151000$1
    sleep $DELAY
    gatttool -i $HCI -b $HANDSETA --char-write-req --handle 0x0b --value 080081341151000$1
    sleep $DELAY
    gatttool -i $HCI -b $WEDOA --char-write-req --handle 0x3d --value 0604010$1
    sleep $DELAY
}

# activate notifications and keep changing colors
gatttool  -i $HCI -b $PUPA --char-write-req --handle 0x0f --value 0100
sleep $DELAY
gatttool -i $HCI -b $PUPB --char-write-req --handle 0x0f --value 0100
sleep $DELAY
gatttool -i $HCI -b $BOOSTA --char-write-req --handle 0x0f --value 0100
sleep $DELAY
gatttool -i $HCI -b $HANDSETA --char-write-req --handle 0x0c --value 0100
sleep $DELAY

while :
do
    for color in $OFF $PINK $PURPLE $BLUE $LIGHTBLUE $LIGHTGREEN $GREEN $YELLOW $ORANGE $RED $WHITE; do
        remoteLED $color
        sleep 1
    done
done

Controlling multiple Powered Up devices

About two years ago I had a dual SBrick “train” setup controlled with my EV3. I never really got much far because there were some hiccups when using one USB BLE dongle to control two SBrick at the same time that didn’t occur with my Ubuntu laptop (same dongle, a CSR 4.0).

By that time, the ev3dev had a BlueZ stack much older than my Ubuntu so I decided to wait and as usual I forgot about it.

Today I’m testing how many Powered Up hubs I can control at the same time with just one BLE “client”. Just a simple bash script, changing the RGB LED colors of the hubs at the same time.

My laptop could control 2. But started to had issues with 3, failing some commands:

Characteristic Write Request failed: Request attribute has encountered an unlikely error

Perhaps sending 3 gatttool commands in-a-row was too much so added a small delay. It got worst:

connect error: Connection timed out (110)

Tuning to a small delay (0.03) seems to be the best but is strange.

Now this laptop is no longer the same I had and it now has an onboard BLE 4.2 chipset, from Intel. Not sure which version.

But I still have the CSR 4.0 dongle on the Ev3 over the desk. So let’s try same script with it.

No errors at all. Not even with 0 delay.

These last years David has been doing a great job with ev3dev kernel so my EV3 and my Ubuntu laptop are now pretty close: (4.14.58-ev3dev-2.2.1-ev3 against 4.15.0-29-lowlatency #31-Ubuntu SMP PREEMPT) so I don’t think this is a BlueZ issue.

I read somewhere that CSR 4.0 allows 5 sessions. So I need to test my script again with more LEGO hubs. But wonder why the Intel only handles two.

Now the script:

#!/usr/bin/env bash

#colors
OFF=0
PINK=1
PURPLE=2
BLUE=3
LIGHTBLUE=4
LIGHTGREEN=5
GREEN=6
YELLOW=7
ORANGE=9
RED=9
WHITE=A

#hubs
PUPA="90:84:2B:06:AB:5D"
PUPB="90:84:2B:03:CA:6E"
BOOSTA="00:16:53:A3:47:EA"

DELAY=0.03

function remoteLED () {
    gatttool -b $PUPA --char-write-req --handle 0x0e --value 080081321151000$1
    sleep $DELAY
    gatttool -b $PUPB --char-write-req --handle 0x0e --value 080081321151000$1
    sleep $DELAY
    gatttool -b $BOOSTA --char-write-req --handle 0x0e --value 080081321151000$1
    sleep $DELAY
}

# activate notifications and keep changing colors
gatttool -b $PUPA --char-write-req --handle 0x0f --value 0100
sleep $DELAY
gatttool -b $PUPB --char-write-req --handle 0x0f --value 0100
sleep $DELAY
gatttool -b $BOOSTA --char-write-req --handle 0x0f --value 0100
sleep $DELAY

while :
do
    for color in $OFF $PINK $PURPLE $BLUE $LIGHTBLUE $LIGHTGREEN $GREEN $YELLOW $ORANGE $RED $WHITE; do
        remoteLED $color
        sleep 1
    done
done

Buy the way, controlling 2 Powered Up “Hub NO.4” and 1 BOOST “Move Hub” at the same time from a single EV3  is already pretty good (if the old hiccups problems are fixed): that’s potentially 8 more motors!

[edit]

Now this is interesting:

I have news, because i did a test. The Broadcom BCM20702 Bluetooth Dongle can handle up to 14 BLE device connections simulateous.
And overall it’s a lot faster than this one from Cambridge Silicon Radio (can handle a max. of 5 BLE device connections simulateous).

Need to search my drawers… almost 100% sure I had a Broadcom LE USB dongle that gave up because ev3dev didn’t like it as much as the Cambridge CSR.
Also Raspberry Pi is Broadcom… time to get back to BrickPi3.

Logic is the beginning of wisdom

This post is part 1 of 8 of  Sniffing the LEGO Interactive Motor

I hope Spock is right because I’m not sure if an headache is a sign of wisdom

First capture

So the only affordable Logic Analyser that works with Linux and I could get nearby to get rid of portuguese evil customs was the BitScope Micro (BS05).

Installation on Ubuntu was easy (amazing how things evolved!) and it works. Documentation isn’t great but it is enough.

Now the tough part: finding sense in all captured data. 300 baud inverted seems… something.

Bash script to control Powered Up motor

Ben Hughes asked for the code for the demo video “LEGO MINDSTORMS EV3 controlling Powered UP motor” so here it is:

#!/usr/bin/env bash

event_left='*code 105 (KEY_LEFT), value 1*'
event_right='*code 106 (KEY_RIGHT), value 1*'
event_down='*code 108 (KEY_DOWN), value 1*'
event_up='*code 103 (KEY_UP), value 1*'
event_enter='*code 28 (KEY_ENTER), value 1*'

function finish {
    # terminate all subshells
    kill 0
    # reset all motors
    gatttool -i hci0  -b 90:84:2B:06:AB:5D --char-write-req --handle 0x0e --value 0800810011510000
    gatttool -i hci0  -b 90:84:2B:06:AB:5D --char-write-req --handle 0x0e --value 0800810111510000
}
trap finish EXIT



{
    while :
    do
        gatttool -i hci0  -b 90:84:2B:06:AB:5D --char-write-req --handle 0x0e --value 0800810011510000
        sleep 0.35
    done
}&


while :
do
    evtest '/dev/input/event1' | while read line
    do
#        echo $line
        case $line in
            $event_left)
                echo "LEFT"
                gatttool -i hci0 -b 90:84:2B:06:AB:5D --char-write-req --handle 0x0e --value 0800810011510060
                sleep 0.1
                ;;
            $event_right)
                echo "RIGHT"
                gatttool -i hci0 -b 90:84:2B:06:AB:5D --char-write-req --handle 0x0e --value 08008100115100A0
                sleep 0.1
                ;;
           $event_down)
                echo "DOWN"
                gatttool -i hci0 -b 90:84:2B:06:AB:5D --char-write-req --handle 0x0e --value 0800810011510000
                sleep 0.1
                ;;
           $event_up)
                echo "UP"
                ;;
           $event_enter)
                echo "ENTER"
                ;;
        esac
    done
done

 

The BLE properties

This post is part 2 of 2 of  LEGO Powered Up Remote Control

First things first: the Remote Control BT Address and friendly name:

A4:34:F1:CE:DC:A2  “Handset”

The BT address is not a LEGO one like the BOOST (00:16:53, “LEGO System A/S IE Electronics Division”) or the Powered Up (90:84:2B, “LEGO System A/S”). It’s a Texas Instruments chipset, probably something like the CC2640, a ARM microcontroller with embedded BLE functions.

The usual browsing of properties with gatttool reveals 3 primary services and a few characteristics:

primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0xffff uuid: 00001623-1212-efde-1623-785feabcd123
characteristics 
handle: 0x0002, char properties: 0x02, char value handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, char properties: 0x02, char value handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, char properties: 0x02, char value handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x000a, char properties: 0x1c, char value handle: 0x000b, uuid: 00001624-1212-efde-1623-785feabcd123
char-desc 
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x0008, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0009, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000a, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000b, uuid: 00001624-1212-efde-1623-785feabcd123
handle: 0x000c, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 00002901-0000-1000-8000-00805f9b34fb

More details from the Nordic nRF Connect app:

The first primary service (1800, Genneric Access) has 3 chars:
Device Name: Handset
Appearance: Unknown
Peripheral Preferred Connection Parameters: Connection Interval: 100.00ms-200.00ms, Slave Latency:0, Supervision Timeout Multiplier: 1000

The second primary service (1801, Generic Attribute) is empty. Not unusual since it is optional.

The last primary service has the same UUID already present on BOOST and Powered Up hubs (i.e. “00001624-1212-efde-1623-785feabcd123”). And like those it has only one characteristic, “LWP ProtocolChar”.

(side note: LWP might mean Light Weight Process or LEGO Wireless Protocol or just Lets Worsen your Pain)

Thats good: since this “Handset” shares the same primary service UUID of the other PF2 / Powered Up devices, it might also work in the same way.

So lets enable notifications and see what we got:

char-write-req 0x0c 0100
Notification handle = 0x000b value: 0f 00 04 00 01 37 00 00 00 00 10 00 00 00 10 
Notification handle = 0x000b value: 0f 00 04 01 01 37 00 00 00 00 10 00 00 00 10 
Notification handle = 0x000b value: 0f 00 04 34 01 17 00 00 00 00 10 00 00 00 10 
Notification handle = 0x000b value: 0f 00 04 3b 01 14 00 02 00 00 00 02 00 00 00 
Notification handle = 0x000b value: 0f 00 04 3c 01 38 00 00 00 00 10 00 00 00 10

Yeap! 4 devices on 5 different ports:

  • Device ’37’ on ports ’00’ and ’01’
  • Device ’17’ present on port ’34’
  • Device ’14’ present on port ‘3B’
  • Device ’38’ present on port ‘3C’

Nathan already told me that device ’37’ is associated to the buttons. So two “pads” of buttons, one on port ’00’ and other on port ’01’.

Device ’17’ is the RGB LED on the BOOST. I’ll look to it later.

Device ’14’ and ’38’, like Nathan pointed, seem Voltage and Current readings. We can activate each with:

char-write-req 0x0b 0a0041[3B/3C]000100000001

The first (3B) will generate regular messages like ’06 00 45 3b a5 0b’ and the second (3C) also generates regular messages like ’05 00 45 3c cc’

So the payload is ‘3B A5 0B’ and ‘3C CC’, reverting and converting to decimal it gives

0BA53B = 763195 = 7.63  Volt ? hard to believe with just 4 AAA batteries

converting to float = 0.00503671 = 5.037 Volt? Perhaps

CC 3C = 52284 = 52 mA ? Why just two bytes and not 4? Hmm….

We can also deactivate with

char-write-req 0x0b 0a0041[3B/3C]000100000000

Really not important, at least for now. Let’s look to the button pads and the RGB LED and give them a good use:

char-write-req --handle 0x0b --value 080081341151000X

The command works like the BOOST (just changed the port, ’32’ to ’34’) and it accepts the same 10 values:

OFF=0
PINK=1
PURPLE=2
BLUE=3
LIGHTBLUE=4
LIGHTGREEN=5
GREEN=6
YELLOW=7
ORANGE=9
RED=9
WHITE=A

Once again, not sure about the color names but those above are good enough for me…

Now the buttons, we activate them with:

char-write-req 0x0b 0a004100000100000001 (Left or 'A')
char-write-req 0x0b 0a004101000100000001 (Right or 'B')

so we now receive a notification each time there is a state change:

Left or A+ on then off:

05 00 45 00 01
05 00 45 00 00

Left or A- on then off:

05 00 45 00 ff
05 00 45 00 00

Left or A Red on then off:

05 00 45 00 7f
05 00 45 00 00

And the same happens for Right or B, just the fourth byte is now ’01’ instead of ’00’.

So we can use our new ‘Handset’ with whatever BLE capable device we want.

Next bash shell loops through the 10 RGB possible values:

#!/usr/bin/env bash

#colors
OFF=0
PINK=1
PURPLE=2
BLUE=3
LIGHTBLUE=4
LIGHTGREEN=5
GREEN=6
YELLOW=7
ORANGE=9
RED=9
WHITE=A

function remoteLED () {
    gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0b --value 080081341151000$1
}

# activate notifications and keep changing colors
gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0c --value 0100

while :
do
    for color in $OFF $PINK $PURPLE $BLUE $LIGHTBLUE $LIGHTGREEN $GREEN $YELLOW $ORANGE $RED $WHITE; do
        remoteLED $color
        sleep 1
    done
done

And the bash script for ev3dev from the last post:

#!/usr/bin/env bash

# identify motors
MOTORA=$(ls /sys/class/lego-port/port4/ev3-ports\:outA\:lego-ev3-l-motor/tacho-motor/)
MOTORB=$(ls /sys/class/lego-port/port5/ev3-ports\:outB\:lego-ev3-l-motor/tacho-motor/)

echo "outA:"$MOTORA
echo "outB:"$MOTORB

MOTORSPEED=1050
MOTORDELAY=0.1

# reset motor positions and initialize
echo reset > /sys/class/tacho-motor/$MOTORA/command
echo reset > /sys/class/tacho-motor/$MOTORB/command
echo brake > /sys/class/tacho-motor/$MOTORA/stop_action
echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORA/speed_sp
echo brake > /sys/class/tacho-motor/$MOTORB/stop_action
echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORB/speed_sp


function finish {
    # terminate all subshells
    kill 0
    # reset all motors
    echo reset > /sys/class/tacho-motor/$MOTORA/command
    echo reset > /sys/class/tacho-motor/$MOTORB/command
}
trap finish EXIT

# activate left pad
gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0b --value 0a004100000100000001
# activate right panel
gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0b --value 0a004101000100000001

# activate notifications and keep listening
while read -r line; do
    message=$( echo "$line" | cut -f2 -d: )
    
#    echo "Line: $line"
#    echo "Msg: $message"

    if  [[ $message = *"05 00 45 00 01"* ]]; then
        echo "L+ ON"
        echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORB/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORB/command

    elif [[ $message = *"05 00 45 00 7f"* ]]; then
        echo "Lr ON"

    elif [[ $message = *"05 00 45 00 ff"* ]]; then
        echo "L- ON"
        echo -$MOTORSPEED > /sys/class/tacho-motor/$MOTORB/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORB/command

    elif [[ $message = *"05 00 45 00 00"* ]]; then
        echo "L  Off"
        echo stop > /sys/class/tacho-motor/$MOTORB/command

    elif [[ $message = *"05 00 45 01 01"* ]]; then
        echo "R+ ON"
        echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORA/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORA/command

    elif [[ $message = *"05 00 45 01 7f"* ]]; then
        echo "Rr ON"

    elif [[ $message = *"05 00 45 01 ff"* ]]; then
        echo "R- ON"
        echo -$MOTORSPEED > /sys/class/tacho-motor/$MOTORA/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORA/command

    elif [[ $message = *"05 00 45 01 00"* ]]; then
        echo "R  Off"
        echo stop > /sys/class/tacho-motor/$MOTORA/command

    fi

done < <(gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0c --value 0100 --listen)

[edit]
Ooops, forgot that EV3 already has an internal BT interface. Sometimes this script works, sometimes don’t. That’s because I don’t specify which BT interface will be used by gatttool command. We should use ‘-i hci0’ or ‘-i hci1’ but sometimes the kernel decides that hci0 is the internal one, sometimes it decides that it is the USB one.

Perhaps a udev rule can force hci0 to always be the USB one, don’t know. Bad quickfix: remove the USB BT adapter and insert it again, this forces ev3dev to switch hci devices.

The new LEGO Powered Up Remote Control

This post is part 1 of 2 of  LEGO Powered Up Remote Control

This week I got a question from Nathan Kunicki about using the BOOST Tacho Motor with the new Powered Up hub.

He already succeeded with the other WeDo 2 and BOOST devices so the motor was the last challenge. So I tried a few ideas but nothing.

I told him that probably the motor was not supported by the current firmware… and then he told me that when we use the new Remote it works (as if a WeDo 2 motor, just ON or OFF).

Well… my lovely wife just gave me this weekend my future birthday gift: the new LEGO Cargo Train. And it has a Powered Up remote so… let me try it.

No, we couldn’t find a way to control the motor. But I learned a bit about the Remote (thanks Nathan!) Enough to use it as a standalone BLE controller without the LEGO Powered Up “HUB NO.4″… it’s so easy that any BLE master can use it.

And, of course, the MINDSTORMS EV3 when running ev3dev:

to be continued…

 

AI2 – selecting BLE devices

This article could also be titled “Read the manual!”

Jetro asked me if it is possible to use the Powered Up smart hub with two train motors in a way that motors work both at same time but in opposite directions. The idea is assembling using a train with one engine wagons at each end like this:

So when the train is moving both motors can be used with just one control.

It is possible with medium motors (my Puppy robot does that when I use the joystick of the App just in a particular axle) and I checked with the only Powered Up train motor I have that it also works (medium motors and train motors seem to have same ID or no ID at all).

So I told Jetro it should be easy to rebuild my App for that specific purpose.

And it really was! Just remove the joystick-related blocks and add two sliders and a few check buttons. So at start only one slider is available and both motors (A and B) run at same speed in opposite directions:

A checkbox allows reversing the direction and the STOP! button quickly stops both motors.

If we want to control the two motors independently another slider appears:

Great, it worked with my Puppy so I asked Jetro for his BT address so I could add to my list of LEGO smart hubs.

But that’s silly!

Yes, I am lazy. But that’s really silly. There must be a way to scan for nearby BLE devices and choose the one we want to use.

So I read the documentation for the AI2 BluetoothLE extension. And they wrote several How Tos including a “Bluetooth Low Energy Basic Connection” that says “Make a basic app that scans for Bluetooth devices and allows you to connect to a selected device”. It also says is for micro:bit and Arduino… but I’m a sceptical old dog.

I didn’t quite copied the example… as I already were using a List Picker button I adapted the example to it.

So these are hte blocks that allow us to use the ‘Choose’ to select which device we want to control:

When the app starts it also starts scanning for nearby BLE devices. The first block above uses “when DeviceFound” to create a list with all devices found. This is list keeps being refreshed while the Scanning process is running.

The list contains the BT Address of each device, it’s friendly name and the RSSI at the time of discovery (a kind of measure of the signal strength that we can use to decide if it is near or far from us).

So when we pick a device from the list (second block above) the text property of the button changes from “Choose” to the friendly name of the device chosen. This name is returned by the “call FoundDeviceName” (not in the original HowTo, that’s why reading documentation is important).

When we press the Connect (or Disconnect) button we now use a slightly different method: “call Connect Index” instead of “call ConnectWithAddress”. I also took the chance to stop the scanning process or restart it (previously the scanning was always running).

So now my App can be used by any one. I feel I’m almost a programmer by now 😀

This is how it works with Puppy:

now I just need to get a second Powered Up train motor to test it with a real LEGO train.

A final note: today at office I found a lots of bluetooth devices nearby. I’m not sure that all are BLE but that’s what the App adds to the list. So I should add a way to filter this list for LEGO-only devices. That means devices whose BT address starts with “”00:16:53” (all my BOOSTs smart hubs) or “90:84:28” (my Powered Up “HUB NO.4” smart hub)… but if LEGO sells lots of these I will probably have to add a few other headers.

EDIT: found a bug when using the APK I built – nothing appears in the listpicker. The BLE extension is lacking proper permissions, you can try the workaround suggested or go to your Android setting and in the App permissions “Your Location” add the App.

Making an Android app for LEGO Powered Up – explanation

So how does this “App Inventor”-thing work?

To create an app for Android we just need a browser to access the online app creator tool. We have a Design view where we add our components like buttons and sliders and a Blocks view where we use the method blocks provided  by each component we added to our Design.

We can build our app and download an ‘apk’ file to install on our Android phone or tablet but that’s not practical while we are still testing some ideas and debugging the way our blocks work. So the best way is installing the MIT AI2 Companion App on our Android device so every action we make in the online tool is synchronized to it through USB or wi-fi.

App Inventor 2 provides a Palette with lots of usefull components but to use LEGO Powered Up we need to add an Extension that allows AI2 to talk with Bluetooth Low Energy devices. At the moment BluetoothLE is the only supported extension and I must say they have been doing a great work this last year (they even gave me access to a beta version a few months ago while fixing a bug I was dealing with) including writing a good explanation of all the blocks provided with some examples for Arduino and BBC micro:bit.

After importing the extension  we just drag it to the Viewer to get a ‘BluetoothLE1′ component at the bottom of the Viewer, on the “Non-visible components” area. Doesn’t seem much but if we change to Blocks view and look to this component we’ll see lots of blocks.

So let’s start creating our App!

We will use some BluetoothLE blocks to communicate with our LEGO “HUB NO.4” device. This blocks require a ServiceUUID and a CharUUID that we will store in global variables:

Currently the ServiceUUID and CharUUID are the same as LEGO BOOST hub but please note that there is no guarantee that future firmware releases will keep them allways equal.

We will also create a list of our devices:

Yes, a list of one device is silly but I have more devices like my BOOST Vernie and of course I’m planning to have a few more Powered Up devices in a near future so a list is usefull. You can call whatever you want to your devices but you need the Bluetooth address of it (so “PUP#1” is just an easy to remember tag that I choose for my “90:84:2B:06:AB:5D” hub).

You can get your BT address installing Nordic nRF Connect for Mobile app on your Android device and scanning nearby BLE devices while turning your LEGO hub on. If you changed its name with the LEGO App you will see a BLE device with that name, if not you will see “HUB NO.4” or “Smart Hub”, depending on the firmware version of your hub:

Now we go to Design View and add all components needed:

From the ‘User Interface’ section:

  • two buttons: ‘BtnConnection’ and ‘BtnRst’
  • one ListPicker

From the ‘Drawing and Animation’ section:

  • one Canvas
  • one ImgSprite

And from the ‘Sensors’ section:

  • one Clock

I added a few others that are really not needed, just used them for aligning and cosmetic purposes.  I also renamed the buttons names to better remember their purpose and changed some of their properties.

Now back to our Blocks view, we need to take care of what happens when our App starts:

We start a Bluetooth LE scan to find all BLE devices nearby. This is necessary later on when we want to connect to our LEGO device.

Then we create our list of Hubs (seen above), set the text of the Button used for the BLE connection, draw our Joystick at the center of the canvas and initialize our Clock.

This Clock will be used to keep the BLE connection active after we connect: we need to keep talking with the LEGO hub because after a pre-defined period without communication it will shutdown to prevent battery draining.

For now we just keep the clock disabled and set the period  to match the global variable “TRACKSPERIOD”.

We also define what happens when we click our ListPicker:

(we change the text to the friendly name of the chosen LEGO hub)

Now we define what happens when we click on our connection Button – we want it to connect to the device we chose whenever there is no connection yet and to disconnect when already is:

(we also activate or deactivate our Clock at the sametime)

I will not explain the blocks related to the Joystick – they are used to calculate the duty cycle (speed) of the two motors from the position of the joystick. These values are store in two global variables: ‘SpeedA’ and ‘SpeedB’.

The next important part is sending the calculated values to the motors.

The hexadecimal command used to control a WeDo 2 Motor (we should probably call it a “Powered Up Medium Motor) is:

0800810 p 115100 dt

where:

  • ‘p’ is ‘0’ if we are using ‘Port A’ and ‘1’ if using ‘Port B’
  • dt is the hexadecimal representation of the duty cycle (a percentage value)

The AI2 BuetoothLE extension uses a list of decimal values so

8 0 129 0/1 17 81 0 dt

Lucky for us the extension also accepts signed or unsigned values so we don’t need to take care of the conversion when duty cycle is negative:

so every time the Clock reaches our “TRACKSPERIOD” value it sends the commands for the two motors. Setting a smaller period allows a better control but also increases the activity of the App so for too small periods it might not work properly. And, of course, setting a larger period will increase the latency of our control and might also cause our connection to drop.

Hope this explanation is clear enough for anyone that wants to try their own app. Feel free to make questions on my YouTube channel, I’ll try to answer the best I can.