Lego Mindstorms.Net
A while back, maybe 7 years or so, my wife bought me a Lego Mindstorms kit. It's all the goodness of legos, robotics, and programming rolled into one. With the kit, you could make robots that carried out simple routines or even respond to input. I created various bots with the included drag-and-drop programming environment that came with the set, and did a few with the NQC (not quite C) language.
A year later when my second son was born, I had to put the kit up because of all the small peices and his rather aggressive form of curiosity.
Just a few days ago, we dug the kit out and started making things with it. "Things" because they have been mostly powered vehicles and not so much robots. The main reason is because we are two motors down, which leaves us with one servo motor and a low-powered standard motor. The other two servo motors are locked up. A quick search on Google revealed there was a manufacturing flaw that caused them to sieze. But, being I did not discover this until years later, Lego could do nothing for me. I had to purchase new ones. I'm not upset that I had to buy new ones. I mean, it was my fault I did not notice the flaw until years later - long after any warranty has expired.
Ok, training off topic here.
While looking for some Managed DirectX info, I stumbed across the Coding4Fun site. There I found "Microsoft .NET Interface for LEGO Mindstorms".
Oh joy!
Now we have Legos, robotics, programming AND C# in one fun package ready for endless possibilities! (did I mention that I think C# is the best thing since sliced bread? Doubt that? Have you ever tried to program with sliced bread? q.e.d.)
To get started, I download and installed the LEGO Mindstorms SDK 2.5, C# LEGO Starter Kits, and located (not install) the original RCX 1.5 CD that came with the set. There's also a download for the Microsoft .NET Interface for LEGO Mindstorms, but I'm not sure if that's needed since the required dlls come with the sample code and I don't need to dig into the source code for them.
The SDK comes with a tool, ScriptEd, that can install the firmware on the RCX brick - which is where the original Lego CD comes in. On it is the firmware file, firm0331.lgo. From ScriptEd's "Special" menu item, choose "Download Firmware". That will prompt you for the above mentioned file. Select it and hit OK.
The C# starter kits have sample solutions; MusicSample, RemoteControlSample, and a RoverBotSample. The MusicSample shows a keyboard on the PC screen and playes the corresponding note on the RCX for each key pressed. The RemoteControlSample shows how you can use the PC keyboard to control the brick. The RoverBotSample demonstrates how to use the sensors and motors AND it pots the roverbot path on the form displayed on the PC.
There are a few differences between the .Net SDK and NQC. One is, obviously, the syntax. The other is the location of the execution. Using the .Net platform, the code executes on the PC and commands are sent to the brick via IR. Using NQC, the program is sent to the brick and it then operates autonomously - needs no connection between it and the PC where the coding took place.
Another difference is the type of execution. The native program operates like a Win32 application with a message loop and uses global constants that you are somehow expected to know.... or lookup from somewhere. A typical RCX NQC program looks somehting like this (I took it from the O'Reilly site about a book on the topic because I don't have any that I created anymore.
#define BACK_TIME 50
#define TURN_TIME 80
task main()
{
SetSensor(SENSOR_1, SENSOR_TOUCH);
SetSensor(SENSOR_3, SENSOR_TOUCH);
OnFwd(OUT_A + OUT_C);
while (true)
{
if (SENSOR_1 == 1)
{
PlayTone(440, 50);
OnRev(OUT_A + OUT_C);
Wait(BACK_TIME);
OnFwd(OUT_A);
Wait(TURN_TIME);
OnFwd(OUT_C);
}
if (SENSOR_3 == 1)
{
PlayTone(880, 50);
OnRev(OUT_A + OUT_C);
Wait(BACK_TIME);
OnFwd(OUT_C);
Wait(TURN_TIME);
OnFwd(OUT_A);
}
}
}
Notice the endless loop "while(true)" in task main(). With each pass, it checks the status of the sensors and sets the motor speeds accordingly. And notice the global constants, SENSOR_TOUCH, OUT_C, SENSOR_1, etc. These are defined in the firmware.
But with the .Net SDK, it uses all the goodness of OOP and event-driven procedures. Here's a sample from the RoverBotSample code;
public class RoverBot
{
static public void Main()
{
// Create and run our RoverBot
RoverBot roverBot = new RoverBot();
roverBot.Run();
}
public RoverBot() { }
public void Run()
{
// Create and configure our RCX
this._rcx = new Rcx();
// Connect to the RCX module (this is done once).
this._rcx.Connect(RcxPort.Usb);
this._rcx.BatteryPowerChanged += new RcxBatteryPowerChangedEventHandler(_rcx_BatteryPowerChanged);
// We will use touch sensors attached to blocks 1 and 3
// to inform us when the RCX runs into obstacles.
this._rcx.Sensor1.SensorType = RcxSensorType.Touch;
this._rcx.Sensor3.SensorType = RcxSensorType.Touch;
this._rcx.Sensor2.SensorType = RcxSensorType.Light;
this._rcx.Sensor1.ValueChanged += new RcxSensorValueChangedEventHandler(Sensor1_ValueChanged);
this._rcx.Sensor3.ValueChanged += new RcxSensorValueChangedEventHandler(Sensor3_ValueChanged);
this._rcx.Sensor2.ValueChanged += new RcxSensorValueChangedEventHandler(Sensor2_ValueChanged);
this.UpdateMovement();
// Let the app run
Application.Run();
}
And of course the events that are called when the sensor values change.
private void Sensor1_ValueChanged(object sender, RcxSensorValueChangedEventArgs e)
{
this.UpdateMovement();
}
private void UpdateMovement()
{
// If the left sensor is pressed, we should turn right
if (this._rcx.Sensor1.Value == 1)
{
this._rcx.MotorA.Power = 8;
this._rcx.MotorC.Power = -8;
}
// If the right sensor is pressed, we should turn left
else if (this._rcx.Sensor3.Value == 1)
{
this._rcx.MotorA.Power = -8;
this._rcx.MotorC.Power = 8;
}
// Otherwise we can go straight
else
{
this._rcx.MotorA.Power = 8;
this._rcx.MotorC.Power = 8;
}
}
I see a few possible improvements that can be made, but it gets the point across; classes, enums and events!
Next, I need to get the NXT. It uses Bluetooth to communicate with the PC. That should increase range and coolness factor. ;-)
