Thursday, October 19, 2006

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. ;-)

Thursday, September 21, 2006

....has too many arguments specified (Part 2)

Recap;
I was trying simple data binding in ASP.Net using a SqlDataSource and a GridView. The data source has four stored procs for the four commands.... though the Insert one is useless since the GridView is incomplete and cannot do that...

Anyway, the Select proc returns all the required fields with their respective names; idOrder, cdName, etc. The Delete proc takes one parameter, @iiOrder (naming convention; first "i" for Int, second "i" for Input). I set the GridView "DataKeyNames" to "idOrder" because that is the PK and the value needed to run the Delete.

But, the page kept throwing "Procedure or function iDBQAScore_CriteriaDelete has too many arguments specified" errors.

Well, yesterday I discovered the missing link. The Stored Proc parameters *must* be named the same as the fields. I can understand that there must be a link there somehow, but I'm still put off by that requirement. well, for one, it's not very intuitive nor documented. It must be discovered by trial and error, or via Google. Heh, searching Google Groups yields better documentation than MSDN.


But through all that experimentation, my boss and I discovered a solution to the issue that drove me to the SqlDataSource over the ObjectDataSource, so I guess it was worth it even if it made me doubt my value as a developer. Hell, I do that anyway ;-)

Wednesday, September 20, 2006

....has too many arguments specified


After having some issues with the ObjectDataSource and a custom DataAccess component (more on that later) I decided to get back to basics and use the SqlDataSource and bind it directly to a GridView.

To start things off, I plopped a SqlDataSource onto a web page, set the ConnectionString and the StoredProc name for the four commands, Delete, Insert, Select, and Update using the Wizzard thing. As a part of that process, it retrieves the parameters for each of the StoredProcs. Good stuff.

Next I added a GridView and set the DataSourceID to the above SqlDataSource. I set EnableEditing and EnableDeleting - they each have an associated StoredProc so it should be good.

Remembering the Demos at the Microsoft Launch Event in Detroit, I hit Ctrl-S and F5 and expected it to work.

Procedure or function iDBQAScore_CriteriaDelete has too many arguments specified.

oh, yeah. The demos were simplistic, non-real-world applicaitons. You know, like embedding SQL code that accesses one table in the web page code. Who does that?!!

A search of Google shows that there are many more out there that don't know what they are doing either... or they just expect the magic to work. About half the help requests go unanswered with the other half being told to Clear() the params and re-add them in the page code. Say it with me, "Who does that?!!" Or more specifically, Why Should That Be Necessary?! If you are going to fudge with the DataAccess components, that should not be done in the page code.

Or I'm an idiot, which seems likely given the number of rants I have about ASP.Net.

On a side note, I'm not a .Net hater. I Love C#. Sure, I started out a little ... hesitant until I got to understand it. Which is why I keep trying with ASP.Net thinking I'll eventually get a grip on it. But, the more I use it, the more I long for the Regular ASP days.

Back to the SqlDataSource and GridView....

After some thought, I figure the automatic databinding is trying to give the SqlDataSource all the fields in the GridView table. So, I convert all the fields to Templates and change "Bind" to "Eval" except the field that should pass it's value to the SqlDataSource. And I make sure the DataKeyNames property on the GridView is set to the PK field.

Ctrl-S & F5....

Procedure or function iDBQAScore_CriteriaDelete has too many arguments specified.

grrrr

I switch to Design mode and examine the SqlDataSource properties via the Properties window. Hitting the ellipsis button by the property "DeleteQuery" brings up the "Command and Parameter Editor". A quick review shows all the parameters are correct. Oh, wait, there's a "Refresh Parameters" button. I hit that and a new parameter is added to the list, "RETURN_VALUE".

Ah hA!

"OK", Ctrl-S & F5

Procedure or function iDBQAScore_CriteriaDelete has too many arguments specified.

WTF?!!

Maybe the "RETURN_VALUE" parameter needs to be set. Don't laugh. When using the EnterpriseLibrary, I ran into a similar situation. I break down and add a
GridView1_RowDeleting event handler to the page code. In it I set the "RETURN_VALUE" DefaultValue to String.Empty... which is odd since the data type for that param is Int32.

Ctrl-S & F5

Procedure or function iDBQAScore_CriteriaDelete has too many arguments specified.

Now I'm beginning to feel like a no-talent hack... moreso than before. Why is something so SIMPLE so damned difficult?!

I wish there was a happy ending, but there isn't. I've been at this all afternoon... (ok, only two hours, but it feels like a long time) and don't have a solution in sight.

Back to the trenches. I'll keep y'all posted.

Friday, September 08, 2006

Rotten Apple, The Second Half

I have good news and bad news.

The bad is that I have to eat my words. I plugged my Canon PowerShot S110 into my PC at work, which is running XP SP2 with all the updates, and, while it did recognize the new USB device as the correct type and model, it did not have the drivers needed to use it.

So, that tells me one of two things; 1) ALL Apples ship with ALL the drivers needed to talk to EVERY camera out there (I limit this statement to only cameras because the commercial used a stereotyped actress to portray a camera and no other device), or 2) Apple's selfish proprietarianism strikes again by forcing all device makers to communicate in one specific manner so that no additional drivers are needed. Is that good or bad? I dunno.

