Microsoft Robotics Studio and Lego Mindstorms NXT

Published 16 July 07 12:00 PM | Coding4Fun 
thumb In this article, Brian Peek will demonstrate how to use Microsoft Robotics Studio to control the Lego Mindstorms NXT kit.  A simple remote-controlled robot will be built and controlled using C# and the MSRS Visual Programming Language (VPL).
ASPSOFT, Inc.

Difficulty: Intermediate
Time Required: 2-3 hours
Cost: $250 for the NXT kit, $40 for the Xbox 360 Controller
Software: Visual Basic or Visual C# Express Editions, Microsoft Robotics Studio v1.5
Hardware: Lego Mindstorms NXT, Xbox 360 Controller for Windows, a Bluetooth adapter and stack installed
Download: Download

 

The Lego Mindstorms NXT kit is an amazing upgrade to the original Lego Mindstorms product.  While the building blocks are not the traditional plastic stud blocks everyone is used to, the new construction parts allow for some very complex designs.  Additionally, Microsoft Robotics Studio supports the Lego NXT kit right out of the box, so it's quite easy to get up and going using MSRS with the Lego kit to start coding a robot in C# or VB.NET.  With that in mind, this article will demonstrate how to use MSRS with the simple TriBot robot that can be easily built using the instructions included in the Lego NXT kit.

LegoNXT TriBot Building

The instructions for building the TriBot are located in the LegoNXT kit.  I am not going to repeat that here as the Lego picture instructions are far better than anything I can come up with.  Really, any 2-wheeled bot will work for this sample, but it is assumed that the TriBot is the one you have constructed.

Plug the wires into brick as follows, looking at the front of the bot so the LCD screen is facing you:

  • A - Middle
  • B - Left
  • C - Right

Additionally, I added the push button sensor to the front of the TriBot which is plugged into port 1 at the bottom.  In the application, when the push button sensor is pressed, the robot will stop in its tracks until the A button is pressed again.  Here is what my TriBot looks like:

CIMG0756

CIMG0757

LegoNXT and Bluetooth Configuration

Setting up Bluetooth can be troublesome.  I have found that the best way to get things working is with the following procedure.  There are known incompatibilities with LegoNXT brick and certain Bluetooth adapters/stacks, so if this doesn't work for you, you may require a different stack/device.

  1. Ensure Bluetooth is enabled on the Lego NXT brick.  This can be done by choosing the Bluetooth option from the main menu, and then selecting On/Off from the Bluetooth menu.  Make sure On is selected.
  2. From your PC, search for Bluetooth devices in range.  The PC should fine one named NXT.  Select it, and pair both the PC and the brick with the passkey 1234 (the brick will default to 1234 on its own).
  3. When the process is complete, you should have a virtual COM port or two installed.  If more than one is installed, make note of the COM port listed as the "outgoing" port.
  4. Open a Command Prompt from the Microsoft Robotics Studio (1.5) program group and run the following command:  dsshost -port:50000 -tcpport:50001 -manifest:samples\Config\LEGO.NXT.Brick.manifest.xml .  This should start a web browser.  If prompted for a username/password, enter your Windows login username and password.
  5. The first line of the page in the browser is a text box labeled COM Port.  In this box, enter the COM port the Lego NXT brick was installed on via Bluetooth above and click the Connect button at the bottom of the page.

If all goes to plan, you will hear the brick beep, the screen will display "Microsoft Robotics Studio", and you will be ready to continue.  If this doesn't happen, attempt the procedure above again.  If you still encounter trouble, try a different Bluetooth adapter.

The web page can also be used to configure various things regarding the sensors, motors, get the current battery level, etc.  Feel free to explore these items, but ensure the defaults are used for the rest of this article.

Writing the Code

