Thursday, July 31, 2008

Custom messages using the PortSet

I am not sure whether this is in the tutorials, but I thought I would highlight it anyway. Making custom messages in MRDS is really easy. Also you can pass state information through them. This post should also give you insight into how the request operations on hardware works.

To create a custom message, the first step is to create the request class. This request class can contain data that you want to send through. It is declared in the <dss_name>Types.cs file. Remember that all properties need to be Serializable. That means (a) the class needs to be a [DataContract] and (b) the properties need to be ints, bools, strings, etc ([DataMember]). I do not recommend customizable objects, since these services are actually designed to pass between computers, what good is a local definition? So create the message of the structure you want:
[DataContract]
public class NewMessageRequest
{
private bool _input;

[DataMember]
public bool Input
{
get { return _input; }
set { _input = value; }
}
}

Then create a class in the <dss_name>Types.cs that inherits from the Update portset:
public class NewMessage : 
Update<NewMessageRequest,
PortSet<ReturnType, Fault>>
{
public NewMessage() :
base(new NewMessageRequest()) { }
}

What is awesome is you can specify the return type. I kinda guessed this behaviour from navel gazing at the code. That means you can post state changes directly back or whatever information you wish. I went for the state, so that the DSS is still 'responsible' for the output it gives. Then you need to write the handler for the request. This occurs in the <dss_name>.cs file:
[ServiceHandler
(ServiceHandlerBehavior.Exclusive)]
public IEnumerator<ITask>
NewMessageHandler(NewMessage msg)
{
if (beh.Body.Input)
{
//perform certain changes
}
else
{
//perform other changes
}
msg.ResponsePort.Post
(/*ReturnType instance*/);
yield break;
}

In this manner, you can create customized messages and defer computation to other services, rather than focusing all computation in one service. This is really distributable computing, making use of DSS and CCR.

Tuesday, July 22, 2008

The pursuit camera

Paul Roberts (blog), the author of the pursuit camera, pointed out that the pursuit camera in fact does follow the bot (I feel ashamed! I was mistaken, I did cross it out...)1. It just needs to be set in the constructor (See his post - done in code: [Pursuit Camera Service]). But since I prefer the VSE (I have my reasons), I wanted to find out how to set it up from there. I realised what I was doing wrong.

When you create the PursuitCamera, a form pops up with the constructor, just like the TriangleMeshEnvironment entity. You can either set the 'target' property (before creation) or set the TargetName property (after creation).

Just type in the name of the bot you wish to pursue, and it does the rest. It is quite nifty! Just don't set it's parent!

1 Firstly, I am so sorry for being over-critical before doing my research! It will not happen again. Secondly, thank you for reading a blog as humble as mine. Thirdly: Please keep up the excellent work! I love this framework. If I had children, regardless of their age and gender, they would be programming robots.

Monday, July 21, 2008

New CTP version of MRDS - just be careful

There is a new version of MRDS out. Read all about it here: [Welcome to July CTP of Microsoft Robotics Developer Studio 2008]. It is available for download here: [Download MRDS CTP July 2008].

I have checked it out and I like the interface for the dssnewservice. It looks really good. Let's hope it fixes some of the other known issues:
  • Tutorials for the manifest editor: Yes! Now my triumph a couple of weeks ago is literally nothing. Of course you have to know to use the manifest editor, which I think was my problem in the first place. My hassle was there were no projects dedicated to simulated and real robots.
  • Meshes being walls in the FloorPlan entity: See next point.
  • Texturing (FloorPlan and TriangleMeshEnvioronment Entities): Nope, no fixes. My 'quick and dirty' method won't even work since the FloorPlan is now limited to walls only, meaning no meshes. The TriangleMeshEnvironment allows for everything, but textures are still not working.

I also noticed there are less project options. The DSS hosing template has been taken out. In fact you can only create a service. But that is a topic for another day.

I like the fact that the simulation environment can be embedded in forms, but I think that was there before, it just didn't work so nicely (I still don't know how to use it, so I'm no authority here). I have vague recollections 2 years ago trying to create a form with a robotics simulation on it. Back then help was scarce...

