Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Задани на лабораторные работы. ПРК / Professional Microsoft Robotics Developer Studio

.pdf
Скачиваний:
125
Добавлен:
20.04.2015
Размер:
16.82 Mб
Скачать

www.it-ebooks.info

Decentralized Software

Services (DSS)

The Decentralized Software Services (DSS) are responsible for controlling the basic functions of robotics applications. As explained in the previous chapter, DSS is built on top of the CCR. There is a DSS base class from which all services are derived, and this draws heavily on the features of the CCR.

DSS is responsible for starting and stopping services and managing the flow of messages between services via service forwarder ports. In fact, DSS itself is composed of several services that load service configurations; manage security; maintain a directory of running services; control access to local files and embedded resources such as icons; and provide user interfaces through web pages that are accessible using a web browser.

DSS uses a protocol called, not surprisingly, DSS Protocol (DSSP). The specification for DSSP can be used for free under the Microsoft Open Software Promise. DSSP is based on the Representational State Transfer (REST) model, which should be a familiar model for anyone who has worked in web development.

In some ways, such as handling errors using faults, DSSP is similar to SOAP (Simple Object Access Protocol), which is used by web services. However, unlike web services, DSSP separates state from behavior and represents all access to a service as operations on the state. In contrast, the state of a web service is hidden. Making the state of a robot fully visible, especially sensor values, is essential to writing control behaviors for the robot. A key feature of both models is asynchronous event notifications, which are important in the dynamic environment of robotics.

In this chapter, you learn how to build services, including the fundamental concepts. Like the last chapter on the CCR, this one is full of new terminology, and it may take you a little while to become completely familiar with DSS.

www.it-ebooks.info

Part I: Robotics Developer Studio Fundamentals

Overview of DSS

As you read through this chapter, you might find that there is too much information to absorb in one go. Don’t panic! Read through the chapter in its entirety, and then come back and hit the highlights later. The repetition throughout the chapter is deliberate. Over time you will begin to absorb the concepts

by osmosis.

The basic building block in MRDS is a service. Services can be combined (or composed) as partners to create applications. This process is referred to as orchestration.

An example of a complete application is shown diagrammatically in Figure 3-1. This Visual Explorer application uses a camera for the robot to explore its environment. The robot hardware is accessed via three generic contracts that describe the application programming interfaces (APIs) for a differential drive (two independently driven wheels), a set of bumpers, and a web camera. The Visual Explorer service does not have to know anything about the hardware in order to use these services.

 

DSS Application – Visual Explorer

 

 

DSS Node A

 

DSS Node B

 

Visual Explorer

 

Vision

 

 

 

Processing

Differential Drive

Web

 

Camera

 

 

 

 

Motor

Bumper

 

 

Motor

Array

 

 

 

Robot “Brick”

 

 

Figure 3-1

 

 

 

At the next level down, the motor service talks to the robot brick service, which in turn communicates directly with the robot. (A brick service is the core component for a robot.) In this example, the web camera is mounted on the robot and controlled via the brick. However, image

processing, which can be a very CPU-intensive task, is carried out on a different computer (DSS Node B). Computer vision packages for MRDS such as RoboRealm (www.roborealm.com) or VOLTS-IQ from Braintech (www.volts-iq.com) could be used for this task.

The services that make up an application can be created and destroyed dynamically. However, in most cases they are specified at startup through a manifest. This is an XML file that lists the required services and their partner relationships. Figure 3-1 shows the Visual Explorer service partnered with the Vision Processing, Differential Drive, Bumper Array, and Web Camera services. The dotted connection to the

84

www.it-ebooks.info

Chapter 3: Decentralized Software Services (DSS)

Robot “Brick” is intended to indicate that sometimes you have to bypass other services and go directly to the hardware to access devices such as LEDs, buzzers, and so on, which are not exposed through generic contracts.

One of the objectives of MRDS is to provide an environment where services are loosely coupled. In Figure 3-1, a different type of robot could be substituted for the existing one and Visual Explorer would not even know, as long as the new robot implemented the same generic contracts. Of course, in practice it is a little more complicated than this because the new robot might have motors that drive faster, a different configuration of bumpers, and a higher-resolution web camera. Nonetheless, the principle still stands.

A service consists of several components:

Contract: This defines the messages you can send to a service, as well as a globally unique reference, called the contract identifier, which identifies the service and is expressed in the form of a URI (Universal Resource Identifier)

Internal state: Information that the service maintains to control its own operation

Behaviors: The set of operations that the service can perform and that are implemented by handlers

Execution context: The partnerships that the service has with other services, and its initial state

Figure 3-2 shows all these components diagrammatically. They are discussed in more detail in the following section, and then covered again later in the chapter when you build your first service. Repetition is the key to learning!

