Matt Rajca

Talking to LEGO NXT Bricks from Cocoa

December 27, 2012

A little over a year ago, I wrote NXT Browser, a LEGO NXT file system browser for Mac OS X. The project was built on top of NXTKit, a Cocoa framework I simultaneously wrote for communicating with NXT Bricks. The framework features a modern Cocoa API and uses Blocks for response callbacks. Furthermore, NXTKit relies solely on Apple’s IOBluetooth and IOKit frameworks for device access, and therefore it does not require the official LEGO NXT driver to be installed.

This article outlines how to get started using NXTKit in your own projects. While NXTKit supports both Bluetooth and USB connectivity, only Bluetooth connections will be discussed for the sake of brevity.

To get started, link your target against Apple’s IOBluetooth and IOBluetoothUI frameworks. Now drag the NXTKit.framework bundle into the Frameworks group of your Xcode project. Follow the steps outlined in Section 1 of this document if you need help linking and bundling a custom framework with an OS X app.

Now we’re ready to dive into the code. First, let’s present some UI to let the user select their NXT Brick. Since we’re using Bluetooth for connectivity, we present a IOBluetoothDeviceSelectorController to display a list of nearby Bluetooth devices:

#import <IOBluetoothUI/IOBluetoothUI.h>
#import <NXTKit/NXTKit.h>

...

IOBluetoothDeviceSelectorController *ctrl = [IOBluetoothDeviceSelectorController deviceSelector];

int res = [ctrl runModal];

if (res != kIOBluetoothUISuccess) {
	// ... handle error
	return;
}

NSArray *results = [ctrl getResults];

if ([results count] == 0) {
	// ... handle no results
	return;
}

IOBluetoothDevice *device = [results objectAtIndex:0];

MRNXTDevice is the fundamental class we will use to send commands (Play Sound File, Set Output State, etc.) to our NXT Brick. MRNXTDevice behaves much like a serial NSOperationQueue; any enqueued commands will be performed serially in FIFO order. To use MRNXTDevice, we first need to construct a USB or Bluetooth transport object, depending on our desired protocol of communication. Since we decided to use Bluetooth, we initialize an instance of MRBluetoothDeviceTransport, passing the NXT Brick selected from the UI presented earlier; then we open a connection to the device:

MRBluetoothDeviceTransport *transport = [[MRBluetoothDeviceTransport alloc] initWithBluetoothDevice:device];

nxtDevice = [[MRNXTDevice alloc] initWithTransport:transport];
[transport release];

[nxtDevice setDelegate:self];

if (![nxtDevice open:&error]) {
	// ... handle error
}

If we wanted to talk to our NXT Brick via USB, we would initialize a MRUSBDeviceTransport object instead. Once a connection to the NXT is established, we can start sending commands to it for processing:

- (void)deviceDidOpen:(MRDevice *)aDevice {
	[self playSound];
}

- (void)playSound {
	MRNXTPlaySoundFileCommand *comm = [[MRNXTPlaySoundFileCommand alloc] init];
	comm.loop = NO;
	comm.filename = @"Woops.rso";

	[nxtDevice enqueueCommand:comm responseBlock:^(MRNXTResponse *response) {
		// work with response, check status, etc ...
	}];

	[comm release];
}

Reference this page for all supported commands. The optional response block will be called once a command completes. Some commands (such as “Get Device Info”) return subclasses of MRNXTResponse that provide additional information (such as the Brick’s name and its free space).

And that’s all it takes to talk to a NXT Brick from Cocoa over Bluetooth or USB! As always, feel free to suggest enhancements or report bugs on NXTKit’s Issues page.

A list of my other NXT-related projects can be found below:

  • NXT Browser - browse your NXT Brick’s file system on Mac OS X
  • NXT Joystick - drive a NXT bot with iPhone
  • NXT Band - record and play NXT melody files (RMD) on Mac OS X