C# SDK for LEGO Bluetooth (LE) Hubs


Tl;dr See the source code (and contribute) on Github.

LEGO & Bluetooth (LE)

LEGO have a new standard for communicating over Bluetooth (Low Energy) with compatible smart hubs that is documented here. The documentation is not being kept up to date but there is enough information there to fill in the gaps using a bit of trial and error.

Some of the older powered components use a different protocol and/or wiring specification. It is not the purpose of this post to document compatibility. I will detail any components I used during my development however.

Project Goal

The specification provides a good amount of detail but there are presently no C# SDKs to allow me to connect to a LEGO hub and control its connected devices remotely using a high level API.

As an example, I would like to be able to do the following…


using (var connectionManager = new BluetoothLEConnectionManager())
{
var connectionA = await connectionManager.FindConnectionById("BluetoothLE#BluetoothLEb8:31:b5:93:3c:8c-90:84:2b:4d:d2:62");
var connectionB = await connectionManager.FindConnectionById("BluetoothLE#BluetoothLEb8:31:b5:93:3c:8c-90:84:2b:4e:1b:dd");
var hubA = new TechnicSmartHub(connectionA);
var hubB = new TechnicSmartHub(connectionB);
// wait until connected
await hubA.Connect();
await hubB.Connect();
// wait until all 3 motors are connected to Hub A
var leftTrack = await hubA.PortA<TechnicMotorXL>();
var rightTrack = await hubA.PortB<TechnicMotorXL>();
var turntable = await hubA.PortD<TechnicMotorL>();
// wait until all 4 motors are connected to Hub B
var primaryBoom = await hubB.PortA<TechnicMotorXL>();
var secondaryBoom = await hubB.PortB<TechnicMotorL>();
var tertiaryBoom = await hubB.PortC<TechnicMotorL>();
var bucket = await hubB.PortD<TechnicMotorL>();
// sequentially calibrate each linear actuator using a torque based range calibration routine
await primaryBoom.RunRoutine(new RangeCalibrationRoutine(50));
await secondaryBoom.RunRoutine(new RangeCalibrationRoutine(50));
await tertiaryBoom.RunRoutine(new RangeCalibrationRoutine(40));
await bucket.RunRoutine(new RangeCalibrationRoutine(35));
// move forwards for 5 seconds
leftTrack.SetSpeedForDuration(50, 100, RotateDirection.Clockwise, 5000);
rightTrack.SetSpeedForDuration(50, 100, RotateDirection.CounterClockwise, 5000);
await Task.Delay(5000);
// rotate boom for 3 seconds
turntable.SetSpeedForDuration(100, 100, RotateDirection.CounterClockwise, 3000);
await Task.Delay(3000);
// reposition boom
primaryBoom.SetSpeedForDuration(100, 100, RotateDirection.Clockwise, 3000);
secondaryBoom.SetSpeedForDuration(75, 100, RotateDirection.CounterClockwise, 3000);
tertiaryBoom.SetSpeedForDuration(100, 100, RotateDirection.CounterClockwise, 2000);
await Task.Delay(3000);
// lift bucket
bucket.SetSpeedForDuration(50, 100, RotateDirection.Clockwise, 2000);
}

view raw

Example.cs

hosted with ❤ by GitHub

I want to abstract the SDK from the connection so that I can distribute the Core as a .NET Standard package that can be used by different application types (e.g. UWP or Xamarin).

It should be possible to interact at a low level issuing commands in a procedural manner but provide an opportunity to eventually register additional information about the model being controlled so that more intelligent instructions can be executed using calibrated constraints and synchronized ports etc.

For this project I used the LEGO Technic set: Liebherr R 9800 (41200). It comes bundled with:

  • 2 x LEGO Technic Smart Hub (6142536)
  • 4 x LEGO Technic Motor L (6214085)
  • 3 x LEGO Technic Motor XL (6214088)

A Control+ application provides connectivity with the model but isn’t extensible or compatibility with custom builds. Other applications provide basic programming capabilities using arrangements of blocks but this will be the only C# SDK to provide more control to users without being dependent on iOS or Android app support.

Functional Overview

Based on the model referenced above, the Control+ components are connected as below:

41200 Configuration

Each Hub/Port controls different aspects of the model as follows:

  • Hub A
    • Port A : Left track
    • Port B : Right track
    • Port D : Turntable
  • Hub B
    • Port A : Primary Boom
    • Port B : Secondary Boom
    • Port C : Tertiary Boom
    • Port D : Bucket

SDK Types

In order to facilitate interop between the SDK and the remote hubs we will have the following types:

IConnection

This interface abstracts the BluetoothLE device connection from the SDK so that it can be used to subscribe to notifications and to read or write values without us being tightly coupled to a specific implementation (e.g. UWP).

Each IConnection has a one to one relationship with a BluetoothLE device based on the device ID.

IMessage

An IMessage is a byte[] that encapsulates all IO communication between the physical hub and the derived Hub class(es). Different concrete implementations provide strongly typed properties (usually enums) to make the interop more readable and to simplify parsing the byte streams.

Hub

This is an abstract class that all specific Hubs must implement and it encapsulates the interactions between the Hub and its assigned IConnection.

A Hub is responsible for taking actions based on messages it received from the IConnection and for writing values based on any outbound IMessage the Hub produces.

Device

This represents anything which can be connected to the Hub either by a physical port (e.g. Motor) or a virtual port (e.g. Internal sensor).

Each concrete implementation of a Device must correspond with an IODeviceType enum value since the Hub will be responsible for instantiating a Device and assigning it to a port.

Devices can produce messages and extensions expose convenience methods based on composition interfaces (e.g. IMotor).

Video Example

More Information

For the source code, please see the Github repo: https://github.com/Vouzamo/Lego

If anyone would like to become a contributor that would be much appreciated as this will be the communication standard for all LEGO hubs moving forward and I would like to get this working for all the potential hubs and devices available.

Other enhancement could include:

  • Registration of control components to for real-time user input.
  • Registration of virtual components for real-time API input (e.g. RESTful).
  • Registration of device constraints to manage calibration for absolute extremes to constrain what commands can be sent to the hub for a given port/device.
  • Registration of device commands that should be invoked based on Hub state or incoming IMessage conditions.

 

 

One thought on “C# SDK for LEGO Bluetooth (LE) Hubs

Leave a comment