Service URI

Contract Identifier

Main

Interleave

 

Port

 

Operations

Notification

Ports

Subscription

Handlers

Notifications

Figure 3-2

 

 

 

 

 

 

 

 

 

 

Service

 

 

 

Other

 

 

Handlers

 

 

 

 

 

 

 

 

 

Services ...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

State

Partners

Requests and

Responses

85

www.it-ebooks.info

Part I: Robotics Developer Studio Fundamentals

Contracts

A contract identifier is used to uniquely identify different services. When you create a new service, as explained next, a contract identifier is created for you. For example, here is the contract identifier from the Dance service in Chapter 14:

///<summary>

///Dance Contract class

///</summary>

public sealed class Contract

{

///<summary>

///The Dss Service contract

///</summary>

public const String Identifier = “http://www.promrds.com/contracts/2007/10/dance.html”;

}

Every service must have a class called Contract, and it must contain a field called Identifier. MRDS uses URIs in the following format:

http://somehost.domain/path/year/month/servicename.html

This looks like a valid URL, but it does not have to exist on the Internet. By default, the host name is www.promrds.com, but most of the Microsoft services use the host and path schemas.microsoft

.com/robotics. The convention of using the year and month in which the service was created helps to keep the URIs unique and enables new versions of the same service to be built.

The important point to note is that the URI must be unique. You can use any host name or/path directory, that you want. This book uses a real web prefix, www.promrds.com/contracts/. Be aware, however, that the URI should be all lowercase or there can be problems with case sensitivity.

The programmatic interface to a service is defined as part of the contract via a set of classes that describe the types of messages to which a service can respond. The objective is to keep this interface clean by only using data structure definitions, and no methods. In particular, there must be at least one PortSet that is public and contains ports for all of the available message types. (Remember that messages are just data types, i.e., classes).

For example, here is the main operations port for the Dance service (although it is called a port, it is actually a PortSet):

///<summary>

///Dance Main Operations Port

///</summary> [ServicePort()]

public class DanceOperations : PortSet<DsspDefaultLookup, DsspDefaultDrop, Get>

{

}

86

www.it-ebooks.info

Chapter 3: Decentralized Software Services (DSS)

Notice that this PortSet is “decorated” with the [ServicePort] attribute, which marks it is as an operations port. MRDS makes extensive use of such attributes to help build the necessary infrastructure for services declaratively. The compiler takes care of generating any code that might be necessary, so you don’t have to worry about it.

DanceOperations contains ports for three types of messages: DsspDefaultLookup, DsspDefaultDrop, and Get. A Lookup operation enables other services to find out information about this service; Drop is used to shut down the service; and Get is used for retrieving a copy of the service’s state. This is the set of message types created automatically when you create a new service.

State

The internal state of a service is a class containing properties that are important to the operation of the service. Some properties are effectively constants for the duration of the service execution. This can include parameters such as the COM port that is used to communicate with a robot. By making this available externally, it is possible to reconfigure the service without recompiling it.

Other state properties change over the lifetime of the service. For example, you might implement a finite state machine (FSM) to control a robot as it wanders around (see Chapter 16). Then you can define the current state of the robot as Drive Straight, Turn Right, Back Up, and so on, and store this in a variable in the service state. (Do not confuse “state” in the FSM with the “state” of a service. In general, the FSM state is a small subset of the overall service state.) In this case, the state changes in response to external events, such as detecting an obstacle in the path of the robot.

Lastly, some properties in the state can represent things happening in the real world, e.g., values obtained from sensors, user input, and so on.

Here is the state from the Stinger Drive By Wire service in Chapter 16:

[DataContract]

public class StingerDriveByWireState

{

// The Headless field indicates if we should run without a GUI private bool _headless;

[DataMember]

public bool Headless

{

get { return _headless; } set { _headless = value; }

}

// Can run with the Motor disabled for testing private bool _motorEnabled;

[DataMember]

public bool MotorEnabled

{

get { return _motorEnabled; } set { _motorEnabled = value; }

}

(continued)

87

www.it-ebooks.info

Part I: Robotics Developer Studio Fundamentals

(continued)

private bool _wanderEnabled;

[DataMember]

public bool WanderEnabled

{

get { return _wanderEnabled; } set { _wanderEnabled = value; }

}

private WanderModes _wanderMode;

[DataMember]

public WanderModes WanderMode

{

get { return _wanderMode; } set { _wanderMode = value; }

}

private int _wanderCounter;

[DataMember]

public int WanderCounter

{

get { return _wanderCounter; } set { _wanderCounter = value; }

}

private double _irLeft;

[DataMember]

public double IRLeft

{

get { return _irLeft; } set { _irLeft = value; }

}

private double _irFront;

[DataMember]

public double IRFront

{

get { return _irFront; } set { _irFront = value; }

}

private double _irRight;

[DataMember]

public double IRRight

{

get { return _irRight; } set { _irRight = value; }

}

}