A note to Vista/XP x64 users:  For the 6 of us on a 64-bit platform, note that you will not be able to use the XInputGamepad service.  Internally this uses XNA which exists in a 32-bit format only.  So, when dssproxy attempts to build the proxy version of your service, it will be loaded as a 64-bit process and will fail to load the 32-bit XNA assemblies.  The same thing happens with dsshost (it will be loaded as a 64-bit process and won't be able to access the 32-bit XNA assemblies).  You will have to use a 32-bit version of Vista/XP or use something like VMWare which supports USB devices so you can connect the controller to the VM.

The code will be written 3 times:  In C#, Visual Basic.NET, and finally in the MSRS Visual Programming Language.  All three versions will perform the same functionality.  It is assumed that you have a fair understanding of Microsoft Robotics Studio.  If you do not, please read through the documentation, specifically the Microsoft Robotics Studio Runtime section.  Additionally, you may wish to read my other MSRS article on Coding4Fun on how to build an R/C car using MSRS which is a bit more introductory.

To begin, we need to create a service to drive our bot.  This will be called LegoTriBot.  Open a Command Prompt from the Microsoft Robotics Studio (1.5) program group and run the following command:

C#:

dssnewservice /service:LegoTriBot

VB

dssnewservice /language:VB /service:LegoTriBot

This will generate a folder with several items, including project and solution files.

Open the generated LegoTriBot.sln file in Microsoft C# 2005 Express Edition or Microsoft Visual Basic 2005 Express Edition. You will see that several files were generated.

This project will use a bumper (the push button sensor), the generic drive service, and the gamepad service so the namespaces will need to be included in our code.  To do this, you will need to set references to the RoboticsCommon.proxy and XInputGamePad.Y2006.M09.proxy assemblies.

references

Next, open the LegoTriBot.cs/.vb and add the following code to the top of the file:

C#

using bumper = Microsoft.Robotics.Services.ContactSensor.Proxy;
using drive = Microsoft.Robotics.Services.Drive.Proxy;
using gamepad = Microsoft.Robotics.Services.Sample.XInputGamepad.Proxy;

VB

Imports bumper = Microsoft.Robotics.Services.ContactSensor.Proxy
Imports drive = Microsoft.Robotics.Services.Drive.Proxy
Imports gamepad = Microsoft.Robotics.Services.Sample.XInputGamepad.Proxy

Next, ports on which to communicate with these devices need to be defined.  One port per object is created as follows:

C#

// partnerships with bumper, differential drive and gamepad
[Partner("bumper", Contract=bumper.Contract.Identifier, CreationPolicy=PartnerCreationPolicy.UseExisting)]
private bumper.ContactSensorArrayOperations _bumperPort = new bumper.ContactSensorArrayOperations();

[Partner("drive", Contract=drive.Contract.Identifier, CreationPolicy=PartnerCreationPolicy.UseExisting)]
private drive.DriveOperations _drivePort = new drive.DriveOperations();

[Partner("XInputGamepad", Contract=gamepad.Contract.Identifier, CreationPolicy=PartnerCreationPolicy.CreateAlways)]
private gamepad.XInputGamepadOperations _gamepadPort = new gamepad.XInputGamepadOperations();

VB

'' partnerships with bumper, differential drive and gamepad
<Partner("bumper", Contract:=bumper.Contract.Identifier, CreationPolicy:=PartnerCreationPolicy.UseExisting)> _
Private _bumperPort As bumper.ContactSensorArrayOperations = New bumper.ContactSensorArrayOperations()

<Partner("drive", Contract:=drive.Contract.Identifier, CreationPolicy:=PartnerCreationPolicy.UseExisting)> _
Private _drivePort As drive.DriveOperations = New drive.DriveOperations()

<Partner("XInputGamepad", Contract:=gamepad.Contract.Identifier, CreationPolicy:=PartnerCreationPolicy.CreateAlways)> _
Private _gamepadPort As gamepad.XInputGamepadOperations = New gamepad.XInputGamepadOperations()

Now that we have ports to communicate with our services, we must subscribe to our gamepad service and bumper service to receive notifications when either changes.  First, we will subscribe to the gamepad service and setup notifications for thumbstick changes and button changes.  Insert the following code in the Start() method:

C#

// subscribe to button presses and thumbstick changes on the 360 pad
gamepad.XInputGamepadOperations gamepadNotify = new gamepad.XInputGamepadOperations();
_gamepadPort.Subscribe(gamepadNotify);
Activate(Arbiter.Receive<gamepad.ThumbsticksChanged>(true, gamepadNotify, ThumbstickHandler));
Activate(Arbiter.Receive<gamepad.ButtonsChanged>(true, gamepadNotify, ButtonHandler));

VB

'' subscribe to button presses and thumbstick changes on the 360 pad
Dim gamepadNotify As gamepad.XInputGamepadOperations = New gamepad.XInputGamepadOperations()
_gamepadPort.Subscribe(gamepadNotify)
Activate(Arbiter.Receive(Of gamepad.ThumbsticksChanged)(True, gamepadNotify, AddressOf ThumbstickHandler))
Activate(Arbiter.Receive(Of gamepad.ButtonsChanged)(True, gamepadNotify, AddressOf ButtonHandler))

This code subscribes to the gamepad service and sets up two methods to be called when the thumbsticks change or the buttons change.  The thumbsticks are used to drive the bot, and the button is used to re-enable the motors after the bumper switch has been pressed.  We will need to maintain the state of whether or not the motors are enabled, and this can be done by adding a boolean variable to the state object.  To do this, add the following code to the LegoTriBotState object in the LegoTriBotTypes.cs/.vb file:

C#

// maintain whether the motors are enabled
public bool MotorEnabled;

VB

'maintain whether the motors are enabled
Public MotorEnabled As Boolean

Next, we need to implement the actual handler methods for these events.  Add the following code to the class:

C#

private void ThumbstickHandler(gamepad.ThumbsticksChanged msg)
{
if(_state.MotorEnabled)
{
// Left/RightWheelPower expects a value from -1.0f to 1.0f.
// the Thumbsticks will return a value form -1.0f to 1.0f. Convenient.

// create a request
drive.SetDrivePowerRequest req = new drive.SetDrivePowerRequest();

// assign the values
req.LeftWheelPower = msg.Body.LeftY;
req.RightWheelPower = msg.Body.RightY;

// post the request
_drivePort.SetDrivePower(req);
}
}

private void ButtonHandler(gamepad.ButtonsChanged msg)
{
if(msg.Body.A)
_state.MotorEnabled = true;
}

VB

Private Sub ThumbstickHandler(ByVal msg As gamepad.ThumbsticksChanged)
If (_state.MotorEnabled) Then
' Left/RightWheelPower expects a value from -1.0f to 1.0f.
' the Thumbsticks will return a value form -1.0f to 1.0f. Convenient.

' create a request
Dim req As drive.SetDrivePowerRequest = New drive.SetDrivePowerRequest()

' assign the values
req.LeftWheelPower = msg.Body.LeftY
req.RightWheelPower = msg.Body.RightY

' post the request
_drivePort.SetDrivePower(req)
End If
End Sub

Private Sub ButtonHandler(ByVal msg As gamepad.ButtonsChanged)
If (msg.Body.A) Then
_state.MotorEnabled = True
End If
End Sub

The above code sets up the controller thumbsticks to drive the TriBot as a tank.  The left stick will control the left motor, and the right stick will control the right motor.  To do this, the value from the LeftY and RightY properties are taken and applied directly to the drive power's LeftWheelPower and RightWheelPower.  This can be done directly since LeftY/RightY return a value between -1.0 and 1.0 and the LeftWheelPower and RightWheelPower properties expect a value between -1.0 and 1.0.  Once the SetDrivePowerRequest object is filled in, it is passed to the _drivePort's SetDrivePower method to turn the wheels.

Finally, we need to setup the bumper functionality.  We must subscribe to the bumper service and receive notifications when the switch is pressed.  In the handler for the switch being pressed, the MotorEnabled property will be set to false so the motors will no longer turn until the user presses the A button on the controller.  First, add the following code to the Start method to subscribe to the bumper:

C#

// subscribe to bumper notifications
bumper.ContactSensorArrayOperations bumperNotify = new bumper.ContactSensorArrayOperations();
_bumperPort.Subscribe(bumperNotify);
Activate(Arbiter.Receive<bumper.Update>(true, bumperNotify, BumperHandler));

VB

' subscribe to bumper notifications
Dim bumperNotify As bumper.ContactSensorArrayOperations = New bumper.ContactSensorArrayOperations()
_bumperPort.Subscribe(bumperNotify)
Activate(Arbiter.Receive(Of bumper.Update)(True, bumperNotify, AddressOf BumperHandler))

Next, implement the BumperHandler method:

C#

private void BumperHandler(bumper.Update msg)
{
if(msg.Body.Pressed)
{
LogInfo("Pressed!");

_state.MotorEnabled = false;

// create a request
drive.SetDrivePowerRequest req = new drive.SetDrivePowerRequest();

// stop the wheels
req.LeftWheelPower = 0.0f;
req.RightWheelPower = 0.0f;

// post the request
_drivePort.SetDrivePower(req);
}
}

VB

Private Sub BumperHandler(ByVal msg As bumper.Update)
If (msg.Body.Pressed) Then
LogInfo("Pressed!")

_state.MotorEnabled = False

' create a request
Dim req As drive.SetDrivePowerRequest = New drive.SetDrivePowerRequest()

' stop the wheels
req.LeftWheelPower = 0.0F
req.RightWheelPower = 0.0F

' post the request
_drivePort.SetDrivePower(req)
End If
End Sub

The code above checks to see if the bumper was pressed.  If it was, it creates a SetDrivePowerRequest object, sets the left and right wheel power to 0 and then sends the request off to the drive port to be handled.

Running the Service

To run the service, we need to tell the MSRS runtime which manifest to load that defines the hardware for the generic services we've used (bumper and drive).  To do this, right-click on the project and select Properties.  In the Debug section, add the following argument to the Command line arguments textbox:

-manifest:"samples\config\LEGO.NXT.TriBot.manifest.xml"

Also note that you may need to re-path the location of the project's manifest file to where you have extracted the sample archive if you are building from the sample code.

That's it!  We can now run our service and drive our TriBot around using the gamepad.  Ensure the Xbox 360 Controller is installed and working.  In Visual Studio, press the F5 button to start the service in debug mode.  Be sure to press the A button first to enable the motors for the first time.

Visual Programming Language (VPL)

The LegoTriBot service we just built in code can very easily be built using the Visual Programming Language included in Microsoft Robotics Studio.  Describing the process of dragging and dropping blocks around isn't very easy, so let's start by looking at the finished VPL diagram.

vpl

Drag an XInputController block onto the design surface.  First, let's set up the functionality where pressing the A button enables the motors.  Drag an If block over to the design surface.  Then, drag a line from the bottom node of the XInputController block to the If block.  A Connections dialog box will appear.  In the From column, select ButtonsChanged.  In the To column, select Condition.  Finally, click in the text box of the If block and choose A.  We have now set up our conditional.

You'll notice that there are two points on the right side of the If block:  one is for the true statement, the other for the false/else statement.  When our A button is pressed, we want to set the MotorEnabled variable to true.  To do this, drag a Calculate block to the surface.  Set its value to true.  Then, drag a Variable block to the surface.  Click the Add button at the lower right corner of the screen.  Create a new bool variable named MotorEnabled.  Finally, connect the If block to the Calculate block, and connect the Calculate block to the Variable block.  Select SetValue from the dialog box.

Next, let's set up the bumper switch.  This is just like the above, with the addition of setting the drive power to 0 for each wheel.

Drag a GenericContactSensor block to the design surface.  In the Properties window, select Use a manifest from the Configuration drop down, and Import the LEGO.NXT.TriBot.manifest.xml file.  Next, drag over an If block, a Calculate block and a Variable block.  Create and connect them just as you did above, but this time assign the value false to the Calculate block.  Connect the GenericContactSensor block to the If block with the ContactSensorUpdated event.  Finally, drag a GenericDifferentialDrive block to the surface.  As with the GenericContactSensor, assign the same manifest file to the block.  Drag a connection from the If block to this block.  Select the SetDrivePower event in the To column.  In the Properties window, set both the LeftWheelPower and RightWheelPower values to 0.

Finally, we must hook up the thumbsticks.  As with code above, we will want to apply the value of the thumbsticks directly to the drive service if the MotorEnabled variable is true.  So, drag out a Variable block and set it to the MotorEnabled variable which already exists.  Then, drag out an If block.  Connect the XInputController to the Variable block with the From set to ThumbsticksChanged and the To set to GetValue.  Then, connect the Variable to the If block, setting the If block's text box to MotorEnabled.  Now comes the tricky part.  We need to get the thumbstick values to a GenericDifferentialDrive block, however, only if the the MotorEnabled value is true.  To do this, we can use the Join block.  A Join block will join two messages together and pass them along to another block, but only if both messages are received.  We can use this by passing the thumbstick values directly to the Join as one message, and the true path of the If block as the second message.  This way, the messages will only be passed on if there's both a thumbstick value and MotorEnabled is true.

So, drop a Join block onto the design surface.  Next, drag a connection from the XInputController to the Join block as the first message using the ThumbsticksChanged event.  Then, drag a connection from the true fork of the If block to the second message of the Join block.  Now we can set the output to a GenericDifferentialDrive block.  Drag that block over, selecting GenericDifferentialDrive from the Add Activity popup window, and connect the Join to it using the SetDrivePower event.  Click the Edit Values Directly from the DataConnections popup and set the LeftWheelPower target to the msg.LeftY parameter from the Join, and the RightWheelPower target to the msg.RightY parameter from the Join.

That's it!  We now have a VPL-written program that will perform identically to the application we coded in C# and VB above.  To start the project, ensure the Lego NXT brick is connected with MSRS and press F5.  This should sync up with the brick and start the service.

One thing to note is that starting with version 1.5 of MSRS, one can generate a .csproj and associated code by choosing Build->Compile as Service from the VPL menu.  Choose an output location and, after the service is compiled, check the directory for the generated code.  This code can be reviewed, edited, recompiled, etc.  You will find this code int he LegoTriBotVPLCS directory in the sample archive above.  Unfortunately, this code generation process appears to be one-way at the moment, so you cannot import your C# code into the VPL environment.

Conclusion

We have created a robot using Lego NXT and can control it with an Xbox 360 controller via Microsoft Robotics Studio by coding a service in C#, VB or VPL.  As you can see, even a non-experienced coder can develop a MSRS service using the VPL language.  If one requires more power and flexibility, a service can be coded directly in C#, or a VPL service can be converted to a C# project and continued.

Bio

Brian is a Microsoft C# MVP and a recognized .NET expert with over 6 years experience developing .NET solutions, and over 9 years of professional experience architecting and developing solutions using Microsoft technologies and platforms, although he has been "coding for fun" for as long as he can remember.  Outside the world of .NET and business applications, Brian enjoys developing both hardware and software projects in the areas of gaming, robotics, and whatever else strikes his fancy for the next ten minutes. He rarely passes up an opportunity to dive into a C/C++ or assembly language project.  You can reach Brian via his blog at http://www.brianpeek.com/.

Filed under: , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Brian's Blog said on July 16, 2007 7:03 PM:

I have published my latest article on MSDN's Coding4Fun titled " Microsoft Robotics Studio and Lego Mindstorms

# bo said on July 19, 2007 10:56 AM:

I am trying to integrate Microsoft Robotics Studio and Lego Mindstorms NXT in an existing sofrware client which uses the strong name option for dlls. By using this option you are not allowed to use any dlls without a stong name, that´s my problem.

Is there any way to handle it or could you please provide the dlls with a strong name?

Thanks and regards

Bo

# help.net said on July 23, 2007 6:59 AM:

Brian has published his latest article on MSDN's Coding4Fun titled " Microsoft Robotics Studio and Lego

# ÎÜñ|‹ø\/\/ñ [ÐëÞrëçã†ëð]'s Blog said on July 26, 2007 10:10 AM:

Fastest residential uplink in the world - 40 GB/sec! Updated programmer stereotypes - updated for &quot;today&#39;s&quot;

# Microsoft Robotics Studio and Lego Mindstorms NXT « Blog de Roberto Erazo said on July 31, 2007 8:32 PM:

PingBack from http://robertoerazo.wordpress.com/2007/08/01/microsoft-robotics-studio-and-lego-mindstorms-nxt/

# Arda Cetinkaya said on August 1, 2007 12:00 PM:

How can I connect NXT with Robotics Studio with USB

# Smartymobile said on August 15, 2007 3:28 AM:

Hoy estuve revisando este artículo pero con la particularidad que queria hacerlo con el UMPC. Esto debido

# Desde mi Oficina Movil said on August 15, 2007 9:16 AM:

Cesar Fong , MVP en Windows Mobile Devices ha colocado un post en su Blog sobre sus "experiencias de

# MSDN Blog Postings » Como usar MS Robotics Studio, el robot de LEGO NXT y una Ultra Mobile PC said on August 15, 2007 9:33 AM:

PingBack from http://msdnrss.thecoderblogs.com/2007/08/15/como-usar-ms-robotics-studio-el-robot-de-lego-nxt-y-una-ultra-mobile-pc/

# 外部部落格 said on August 15, 2007 10:17 AM:

Cesar Fong , MVP en Windows Mobile Devices ha colocado un post en su Blog sobre sus &quot;experiencias

# .NET Blogs said on August 17, 2007 1:31 AM:

Hoy estuve revisando este artículo pero con la particularidad que queria hacerlo con el UMPC. Esto debido

# Robotics » Blog Archive » iRobot Makes Significant Advance in Making Robotics Mundane said on September 5, 2007 1:56 PM:

PingBack from http://www.tech-times.net/blog/Robotics/?p=85

# ??????????????????????????????????????????????????????????????? Microsoft Robotics Studio « like a toy but it strong said on September 25, 2007 12:31 AM:

PingBack from http://aongaang.wordpress.com/2007/09/25/%e0%b9%82%e0%b8%9b%e0%b8%a3%e0%b9%81%e0%b8%81%e0%b8%a3%e0%b8%a1%e0%b8%84%e0%b8%a7%e0%b8%9a%e0%b8%84%e0%b8%b8%e0%b8%a1%e0%b8%ab%e0%b8%b8%e0%b9%88%e0%b8%99%e0%b8%a2%e0%b8%99%e0%b8%95%e0%b9%8c-microsoft/

# Bob said on November 30, 2007 5:59 PM:

How can I connect NXT with Robotics Studio with USB

# unknown said on December 6, 2007 1:45 AM:

(reply on what bob said) you connect one end of the usb to the nxt control brick and the other end at a usb port at either the front or back of your computer.

# Sony Announces a Dancing iPod Killer-Wannabe? said on December 16, 2007 10:44 PM:

PingBack from http://coopnews.org/technology/sony-announces-a-dancing-ipod-killer-wannabe/

# Cossacks Breaking News » Sony Announces a Dancing iPod Killer-Wannabe? said on December 25, 2007 12:04 PM:

PingBack from http://cossacks.org.uk/computers/sony-announces-a-dancing-ipod-killer-wannabe/

# pk said on February 20, 2008 8:09 AM:

Come on! Go open source, Windows is like a car that has a welded bonnet. You can't tinker or fine tune it.

# erica said on March 5, 2008 10:30 PM:

i'm still having problems with getting the controller to start moviing the NXTrobot. i have done everything that was listed above under the VPL.  

what ports should i use on VPL?

what should HTTP and the TCP prots be?

when do i connect my controller to my PC?

how do i get the controller to start moving the NXT robot?

please give me detailed info... thanks.

# Microsoft, Intel to team on new parallel, multicore research efforts | All about Microsoft | ZDNet.com said on March 18, 2008 3:13 PM:

PingBack from http://blogs.zdnet.com/microsoft/?p=1275

# Xbox &raquo; Blog Archive &raquo; Coding4Fun : Microsoft Robotics Studio and Lego Mindstorms NXT said on May 13, 2008 5:48 PM:

PingBack from http://xbox.qoablog.info/?p=16528

Leave a Comment

(required) 
(optional)
(required) 
Page view tracker