<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9 - Entries tagged with Phidgets</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Tags/phidgets/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9 - Entries tagged with Phidgets</title>
      <link>http://channel9.msdn.com/Tags/phidgets</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Tags/phidgets</link>
    <language>en</language>
    <pubDate>Wed, 19 Jun 2013 05:17:03 GMT</pubDate>
    <lastBuildDate>Wed, 19 Jun 2013 05:17:03 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>3</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Boxing Bots: An Overview</title>
      <description><![CDATA[<h2>Introduction</h2><p>In early January, we were tasked with creating a unique, interactive experience for the <a href="http://sxsw.com/interactive">SXSW Interactive</a> launch party with <a href="http://www.frogdesign.com/">Frog Design</a>. We bounced around many ideas, and finally settled on a project that Rick suggested during our first meeting: boxing robots controlled via Kinect.</p><p>The theme of the opening party was Retro Gaming, so we figured creating a life size version of a classic tabletop boxing game mashed up with a &quot;Real Steel&quot;-inspired Kinect experience would be a perfect fit. Most importantly, since this was going to be the first big project of the new Coding4Fun team, we wanted to push ourselves to create an experience that needed each of us to bring our unique blend of hardware, software, and interaction magic to the table under an aggressively tight deadline.</p><h2>Hardware</h2><p>The BoxingBots had to be fit a few requirements:</p><ol><li>They had to be fun </li><li>They had to survive for 4 hours, the length of the SXSW opening party </li><li>Each robot had to punch for 90 seconds at a time, the length of a round </li><li>They had to be life-size </li><li>They had to be Kinect-drivable </li><li>They had to be built, shipped, and reassembled for SXSW </li></ol><p>Creating a robot that could be beaten up for 4 hours and still work proved to be an interesting problem. After doing some research on different configurations and styles, it was decided we should leverage a prior project to get a jump start to meet the deadline. We repurposed sections of our Kinect drivable lounge chair, <a href="http://channel9.msdn.com/coding4fun/articles/Jellybean-the-Kinect-Drivable-Lounge-Chair">Jellybean</a>! This was an advantage because it contained many known items, such as the motors, motor controllers, and chassis material.&nbsp; Additionally, it was strong and fast, it was modular, and the code to drive it was already written.</p><p>Jellybean would only get us part of the way there, however.&nbsp; We also had to do some retrofitting to get it to work for our new project. The footprint of the base needed to shrink from 32x50 inches to 32x35 inches, while still allowing space to contain all of the original batteries, wheels, motors, motor controllers, switches, voltage adapters. We also had to change how the motors were mounted with this new layout, as well as provide for a way to easily &quot;hot swap&quot; the batteries out during the event. Finally, we had to mount an upper body section that looked somewhat human, complete with a head and punching arms.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0087%5B4%5D.jpg"><img title="IMG_0087" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0087_thumb%5B1%5D.jpg" alt="IMG_0087" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0089%5B9%5D.jpg"><img title="IMG_0089" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0089_thumb%5B4%5D.jpg" alt="IMG_0089" width="240" height="180" border="0"></a><br><strong>Experimenting with possible layouts</strong></p><p>The upper body had its own challenges, as it had to support a ton of equipment, including:</p><ul><li>Punching arms </li><li>Popping head </li><li>Pneumatic valves </li><li>Air manifold </li><li>Air Tank(s) </li><li>Laptop </li><li>Phidget interface board </li><li>Phidget relay boards </li><li>Phidget LED board </li><li>Xbox wireless controller PC transmitter / receiver </li><li>Chest plate </li><li>LEDs </li><li>Sensors to detect a punch </li></ul><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0113%5B5%5D.jpg"><img title="IMG_0113" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0113_thumb%5B2%5D.jpg" alt="IMG_0113" width="500" height="667" border="0"></a><br><strong>Brian and Rick put together one of the upper frames</strong></p><h3>Punching and Air Tanks</h3><p>We had to solve the problem of getting each robot to punch hard enough to register a hit on the opponent bot while not breaking the opponent bot (or itself). Bots also had to withstand a bit of side load in case the arms got tangled or took a side blow. Pneumatic actuators provided us with a lot of flexibility over hydraulics or an electrical solution since they are fast, come in tons of variations, won't break when met with resistance, and can fine tuned with a few onsite adjustments.</p><p>To provide power to the actuators, the robots had two 2.5 gallon tanks pressurized to 150psi, with the actuators punching at ~70psi.&nbsp; We could punch for about five 90-second rounds before needing to re-pressurize the tanks.&nbsp; Pressurizing the onboard tanks was taken care of by a pair of off-the-shelf DeWalt air compressors.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0134%5B4%5D.jpg"><img title="IMG_0134" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0134_thumb%5B1%5D.jpg" alt="IMG_0134" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0184%5B4%5D.jpg"><img title="IMG_0184" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0184_thumb%5B1%5D.jpg" alt="IMG_0184" width="240" height="180" border="0"></a><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0279%5B4%5D.jpg"><img title="IMG_0279" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0279_thumb%5B1%5D.jpg" alt="IMG_0279" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0172%5B4%5D.jpg"><img title="IMG_0172" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0172_thumb%5B1%5D.jpg" alt="IMG_0172" width="240" height="180" border="0"></a></p><h3>The Head</h3><p>It wouldn’t be a polished game if the head didn’t pop up on the losing bot, so we added another pneumatic actuator to raise and lower the head, and some extra red and blue LEDs. This pneumatic is housed in the chest of the robot and is triggered only when the game has ended.</p><p>To create the head, we first prototyped a concept with cardboard and duct tape. A rotated welding mask just happened to provide the shape we were going for on the crown, and we crafted each custom jaw with a laser cutter.&nbsp; We considered using a mold and vacuum forming to create something a bit more custom, but had to scrap the idea due to time constraints.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0169%5B4%5D.jpg"><img title="IMG_0169" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0169_thumb%5B1%5D.jpg" alt="IMG_0169" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0201%5B4%5D.jpg"><img title="IMG_0201" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0201_thumb%5B1%5D.jpg" alt="IMG_0201" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0268%5B4%5D.jpg"><img title="IMG_0268" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0268_thumb%5B1%5D.jpg" alt="IMG_0268" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0291%5B4%5D.jpg"><img title="IMG_0291" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0291_thumb%5B1%5D.jpg" alt="IMG_0291" width="240" height="180" border="0"></a></p><h3>Sensors</h3><p>Our initial implementation for detecting punches failed due to far too many false positives. We thought using IR distance sensors would be a good solution since we could detect a “close” punch and tell the other robot to retract the arm before real contact. The test looked promising, but in practice, when the opposite sensors were close, we saw a lot of noise in the data. The backup and currently implemented solution was to install simple push switches in the chest and detect when those are clicked by the chest plate pressing against them.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0200%5B4%5D.jpg"><img title="IMG_0200" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0200_thumb%5B1%5D.jpg" alt="IMG_0200" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0205%5B4%5D.jpg"><img title="IMG_0205" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0205_thumb%5B1%5D.jpg" alt="IMG_0205" width="240" height="180" border="0"></a></p><h3>Power</h3><p>Different items required different voltages. The motors and pneumatic valves required 24V, the LEDs required 12V and the USB hub required 5V. We used Castle Pro BEC converters to step down the voltages. These devices are typically used in RC airplanes and helicopters.</p><h3>Shipping</h3><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0278%5B4%5D.jpg"><img title="IMG_0278" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0278_thumb%5B1%5D.jpg" alt="IMG_0278" width="240" height="180" border="0"></a>&nbsp;<a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0280%5B4%5D.jpg"><img title="IMG_0280" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0280_thumb%5B1%5D.jpg" alt="IMG_0280" width="240" height="180" border="0"></a></p><p>So how does someone ship two 700lb robots from Seattle to Austin? We did it in 8 crates. <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif?v=c9' alt='Smiley' />. The key thing to note is that the tops and bottoms of each robot were separated. Any wire that connected the two parts had to be able to be disconnected in some form. This affected the serial cords and the power cords (5V, 12V, 24V).</p><h2>Software</h2><p>The software and architecture went through a variety of iterations during development. The final architecture used 3 laptops, 2 desktops, an access point, and a router. It's important to note that the laptops of Robot 1 and Robot 2 are physically mounted on the backs of each Robot body, communicating through WiFi to the Admin console. The entire setup looks like the following diagram:</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/network%5B4%5D.png"><img title="network" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/network_thumb%5B2%5D.png" alt="network" width="387" height="426" border="0"></a></p><h3><strong>Admin Console</strong></h3><p>The heart of the infrastructure is the Admin Console. Originally, this was also intended to be a scoreboard to show audience members the current stats of the match, but as we got further into the project, we realized this wouldn't be necessary. The robots are where the action is, and people's eyes focus there. Additionally, the robots themselves display their current health status via LEDs, so duplicating this information isn't useful. However, the admin side of this app remains.</p><h3><strong>Sockets</strong></h3><p>The admin console is the master controller for the game state and utilizes socket communication between it, the robots, and the user consoles. A generic socket handler was written to span each computer in the setup. The <strong>SocketListener</strong> object allows for incoming connections to be received, while the <strong>SocketClient</strong> allows clients to connect to those <strong>SocketListeners</strong>. These are generic objects, which must specify objects of type <strong>GamePacket</strong> to send and receive:</p><p><pre class="brush: csharp">
public class SocketListener&lt;TSend, TReceive&gt; where TSend : GamePacket                                                
                                             where TReceive : GamePacket, new()
</pre></p><p><br>&nbsp;</p><p><strong>GamePacket</strong> is a base class from which specific packets inherit:</p><p><pre class="brush: csharp">
public abstract class GamePacket
{
    public byte[] ToByteArray() 
    {   
        MemoryStream ms = new MemoryStream();           
        BinaryWriter bw = new BinaryWriter(ms);
                
        try
        {           
            WritePacket(bw);
        }
        catch(IOException ex)
        {
            Debug.WriteLine(&quot;Error writing packet: &quot; &#43; ex);
        }
        
        return ms.ToArray();
    }
        
    public void FromBinaryReader(BinaryReader br)
    {        
        try
        {    
            ReadPacket(br);       
        }
        catch(IOException ex)       
        {
            Debug.WriteLine(&quot;Error reading packet: &quot; &#43; ex);
        }
    }
    
    public abstract void WritePacket(BinaryWriter bw);
    public abstract void ReadPacket(BinaryReader br);
}
</pre></p><p>For example, in communication between the robots and the admin console, <strong>GameStatePacket</strong> and <strong>MovementDescriptorPacket</strong> are sent and received. Each <strong>GamePacket</strong> must implement its own <strong>ReadPacket</strong> and <strong>WritePacket</strong> methods to serialize itself for sending across the socket.</p><p>Packets are sent between machines every &quot;frame&quot;. We need the absolute latest game state, robot movement, etc. at all times to ensure the game is functional and responsive.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/image%5B20%5D-2.png"><img title="image" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/image_thumb%5B12%5D-3.png" alt="image" width="640" height="278" border="0"></a></p><p>As is quite obvious, absolutely no effort was put into making the console &quot;pretty&quot;. This is never seen by the end users and just needs to be functional. Once the robot software and the user consoles are started, the admin console initiates connections to each of those four machines. Each machine runs the <strong>SocketListener</strong> side of the socket code, while the Admin console creates four <strong>SocketClient</strong> objects to connect to each those. Once connected, the admin has control of the game and can start, stop, pause, and reset a match by sending the appropriate packets to everyone that is connected.</p><h3><strong>Robot</strong></h3><p>The robot UI is also never intended to be seen by an end user, and therefore contains only diagnostic information.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/image%5B19%5D-1.png"><img title="image" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/image_thumb%5B11%5D-1.png" alt="image" width="640" height="361" border="0"></a></p><p>Each robot has a wireless Xbox 360 controller connected to it so it can be manually controlled. The UI above reflects the positions of the controller sticks and buttons. During a match, it's possible for a bot to get outside of our &quot;safe zone&quot;. One bot might be pushing the other, or the user may be moving the bot toward the edge of the ring. To counter this, the player's coach can either temporarily move the bot, turning off Kinect input, or force the game into &quot;referee mode&quot; which pauses the entire match and turns off Kinect control on both sides. In either case, the robots can be driven with the controllers and reset to safe positions. Once both coaches signal that the robots are reset, the admin can then resume the match.</p><h3>Controlling Hardware</h3><p>Phidget hardware controlled our LEDs, relays, and sensors. Getting data out of a Phidget along with actions, such as opening and closing a relay, is shockingly easy as they have pretty straightforward C# APIs and samples, which is why they typically are our go-to product for projects like this.</p><p>Below are some code snippets for the LEDs, relays, and sensor.</p><p><strong>LEDs – from LedController.cs</strong></p><p>This is the code that actually updates the health LEDs in the robot's chest. The LEDs were put on the board in a certain order to allow this style of iteration. We had a small issue of running out of one color of LEDs so we used some super bright ones and had to reduce the power levels to the non-super bright LEDs to prevent possible damage:</p><p><pre class="brush: csharp">
private void UpdateLedsNonSuperBright(int amount, int offset, int brightness)
{
    for (var i = offset; i &lt; amount &#43; offset; i&#43;&#43;)
    {
        _phidgetLed.leds[i] = brightness / 2;
    }
}

private void UpdateLedsSuperBright(int amount, int offset, int brightness)
{
    for (var i = offset; i &lt; amount &#43; offset; i&#43;&#43;)
    {
        _phidgetLed.leds[i] = brightness;
    }
}
</pre></p><p>&nbsp;</p><p><strong>Sensor data – from SensorController.cs</strong></p><p>This code snippet shows how we obtain the digital and analog inputs from the Phidget 8/8/8 interface board:</p><p><pre class="brush: csharp">
public SensorController(InterfaceKit phidgetInterfaceKit) : base(phidgetInterfaceKit)
{    
    PhidgetInterfaceKit.ratiometric = true;
}

public int PollAnalogInput(int index)
{
    return PhidgetInterfaceKit.sensors[index].Value;
}

public bool PollDigitalInput(int index)
{
    return PhidgetInterfaceKit.inputs[index];
}
</pre></p><p>&nbsp;</p><p><strong>Relays – from RelayController.cs</strong></p><p>Electrical relays fire our pneumatic valves. These control the head popping and the arms punching. For our application, we wanted the ability to reset the relay automatically. When the relay is opened, an event is triggered and we create an actively polled thread to validate whether we should close the relay. The reason why we actively poll is someone could be quickly toggling the relay. We wouldn't want to close it on accident. The polling and logic does result in a possible delay or early trigger for closing the relay, but for the BoxingBots the difference of 10ms for a relay closing is acceptable:</p><p><pre class="brush: csharp">
public void Open(int index, int autoCloseDelay)
{   
    UseRelay(index, true, autoCloseDelay);
}

public void Close(int index)
{
    UseRelay(index, false, 0);
}

private void UseRelay(int index, bool openRelay, int autoCloseDelay)
{
    AlterTimeDelay(index, autoCloseDelay);
    PhidgetInterfaceKit.outputs[index] = openRelay;
}

void _relayController_OutputChange(object sender, OutputChangeEventArgs e)
{
    // closed
    if (!e.Value)
        return;

    ThreadPool.QueueUserWorkItem(state =&gt;
    {                                          
        if (_timeDelays.ContainsKey(e.Index))
        {                                              
            while (_timeDelays[e.Index] &gt; 0)                       
            {
                Thread.Sleep(ThreadTick);           
                _timeDelays[e.Index] -= ThreadTick;
            }                                            
        }
                                            
        Close(e.Index);
                                        
    });
}

public int GetTimeDelay(int index)
{
    if (!_timeDelays.ContainsKey(index))
        return 0;
    return _timeDelays[index];
}

public void AlterTimeDelay(int index, int autoCloseDelay)
{
    _timeDelays[index] = autoCloseDelay;
}
</pre></p><p>&nbsp;</p><h3><strong>User Console</strong></h3><p>&nbsp;</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0297%5B5%5D.jpg"><img title="IMG_0297" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0297_thumb%5B2%5D.jpg" alt="IMG_0297" width="500" height="375" border="0"></a></p><p>Since the theme of the party was Retro Gaming, we wanted to go for an early 80's Sci-fi style interface, complete with starscape background and solar flares! We wanted to create actual interactive elements, though, to maintain the green phosphor look of early monochrome monitors. Unlike traditional video games, however, the screens are designed not as the primary focus of attention, but rather to help calibrate the player before the round and provide secondary display data during the match. The player should primarily stay focused on the boxer during the match, so the interface is designed to sit under the players view line and serve as more of a dashboard during each match.</p><p>However, during calibration before each round, it is important to have the player understand how their core body will be used to drive the Robot base during each round. To do this, we needed to track an average of the joints that make up each fighter's body core. We handled the process by creating a list of core joints and a variable that normalizes the metric distances returned from the Kinect sensor into a human-acceptable range of motion:</p><p><pre class="brush: csharp">
private static List&lt;JointType&gt; coreJoints = newList&lt;JointType&gt;( 
    newJointType[] {
        JointType.AnkleLeft,
        JointType.AnkleRight,
        JointType.ShoulderCenter,
        JointType.HipCenter
    });
private const double RangeNormalizer = .22;
private const double NoiseClip = .05;
</pre></p><p>And then during each skeleton calculation called by the game loop, we average the core positions to determine the averages of the players as they relate to their playable ring boundary:</p><p><pre class="brush: csharp">
public staticMovementDescriptorPacket AnalyzeSkeleton(Skeleton skeleton)
{           
    // ...

    CoreAverageDelta.X = 0.0;
    CoreAverageDelta.Z = 0.0;
    foreach (JointType jt in CoreJoints)
    {
        CoreAverageDelta.X &#43;= skeleton.Joints[jt].Position.X - RingCenter.X;
        CoreAverageDelta.Z &#43;= skeleton.Joints[jt].Position.Z - RingCenter.Z;
    }

    CoreAverageDelta.X /= CoreJoints.Count * RangeNormalizer;
    CoreAverageDelta.Z /= CoreJoints.Count * RangeNormalizer;

    // ...

    if (CoreAverageDelta.Z &gt; NoiseClip || CoreAverageDelta.Z &lt; -NoiseClip)
    {
        packet.Move = -CoreAverageDelta.Z;
    }

    if (CoreAverageDelta.X &gt; NoiseClip || CoreAverageDelta.X &lt; -NoiseClip)
    {
        packet.Strafe = CoreAverageDelta.X;
    }
}
</pre></p><p>In this way, we filter out insignificant data noise and allow the player's average core body to serve as a joystick for driving the robot around. Allowing them to lean at any angle, the move and strafe values are accordingly set to allow for a full 360 degrees of movement freedom, while at the same time not allowing any one joint to unevenly influence their direction of motion.</p><p>Another snippet of code that may be of interest is the WPF3D rendering we used to visualize the skeleton. Since the Kinect returns joint data based off of a center point, it is relatively easy to wire up a working 3D model in WPF3D off of the skeleton data, and we do this in the ringAvatar.xaml control.</p><p>In the XAML, we simply need a basic <strong>Viewport3D</strong> with camera, lights, and an empty <strong>ModelVisual3D</strong> container to hold or squares. The empty container looks like this:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p><p><pre class="brush: xml">
&lt;ModelVisual3D x:Name=&quot;viewportModelsContainer2&quot;&gt;                   
    &lt;ModelVisual3D.Transform&gt;
        &lt;Transform3DGroup&gt;           
            &lt;RotateTransform3D x:Name=&quot;bodyRotationCenter&quot; CenterX=&quot;0&quot; CenterY=&quot;0&quot; CenterZ=&quot;0&quot;&gt;      
                &lt;RotateTransform3D.Rotation&gt;             
                    &lt;AxisAngleRotation3D x:Name=&quot;myAngleRotation&quot; Axis=&quot;0,1,0&quot; Angle=&quot;-40&quot;/&gt;                 
                &lt;/RotateTransform3D.Rotation&gt;           
            &lt;/RotateTransform3D&gt; 
        &lt;/Transform3DGroup&gt; 
    &lt;/ModelVisual3D.Transform&gt;
&lt;/ModelVisual3D&gt;
</pre></p><p>In the code, we created a generic <strong>WPF3DModel</strong> that inherits from <strong>UIElement3D</strong> and is used to store the basic positioning properties of each square. In the constructor of the object, though, we can pass a reference key to a XAML file that defines the 3D mesh to use:</p><p><pre class="brush: csharp">
public WPF3DModel(string resourceKey)
{
    this.Visual3DModel = Application.Current.Resources[resourceKey] as Model3DGroup;
}
</pre></p><p>This is a handy trick when you need to do a fast WPF3D demo and require a certain level of flexibility. To create a 3D cube for each joint when ringAvatar is initialized, we simply do this:</p><p><pre class="brush: csharp">
private readonly List&lt;WPF3DModel&gt; _models = new List&lt;WPF3DModel&gt;();
private void CreateViewportModels()
{           
    for (int i = 0; i &lt; 20; i&#43;&#43;)
    { 
        WPF3DModel model = new WPF3DModel(&quot;mesh_cube&quot;);
        viewportModelsContainer2.Children.Add(model);

        // ...

        _models.Add(model);
    }

    // ...
}
</pre></p><p>And then each time we need to redraw the skeleton, we loop through the skeleton data and set the cube position like so:</p><p><pre class="brush: csharp">
if (SkeletonProcessor.RawSkeleton.TrackingState == SkeletonTrackingState.Tracked)
{
    int i = 0;  

    foreach (Joint joint in SkeletonProcessor.RawSkeleton.Joints)
    {
        if (joint.TrackingState == JointTrackingState.Tracked)
        {
                                        
            _models[i].Translate(                                        
                joint.Position.X * 8.0,                                    
                joint.Position.Y * 10.0,
                joint.Position.Z * -10.0);

            i&#43;&#43;;
        }
    }

    // ...

}
</pre></p><p>There are a few other areas in the User Console that you may want to further dig into, including the weighting for handling a punch as well dynamically generating arcs based on the position of the fist to the shoulder. However, for this experience, the User Console serves as a secondary display to support the playing experience and gives both the player and audience a visual anchor for the game.</p><h3>Making a 700lb Tank Drive like a First Person Shooter</h3><p>The character in a first person shooter (FPS) video game has an X position, a Y position, and a rotation vector. On an Xbox controller, the left stick controls the X,Y position. Y is the throttle (forward and backward), X is the strafing amount (left and right), and the right thumb stick moves the camera to change what you're looking at (rotation).&nbsp; When all three are combined, the character can do things such as run around someone while looking at them.</p><p>In the prior project, we had existing code that worked for controlling all 4 motors at the same time, working much like a tank does, so we only had throttle (forward and back) and strafing (left and right). Accordingly, we can move the motors in all directions, but there are still scenarios in which the wheels fight one another and the base won't move. By moving to a FPS style, we eliminate the ability to move the wheels in an non-productive way and actually make it a lot easier to drive.</p><p>Note that Clint had some wiring &quot;quirks&quot; with polarity and which motor was left VS right, he had to correct in these quirks in software <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif?v=c9' alt='Smiley' />:</p><p><pre class="brush: csharp">
public Speed CalculateSpeed(double throttleVector, double strafeVector, double rotationAngle)
{
    rotationAngle = VerifyLegalValues(rotationAngle);
    rotationAngle = AdjustValueForDeadzone(rotationAngle, AllowedRotationAngle, _negatedAllowedRotationAngle);

    // flipped wiring, easy fix is here  
    throttleVector *= -1;
    rotationAngle *= -1;
    
    // miss wired, had to flip throttle and straff for calc
    return CalculateSpeed(strafeVector &#43; rotationAngle, throttleVector, strafeVector - rotationAngle, throttleVector);
}

protected Speed CalculateSpeed(double leftSideThrottle, double leftSideVectorMultiplier, double rightSideThrottle, double rightSideVectorMultiplier) 
{ /* code from Jellybean */ }
</pre></p><h2>Conclusion</h2><p>The Boxing Bots project was one of the biggest things we have built to date. It was also one of our most successful projects. Though it was a rainy, cold day and night in Austin when the bots were revealed, and we had to move locations several times during setup to ensure the bots and computers wouldn't be fried by the rain, they ran flawlessly for the entire event and contestants seemed to have a lot of fun driving them.</p><p><a href="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0302%5B5%5D.jpg"><img title="IMG_0302" src="http://files.channel9.msdn.com/wlwimages/1932b237046e4743a4e79e6800c0220f/IMG_0302_thumb%5B2%5D.jpg" alt="IMG_0302" width="500" height="375" border="0"></a></p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/phidgets/RSS&WT.dl=0&WT.entryid=Entry:RSSView:247dcab61560403d8e5da04e01521034">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Boxing-Bots-An-Overview</comments>
      <itunes:summary>IntroductionIn early January, we were tasked with creating a unique, interactive experience for the SXSW Interactive launch party with Frog Design. We bounced around many ideas, and finally settled on a project that Rick suggested during our first meeting: boxing robots controlled via Kinect. The theme of the opening party was Retro Gaming, so we figured creating a life size version of a classic tabletop boxing game mashed up with a &amp;quot;Real Steel&amp;quot;-inspired Kinect experience would be a perfect fit. Most importantly, since this was going to be the first big project of the new Coding4Fun team, we wanted to push ourselves to create an experience that needed each of us to bring our unique blend of hardware, software, and interaction magic to the table under an aggressively tight deadline. HardwareThe BoxingBots had to be fit a few requirements: They had to be fun They had to survive for 4 hours, the length of the SXSW opening party Each robot had to punch for 90 seconds at a time, the length of a round They had to be life-size They had to be Kinect-drivable They had to be built, shipped, and reassembled for SXSW Creating a robot that could be beaten up for 4 hours and still work proved to be an interesting problem. After doing some research on different configurations and styles, it was decided we should leverage a prior project to get a jump start to meet the deadline. We repurposed sections of our Kinect drivable lounge chair, Jellybean! This was an advantage because it contained many known items, such as the motors, motor controllers, and chassis material.&amp;nbsp; Additionally, it was strong and fast, it was modular, and the code to drive it was already written. Jellybean would only get us part of the way there, however.&amp;nbsp; We also had to do some retrofitting to get it to work for our new project. The footprint of the base needed to shrink from 32x50 inches to 32x35 inches, while still allowing space to contain all of the original batteries, wheels, motors, m</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Boxing-Bots-An-Overview</link>
      <pubDate>Thu, 04 Oct 2012 21:00:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Boxing-Bots-An-Overview</guid>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/959a6e59-5e5d-4824-aff5-01cc0ea75b19.png" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/ecb530a9-ffa6-418d-a3e1-96fec970031b.png" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/48e5dab5-8103-4fc6-a3a6-9bd49223e294.jpg" height="288" width="512"></media:thumbnail>      
      <dc:creator>Brian Peek, Clint Rutkas, Dan Fernandez, Rick Barraza</dc:creator>
      <itunes:author>Brian Peek, Clint Rutkas, Dan Fernandez, Rick Barraza</itunes:author>
      <slash:comments>10</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Boxing-Bots-An-Overview/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Kinect</category>
      <category>WPF</category>
      <category>Phidgets</category>
    </item>
  <item>
      <title>Dancing Lights!</title>
      <description><![CDATA[ <p>A few years ago, Brian Peek, created a <a href="http://blogs.msdn.com/b/coding4fun/archive/2007/12/23/1230660.aspx">light sequencing application phidgets to animate your holiday cheer</a> and Don, a coding4fun reader, leveraged it to animate some lights of his own for this year!</p><div id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:0332c214-61c6-4d65-88c8-ef57e864e24e" class="wlWriterEditableSmartContent"><div id="1f8bd787-16c3-46e8-a0be-49adac0e4a87"><div><a href="http://www.youtube.com/watch?v=b3vsHCBDpEM" target="_new"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10104847/video28d9e9295546.jpg" alt=""></a></div></div></div><p>Awesome job Don and thanks for telling us about it!&nbsp; </p><p>Update:&nbsp; Don has <a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10104847/lightSeq_cBrown.zip">shared his sequence file with us</a>!</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/phidgets/RSS&WT.dl=0&WT.entryid=Entry:RSSView:992ca31aafb64656afaa9e7600c6eabc">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/blog/Dancing-Lights</comments>
      <itunes:summary> A few years ago, Brian Peek, created a light sequencing application phidgets to animate your holiday cheer and Don, a coding4fun reader, leveraged it to animate some lights of his own for this year! Awesome job Don and thanks for telling us about it!&amp;nbsp;  Update:&amp;nbsp; Don has shared his sequence file with us! </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/blog/Dancing-Lights</link>
      <pubDate>Tue, 14 Dec 2010 15:40:12 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/blog/Dancing-Lights</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/10104847_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/10104847_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Clint Rutkas</dc:creator>
      <itunes:author>Clint Rutkas</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/blog/Dancing-Lights/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>C4FNews</category>
      <category>Phidgets</category>
      <category>old projects made new</category>
      <category>relays</category>
    </item>
  <item>
      <title>Wi-Fi Warthogs</title>
      <description><![CDATA[
<p>If you were at PDC09, you might have played “WI-FI Warthogs”, a computer robotics Laser Tag Game that uses the Xbox 360 controller to remotely control Power Wheels vehicles. In this article, I'll tell you how to build your very own WI-FI Warthogs game, from
 start to finish.
</p>
<h3>Getting Started</h3>
<p>I'll start with the Hardware and then move on to the main application and engines that run the robotics.</p>
<p>To get started, all you need are the parts and software listed above, and some basic DIY skills. I found my parts at many different places, one of the best of which was
<a href="http://www.trossenrobotics.com">Trossen Robotics</a> (which also has a great forum site). I found automotive relays and wiring harnesses at
<a href="http://www.allelectronics.com">All Electronics</a> website, cheap Power Wheels ($15) at garage sales, and additional parts at the local junk yard.
</p>
<p>If your Power Wheels car is in need of repairs, check out the <a href="http://www.modifiedpowerwheels.com">
Modified Power Wheels</a> website for more info.</p>
<p>The video below shows pictures I started taking on the first day—they continue all the way through the prototyping life cycle.
</p>
<div id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:3701b7bf-df0f-4caa-8624-4950d4411637" class="wlWriterEditableSmartContent">
<div id="7d17a4f8-d8dc-486d-93c6-f6695b00eb56">
<div><a href="http://www.youtube.com/watch?v=pvhLJexOwaY&amp;hl=en_US&amp;fs=1&amp;" target="_new"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/video07d9f3dcd7e4.jpg" alt=""></a></div>
</div>
</div>
<h3>Hardware</h3>
<h4>Modifying the Cars</h4>
<p>To modify the car, I removed all the existing controls from my Power Wheels Barbie Jeeps and wired their rear motors together. (Keep in mind that in order for the car to go forward or in reverse, the wires on ONE of the motors has to be reversed. Otherwise,
 when you connect the two red wires together and the two blue ones together and give it power, one wheel will spin forward while the other one spins backwards.)</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image004_2.jpg"><img title="clip_image004" border="0" alt="clip_image004" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image004_thumb.jpg" width="455" height="606"></a></p>
<p>Next, I attached the motors to a set of automotive relays, forming a DPDT switch. This was in turn connected to a Phidgets four relay board. Two of the Phidgets relays will control the transmission.</p>
<p>For the steering, I used the tracks from an electric car seat to move the tires from right to left. Any 12 volt electric car seat should work—you can get them at an auto salvage yard, usually at a reasonable price. You could also use an old cordless drill,
 as seen <a href="http://www.waterhobo.com/blogengine.net/post/2009/12/10/WiFi-Warthogs-Alternate-Steering.aspx">
here</a>. </p>
<p>Note that you'll have to modify your car for the steering unit. To do this, I fitted a 2x4 into the front section of the car. On the board, I screwed in the seat track, giving it something solid to sit on.</p>
<p>The wiring for the steering motor was the same as the transmission, except I needed to add limiting switches to keep the tires from going too far left or right. I tied these to the automotive relays. Then, I wired the relays for steering to the Phidgets
 4 relay board. (See wiring diagram. Or, for more on automotive relay, see <a href="http://www.waterhobo.com/hobofiles/autorelay.doc">
here</a>.)</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image006_2.jpg"><img title="clip_image006" border="0" alt="clip_image006" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image006_thumb.jpg" width="422" height="317"></a></p>
<p>I had two different versions of the jeeps and my process was a little different each time, so you might have a little trial and error to find the right fit for the car.</p>
<p>The plastic and drywall screws work great to hold everything in place but you might have a few extra screw holes when you're finished. I call that “character”.
</p>
<p>Also, relays and motors can cause EMI noise. For ways to control it, read <a href="http://www.phidgets.com/documentation/Tutorials/Addressing_EMI_Issues_Tutorial.pdf">
this</a>.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image008_2.jpg"><img title="clip_image008" border="0" alt="clip_image008" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image008_thumb.jpg" width="500" height="344"></a></p>
<p>You can now drive the car forward, reverse, left and right. To test this, try running the Phidgets test program or use my code. For a Phidgets test, right click on the Phidgets item in the tray on your computer. Then, select the 004 device and right click
 to bring up a screen that lets you manually control the device.</p>
<p>Remember to NEVER turn on both relays to transmission or steering at same time, or you will blow your motors, Phidgets and possibly the USB port to your computer. You can turn on one from steering and one from transmission—just turn them off before you switch
 to the other relays. My program does all of this for you. (The Phidgets driver also does all this for you, but beware: it gives you total control, so you can turn all relays on at once. As mentioned, this would cause bad things to happen.)</p>
<h4>Adding a Gun Turret </h4>
<p>To control the gun, we'll use three more Phidgets devices: the 888 interface IO board, the voltage board, and dual relay daughter boards. The voltage board will tell the 888 board when it sees a voltage spike, which happens when one gun hits another. The
 dual relay board acts like a simple switch; it fires the gun and allows it to reload ammo.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/gunwire_5B1_5D_2.jpg"><img title="gunwire[1]" border="0" alt="gunwire[1]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/gunwire_5B1_5D_thumb.jpg" width="500" height="375"></a></p>
<p>To aim the gun and move it from right to left, we'll use the Phidgets servo controller. As a cheaper option, you could replace the laser tag guns with just about anything else. (In a prior version, for example, I used only a relay and was able to shoot water
 from a windshield washer pump by using the relay as a switch and turning the power to the pump on and off.) We now have our hardware in place.
</p>
<p>The gun is mounted in a holster that can be turned by the servo. I used the “lazy Susan” concept, the same as what most people have in their houses. I made a wooden box that the gun fits in and mounted it on a ball bearing swivel. The servo is mounted directly
 below it, and everything is control from the Xbox controller (you can buy them from
<a href="http://Sparkfun.com">Sparkfun.com</a>). It's now time to control the car with the computer.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image012_2.jpg"><img title="clip_image012" border="0" alt="clip_image012" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9950111/clip_image012_thumb.jpg" width="409" height="307"></a></p>
<h4>Computers</h4>
<p>I used Asus EeePCs models 904 and 1000HE, but any computer with XP or newer installed on it will work. You can pick up a used Netbook (a great and cheap option for robotics) from EBay for little to nothing—I recently bought one that had a 32GB SSD and the
 1.6 GHz Atom processor for $250. If possible, get one with a shock-resistant SSD drive. The ones we used at PDC all had standard hard drives and worked fine, but you have to watch for hard hits, which can damage the hard drives.</p>
<h4>Controller Application</h4>
<p>First, I have to give credit Joel Ivory Johnson, whose article and <a href="http://www.codeproject.com/KB/game/XNA_360_Controller_Input.aspx">
sample</a> will make understanding the controller code much easier. His sample is also great for testing functionality and making sure the drivers are working properly for the Xbox 360 controller.</p>
<p>The main controller app is a simple program: an action happens (a button pushed, joystick moved, etc). Then, a call is made to the proper method. Finally, the method fires off a message to its queue and goes back to waiting for the next action (fire and
 forget). I created two methods: “Drivecar” and “GunControl”. The names pretty much tell you what's going to happen.</p>
<p>In addition to the two main functions, there are two timer events. One controls the main loop; the other allows feedback to be given back to the main program. The feedback can come from any of the engines, or from the scoreboard. I use the feedback timer
 to supply the players' vibrations to their controllers when they get hit. I also use it for beginning and ending a game.</p>
<p>I used Microsoft message queue to send messages from the application to the different engines.</p>
<p>So to summarize: I have feedback, 888 IO interface, servo, and relay interface queues that are installed on each Netbook. The queues operate on their own; we'll discuss them more below.</p>
<p>I have 3 cars and 3 computers (you could use more or less). I can bring on more cars or switch the computers around to different cars. I do this by using the DNS name of the computer and syncing it up with a configuration file. The engines will pull all
 their configuration data in from this file. Below is an example of one of the nodes, along with the code I use to read the node:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Car</span><span class="kwrd">&gt;</span>    
    <span class="kwrd">&lt;</span><span class="html">carnumber</span><span class="kwrd">&gt;</span>TimCar2<span class="kwrd">&lt;/</span><span class="html">carnumber</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">relaycar</span><span class="kwrd">&gt;</span>FormatName:DIRECT=OS:timcar2\private$\relaycar<span class="kwrd">&lt;/</span><span class="html">relaycar</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">servocar</span><span class="kwrd">&gt;</span>FormatName:DIRECT=OS:timcar2\private$\servocar<span class="kwrd">&lt;/</span><span class="html">servocar</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">interface888</span><span class="kwrd">&gt;</span>FormatName:DIRECT=OS:timcar2\private$\interface888<span class="kwrd">&lt;/</span><span class="html">interface888</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">feedback</span><span class="kwrd">&gt;</span>FormatName:DIRECT=OS:timcar2\private$\feedback<span class="kwrd">&lt;/</span><span class="html">feedback</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">ok2reload</span><span class="kwrd">&gt;</span>Y<span class="kwrd">&lt;/</span><span class="html">ok2reload</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">relayserialnum</span><span class="kwrd">&gt;</span>8694<span class="kwrd">&lt;/</span><span class="html">relayserialnum</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">serialnum888</span><span class="kwrd">&gt;</span>30448<span class="kwrd">&lt;/</span><span class="html">serialnum888</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">servoserialnum</span><span class="kwrd">&gt;</span>88630<span class="kwrd">&lt;/</span><span class="html">servoserialnum</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">scorecard</span><span class="kwrd">&gt;</span>FormatName:DIRECT=OS:timcar3\private$\scorecard<span class="kwrd">&lt;/</span><span class="html">scorecard</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">scorecardnolimit</span><span class="kwrd">&gt;</span>False<span class="kwrd">&lt;/</span><span class="html">scorecardnolimit</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">scorecardnolimittime</span><span class="kwrd">&gt;</span>1800<span class="kwrd">&lt;/</span><span class="html">scorecardnolimittime</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Car</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Each node (Car) has a “Carnumber” that's equal to the DNS name of the computer. The other information you see is the location of the private queues, the serial numbers of the different Phidgets devices, and some additional configuration data on how the game
 operates. The file is in XML format and the values are read in with the following code:</p>
<pre class="csharpcode">ProjectUtils.Utilities x = <span class="kwrd">new</span> ProjectUtils.Utilities();

whatcar = System.Net.Dns.GetHostName();
scorecard = x.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;scorecard&quot;</span>);
relaycar1 = x.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;relaycar&quot;</span>);
servocar1 = x.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;servocar&quot;</span>);
interface888car1 = x.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;interface888&quot;</span>);
feedbackque1 = x.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;feedback&quot;</span>);</pre>
<p>Another function of the controller program is to determine how many players (1 or 2) are attached to this receiver. If there are two players, player 1 will be the driver and player 2 will be the gunner. If there is only one player, he will need to press
 the “A” button to switch back and forth between the different modes of play, since it's not safe to drive and shoot at the same time.
</p>
<pre class="csharpcode"><span class="kwrd">if</span> (<span class="kwrd">this</span>.gamePadState1.IsConnected == <span class="kwrd">true</span>)
{
    player1active = <span class="kwrd">true</span>;
    numberOfPlayers&#43;&#43;;

    <span class="rem">//what if only one player let them choose if they want to be in driver or</span>
    <span class="rem">// gunner mode</span>
    <span class="kwrd">if</span> (<span class="kwrd">this</span>.gamePadState2.IsConnected == <span class="kwrd">false</span>)
    {
        <span class="kwrd">if</span> (!<span class="kwrd">this</span>.gamePadState1.Buttons.Equals(<span class="kwrd">this</span>.previousState1.Buttons))
        {
            <span class="kwrd">if</span> (<span class="kwrd">this</span>.gamePadState1.Buttons.A == Input.ButtonState.Pressed)
            {
                <span class="kwrd">if</span> (player1Driver == <span class="kwrd">true</span>)
                {
                    player1Driver = <span class="kwrd">false</span>;
                    lbT1Player1.Text = <span class="str">&quot;Gunner&quot;</span>;
                }
                <span class="kwrd">else</span>
                {
                    player1Driver = <span class="kwrd">true</span>;
                    lbT1Player1.Text = <span class="str">&quot;Driver&quot;</span>;
                }
            }

        }
    }

}
<span class="kwrd">else</span>
{
    lbT1Player1.Text = <span class="str">&quot;Not Connected&quot;</span>;
    player1active = <span class="kwrd">false</span>;
}

<span class="kwrd">if</span> (player1active == <span class="kwrd">true</span>)
{
    <span class="kwrd">if</span> (player1Driver == <span class="kwrd">true</span>)
    {
        lbT1Player1.Text = <span class="str">&quot;Driver&quot;</span>;
        DriveCar(gamePadState1, previousState1, 1);
        PlayRadio(gamePadState1, previousState1, 1);
    }
    <span class="kwrd">else</span>
    {
        lbT1Player1.Text = <span class="str">&quot;Gunner&quot;</span>;
        GunControl(gamePadState1, previousState1, 2);
    }
}

<span class="kwrd">if</span> (<span class="kwrd">this</span>.gamePadState2.IsConnected == <span class="kwrd">true</span>)
{
    player2active = <span class="kwrd">true</span>;
    numberOfPlayers&#43;&#43;;
    GunControl(gamePadState2, previousState2, 2);
    lbT1Player2.Text = <span class="str">&quot;Connected&quot;</span>;
}
<span class="kwrd">else</span>
{
    lbT1Player2.Text = <span class="str">&quot;Not Connected&quot;</span>;
    player2active = <span class="kwrd">false</span>;
}</pre>
<p>In XNA programming for the Xbox controller, there are previous and current states. For the most part I care only about the current state of the controller, but I do use the previous state to see if the button or joystick has moved between the last loop and
 the current loop. The loops happen every 100 milliseconds for the main loop (10 times a second, 1000 milliseconds = 1 second).</p>
<p>Below is the code for the “DriveCar” function. As you can see, it's pretty straightforward—I simply pass in the previous and current states of the game controller. For steering, I interrogate the state of the right joystick. If it's a different value than
 the last time we were here, I send a message to the “InterfaceIO” (004 Phidgets interface board) message queue, passing the current state value of the joystick. The drive engine will take the value and determine the action. The transmission is handled the
 same way, except that we check the left joystick.</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> DriveCar(GamePadState gameController, GamePadState prevState, <span class="kwrd">int</span> player)
{
    <span class="rem">//either player 1 or 2 will send their current GamePadState</span>
    <span class="kwrd">int</span> xStickCurrent;
    <span class="kwrd">int</span> xStickPrev;
    <span class="kwrd">int</span> yStickCurrent;
    <span class="kwrd">int</span> yStickPrev;
    <span class="kwrd">string</span> steerPos = <span class="str">&quot;&quot;</span>;

    <span class="kwrd">if</span> (allstop == <span class="kwrd">false</span>)
    {
        <span class="rem">//Steering</span>
        xStickCurrent = (<span class="kwrd">int</span>)((gameController.ThumbSticks.Right.X &#43; 1.0f) * 100.0f / 2.0f);
        xStickPrev = (<span class="kwrd">int</span>)((prevState.ThumbSticks.Right.X &#43; 1.0f) * 100.0f / 2.0f);

        steerPos = xStickCurrent.ToString();

        <span class="kwrd">if</span> (xStickCurrent != xStickPrev)
        {
            queueCount&#43;&#43;;
            <span class="rem">//6 = servo number , steerPos = joystick position</span>
            listBox1.Items.Add(<span class="str">&quot;steering&quot;</span> &#43; steerPos);
            qM.SendMsgNoTransaction(3, <span class="str">&quot;3&quot;</span> &#43; steerPos, relaycar1);
            xStickPrev = xStickCurrent;
        }

        <span class="rem">//Transmission</span>
        <span class="rem">//0-49(backward) 51- 100(forward) 50 = Neutral</span>

        yStickCurrent = (<span class="kwrd">int</span>)((gameController.ThumbSticks.Left.Y &#43; 1.0f) * 100.0f / 2.0f);
        yStickPrev = (<span class="kwrd">int</span>)((prevState.ThumbSticks.Left.Y &#43; 1.0f) * 100.0f / 2.0f);

        <span class="kwrd">if</span> (yStickCurrent != yStickPrev)
        {
            queueCount&#43;&#43;;
            listBox1.Items.Add(<span class="str">&quot;transmission &quot;</span> &#43; yStickCurrent.ToString());
            qM.SendMsgNoTransaction(3, <span class="str">&quot;4&quot;</span> &#43; yStickCurrent.ToString(), relaycar1);
            yStickPrev = yStickCurrent;
        }
    }
    <span class="kwrd">else</span>
    {
        <span class="rem">//we are in all stop do not allow any sends to car...</span>
        <span class="rem">//if we have not sent all stop to relay engine do it..</span>
        <span class="kwrd">if</span> (sentallstop == <span class="kwrd">false</span>)
        {
            sentallstop = <span class="kwrd">true</span>;
            <span class="rem">//tell transmission to go to neutral</span>
            qM.SendMsgNoTransaction(3, <span class="str">&quot;450&quot;</span>, relaycar1);
        }
    }
}</pre>
<p>Each of the queue engines (feedback, drivetrain, 888interface) is set up pretty much the same way. The “Main” function sets up the Phidgets device it will control. It then goes into an endless loop until you cancel the program. In the loop, it checks the
 Message queue for any new messages and calls the proper function based on the content of the message. Then, it gives the processor back to the computer via the do events call while it waits for the next message.
</p>
<p>Below is the “Main” function from the drivetrain queue engine. It sets itself up based on the configuration file and creates the events that the Phidgets devices require. The code then enters its loop and waits for messages to process.</p>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)
{
    whatcar = System.Net.Dns.GetHostName();
    relaycar = projectUtils.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;relaycar&quot;</span>);
    ioboardserialnum = projectUtils.ReadXMLFile4CarElementValue(<span class="str">&quot;c:\\deploy\\carconfig.xml&quot;</span>, whatcar, <span class="str">&quot;relayserialnum&quot;</span>);

    <span class="rem">//write to the console what is happening, useful for debugging</span>
    Console.WriteLine(<span class="str">&quot;Configured Car number - &quot;</span> &#43; whatcar &#43; <span class="str">&quot;\r\n&quot;</span>);
    Console.WriteLine(<span class="str">&quot;Configured Relay serial number - &quot;</span> &#43; ioboardserialnum &#43; <span class="str">&quot;\r\n&quot;</span>);

    <span class="rem">//Wiring up the Phidgets devices with their events</span>
    ifKit = <span class="kwrd">new</span> InterfaceKit();

    ifKit.Attach &#43;= <span class="kwrd">new</span> AttachEventHandler(ifKit_Attach);
    ifKit.Detach &#43;= <span class="kwrd">new</span> DetachEventHandler(ifKit_Detach);
    ifKit.Error &#43;= <span class="kwrd">new</span> ErrorEventHandler(ifKit_Error);

    ifKit.InputChange &#43;= <span class="kwrd">new</span> InputChangeEventHandler(ifKit_InputChange);
    ifKit.OutputChange &#43;= <span class="kwrd">new</span> OutputChangeEventHandler(ifKit_OutputChange);
    ifKit.SensorChange &#43;= <span class="kwrd">new</span> SensorChangeEventHandler(ifKit_SensorChange);

    ifKit.open(<span class="kwrd">int</span>.Parse(ioboardserialnum));

    <span class="kwrd">while</span> (<span class="kwrd">true</span>)
    {
        <span class="kwrd">try</span>
        {
            <span class="rem">// get the message from the message queue </span>
            o = qM.PullMsg(relaycar);

            <span class="rem">//body will have for servo 1 to 7 rest of string is position to move too.</span>
            <span class="kwrd">if</span> (o != <span class="kwrd">null</span> &amp;&amp; o.QueMsgBody != <span class="str">&quot;&quot;</span>)
            {
                mycount&#43;&#43;;
                Console.WriteLine(<span class="str">&quot;process body and count &quot;</span> &#43; o.QueMsgBody &#43; <span class="str">&quot;  &quot;</span> &#43; mycount.ToString() &#43; <span class="str">&quot;\r\n&quot;</span>);
                inputDeviceNum = Int32.Parse(o.QueMsgBody.Substring(0, 1));
                msgMainBody = <span class="kwrd">int</span>.Parse(o.QueMsgBody.Substring(1));

                <span class="kwrd">switch</span> (inputDeviceNum)
                {
                    <span class="kwrd">case</span> 3:
                        steering(msgMainBody);
                        <span class="kwrd">break</span>;
                    <span class="kwrd">case</span> 4:
                        transmission(msgMainBody);
                        <span class="kwrd">break</span>;
                }
            }
            <span class="kwrd">else</span>
            {
                Console.WriteLine(<span class="str">&quot;null or 0 length queue message&quot;</span> &#43; <span class="str">&quot;\r\n&quot;</span>);
            }

            Application.DoEvents();
            Thread.Sleep(100);
        }
        <span class="kwrd">catch</span> (Exception ex)
        {
            projectUtils.WriteEventToApplicationLog(<span class="str">&quot;PhidgetsIO&quot;</span>, <span class="str">&quot;Main -&gt; &quot;</span> &#43; ex.ToString());
        }
    }
}</pre>
<p>This snippet of code is the “transmission” function, which allows the car to move forward, in reverse or stop. This is where I determine what action I need to do based on the joystick's position.
</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> transmission(<span class="kwrd">int</span> myPos)
{
    <span class="kwrd">try</span>
    {
        <span class="kwrd">if</span> (myPos &lt; 20)
        {
            myMsg = <span class="str">&quot;Moving transmission to =&gt; Reverse&quot;</span>;
            currentSteerPos = <span class="str">&quot;R&quot;</span>;
        }
        <span class="kwrd">else</span> <span class="kwrd">if</span> (myPos &gt; 80)
        {
            myMsg = <span class="str">&quot;Moving transmission in Forward&quot;</span>;
            currentSteerPos = <span class="str">&quot;F&quot;</span>;
        }
        <span class="rem">// giving most range from the joystick to stop the car, being safe</span>
        <span class="kwrd">else</span>
        {
            myMsg = <span class="str">&quot;Moving Transmission to =&gt;  Neutral&quot;</span>;
            currentSteerPos = <span class="str">&quot;N&quot;</span>;
        }

        Console.WriteLine(myMsg &#43; <span class="str">&quot;\r\n&quot;</span>);
        <span class="rem">//first stop motor, then wait  and finally do new command.</span>
       <span class="rem">// we stop only long enough for the electricity to stop energising the relay</span>
        <span class="rem">//since we are turning both relays to off (false) that is the same as Neutral so we</span>
        <span class="rem">//do not need to check for it.</span>

        <span class="kwrd">if</span> (ifKit.Attached == <span class="kwrd">true</span>)
        {
            <span class="rem">//set relay 3 to not be engerized, relays start with 0 base count</span>
            ifKit.outputs[2] = <span class="kwrd">false</span>;
            Thread.Sleep(20);
        }

        <span class="kwrd">if</span> (ifKit.Attached == <span class="kwrd">true</span>)
        {
            <span class="rem">//set relay 3 to not be engerized, relays start with 0 base count</span>
            ifKit.outputs[3] = <span class="kwrd">false</span>;
            Thread.Sleep(20);
        }

        <span class="kwrd">if</span> (currentSteerPos == <span class="str">&quot;F&quot;</span>)
        {
            <span class="kwrd">if</span> (ifKit.Attached == <span class="kwrd">true</span>)
            {
                <span class="rem">// turn on relays to power motors forward</span>
                ifKit.outputs[2] = <span class="kwrd">true</span>;
            }
        }
        <span class="kwrd">else</span> <span class="kwrd">if</span> (currentSteerPos == <span class="str">&quot;R&quot;</span>)
        {
            <span class="rem">// turn on relays to power motors reverse</span>
            <span class="kwrd">if</span> (ifKit.Attached == <span class="kwrd">true</span>)
            {
                ifKit.outputs[3] = <span class="kwrd">true</span>;
            }
        }
    }
    <span class="kwrd">catch</span> (Exception ex)
    {
        projectUtils.WriteEventToApplicationLog(<span class="str">&quot;PhidgesIO&quot;</span>, <span class="str">&quot;Transmission -&gt; &quot;</span> &#43; ex.ToString());
    }
}</pre>
<h3>Notes</h3>
<p>First, remember to always turn off relays before changing direction, so you never have both relays running at the same time.
</p>
<p>Also, there is more code in the “main” function (instead of in a timer routine) because of performance issues. When I created a timer and added all the code to the event, the processor showed like it was redlined at 100%. When I put the “do events” in the
 timer event everything worked fine, but it still looked like the process was redlined. However, when I moved everything into the “Main “ function and added a “do events”, everything worked fine and the processor dropped to about 8% usage—even with all of the
 engines running and the main program processing the Xbox controller commands.</p>
<h3>Conclusion</h3>
<p>This was a fun project that gave me a better understanding of robotics and C# functionality. Like I said in the beginning, there are many things you could do to make it better and even faster—I simply gave you a starting point. Questions to ponder: Why console
 apps and not Windows services? Why MSMQ and not WFC? </p>
<p>If you have any questions or thoughts, feel free to ask them here or over at my
<a href="http://www.waterhobo.com/blogengine.net/">blog</a>. </p>
<h3>About The Author</h3>
<p>Tim is an IT Director in the Enterprise Architect Group for <a href="http://www.maritz.com">
Maritz</a>, a sales and marketing services company. He has developed many systems in numerous languages over the years and is currently working with C#. In his off time he enjoys coming up with off the wall ideas and then seeing if he can make them happen.
 Tim's blog is finally getting started and can be seen at <a href="http://www.waterhobo.com/blogengine.net/">
Waterhobo.com</a> where he tries to explain them; he can be emailed at <a href="mailto:tbh726@gmail.com">
tbh726@gmail.com</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/phidgets/RSS&WT.dl=0&WT.entryid=Entry:RSSView:d1be66ff24844dc682bc9e7600ca4878">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Wi-Fi-Warthogs</comments>
      <itunes:summary>
If you were at PDC09, you might have played “WI-FI Warthogs”, a computer robotics Laser Tag Game that uses the Xbox 360 controller to remotely control Power Wheels vehicles. In this article, I&#39;ll tell you how to build your very own WI-FI Warthogs game, from
 start to finish.
 
Getting Started
I&#39;ll start with the Hardware and then move on to the main application and engines that run the robotics. 
To get started, all you need are the parts and software listed above, and some basic DIY skills. I found my parts at many different places, one of the best of which was
Trossen Robotics (which also has a great forum site). I found automotive relays and wiring harnesses at
All Electronics website, cheap Power Wheels ($15) at garage sales, and additional parts at the local junk yard.
 
If your Power Wheels car is in need of repairs, check out the 
Modified Power Wheels website for more info. 
The video below shows pictures I started taking on the first day—they continue all the way through the prototyping life cycle.
 





Hardware
Modifying the Cars
To modify the car, I removed all the existing controls from my Power Wheels Barbie Jeeps and wired their rear motors together. (Keep in mind that in order for the car to go forward or in reverse, the wires on ONE of the motors has to be reversed. Otherwise,
 when you connect the two red wires together and the two blue ones together and give it power, one wheel will spin forward while the other one spins backwards.) 
 
Next, I attached the motors to a set of automotive relays, forming a DPDT switch. This was in turn connected to a Phidgets four relay board. Two of the Phidgets relays will control the transmission. 
For the steering, I used the tracks from an electric car seat to move the tires from right to left. Any 12 volt electric car seat should work—you can get them at an auto salvage yard, usually at a reasonable price. You could also use an old cordless drill,
 as seen 
here.  
Note that you&#39;ll have to modify your car for</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Wi-Fi-Warthogs</link>
      <pubDate>Mon, 18 Jan 2010 22:55:14 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Wi-Fi-Warthogs</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9950111_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9950111_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Tim Higgins </dc:creator>
      <itunes:author>Tim Higgins </itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Wi-Fi-Warthogs/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>PDC</category>
      <category>WPF</category>
      <category>XNA</category>
      <category>XNA framework</category>
      <category>Phidgets</category>
    </item>    
</channel>
</rss>