The good news is that Tim Buckley over at CTRL+ALT+DEL Comics did a very good strip covering the whole Rotten Apple Ad Campaign.

I think it'll use the last frame as my new Tag Line

Thursday, August 31, 2006

Today's ASP.Net Gripes

- In a web.sitemap file, an external link (a link to a web site not in the current web application) in the top-most node will cause the entire asp:menu to not render at all.

- If the same external link is placed anywhere else in the web.sitemap file, the corresponding menu node will not render, though the other menu items will. wtf?

- The properties ShowStartingNode and StartFromCurrentNode of SiteMapDataSource combined with the Web.Sitemap's siteMapNode nesting requirements makes for a dizying combination of possibilities of which only one actually comes close to the behavior desired. Hard to understand what I'm saying? I'll work on a sample.... eventually.

- The asp:Menu is incredibly difficult to impliment a style that matches the other controls on that page.

- The customErrors-error section of the web.config file can only accept an Int32 for the statusCode even though non-int HTTP errors exits. This makes it impossible to set up custom pages for most errors. For example, 401.2 "Access Denied" when using Windows authentication mode. Sure it can be set up in IIS, but then what's the point of even having a customErrors section?


The answer to the gripes; "Don't do that." or "If you find you need to do that, you are obviously making a huge architectural error."

Or perhapse, and most likely, I don't know enough about ASP.Net just yet. .. which brings up a different point. All these features, libraries and controls are designed to simplify development, but instead they just shift the complexity from one area to another. So instead of trying to figure out how to create a role-specific menu, I have to figure out how to impliment a pre-defined menu control that someone else decided has all the base abilities that I need.


There is always construction.... I make a hella shed ;)

Wednesday, August 09, 2006

"Oh, and next Friday... is Hawaiian shirt day... so, you know.."

My office is holding a picnic today and the dress code has been relaxed a bit; shorts are permissible. So, yes, I'm wearing shorts.

In the office.

Sitting in my chair.

The vary chair that I've sat in for the past 5 years with long pants.

But now, in shorts, my skin is touching the chair. Sure, the shorts go down to just above the knee when I'm standing. But in the sitting position they creep up a little... a little to far to be comfortable... at work.... in my chair.

I feel so naked.

Monday, August 07, 2006

XML Lookup in XSL

Or should I call this "XSL transform with an XML lookup"?

meh. Whatever I call it, the jist is that I was finally able to fugure out how to use another XML file to lookup description-type data that relates to a main XML file (parent-child) and output it all to HTML using an XSLT file... all in PHP. ;-)

Let me back up a bit to cover why I was trying to do it in the first place.

Sid Meier's Civilization IV was designed to be mod-able. I'd suggest reading about the game if you don't know it, because I'm not going to cover it here. But I will mention that it uses XML files for unit, terrain, technologies, leader and other rules and information.

So I wanted to make a way to display all the information in one simple, easy to view place - be it a web page or a windows form or whatever. But since I've been playing with PHP, I chose to give that a go.

The first thing I had to do was enable XML/XSL on my PHP web server. To do that, in the PHP.ini file change
;extension=php_xmlrpc.dll
;extension=php_xsl.dll

to
extension=php_xmlrpc.dll
extension=php_xsl.dll

and add these files to the PHP install folder
  • libxslt.dll
  • libxml2.dll
  • libexslt.dll

and these to (PHP Install)/ext folder

  • php_xmlrpc.dll
  • php_xsl.dll

You might be able to do it without one or two of those, but it works the way it is for me. :-)

After that, it's easy to load an XML file and apply an XSL stylesheet (is taht redundant? Like ATM Machine?) .




<?php//load the and stylesheet
$xsl = new DomDocument();
$xsl->load("CIV4UnitInfo.xsl");
//Load the xml
$inputdom = new DomDocument();
$inputdom->load("CIV4UnitInfos.xml");
// create the processor and import the stylesheet
$proc = new XsltProcessor();
$xsl = $proc->importStylesheet($xsl);
/* transform and output the xml document */
$newdom = $proc->transformToDoc($inputdom);
print $newdom->saveXML(); ?>


I got that from .... well, just about every sample out there.

The Unit data is in the "CIV4UnitInfos.xml" file (I didn't name it so don't harp on me about 'infos') and the lookup data is in "CIV4GameTextInfos_Objects.xml" but that's linked in my XSL file, "CIV4UnitInfo.xsl".

Heads up, I had to remove the namespace declaration from Sid's xml files. The xsl transform would not work unless I did. I'm not sure why.

In the file "CIV4UnitInfos.xml" there's a lookup key that refers to a description in "CIV4GameTextInfos_Objects.xml". So, part of my transform I need to get that description for output.

I start with the header and declaration stuff

Ok, I forgot how painful it is to try to post code on this blog. In order to preserve my sanity, I'll skip to the pertinent stuff.

First is the lookup variable declaration. This is what includes the "CIV4GameTextInfos_Objects.xml" file.

<xsl:variable name="unitLookup" select="document('CIV4GameTextInfos_Objects.xml')/Civ4GameText/TEXT"/>


Then in the <xsl:template match="UnitInfo"> section, I lookup the current key value using
Desc:<xsl:value-of select="$unitLookup[Tag=current()/Description]/English"/>


I'd love to post more xsl code and some xml to show the structure, but....

Next I tackle the technology tree!


View My Stats