What is really good is the DSS Manifest Editor loads really quickly! Also if you stop the VSE without stopping a manifest, the manifest editor just runs a shutdown rather than throwing errors. The VSE is (more) amazing - they have at least removed the editable options that did not change dynamically. It used to be that, when you clicked on an entity in the tree, you could 'edit' the entity in the left menu. The problem was, none of those changes would take effect. You had to click 'Edit Entity' and change the properties there. At least now you aren't fooled into thinking you have made changes.

The only hassle is when you do that with a Camera entity is creates a new camera. Annoying. I know for a fact it didn't do that in the older CTP. At least it effects both cameras and so it's just a matter of deleting the duplicate. Also when you load a previously edited VSE manifest is resets the camera to a high weird position.

They also added a pursuit camera... Which is a great idea, but not really useful. I was hoping for a 'third person' view. It seems it looks behind, and it is really static in terms of its relation to the parent object. [23 JULY 2008: CORRECTION]

In code, a lot of the references have changed. Not in terms of names, but location and namespace, so it's just the DLLs in the references that need updating:
  • Ccr.Core is now Microsoft.Ccr.Core
  • DssBase is now Microsoft.Dss.Base
  • DssEnvironment is now Microsoft.Dss.Environment
  • DssRuntime is now Microsoft.Dss.Runtime

This change is for the best, at least you know whose DSS and CCR you are using :) Be careful because I suspect there are a lot more than that.

I noticed in the tutorials some of the pictures are missing. The Robotics Introductory Course is missing all images. That could hinder. The simulation tutorials need to be re-numbered. I know that 3 and 6 are somewhere else, but really... how disturbing! Simulation Tutorials 3 and 6 are language independent.

I got my main project working in the new version in a matter of minutes. So at least there are no changes that are going to drastically affect or hinder progress.

Remember that CTP stands for Community Technical Preview, which means that it is not an official release, but is up for technical revision. So get on the forums and make comments! But I think that Microsoft Robotics are coming closer and closer to a very squeaky-clean package that is going to take robotics to the next level.

Sunday, July 20, 2008

A word to the wise: careful of your types for DataMembers

I was getting a pretty strange error in MRDS. I was trying to use the REST (representational state transfer) to transfer an array of objects, when it failed on compilation:
private object[] _list;

[DataMember]
public object[] List
{
get { return _list; }
set { _list = value; }
}
It throws an error:

