he software development world has evolved quite a bit over the last 20 odd years. We went from object-oriented development to component-oriented development and now to service-oriented development. Each step along the way, the current programming methodology has borrowed useful ideas from its predecessor and tried to improve upon the technology. Service-oriented development seeks to decouple applications while still providing a robust, secure, and maintainable architecture.
In 2006, Microsoft quietly introduced a new product named Microsoft Robotics Studio (MSRS). MSRS, which has since been renamed to Microsoft Robotics Development Studio (MRDS) offers a service-oriented runtime along with tools that allow developers to build robotic applications. What most people have missed is that MRDS is more than just a tool for nerds that want to build their own R2-D2. MRDS utilizes components that will become mainstream in the next generation of service-oriented applications. This includes Decentralized Software Services (DSS) and Concurrency and Coordination Runtime (CCR)?key components of the MRDS runtime.
DSS is a lightweight application model that can be used to monitor services interactively and in real time. CCR is an asynchronous programming model that allows you to easily build applications that process data concurrently. Combined, these components allow you to build powerful and distributed embedded systems that are capable of handling a vast amount of concurrent processes.
This article will explore some of the basics involved with creating a service with MRDS. You’ll learn how to create a service that captures the coordinates of the mouse and makes it available to other services through the service state. Even though you’ll be using MRDS, there is no need for you to have a robot and the MRDS software is free to download.
Understanding Services
Services are key objects in MRDS and a typical robotics application will utilize more than one service to accomplish a common goal. Each service may perform a specific function, such as reading data from a sensor or sending commands to an actuator. Central services, known as orchestration services, will be used to coordinate the actions of all the other services. Each service will expose the data that it collects through state variables. These state variables represent the service at the time they are requested.
Since more than one service can be involved in an application, they need a to communicate with each other. Services communicate by sending and receiving messages through DSS ports. A DSS port is similar to the port assigned when you run an application in Visual Studio. Messages contain operations, which indicate what the request is for. For example, a GET operation is used to get the entire state for a service. The SUBSCRIBE operation allows a service to receive event notifications regarding state changes with another service.
![]() Figure 1. The Control Panel Interface: This diagram shows the flow of information between services responsible for collecting and displaying data from a robot’s sensors. | ? | ![]() Figure 2. MouseTracker: Select Simple Dss Service RDS 2008 as the new project template. |
To understand how this works, let’s examine a situation in which multiple services are responsible for collecting information from a robot’s sensors and displaying that information in a control panel. While Service A collects information from a robot’s sound sensor, Service B collects information from its touch sensor. Both services make their data available to other services through state variables. An orchestration service, Service C, is responsible for subscribing to state changes for Service A and Service B. It then displays the data it collects in a Control Panel interface, which is used to view the robot’s sensor data (see Figure 1).
Creating a Service in MRDS
If you are new to MRDS, you may want to take a few minutes to get familiar with the features it supports. You can refer to my previous article, “An Introduction to Programming Robots with Microsoft Robotics Studio.” To follow along with the code in this article, you will need to have both Visual Studio 2008 and MRDS 2008 CTP installed on your machine. Download the CTP version of MRDS here.
MRDS provides a Visual Studio 2008 template for creating new service projects. Once you have installed MRDS, go to File?>New?>Project. You should see a Robotics project type and, within that, a template named Simple Dss Service RDS 2008. Select this as the template and enter a name and location for the project. In the sample code available with this article, the project is called MouseTracker (see Figure 2).
Author’s Note: Avoid renaming projects after they have been created. By default, the service will be named DssService1. If you create the project DssService1, do not attempt to rename the project after it is created. Several references to this project name have been added to the properties of the project and unless you change them all, you could have difficulty executing your application. |
Contract Class
When you select the Visual Studio template, the project automatically adds class files which represent the contract and implementation class. If you named the project MouseTracker, then the contract class will be named MouseTrackerTypes.cs. This is where you will define the state variables and DSS operations associated with the service.
The following important elements are contained within the contract class:
- Contract
- State Variables
- Message Operations
The contract contains the information that other services will need to use this service. The Universal Remote Identifier (URI) associated with the MouseTracker service is included by default when you create the project using a template. This identifier should be unique to the service and must be preceded by the DataMember attribute, such as in the following code snippet:
[DataMember()]public const String Identifier = "http://schemas.tempuri.org/2008/05/mousetracker.html";
Since the goal of the mouse tracker project is to track the mouse position, it makes sense to include the mouse coordinate points as state variables. To do this, add variables, preceded by the DataMember attribute to the class named MouseTrackerState:
//Add the Mouse position as a state variableprivate PointF _mousePos = new PointF();[DataMember]public PointF MousePos{ get { return _mousePos; } set { _mousePos = value; }}
The last important element in the contract class is the message operations. Services created with the template include one main operations port, in which all service operations should be posted. Any operations that need to be performed for a service must be defined in the services PortSet.
The PortSet, which is created by default when you use the Visual Studio template, includes three standard message operations (DsspDefaultLookup, DsspDefaultDrop, and Get). In addition to these operations, you will need to include operations named HttpGet, UpdateMousePosition, and Replace. The code implemented in these operations will be covered in a later step. For now, we are just defining the list of valid operations that can be posted to the port. The PortSet for the MouseTracker service should look like the following:
[ServicePort()]public class MouseTrackerOperations : PortSet{}
The GET operation, which is included by default when you use the template, will return XML as a SOAP message. For the MouseTracker service, include the HttpGet operation, which allows you to return the XML as HTTP instead. HttpGet is used since you’ll query the state through a web browser in a later step. The UpdateMousePosition handler is responsible for updating the MousePos state variable defined earlier. And finally, the Replace operation is responsible for updating all of the state variables for the service.
Implementation Class
The implementation class, which should be named MouseTracker.cs, is where you will place the majority of the service code. This includes message handlers, which contain the code that is executed when one of the DSS operations is called. The following important elements are contained in the implementation:
- ServiceState declaration
- ServicePort declaration
- Start method
- Message Handlers
As mentioned earlier, the service state contains useful information and represents the service at the time the state is requested. The MousePos variable contains the actual mouse position, but the state itself is represented through a variable named _state. This declaration is included at the top of the implementation class and is marked with the ServiceState attribute, such as the following:
[ServiceState()] private MouseTrackerState _state = new MouseTrackerState();
The MouseTracker service utilizes a main port represented by the variable _main. This is where the internal state is posted and the declaration should be preceded by the ServicePort declaration, such as the following:
[ServicePort("/mousetracker", AllowMultipleInstances=false)] private MouseTrackerOperations _mainPort = new MouseTrackerOperations();
In addition to the main port, the MouseTracker service utilizes another port represented through the _timerPort variable. The TimerPort is used to post the date and time for the service timer. The timer is necessary because you’ll need to constantly poll for the mouse position.
The Start method is the entry point for the service and it is called when service initialization is complete. It’s primarily responsible for starting the service and this is where you’ll add any code that needs to be executed at service startup. For the MouseTracker service, you’ll include code to initialize the TimerPort and assign a handler for the Timer control. The code for the Start method is seen as follows:
protected override void Start(){ base.Start(); // Activate the TimerHandler which will be used to // get the mouse position _timerPort.Post(DateTime.Now); Activate(Arbiter.Receive(true, _timerPort, TimerHandler)); }
The final things to add are the message handlers. For the MouseTracker service, you’ll need to associate a message handler with each of the message operations you’ve added to the PortSet, as shown in Listing 1.
You should notice that each handler is preceded by a ServiceHandler attribute. This attribute includes a property which indicates whether the code can execute concurrently with other code. For example, when the ServiceHanderBehavior is set to Exclusive, no other handlers can execute. When set to concurrent, other handlers are allowed to execute in parallel. This distinction should be made whenever the handler must update state. Just like when updating values in a database, you must ensure the integrity of the state data during updates.
In addition to the message operation handlers, you will need to add a handler for the timer control. This handler is activated in the Start method and should initiate a loop that executes every 1000 milliseconds. The TimerHandler uses the Arbiter class to set up a single item receiver that will handle notifications through the timer port. The code for this handler is seen in Listing 2.
Running the Simulation
Once the code has been successfully compiled, you can run the simulation by clicking F5 to start debugging or Ctrl+F5 to start without debugging. The application should display a command window and take a few seconds to load files for the service. Once the service is completely loaded, you should start seeing mouse position coordinates displayed every one second in the Visual Studio Output window. The command window should also display the message, “Manifest load complete.”
As mentioned previously, the mouse position is displayed as output from debug. Alternatively, you can query the state for the service, by opening a web browser and navigating to the following URL:
![]() | |
Figure 3. The Final Results: The web browser results after querying the state for the MouseTracker service. |
http://localhost:50000/MouseTracker/
Depending on your operating system, you may need to enter authentication information for your development machine. The final result should look similar to Figure 3. Notice that the X and Y mouse coordinates are displayed as formatted XML. If you move the mouse and then click refresh, you should see the coordinate values change.
What Else Could Be Done with This information?
In addition to displaying the information in an Output window or a web browser, you could also create a second service that established a partnership with this service. The second service could then subscribe to the first service and receive notifications when the state changed.