88

www.it-ebooks.info

Chapter 3: Decentralized Software Services (DSS)

The StingerDriveByWireState class defines the internal state of the service. Notice that it is also part of the service contract because it has the [DataContract] attribute. When another service issues a Get request, it knows from the contract exactly what information it will receive in the response message.

DSS nodes implement a web server so you can use a web browser and enter the URL for a service to see its state. Requesting a web page from the service executes an HttpGet operation, which returns an XML file. Being able to examine the state of a service remotely using a web browser gives you some insight into the service without having to run it in the debugger.

The state can be stored in a saved state or config file, which is an XML file. This can be reloaded the next time that the service is run so it “remembers” parameter settings. An example of a config file is shown here for the Stinger Drive By Wire service:

<?xml version=”1.0” encoding=”utf-8”?>

<StingerDriveByWireState xmlns:s=”http://www.w3.org/2003/05/soap-envelope” xmlsn:wsa=”http://schemas.xmlsoap.org/ws/2004/08/addressing” xmlsn:d=”http://schemas.microsoft.com/xw/2004/10/dssp.html” xmlsn=”http://schemas.tempuri.org/2007/11/stingerdrivebywire.html”>

<Headless>false</Headless> <MotorEnabled>true</MotorEnabled> <WanderEnabled>false</WanderEnabled> <WanderMode>None</WanderMode> <WanderCounter>0</WanderCounter> <IRLeft>61.3</IRLeft> <IRFront>80</IRFront> <IRRight>79.8</IRRight>

</StingerDriveByWireState>

The state has values that are supposed to be set by editing the saved state file: Headless, MotorEnabled, and WanderEnabled. It also contains internal information that provides some insight into how the Wander behavior is running: WanderMode and WanderCounter. The last three fields are the IR sensor values, obtained from other services but included here to make them easier to see.

The WanderMode controls the internal FSM during wandering. It uses an enum that is also part of the contract (because it has a [DataContract] attribute too):

// Modes that the robot can be in while wandering [DataContract]

public enum WanderModes

{

None,

DriveStraight,

VeerLeft,

VeerRight,

TurnLeft,

TurnRight, BackUp

}

When the state is serialized (into XML), the WanderMode appears as one of the names in the enum. There is no need to memorize “magic” numbers so you can tell what is happening when you view the state. In your code, you simply use the symbolic values, such as WanderModes.DriveStraight.

89

www.it-ebooks.info

Part I: Robotics Developer Studio Fundamentals

You can poll a service by requesting its state on a regular basis using a Get operation. This places the responsibility on your service to request the updates (and wait for them to arrive). Determining an appropriate polling interval is one of the challenges of robotics. If you poll too fast, you might overload the other service, or simply receive the same old stale information. If you don’t poll often enough, you might miss important information, such as a looming wall, and then crash!

One of the key features of DSSP is that messages can be sent asynchronously, i.e., unsolicited. These are referred to as notifications. Services can offer subscriptions to their state information, so you can avoid polling. (Subscriptions are covered in Chapter 4).

For example, a laser range finder (LRF) produces range scans about once a second. Services that are interested in this data can subscribe to the LRF service and receive notifications when new range scan data becomes available. (The LRF data is part of the service’s state, so the LRF service is sending state update notifications.) These updates continue to arrive until one of the services is shut down or the subscriber decides to unsubscribe.

Note that the LRF service sends the range data as part of the notification message. However, a Webcam service simply sends a message to say that a new frame is available because of the large amount of data involved. It is then up to the recipient to request the frame. If the recipient is slow and misses a couple of updates, very little bandwidth is wasted because the images are not sent in notifications anyway.

Putting this all together, the diagram shown in Figure 3-3 depicts a sequence of messages passing between hypothetical services.

Service A

 

Service B

 

Service C

 

Service D

 

 

 

 

 

 

 

Update

Request

Update

Response

Figure 3-3

In Figure 3-3, note the following:

Query

Request

Query

Response

Update

Notification

Update

Notification

Service A generates new information and sends it to Service B as an Update request. Perhaps Service A has obtained a new sensor reading. An Update only changes part of the state, as opposed to Replace, which overwrites the entire state.

90

www.it-ebooks.info

Chapter 3: Decentralized Software Services (DSS)

Service B realizes that in order to complete the update, it needs another piece of information from Service C, so it makes a Query request. (This is somewhat artificial, but just play along.) A Query is used to retrieve part of the state, whereas a Get returns the whole state.

