Beruflich Dokumente
Kultur Dokumente
Stinger CE Application Development Guide for
Microsoft Robotics Studio (MSRS)
Author: Jason Summerour
November 6, 2007
Contents
Introduction ...................................................................................................................................................................................... 3
Debugging Environment ................................................................................................................................................................... 4
Desktop Development Environment ............................................................................................................................................ 4
Windows CE Development Environment ..................................................................................................................................... 5
Microsoft Robotics Studio Services ................................................................................................................................................... 6
Serializer Services Installation ...................................................................................................................................................... 6
Starting a few Serializer Services ................................................................................................................................................. 8
Serializer Services Overview ...................................................................................................................................................... 13
Motor Control Example .............................................................................................................................................................. 15
Run It! ................................................................................................................................................................................... 22
Let’s Partner! ......................................................................................................................................................................... 22
Tick, Tick, Tick… ..................................................................................................................................................................... 23
Let’s talk about Geometry ..................................................................................................................................................... 26
Talking to yourself ..................................................................................................................... Error! Bookmark not defined.
Querying a Line Following Sensor .................................................................................................. Error! Bookmark not defined.
Organizing a Solution ................................................................................................................................................................. 32
Solving a Maze ............................................................................................................................... Error! Bookmark not defined.
Building an MSRS CF Project ........................................................................................................................................................... 33
COM Port Configuration ................................................................................................................................................................. 34
Auto Launch MSRS Services ....................................................................................................................................................... 36
Application Auto Launch ................................................................................................................................................................. 36
Introduction
This step‐by‐step guide teaches users how to develop sophisticated Microsoft Robotics Studio (MSRS) applications that leverage
our Serializer Services and Stinger CE Robotics Kit. By the end of the guide, you should feel comfortable building new
applications on top of the Serializer Services and Stinger CE Robotics Kit running under Windows CE 6.0.
More to come…
Requirements:
• Visual Studio 2005 Installed
• Microsoft Robotics Studio (MSRS) 1.5 framework installed
• A working knowledge of the MSRS framework (work thru tutorials)
• Development PC/Laptop
• Batteries
• Anything else ??
Debugging Environment
Debugging applications on the desktop is a great deal easier than debugging applications on an embedded system. Therefore,
this guide introduces the content by developing applications developed for the desktop under Windows XP. Once the
applications have been debugged on the desktop, they will be built for, configured for, and deployed under Windows CE. This
logical progression will save the user countless hours of debugging time, and makes the whole development experience a lot of
fun, which is the point!
This guide uses two scenarios for developing applications for the Stinger CE.
• Applications developed and debugged from a development machine under Windows XP.
• Applications developed on development machine, and deployed/ran under Windows CE 6.0 on the eBox‐2300
Desktop Development Environment
To begin with, you will be utilizing the desktop development environment pictured below. Now would be a good time to hook
up the hardware as shown in Figure 1.
Figure 1 ‐ Stinger CE Desktop/Debug Environment
While the diagram depicts the components in a loose configuration, it’s preferred that your Stinger CE be completely
assembled. Thus, all you will have to do is connect the Serializer to your Development Station using an RS‐232 Serial cable. If
your development station doesn’t have an RS‐232 port, you can use a USB to RS‐232 adapter cable, or you can purchase a USB
module from www.roboticsconnection.com and use a USB cable to connect directly to the Serializer.
Figure 2 – USB to RS‐232 Adapter Cable, and USB Module Direct Connection
Windows CE Development Environment
Once the applications have been debugged, we will move over to deploying and debugging applications on the eBox‐2300.
Figure 3 ‐ Stinger CE Windows CE Development/Debug Environment
Microsoft Robotics Studio Services
The Serializer Services provide an MSRS service based interface to the RoboticsConnection Serializer WL Robot Controller. This
allows customers to easily interface the MSRS framework with a plethora of ready to use robotic components (sensors, motors,
general purpose I/O, i2c, etc.) that interface with the Serializer. In this section, we’ll show you how to install and use the
Serializer Services with our Stinger CE robot, fitted with a basic set of sensors. Example after example, you will build a working
application that will allow your robot to follow a line. Eventually, you will be developing applications of your own.
This guide will not delve into the fine points of MSRS, and the inner workings. Rather, it will focus only on getting the Serializer
Services installed and working, and teach you how to develop orchestration services that leverage those services. You will have
to read through the MSRS User Documentation, and work through the Service Tutorials before continuing any further. That
way, you will have a better understanding of how MSRS Services work, as well as the terminology used. The best
documentation is included in the MSRS 1.5 installation, which includes HTML help files, as well as Service examples. You can
download the latest version of MSRS here:
http://www.microsoft.com/robotics
Serializer Services Installation
Let’s start by downloading and installing the Serializer Services for Microsoft Robotics Studio. At this point, you must have
MSRS 1.5 Installed on your development machine. You must also have Visual Studio 2005 installed on your machine (included
with the eBox‐2300 Jump Start Kit).
You can download our Serializer Services here:
http://www.roboticsconnection.com/t‐microsoftroboticsstudio.aspx
Once you have downloaded the latest Serializer Services zip file, follow these directions for installation:
1. Open the RoboticsConnection_Services_MSRS_1.5.zip file and extract the contents to the following directory:
C:\Microsoft Robotics Studio (1.5)\samples\Platforms
2. You should now have the following directories, with appropriate sub‐directories.
C:\Microsoft Robotics Studio (1.5)\samples\Platforms\RoboticsConnection\SerializerServices
C:\Microsoft Robotics Studio (1.5)\samples\Platforms\RoboticsConnection\TraxsterDriveService
3. Open Visual Studio 2005.
4. From the File‐>Open menu, navigate to Microsoft Robotics Studio (1.5)\samples\Platforms\RoboticsConnection
and double click the RoboticsConnection.sln file to load the Visual Studio solution containing the various projects that
make up the Serializer Services.
NOTE: For the purpose of this guide, you will not be able to utilize Visual Studio C# Express Edition, since it doesn’t
support the Compact Framework projects, “cf.SerializerServices”, required for this project.
5. This solution includes the TraxsterDriveService project, but we will not be using that for the purpose of this guide.
Before we can build the project, we’ll want to disable the TraxsterDriveService from being built. So, right click on the
RoboticsConnection solution in the Solution Explorer (top, right), and select Configuration Manager (see Figure 5 & 6
below). This will pop up the Configuration Manager dialog. Uncheck the checkbox in the build column for the
TraxsterDriveService.
Figure 4 ‐ Opening up the Configuration Manager
6. Now, build the project. The SerializerServices project should build first, followed by the cf.SerializerServices
project.
7. In case you aren’t aware, when you build the Serializer Services, three assemblies are created, and stored under
C:\Microsoft Robotics Studio (1.5)\bin.
• The main service (or implementation) assembly. For example, SerializerServices.dll – contains the
functionality of the service.
• The proxy assembly. For example, SerializerServices.proxy.dll – contains the stubs for all the public
interfaces for the service.
• The transform assembly. For example, SerializerServices.transform.dll – contains the code that allows
types to be converted between the proxy and the service assemblies.
Three assemblies are also created for the Compact Framework project, and stored under
C:\Microsoft Robotics Studio (1.5)\bin\CF.
• cf.SerializerServices.dll
• cf.SerializerServices.proxy.dll
• cf.SerializerServices.transform.dll
To send messages to another service, reference the service's proxy assembly rather than the implementation
assembly. This is done for a number of reasons: if you are communicating with a service on another node, you may
not have a copy of the implementation assembly on the local machine; also, by using proxies, the partner service does
not have any code that executes within the context of your service [Ref: MSRS Service Tutorial #5].
8. Copy all of the configuration xml files, which are used to load/save the initial service state, from:
C:\Microsoft RoboticsStudio(1.5)\samples\Platforms\RoboticsConnection\SerializerServices\Config
to:
C:\Microsoft Robotics Studio (1.5)\bin
When any of the Serializer Services start up, they will look in “C:\Microsoft Robotics Studio (1.5)\bin” for an xml file
containing their initial state. If found, the service will populate its initial state with the contents of the xml file. The
configuration files have been pre‐populated with a known working state. If you wish to modify the initial state of any
of the Serializer Services, modify these files.
9. We will want to modify the state of the SerializerServices.config.xml file to ensure that the COM port is properly
set for the Serializer Core Service. Since the Serializer Core Service is a Partner to all of the other Serializer Services, it
will always get started (if it isn’t already) when any one of the other Serializer Services starts.
Specifically, change the <ComPort> field to the appropriate COM port that your Serializer is connected to. You might
want to use Hyperterm to determine which serial port your local development machine is using to connect to the
Serializer. If you’re using a direct serial connection, it will probably be COM1 or COM2, but if you’re using a USB to
Serial converter, it may be different. When you determine which port to use, just enter the number of the port, and
drop the ‘COM’ prefix.
<?xml version="1.0" encoding="utf‐8"?>
<State xmlns:s="http://www.w3.org/2003/05/soap‐envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:d="http://schemas.microsoft.com/xw/2004/10/dssp.html"
xmlns="http://www.roboticsconnection.com/2006/08/Serializer.html">
<TimeStamp>0001‐01‐01T00:00:00</TimeStamp>
<ComPort>1</ComPort>
<BaudRate>19200</BaudRate>
<Version>Not initialized</Version>
<Units>English</Units>
<IsConnected>false</IsConnected>
<InteractiveHistory />
</State
10. Make sure you save the SerializerServices.config.xml file.
Starting a few Serializer Services
Now that we have successfully built the Serializer services, and put the initial state configuration files in place, let’s start up a
few services. For now, we’re just going to start the services on the local development computer. Later, we will start them up
under Windows CE on the eBox‐2300.
Start a new DSS Node via Start‐>All Programs‐>Microsoft Robotics Studio (1.5)‐>Run DssNode. A command window, as well as
a web browser should pop up (or another tab should appear within your browser) and you should see the Robotics Studio Web
Panel as shown below. Note the URL specified at the top of the browser (http://localhost:50000), which informs us that the
DSSNode was started up on the local development machine, and it is communicating over port 50000.
Figure 5 ‐ Robotics Studio Web Panel
Under System Services in the left hand pane, select ‘Control Panel’. This will bring up a list of services which are available to use
on the current DSS Node. If you scroll down, you’ll see all of the Serializer Services listed.
Let’s start up a ‘LineSensor Service’ by selecting the ‘Create’ button to the right of the highlighted service (NOTE: The
highlighted ‘Serializer Core Services’ will automatically get started since it’s a Partner of the LineSensor Service). Don’t worry
about specifying a manifest at this point, since the services know which partners to rely on.
Figure 6 ‐ Robotics Studio Service Control Panel
Now, select the ‘Service Directory’ web page from the left hand pane. This will bring up the Service Instance Directory,
displaying the instances of services currently running.
You should see highlighted ‘/linesensorservice’ and ‘/serializer’ instances listed in the right hand pane. This means that the
services were started up properly. If you do not see these service instances listed, click on the ‘Debug and Trace Messages’ to
figure out why the services didn’t start.
Figure 7 ‐ Service Instance Directory
Now if you click on the /serializer link, a web page, displaying the current state of the Serializer, will display in the browser.
You might think “Wow!”, the Serializer state has a nice web interface. This is because the state, which is stored in xml (as you
saw a few steps ago), has been transformed from xml to html using an XSLT stylesheet (see MSRS Service Tutorial #6). Had a
stylesheet not been applied, you would see the state displaying in raw xml (identical to that stored in the configuration files).
You will notice that not only is the state provided, but there are a few controls as well. The controls allow you to change the
COM port, as well as type in any Serializer command you wish, and send it directly. Once you type a command, it is saved in
History, for you to use again. This is a very useful debugging facility, so remember that it’s available.
Rather than changing the SerializerServices.config.xml file, we could have waited until now to change the COM port; however,
it will prove beneficial later when we start developing orchestration services.
The status displayed on the page tells you if the Serializer Core service was able to connect with the Serializer board. In the
picture below, it was unable to connect. Once a connection is made, the status will change to ‘Connected’, and the latest
version of the Serializer firmware will be displayed.
Figure 8 ‐ Serializer Core Service State
Now let’s navigate back to the Service Instance Directory page, and click on the /linesensorservice link. This will bring up a web
page containing the LineSensor service state, rendered in pretty html, featuring a few user controls.
Figure 9 ‐ LineSensor Service State
You can set the value of I2CAddress, and UpdateFrequency state members by entering their values in the text boxes, and
clicking ‘Update’. These values will be used the next time the Line Sensor is queried.
Once a Serializer Core Service connects to an actual Serializer with a Line Sensor attached, you can move a white/black line in
front of the sensor, hit ‘Refresh Page’ at the bottom of the browser page, and you will see the circles update to reflect the
values that the sensor sees. If the Serializer cannot communicate with the Line Sensor (e.g. incorrect address), then the circles
will be red, indicating it wasn’t able to query the values.
Before we go and develop an orchestration service to leverage the Serializer Services, let’s talk about how the Serializer
Services are structured in the next section.
Serializer Services Overview
While it isn’t necessary for you to fully understand the internal workings of the Serializer Services, it would be good to have a
basic understanding of how they work. This will also help you debug problems that arise going forward.
The Serializer Services were written as a collection of separate services that allow users to pick and choose from the
functionality supported by the Serializer, À la carte.
The following services are currently included in the Serializer Services:
• Serializer Core* (required by all subsequent services)
• Gpio (General Purpose I/O)
• Motor (Pwm Motor Control)
• Pid (Proportional Integral Derivative Motor Control)
• AirTemp Sensor
• Cmps03 Sensor
• Encoder Sensor (Wheel encoders)
• Gp2d12 Sensor (Infrared Distance Sensor)
• Gp2d120 Sensor (Infrared Distance Sensor)
• Line Sensor
• Maxez1 (Sonar Distance Sensor)
• SRF08 (Sonar Distance Sensor)
• Tpa81 (Temperature Sensor)
• Servo
The Serializer Core service is the only service which communicates with the Serializer board directly, via a serial port. All other
Serializer Services (e.g. PID, Line Sensor, etc.) require the use of the Serializer Core service, as a Partner, to communicate w/ the
physical Serializer board.
The Serializer Core service exposes the ‘Execute’ operation, which is called by the other Serializer services (e.g. PID, Line Sensor,
etc.) to send a command to the Serializer board. Once the response is received, it is posted back to the original service invoking
the operation.
To better understand how this is accomplished study the diagram below, where a Line Sensor service sends a command to the
Serializer Core Service, which then sends it to the Serializer board. The Serializer then queries the Line Sensor, and returns its
current value back. The Serializer Core service receives the response, and then sends it back to the Line Sensor service, which is
then stored in its internal state.
6 4
‘00100’ ‘line 80’
Line Sensor
5
I2C Protocol
Serializer
Line
Figure 10 ‐ A day in the life of a typical MSRS Serializer Message
1. The LineSensor’s TimerHandler() is invoked over the TimerPort at a specified UpdateFrequency (Timeout interval)
2. TimerHandler() creates an Execute message, containing the appropriate command (‘line 80’ in this case), and posts
the message to the Serializer Service.
3. The SerializerService has ExecuteHandler() wired so that it will handle Execute messages as they come in over the
main port.
4. ExecuteHandler() takes the command in the Execute message, in this case it is ‘line 80’, and sends it over the Serial
Port to the Serializer.
5. The Serializer receives the ‘line 80’ command, and then queries the actual Line Sensor at I2C address 80 for its current
status.
6. The Serializer sends the Line Sensor status back out the Serial port, which is then received by the ExecuteHandler().
7. ExecuteHandler() then posts the response string, via a Response message, back to the Line Sensor Service.
8. HandleResponse() receives the response message and parses the response string to ensure it’s properly formatted.
9. HandleResponse() saves the status to the service State.
10. Other services can now query the Line Sensor service to obtain the latest state/status.
All Serializer services follow a similar sequence of steps, so you should now be able to look at the code understand how each
service operates internally. For example, the SRF08 service periodically sends the appropriate command to query an SRF08
Sonar Sensor connected to the Serializer, at a specified address. On the other hand, a GPIO service might send a command to
the Serializer to set and I/O line from 0 to 1, triggered by a message sent from an orchestration service when a user pressed a
button.
Now that you have a basic understanding of how the Serializer services interact w/ the Serializer board, let’s start developing an
MSRS service application.
Motor Control Example
Let’s start by writing a fun application that can make the Stinger drive around, a specified distance, using the PID (Motor
Control) Service. The Serializer has built in Velocity and Distance PID algorithms that allow you to easily command a motor and
encoder combo to maintain the specified velocity as well as travel the specified distance exactly. The PID Service serves as an
interface to that functionality.
Start by creating a new Simple Dss Service project under C:\Microsoft Robotics Studio
(1.5)\samples\Platforms\RoboticsConnection as shown below. Let’s call the project ‘StingerCEApp’.
Figure 11 ‐ Creating a new StingerCEApp Dss Service Project
Now, we need to add in a reference to the Serializer Services. Right click on ‘References’, then select ‘Add Reference’. An Add
Reference Dialog will appear, and you will need to scroll down to the ‘SerializerServices.Y2006.M08.Proxy’ Component Name,
and select it. If you do not see the SerializerServices.Y2006.M08.Proxy, then you probably haven’t built the SerializerServices.
Figure 12 ‐ Add Reference
Figure 13 ‐ Adding SerializerServices.Y2006.M08.Proxy dll
The SerializerServices.Y2006.M08.Proxy will appear under the list of References as shown.
Figure 14 ‐ SerializerServices.Y2006.M08.Proxy added to References
Since we’re interested in invoking the public interfaces provided by the SerializerServices, we can just add the
SerializerServices.Y2006.M08.Proxy assembly.
Finally, select the SerializerServices.Y2006.M08.Proxy assembly in the Solution Explorer and set the Copy Local and Specific
Version fields to False under the Properties Window (lower right).
Before we continue, let’s attempt to build the solution and ensure that everything is wired up properly. From the Visual Studio
menu, select ‘Build’‐>’Build Solution’, or simply press ‘F7’. You should get a successful build, but if not, make sure your
references are set up correctly.
Before we add any code, let’s talk about how this application will work. The diagram below depicts the basic communication
path that our StingerCEApp will use to control the motors using the PIDService. As you can see, there is a Timer set up in
StingerCEApp, which will periodically send a ‘SetDistancesRequest’ to the PIDService. The PIDService, in turn, sends an Execute
message (containing a ‘digo’ command) to the Serializer. The Serializer then executes the command, sets the motors to the
desired speed, and measures the encoder ticks to ensure that the robot travels the exact distance specified.
Please note that the Serializer will immediately return an ‘ACK’ (if all params were correct), and doesn’t wait on the internal PID
action to finish. We provided a ‘pids’ command that can be used to query the state of the PID action, to determine when it has
completed. It will return 0 if finished, and 1 if it’s busy.
Notice the call to ‘SetDistancesRequest’. The ‘Distances’ refers to the ability to set distance and speed for both motors. There
are also other PID Service operations which can control the distance to a single motor. Likewise, there are operations available
to control the speed of one or both motors, such as ‘SetVelocityRequest’, and ‘SetVelocitiesRequest’, respectively.
Furthermore, the PIDService provides operations to configure the PID Distance and Velocity parameters. However, the default
PID parameters that work with the Stinger CE robot are already stored in the Serializer by default, and the PID Service uses
these default values. The PID parameters are listed below in the PID Service state. While we won’t cover using these
operations in this guide, sending messages to configure those properties is similar to sending any other message, and you can
learn about their exact signatures by perusing the PID Service source code included in the Serializer Services solution you
previously installed.
Lastly, the PID Service will send a response back to the StingerCEApp, indicating if the call was a success or failure.
Figure 15 ‐ StingerCEApp Motor Control Diagram
Now that we have a clear understanding of how the StingerCEApp will operate, we can start coding. We’ll start by adding a few
using statements, so that we can use the Serializer Services. Open StingerCEApp.cs file from the Solution Explorer. Add the
following using statements:
Figure 16 ‐ Adding the proper namespaces
Next, let’s create a new file that we’ll use to store only the state definition in. Right click the StingerCEApp project in the
Solution Explorer, then select ‘Add’, then ‘New Item’. In the Add New Item dialog, select ‘C# Class’, then name the new class
StingerCEAppState.cs. Click ‘Add’ to complete the process.
Figure 17 ‐ Adding a new StingerCEAppState class
You should now see the StingerCEAppState.cs file in the Solution Explorer in the right hand pane. Double click it to open the
file. Also, open up StingerCEAppTypes.cs.
Figure 18 ‐ Open up StingerCEAppState.cs and StingerCEAppTypes.cs
Now, cut the Contract and StingerCEApp classes (highlighted below in blue) from StingerCEAppTypes.cs, and paste them in
StingerCEState.cs. We’re doing this so that these classes will be contained in a separate state file for ease of use.
Figure 19 ‐ Cut the Contract and State from StingerCEAppTypes.cs, and paste into StingerCEAppState.cs
Also, add the namespace ‘Microsoft.Dss.Core.Attributes’ to the StingerCEAppState.cs file as shown below. This is needed for
the [DataContract()] attribute, which specifies that the StingerCEAppState class is XML serializable. We also renamed the
Contract Identifier to use ‘www.roboticsconnection.com’ in the url. Your StingerCEAppState.cs file should now look like the one
below.
Figure 20 ‐ Adding Microsoft.Dss.Core.Attributes namespace & updating the Contract Identifier
From the Solution Explorer pane, open the StingerCEApp.manifest.xml file, and change the value of the <dssp:Contract>
element to reflect the updated URL set for the Contract Identifier above (http://www.roboticsconnection.com/2007/11/stingerceapp.html)
Figure 21 ‐ StingerCEApp.manifest.xml
Now, let’s add a few members to the state (in StingerCEAppState.cs), which will be used to keep track of the drive modes.
First, add an enumeration, called DriveModes, which will consist of ‘Straight’ and ‘TurnRight’. Then add a DriveMode property,
which will be used to keep track of which mode this service is currently operating under. Don’t forget to adorn the enum and
and DriveMode classes with the proper [DataContract] and [DataMember] attributes, so that they can be properly serialized!
Figure 22 ‐ Adding DriveMode State members
It is a good time to hit ‘F7’ and build your project to ensure that it still builds okay.
Since the StingerCEApp will be serving more in an orchestration role, we shouldn’t need to add too many new message
interfaces for external services. However, we’ll definitely want to add HttpGet message. This is because later, we’ll want to
retrieve the StingerCEApp’s state in a serialized xml format from a browser. Furthermore, we’ll be able to apply a stylesheet to
the xmlified state, and render it using HTML.
In the file StingerCETypes.cs, let’s add an HTTPGet message to the list of messages supported by the StingerCEApp’s service
port. Also, add the namespace ‘Microsoft.Dss.Core.DsspHttp’.
Figure 23 ‐ Adding HttpGet to the list of messages to service
A port is a mechanism through which messages are communicated between services. A PortSet is just a
collection of ports.
Now open StingerCEApp.cs, and add in the namespace ‘Microsoft.Dss.Core.DsspHttp’ at the top of the file. Now, add an
HttpGet handler in there to handle incoming HttpGet requests as shown.
Figure 24 ‐ Adding an HttpGet message handler
This handler sends an HttpResponseType message to the response port of the HttpGet message. The HTTP
infrastructure within the DSS node will serialize the provided state to XML and set that as the body of response to the
HTTP request.
Run It!
Now, let’s build the application again, and run it, by pressing ‘F5’. While it’s running, open up a web browser, and navigate to
http://localhost:50000/StingerCEApp. You should see the serialized state represented in the browser.
Figure 25 ‐ Viewing StingerCEApp state in a browser
Let’s Partner!
Now we need partner up with the SerializerServices. This will allow the StingerCEApp to invoke all of the SerializerService’s
interfaces, and use the underlying Serializer controller.
Start by adding the following snippet (highlighted in yellow) in the StingerCEAppService class (StingerCEApp.cs) just after the
_mainPort creation as shown below. This will create a port that will allow us to invoke the PIDMotor interface.
Figure 26 ‐ Adding a PID service Partner
Notice how the port creations are wrapped with a “#region PORT INITIALIZATION” and “#endregion”. This isn’t
required, but I suggest you make liberal use of them. It will allow you to expand and collapse portions of your code
down using the ‘+’, ‘‐‘ blocks on the left of the Visual Studio code window. The SerializerServices have regions for
Enums, State & Internal Objects, Port Initializataion, Constructors, Message Handler Mapping, Message Handlers,
Internal Message Handlers, Timer Message Handlers, Http Message Handlers, Subscriptions, and Helper Functions.
By specifying that the StingerCEApp needs the PID service as a partner, and specifying a CreationPolicy of ‘UseExistingOrCreate’,
then when the StingerCEApp starts up, the PID Service will be started automatically, if it hasn’t already been started. So, this is
a way to programmatically specify your required partners for the StingerCEApp service. Likewise, all of the various Serializer
Services (e.g. PID, GP2D120, LineFollowing, etc.) all specify the SerializerCore service as a partner. So anytime one of the
Serializer Services are started, the SerializerCore services is also started, again if it hasn’t been already.
So, now we have a port to send messages to the PID Service. Before we do so, let’s set up timing loop that will allow us to
periodically run through a sequence of steps (drive steps) to make the Stinger CE perform some basic driving.
Tick, Tick, Tick…
Since we will want to run through a sequence of steps to make the Stinger CE drive around, we’ll need some way to periodically
run through the list. We can set up a periodic loop using a TimeoutPort as shown below. Basically, StartTimer() will be called
using a delay (in milliseconds). The Arbiter.Receive() method defines a one‐time receiver that will take the message sent when
the timer interval specified in the call to TimeoutPort expires and passes it as the parameter to the anonymous delegate
specified as the third parameter to Arbiter.Receive(), which is TimerHandler().
Once the timing delay has been reached, TimerHandler() will be invoked. We can then perform whatever we like within the
handler, and before finishing, StartTimer() needs to be called again.
Note that the TimeoutPort receiver is not persistent, since the first parameter is false. This is because the port created by the
TimeoutPort() method receives one message after the specified interval (in this case 1000 milliseconds) expires.
Figure 27 ‐ Adding Timer Methods
Now, we need to invoke StartTimer() to kick off the timing loop. We can do that in the call to Start(), which was automatically
added to StingerCEApp.cs when we generated the DSS application.
Figure 28 ‐ Adding StartTimer() within Start()
We’re almost ready to test the Timer handler, but first we need to add a bit of configuration entries to the
StingerCEApp.manifest.xml. Basically, we want to add an entry that will allow us to specify the configuration file to use to
configure the SerializerCore Service. Specifically, we want to be able to configure the Baud Rate and COM Port.
To do this, add a new namespace (xmlns:StingerCE), and a <ServiceRecordType> entry as shown below. This basically says, use
the SerializerServices.Config.xml file, at http://localhost/mountpoint/bin/SerializerServices.Config.xml to configure the state of
the SerializerCore service. The http://localhost/mountpoint resolves to C:\Microsoft Robotics Studio (1.5)\.
Notice that the <dssp:Contract> points to the contract defined in the SerializerTypes.cs file.
Figure 29 ‐ Adding Serializer Configuration to the Manifest
Now, we should be set to start up the service, and see the tick() message print to the screen every 1000msec. So, go ahead and
start up the service. If you see errors at runtime, you might not have copied the configuration files to C:\Microsoft Robotics
Studio (1.5)\bin directory as we did earlier in this guide.
Figure 30 ‐ Console output of StingerCEApp service showing TickHandler() working
Now let’s go to the browser, and see what services have been started. Using the url: http://localhost:50000/directory, you will
see a list of services currently running on the DSS node. As you can see, the stingerceapp is running, which used the pidservice
as a partner, so it started up. The pidservice needed the serializer as a partner, so it was started too. Note: The Service
Instance names shown below are specified in the ServicePort definition for the main port within that service. It’s a string, so
you can call it whatever you like.
Figure 31 ‐ Service Instances currently running
Another interesting thing to look at is the /manifestloaderclient. It’s responsible for loading the manifest specified, and
resolving the information within it. Click on /manifestloaderclient, and you will see that it loaded the manifest specified by the
StingerCEApp properties (Debug tab‐>Start Options), as well as loaded the appropriate SerializerServices.Config.xml, which has
our COM Port and Baud Rate configurations it in.
Figure 32 ‐ Manifest Loader CLient
Let’s talk about Geometry
So, now that we know our periodic loop works, we can *finally* add a sequence of steps that invoke the PIDService interfaces
to control the motors.
It would make sense to create some functions that can be used to make the robot travel for a specified distance, at a specified
velocity. Those functions would create the appropriate PID messages, and send them to the PIDService. You could add a
function to make the robot travel in a straight line, rotate, arc, etc. So, let’s create some Helper functions to do just that.
We’ll need to know some geometrical data about the Stinger, so that we can translate ticks fed back from the encoders, to
distances traveled by the robot, based on wheel diameters. The unloaded wheel diameter of the Stinger is 2.26”. However,
once weight is applied to the wheels, as in a driving position, the foam wheels compress a little bit, and the Effective Diameter
is about 0.010” less. So, let’s plan on the Effective Wheel Diameter being 2.25”. This would make the Circumference about
7.068”. Thus, one wheel revolution means the Stinger travels 7.068”. The built in quadrature wheel encoders provide 624
pulses per shaft (or wheel) revolution. This means you have about 0.011” of linear resolution per tick. Not too bad! ☺
Another way to look at it is that you get about 88 ticks/inch.
Now, if we know the distance we want to travel, we can multiply that by 88 ticks/inch, to arrive at the number of ticks we need
to provide to the PIDService.
Encoder Resolution: 624 Ticks/Rev
Wheel Diameter = 2.25" Circumference
(Pi x Diameter)
7.086"
TRACK
8.69“ Rotational Diameter
Rotational Pivot Point
Figure 33 ‐ Stinger Wheel Geometry
Since this is a specific attribute for the Stinger, it doesn’t make sense for the PIDService to have a TicksPerInch property.
Rather, it belongs in a service specific to the Stinger. Thus, let’s add a TicksPerInch state property, which we will used in the
helper functions to calculate the number of ticks required to travel based on given distances.
We also need to know the track distance between the centers of the Stinger drive wheels. This will be important when we
want to calculate how many ticks it will take to rotate X number of degrees. The Stinger track distance is approximately 8.69
inches. The Stinger pivots about an instant center exactly between its two wheels. That means the rotational diameter is
8.69”, and a rotational circumference would be 27.29”.
Thus, if we want to calculate how many ticks it takes to rotate an X number of degrees, then we can:
Ticks = ((number of desired degrees / 360) x 27.29) x TicksPerInch NOTE: (1 <= degrees <= 360)
For example, let’s say we want to rotate 180 degrees:
Ticks = ((180 / 360) x 27.29) x 88
Ticks = 1200
Each wheel would then need to rotate that distance, in opposing directions, to achieve the desired amount of rotation.
That’s all great, theoretically; however, in the real world, uneven surfaces, varying motor speeds, and friction affect the amount
of degrees that the Stinger will actually rotate. So, don’t be surprised if the Stinger overshoots, or undershoots the target
rotation amount. The biggest factor that affects the outcome of the calculation is the Rotational Diameter. So, you can tweak
that somewhat to get a better result.
Okay, now it’s time to implement all of this information in our service. Let’s start by adding a few new State properties based
on the geometrical data we just calculated, as shown below. We need to add TicksPerInch, WheelTrack, and
RotationalDiameter. Notice that the RotationalDiameter is automatically set when the Wheel Track property changes, and that
you can query its value directly, but not set it. These state members will come in handy for calculating ticks based of off
distances in the helper functions.
Figure 34 ‐ Adding Geometrical State Members to StingerCEAppState
Now, let’s start adding those helper functions in the StingerCEAppService class. We need functions to allow use to set single
and dual PID motor velocities and distances. Being able to set PID Motor velocities and speeds atomically is important, since
we’ll want both motors to start simultaneously, hence the need for dual PID motor velocity and distance control. We’ll also
want some simple drive functions to allow us to drive in a straight line, and rotate. The following helper functions achieve
these requirements.
Figure 35 ‐ DoPidDistance() helper function
Figure 36 ‐DoDualPidDistance() helper function
Figure 37 ‐ DoPidVelocity() helper function
Figure 38 ‐ DoDualPidVelocity() helper function
Figure 39 ‐ DoStopAll() helper function
Figure 40 ‐ GoStraight(), RotateRight(), and RotateLeft() helper functions
Now that we have helper functions available to do the PID messaging for us, let’s add some logic to the TimerHandler() method
to invoke those functions. We can also use the DriveMode state member to run through alternating drive sequences to make
the robot drive in a square. As you can see below, the logic alternates between driving straight, and turning 90 degrees to the
right, creating a square driving path.
Figure 41 ‐ Adding logic in TimerHandler() to invoke driving methods
Now build the application, and resolve any errors that may have been introduced. For testing, we inserted a Serializer
Bluetooth module in the Serializer (with an BT Antenna), to have an untethered serial connection to our development machine
(fitted w/ a Bluetooth radio). You can choose to purchase a Serializer Bluetooth module for debugging, or you can just use
some long USB or Serial Cables until we get this application running under CE on the eBox‐2300. You can also sit your Stinger
Robot upside down on a box, for testing (which is fine for now).
Just for kits, let’s view the StingerCEApp service state again, by navigating to http://localhost:50000/StingerCEApp in a browser.
You’ll see that you can now view the additional state properties we added.
Figure 42 ‐ Viewing StingerCEApp State
User Input/Output
Now that we have had a taste for interfacing one of the Serializer Services, let’s interface another. Let’s add the ability to
communicate w/ the Stinger CE robot. The Stinger CE includes a Push Button I/O (PBIO) board that can be used Input/Output
to/from the robot. The PBIO is connected to the Serializer’s I/O header pins. Thus, we’re going to integrate the GPIO (General
Purpose I/O) service to allow us to query the state of the Push Buttons on the PBIO board, as well as twiddle the PBIO LEDs, and
operate the buzzer.
Additionally, we’re going to want to create a simple state machine, which represents the current Operating State of the service.
Let’s have three states: Start, Running, and Waiting. The service will initially enter the Start state. While briefly here, it will use
the buzzer to beep once to indicate that the Service has fully started, and that the robot is ready to perform some tasks. It will
then automatically enter the Waiting state (never to return to the Start state again). It will remain in the Waiting state until a
user presses a button on the PBIO board. Once this occurs, the StingerCEApp will go into the Running state, and one of the
PBIO LEDs will be lit. If the user presses the same button again, the Operating mode will return to the Waiting state, and the
LED will turn off.
This will give us some useful interaction with the robot, and allow us to debug services going forward.
Figure 43 ‐ StingerCEApp Operating States
Now let’s start implementing this state machine. First, let’s define the operating states within the service. We’ll do that using
an Enumeration in the main Service class.
Figure 44 ‐ Operating State Enumeration
Foo
Bar
Bam
Following a line
Now that we have had a taste for interfacing one of the Serializer Services, let’s interface another. This time, we’re going to
interface the LineSensor service to follow a line through a maze. We’ll add the logic to follow the line in the StingerCEApp
service.
Solving a Maze
Now that we have had a taste for interfacing one of the Serializer Services, let’s interface another. However, we’re going to
create a brand new service yet again. We’ll develop a stand‐alone service, which can solve a maze. Why not just build on the
service we just wrote? Because a service which can solve a maze could be very useful to others, and it makes sense to
encapsulate that functionality into a single service, and make reusable.
We will use the maze solving service….
Organizing a Solution
Before we go off and start creating several projects to perform various tasks, let’s create a common Visual Studio Solution that
will encompass all projects, and keep them in an organized place. This will make it easier to refer back to each project as we
progress through developing more sophisticated services.
Start up Visual Studio 2005, and go to File‐>New‐>Project. A New Project dialog box will appear. Under ‘Other Projects’, select
‘Visual Studio Solutions’, and then highlight ‘Blank Solution’. Name the Solution ‘Stinger CE’ in the Name field, and then click on
the ‘Browse’ button, and navigate to:
C:\Microsoft Robotics Studio (1.5)\samples\Platforms\RoboticsConnection
To set the Solution location:
Finish by clicking the ‘Ok’ button. A new, empty solution, called StingerCE, will appear.
Now, we can add the previous LineFollowing project, and other projects as we go along for the various experiments, and have
them located in one solution.
Building an MSRS CF Project
Show how to create a MRS CF project
COM Port Configuration
Before we can develop any applications for Windows CE, we have to ensure that the eBox‐2300s onboard serial port is
configured properly. Even though you have created and launched working CE image, you still have to create a Serial
Connection under CE. You can do this by following the procedure below:
1. From the CE 6.0 Desktop, select ‘Settings’, and ‘Network and Dial‐up Connections’ as shown below:
2. Within the window that pops up, double click on ‘Make New Connection’.
3. Type in ‘COM1’ to name the port, and select ‘Direct Connection’.
4. A Device dialog box will appear. Within the drop‐down list, select ‘Serial Cable on COM1:’. Then, click on the
‘Configure’ button.
5. The Device Properties dialog box will appear. Ensure that the Baud Rate, Data Bits, Parity, Stop Bits, and Flow Control
match those in the image below. Select ‘OK’, to close the dialog, then click ‘Finish’ on the previous dialog.
6. Now, we need to ensure that these settings get persisted after a reboot. To do this, simply select ‘Start’, and then
‘Suspend’. The screen will go black. Now, press a key on the keyboard to bring the Desktop back. Your serial
configuration has now been saved, and will persist a reboot.
Auto Launch MSRS Services
We will show you how to auto launch an MSRS Service.
Application Auto Launch
Now that we have a working application, let’s work on getting it automatically launched at boot time. This actually pretty easy,
and it can be accomplished in a few steps.
1. Start by navigating to the SerialCommTest directory under “\Program Files” by right clicking on “My Device” on the
desktop, and selecting ‘Open’, and then navigate to the directory in Windows Explorer as shown.
2. Right click on the “SerialCommTest.exe” application, and select ‘Copy’ as shown above.
3. Navigate to the \Windows\Startup folder, and right click the folder to bring up the dialog box as shown below. Select
‘Paste Shortcut’ to save the shortcut to this folder.
4. You should now see the shortcut in the folder, called “Shortcut to SerialCommTest.lnk”. Right click on the shortcut,
and select “Properties”.
5. The following dialog box will appear. Click on the ‘Shortcut’ tab. You should now see the ‘Target’ properties. Verify
that it looks correct.
6. To ensure that this shortcut gets persisted to disk, let’s go to ‘Start’, then, select ‘Suspend’. Once the screen goes
black, strike any key on the keyboard to bring the desktop back up.
7. The SerialCommTest application is now set up to launch at boot time, so let’s test it. Turn off the eBox‐2300, and
then turn it back on. After the Desktop appears, you should see the SerialCommText application launch after a few
seconds. If it does not, then something in the ‘Target’ property link for the Shortcut is probably incorrect (e.g. missing
or misplaced quotes). There are a few tricks to launching MSRS services, which we’ll cover in the next chapter.