Error 1 Unable to Clone System.Object at Microsoft.Dss.Services.ContractManager.TransformUnit.WriteTransformMethod(TextWriter w, String prefix, DssClassType dssClass, CopyK ...\Microsoft Robotics Dev Studio 2008\projects\<ServiceName>1\EXEC <ServiceName>

Error 2 The command ""...\Microsoft Robotics Dev Studio 2008\bin\dssproxy.exe" /dll:"...\Microsoft Robotics Dev Studio 2008\bin\<ServiceName>.Y200#.M##.dll" /vstarget:VS2008 /proxyprojectpath:"...\Microsoft Robotics Dev Studio 2008\projects\<ServiceName>\Proxy " /keyfile:"...\Microsoft Robotics Dev Studio 2008\samples\mrisamples.snk" /binpath:". " /referencepath:"...\Microsoft Robotics Dev Studio 2008\bin\ " /referencepath:"...\Microsoft Robotics Dev Studio 2008\bin\ " " exited with code 10. <ServiceName>


If you compile it again, it seems fine. It's not fine. Remove it. I also got an error, which revealed the problem, when trying a similar move with an ArrayList object:
private ArrayList _list;

[DataMember]
public ArrayList List
{
get { return _list; }
set { _list = value; }
}

Error 1 Invalid [DataMember] field. ...\Microsoft Robotics Dev Studio 2008\projects\<ServiceName>\EXEC <ServiceName>

Error 2 The command ""...\Microsoft Robotics Dev Studio 2008\bin\dssproxy.exe" /dll:"...\Microsoft Robotics Dev Studio 2008\bin\<ServiceName>.Y200#.M##.dll" /vstarget:VS2008 /proxyprojectpath:"...\Microsoft Robotics Dev Studio 2008\projects\<ServiceName>\Proxy " /keyfile:"...\Microsoft Robotics Dev Studio 2008\samples\mrisamples.snk" /binpath:". " /referencepath:"...\Microsoft Robotics Dev Studio 2008\bin\ " /referencepath:"...\Microsoft Robotics Dev Studio 2008\bin\ " " exited with code 20. <ServiceName>


The right way to deal with this kind of situation is to use the Array object. You set the array by using the Array.CreateInstance method.

Thursday, July 10, 2008

Quick and dirty textures for TriangleMeshEnvironment entities

I have not found a nice way of doing this yet. So this blog is subject to serious revision. If you want a texture applied to a TriangleMeshEnvironment entity, I recommend you create the TriangleMeshEnvironment entity as described [HERE].

You will notice you can't load a mesh. But I did find one way. Create a new floorplan entity. Then click 'Edit Entity' (YOU MUST CLICK IT) --> Edit the Entity state and select the same mesh ('.obj' file) as you did for the TriangleMeshEnvironment entity and also the texture you want. Then just click on the 'Wall' button and the 'Ok' button. I created the FloorPlan 10m higher so I can tell the difference between the two.

Then all I did was remove the FloorPlan entity. The TriangleMeshEnvironment entity keeps the texture. But it will not reload properly. For now I recommend sticking with just the effects.

Monday, July 7, 2008

Create a neat 3D customizable maze for MRDS/MSRS

For my masters, I want to create a maze environment for the robots to navigate through. I found that I could not use all of [Trevor Taylor's code], because there were some errors. They probably have something to do with using C# 2008 and the latest MRDS framework. So I just modified it so that it can be used. The error I got when I tried to run the original code was:

Could not load file or assembly 'DssCmdArgs, Version=2.0.730.3, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.


So I took the code I needed and removed the DssCmdArgs reference and the corresponding namespace
using Microsoft.Dss.Tools.CommandLine;

I also took the Maze generation code from Chapter 9 and made the solution a complete package. So now I have a maze mesh generation tool. It's awesome. Another change you will notice is that it is in black and white only. The generation code as described in Professional MRDS does not seem to work well with colours. I was getting a maze mesh with a 'roof' on it - exactly what I do not want.



So the first thing you'll want is the program. It uses all code from Trevor Taylor and Kyle Johns, who in turn modified a Depth First Search algorithm implemented [HERE]. I put it all together and modified it as described. It may not be the most elegant, but it works well. Click [HERE] to download the complete code. It draws the maze and the 'generate' button will create a '.obj' file type for you.

To see the maze in the simulation environment is fairly simple. Generate a mesh using bmp2mesh (or you can create an load your own - click "Browse") and make sure you remember where you saved the .obj file. The program automatically allocates a name to the same location as the image.

Next load a simulation environment. To load the mesh, you want a new entity. Choose a TriangleMeshEnvironmentEntity entity. Once you have returned to the normal edit screen select the TriangleMeshEnvironmentEntity. Then click ok, but do not be concerned about the errors (you could just paste the entire path of the '.obj' file if you are that concerned about seeing errors). You must click 'Edit Entity.' Modify the EntityState and select the '.obj' file you created using my program. I strongly recommend you apply an effect, like Terrain.fx. I am still working on textures.



It may take a few seconds, but the mesh should load. You will be interested to know, the entity itself generates a '.bos' file for you. The mesh is actually sitting below the floor, so you can raise it if you want the walls higher.



There are several reasons why I prefer my solution:
  • Complete: It works neatly and in one package
  • Error-free: There are no unnecessary dependencies in the code
  • Usability: The form doesn't re-size for every maze generated, rather, it just stretches the maze image

The main limitation of my program is that you may only use bitmap images. The code may be modified and extended to support other file formats, but it is unnecessary.

Thursday, July 3, 2008

Using MRDS/MSRS to create simulated hardware entities

My goal is to use a hardware differential drive on a simulated bot. Now the problem was I could not seem to connect the bot to the hardware drive I programmed in. As you can imagine it was a frustrating WEEK that I wasted trying to get it to work, however, thanks to the personal effort of Trevor Taylor, the author of "Professional Microsoft Robotics Development Studio", I managed to figure out the problem.

Here are the forums I used:

Firstly, create the program that controls your robot. I called mine Actuator (my creative team is on holiday and I will have a better name soon), and all it has is the differential drive. So far, I have only imported RoboticsCommon.Proxy and the only namespace is:
using drive =
Microsoft.Robotics.Services.Drive.Proxy;

Then I created a perform method of type IEnumerator<ITask>, in which all actions can be spawned. Be careful, however, that you time the robots actions appropriately when calling the methods in this fashion. If you travel a long distance, make the timeout operation longer. I think it is more effective that actuators react based on sensor information, but the point of this blog is to get you to a certain point and let you figure out the rest.

private IEnumerator<ITask> perform()
{
//drive a set distance
SpawnIterator<double, double>
(2.0, 1.0, driveRobotDistance);
//wait
yield return Arbiter.Receive
(false, TimeoutPort(2000),
delegate(DateTime t) { });
//turn
SpawnIterator<double, double>
(90.0, 1.0, turnRobot);
//wait
yield return Arbiter.Receive
(false, TimeoutPort(2000),
delegate(DateTime t) { });
//drive again
SpawnIterator<double, double>
(2.0, 1.0, driveRobotDistance);

yield break;
}

private IEnumerator<ITask> driveRobotDistance
(double distance, double power)
{
drive.DriveDistanceRequest driveRequest =
new drive.DriveDistanceRequest
(distance, power);

yield return Arbiter.Choice
(
_drivePort.DriveDistance(driveRequest),
delegate
(DefaultUpdateResponseType response)
{
},
delegate(Fault fault)
{
LogError
(null,
"Unable to drive robot",
fault);
}
);
}

private IEnumerator<ITask> turnRobot
(double angle, double power)
{
drive.RotateDegreesRequest request =
new drive.RotateDegreesRequest
(angle, power);

yield return Arbiter.Choice(
_drivePort.RotateDegrees(request),
delegate
(DefaultUpdateResponseType response)
{
},
delegate(Fault fault)
{
LogError
(null,
"Unable to turn robot",
fault);
}
);
}

That's all there is to this drive. But the point remains that in code some physical differential drive is being told to drive and we can see in what manner to make other physical entities work, as well as react.

Well, that's all there is on this side. Now we need to create an environment. Go to the visual simulation editor and create entities in the same manner as I describe in my post on how to create a custom simulation environment [HERE]. There are a few changes though:
  1. Make sure that the lego has the Simulated differential drive contract (not actually a change, just a reminder. Don't try make it the physical drive.)
  2. (I left this out the last time - how embarrassing!) Make sure that you add wheels to the LegoNXTTribot. You must edit the Left and Right wheel's entity state and load a mesh:

Save the manifest, but make sure you know where the manifest is stored. Then load up the DSS Manifest Editor. This is the power of MRDS / MSRS. You have created a hardware project. You have created a simulated 'version' of the hardware's environment. Now to plug them into each other.

In the manifest editor, load the manifest of the simulation environment. It should look something like this:

What you should notice is that the simulated differential drive actually has an entity: the LegoNXTTribot. I am still not sure in what manner we can do this in code, but at least the entity is there, and we can modify it with the VSE.

Now drag and drop the Actuator file on top of the simulated differential drive, not the entity. This creates an instance of the Actuator for the whole manifest. (To make sure it is not added to the entity, click the entity, it should not highlight any relationships). Then either: drag and drop the existing simulated differential drive on to the Actuator's DRIVE object, or you can just drag a simulated differential drive object from the services section and make sure it is the same one as previously loaded. It should look like this:

Then you can either save the manifest over the manifest for your Actuator application and run from code, or you can run the manifest from the editor by pressing F5. But that is the basics of loading a simulation environment and then plugging in your hardware devices. Happy Botting©!