Service C responds to Service B, so then Service B can respond to Service A. The Update transaction is now complete. However, the state of Service B has changed and it has two subscribers: Service C and Service D. Therefore, it sends notification messages to both of these services. Note that (apart from the original subscription message) Services C and D just wait patiently and do not send any messages.

Note two distinct patterns in Figure 3-3. One is the classic request/response pattern. You have the option to wait for the response or ignore it. The response could be a Fault if the other service encountered an error processing the request. You can also explicitly set the request’s TimeSpan property so that it times out if the other service doesn’t respond.

The other pattern is asynchronous notifications to multiple subscribers. The subscribers first request notifications (these messages are not shown in Figure 3-3) and then they continue to receive updates whenever they become available. No acknowledgment is required for notifications.

Behavior

Service behavior describes what the service actually does. Behavior includes the algorithms that a service uses to achieve its purpose, such as wandering around without bumping into obstacles. Orchestration is a form of behavior. Behavior also includes simple functions such as returning the state when it is requested.

All services implement a certain minimum set of operations that are defined when you create a new service (as shown earlier in “Contracts”), so even an “empty” service has some behavior. An operation is a function that a service can perform. Operations are defined by the ports that represent them, and ports use particular classes (or data types) for their messages. This is discussed in more detail below.

This terminology gets a little messy. Sometimes operations are also referred to as requests or

responses — a request occurs when a message is sent to a service (using a specified data type associated with a port), and a response is sent back by the service (using another data type).

Note that operations are not required to send a response; it is up to you as the programmer to define whether or not a response is sent. At runtime, you can also set ResponsePort to null in the request — that is, you can explicitly say that you don’t want a response. DSSP uses TCP/IP or HTTP, both of which are reliable transports, so there is no need to acknowledge every message.

However, if you anticipate that a request might fail and you want to know about it, then you must specify a response port (and set up a receiver to read from the port) or set up a causality. Causalities are like structured exception handling on steroids. They allow exceptions that occur anywhere along the execution path of a message sequence to be posted back to a single port. These exceptions might even occur concurrently due to the multi-threaded nature of the CCR.

Internally, a service uses handlers to process operations. Handlers operate asynchronously and possibly in parallel. Most handlers are controlled by a CCR Interleave (called MainPortInterleave), which is created automatically for you. As shown in the previous chapter, the handlers attached to an interleave

91

www.it-ebooks.info

Part I: Robotics Developer Studio Fundamentals

can belong to the Exclusive or Concurrent groups (or the special case called TearDown, which is usually just for Drop messages).

Here is a handler for a Get operation that retrieves the state from a service:

///<summary>

///Get Handler

///</summary>

///<param name=”get”></param>

///<returns></returns> [ServiceHandler(ServiceHandlerBehavior.Concurrent)] public virtual IEnumerator<ITask> GetHandler(Get get)

{

get.ResponsePort.Post(_state); yield break;

}

This is a very simple handler — it just sends back a copy of the service state. It is annotated with the [ServiceHandler] attribute, which specifies that it belongs to the Concurrent group. This handler is allowed to execute simultaneously with other Concurrent handlers, but it is not allowed to execute while an Exclusive handler is running.

In effect, operations are the APIs that can be used to query and manipulate a service, e.g., retrieve (Get) or change (Replace, Update) the state. In a traditional programming environment, you link your code against a library of subroutines and use local procedure calls (the APIs for the library) to execute the functions in the library. In MRDS, operations are executed via SOAP requests, which means that they are similar to remote procedure calls and can therefore be executed on another computer anywhere in the network.

If an unhandled exception occurs during the execution of a handler, then DSS automatically creates a Fault and returns it as the response. However, if you are running the code in the debugger, it catches the exception and suspends execution. You can simply continue executing the code so DSS gets a chance to handle it.

Note that the contract is embodied in a Proxy DLL that is created automatically when you compile your service by a program called DssProxy. (Because .NET assemblies are self-describing, you can find out about the contract using reflection, but that is another topic.) You do not make calls directly to the service DLL; instead, you call routines with the same signatures in the Proxy DLL.

When you set up references to other services in Visual Studio, as a general rule you should always link to the Proxy DLL, rather than the service implementation DLL.

If you understand web services, then you know that parameters that are passed to and from services have to be marshaled, i.e., converted to a neutral format that both the client and the server understand. For web services, this format is XML. Because DSSP is based on SOAP, it also uses XML for requests over HTTP. However, for direct communication using TCP/IP, a binary serialization is used that is 10 to 20 times faster. (When you get to the “Running a DSS Node” section, you will see that two ports are specified when you start DSS: one for HTTP requests and one for direct TCP/IP connections.)

92