<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[mike bourgeous]]></title>
  
  <link href="http://blog.mikebourgeous.com/" />
  <updated>2013-04-29T22:35:04-06:00</updated>
  <id>http://blog.mikebourgeous.com/</id>
  <author>
    <name><![CDATA[Mike Bourgeous]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/NitrogensPosterous" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="nitrogensposterous" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[How I migrated from Posterous to Octopress while keeping page rank]]></title>
    <link href="http://blog.mikebourgeous.com/2013/04/29/how-i-migrated-from-posterous-to-octopress/" />
    <updated>2013-04-29T21:11:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2013/04/29/how-i-migrated-from-posterous-to-octopress</id>
    <content type="html"><![CDATA[<p>When Posterous announced their pending closure (which takes place tomorrow,
Apr. 30, 2013), I immediately began searching for a new blogging platform.  I
wanted a self-hosted setup on my own domain, so I would never again be subject
to another blog service&#8217;s site closure.  I settled on [Octopress][0] (based on
<a href="http://jekyllrb.com/">Jekyll</a>), due to its hacker-friendly command line nature, integration with
<a href="http://git-scm.com/">Git</a>, ability to <a href="https://gist.github.com/stephenalexbrowne/4385707">publish to Amazon S3</a>, and easily customizable default
theme.</p>

<p>Migration from Posterous required three major steps:</p>

<ol>
<li>Exporting posts from Posterous</li>
<li>Importing posts into Octopress</li>
<li>Setting up redirection from Posterous to my new blog</li>
</ol>


<p>Follow along below to back up your own Posterous blog.<!-- more --></p>

<h2>Export posts from Posterous</h2>

<p>This part was quite straightforward.  I used the <a href="http://posterous.com/#backup">Backup tool</a> in Posterous&#8217;s
control panel to create a .zip archive of my blog&#8217;s data.  There&#8217;s a delay
of a few minutes to hours between requesting a backup and the backup becoming
available, so check back periodically.  Although Posterous shuts down tomorrow,
it&#8217;s not too late to request a backup of your old Posterous space.  According to
the <a href="http://blog.posterous.com/thanks-from-posterous">Posterous shutdown announcement</a>, the backup feature will be available
until May 31, 2013.  If you haven&#8217;t done so already, back up your old space
ASAP.</p>

<p>Once you have your backup, a bit of postprocessing is needed because Posterous&#8217;s
generated XML in <code>wordpress_export_1.xml</code> appears to strip extended
characters outside of 7-bit ASCII.  Even simple things like M- and N-dashes
might be replaced with &#8220;???&#8221;.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> /path/to/space-<span class="o">[</span>numbers, name, etc.<span class="o">]</span>
</span><span class='line'>cat head.xml posts/*.xml &gt; fixed_export.xml
</span><span class='line'><span class="nb">echo</span> <span class="s1">&#39;&lt;/channel&gt;&lt;/rss&gt;&#39;</span> &gt;&gt; fixed_export.xml
</span></code></pre></td></tr></table></div></figure>


<h2>Import posts into Octopress or Jekyll</h2>

<p>Importing, editing, and fixing links within dozens of posts by hand seemed
rather tedious and boring, so I wrote a script in Ruby to do the job for me.
This script loads the fixed-up RSS feed generated in the previous step, then
generates files under source/_posts.  Images within posts are downloaded into
post-specific directories, organized hierarchically by date.  Encoded versions
of videos are downloaded from Posterous (this is likely to stop working on Apr.
30!).  Links to other posts on the same blog will be adjusted to point to their
new location on the new blog.</p>

<div><script src='https://gist.github.com/5200766.js'></script>
<noscript><pre><code></code></pre></noscript></div>


<p>To use the script, save it as posterous_import.rb in your Octopress or Jekyll
blog&#8217;s base directory, then run the script with the path to fixed_export.xml
generated in the last step:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> /path/to/new/blog
</span><span class='line'>./posterous_import.rb /path/to/space-<span class="o">[</span>numbers, name, etc.<span class="o">]</span>/fixed_export.xml
</span></code></pre></td></tr></table></div></figure>


<p>Complete usage information is included in the script.</p>

<h2>Set up redirection from Posterous</h2>

<p>Posterous doesn&#8217;t explicitly support redirection to a new blog.  It <em>does</em>,
however, allow one to use a custom domain with a Posterous blog.  Once you set
up a custom domain with Posterous, all of your old <em>XYZ</em>.posterous.com URLs will
redirect to the custom domain, which is expected to point to Posterous&#8217;s own
servers.  We can cleverly exploit this behavior to try to transfer search engine
rankings to our new custom blog.  Unfortunately there may not be enough time
left for Google to crawl your old blog and find the redirections before
Posterous shuts down.</p>

<h3>Set up permalink redirectors</h3>

<p>Since Octopress defaults to permalinks with dates, it&#8217;s necessary to redirect
the top-level Posterous shortlinks to the correct location on the new blog.  I
added an option to posterous_import.rb to do just this (<code>--links</code> must be
the first argument to the script):</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">cd</span> /path/to/new/blog
</span><span class='line'>./posterous_import.rb --links /path/to/space-<span class="o">[</span>numbers, name, etc.<span class="o">]</span>/fixed_export.xml
</span></code></pre></td></tr></table></div></figure>


<p>This will create a directory under source/ for each post in the Posterous
backup.  Within each of those directories an index.html file will be generated
that contains a redirection to the post&#8217;s new location.</p>

<h3>Redirect feed.xml to atom.xml</h3>

<p>I recommend setting up a 301 redirection from /rss.xml to /atom.xml.  Octopress
generates /atom.xml, while Posterous used /rss.xml.  The file formats may not be
the same, but most, if not all, feed readers can handle all the major feed
formats.</p>

<p>This will allow subscribed RSS readers to find your new blog&#8217;s feed (until
Posterous stops redirecting tomorrow).  I used the S3 management console to
create the redirection for my blog; your own hosting solution will have its own
method.</p>

<h3>Point Posterous at the custom domain</h3>

<p>Here&#8217;s where the magic happens.  Using Posterous&#8217;s control panel, I clicked
Spaces at the top, clicked the gear icon next to my blog&#8217;s entry under Your
Spaces, then clicked Space Settings in the popup menu.  The first entry on the
settings page is &#8220;Name Your Space&#8221;.  Click the big Edit button to the right of
your blog&#8217;s name and URL.  At the bottom of the new page, there is a &#8220;Custom
Domains&#8221; section.  Here you can tell Posterous your blog is hosted at the domain
of your choosing.</p>

<p>Thankfully, the Posterous engineers decided not to verify that the domain we
enter points to Posterous.  Instead of entering a domain that points back to
Posterous, we&#8217;ll enter the domain that points to our new blog.  At this point,
all requests to <em>XYZ</em>.posterous.com/<em>url</em> will be redirected to our new blog.</p>

<h2>Verify it works</h2>

<p>If you&#8217;re just completing this process now, it&#8217;s likely that Google and other
search engines won&#8217;t crawl the redirections in time.  However, since I migrated
my blog several weeks ago, I can check to see whether my new blog has replaced
the old one in search queries.  I&#8217;m hoping that GoogleBot caches the 301 results
after Posterous shuts down, for the sake of all those links on news sites to my
old blog.</p>

<p>My old blog used to rank on the first page of results for some searches related
to home automation.  Sure enough, when I try these queries now, the new blog
shows up instead, and my new blog&#8217;s traffic has risen to match the old blog&#8217;s
levels.  At this point the new blog is running smoothly.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[This week only: Depth Camera Controller price reduced]]></title>
    <link href="http://blog.mikebourgeous.com/2013/04/23/this-week-only-depth-camera-controller-price-reduced/" />
    <updated>2013-04-23T19:52:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2013/04/23/this-week-only-depth-camera-controller-price-reduced</id>
    <content type="html"><![CDATA[<p><a href="http://www.nitrogenlogic.com/products/depth_controller.html"><img class="left" src="http://blog.mikebourgeous.com/images/2013/04/23/this-week-only-depth-camera-controller-price-reduced/depth_overhead_sm.png"></a>
<em>Hi everyone!</em>  To celebrate the warming of the weather, <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a> is
offering a one week only discount on the <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a>.  Through
the end of Apr. 30, 2013 (MDT), you can get a Depth Camera Controller for $200
instead of the usual $250 (20% off).</p>

<p>The <a href="http://www.nitrogenlogic.com/products/automation_controller.html">Automation Controller</a> will be reduced from $325 to $250 for the same
time period.  Quantity discounts will also be adjusted; get in touch using the
<a href="http://www.nitrogenlogic.com/contact.html">Contact Us</a> page to place an order or to inquire about quantity discounts.</p>

<p>If you&#8217;ve been waiting to outfit your home or business with Kinect-based
automation, this is a great opportunity to get started!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Beta firmware with Hue support for Depth Camera Controller]]></title>
    <link href="http://blog.mikebourgeous.com/2013/04/17/beta-firmware-with-hue-support/" />
    <updated>2013-04-17T15:17:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2013/04/17/beta-firmware-with-hue-support</id>
    <content type="html"><![CDATA[<p>I&#8217;ve uploaded a new beta version of the <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a> firmware
that includes initial support for controlling Philips Hue lights with the
Kinect.  This beta firmware can be downloaded by clicking the <em>Check for
Updates</em> link on the Depth Camera Controller&#8217;s Settings page.</p>

<hr />

<h3>new in build 43 beta</h3>

<ul>
<li>Hue bridge discovery and registration</li>
<li>Basic control and identification of Hue lights and groups</li>
<li>Automation rules &#8211; set Hue lights and groups based on Zone events</li>
<li>Minor page layout improvements</li>
<li>Fixed a bug that can occur if the power fails at just the right time</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Hue Support WIP]]></title>
    <link href="http://blog.mikebourgeous.com/2013/04/04/hue-support-wip/" />
    <updated>2013-04-04T20:40:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2013/04/04/hue-support-wip</id>
    <content type="html"><![CDATA[<p>Exciting news: after tons of work, my local build of the <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a>
software is now able to change Hue lights based on zones!  Using a system of
automation rules similar to the <a href="http://www.nitrogenlogic.com/products/pc_remote.html">Nitrogen Logic PC Remote</a>, the Depth Camera
Controller web interface is able to use zone events to trigger your Philips Hue
lights.</p>

<p><img src="http://blog.mikebourgeous.com/images/2013/04/04/hue-support-wip/n2l_automation_rules.png"></p>

<p>There&#8217;s a good bit of work left to do to get it ready for production, but I just
tested the first implementation and it works great!  I welcome your feedback on
the UI design for automation rules via the Nitrogen Logic <a href="http://www.nitrogenlogic.com/contact.html">Contact Us</a> page.</p>

<p>More details to come in the future&#8230;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Depth Camera Controller Firmware Update: Build 35]]></title>
    <link href="http://blog.mikebourgeous.com/2013/03/16/depth-camera-controller-firmware-update-build-35/" />
    <updated>2013-03-16T11:48:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2013/03/16/depth-camera-controller-firmware-update-build-35</id>
    <content type="html"><![CDATA[<p>Today I&#8217;m announcing build 35 of the <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a> <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a>
firmware.  This is a relatively minor update focused mostly on user interface
tweaks.</p>

<p>You can update your Depth Camera Controller&#8217;s firmware by clicking the <em>Check
for updates&#8230;</em> link on the controller&#8217;s Settings page, downloading the
appropriate file, then uploading it to the controller using the firmware update
section of the Settings page.</p>

<h3>new in build 35</h3>

<ul>
<li>Added a confirmation prompt before deleting a zone.</li>
<li>Tweaked the page layout for improved consistency.</li>
<li>Added Surface Area to the zone attributes displayed in the web interface (this
should have been there a long time ago; Surface Area values were already
calculated and reported through the TCP/IP interface on port 14308).</li>
<li>Fixed the display of zone attributes when a zone is added in another browser
window or from a different device.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[New App: Nitrogen Logic PC Remote]]></title>
    <link href="http://blog.mikebourgeous.com/2013/03/13/new-app-nitrogen-logic-pc-remote/" />
    <updated>2013-03-13T19:55:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2013/03/13/new-app-nitrogen-logic-pc-remote</id>
    <content type="html"><![CDATA[<p>Some of you may have been wondering why it&#8217;s taking so long to get Philips Hue
support implemented, especially now that Philips has released official
documentation for the API.  The reason is that I&#8217;ve been working on a new
application that satisfies a very cool feature request.</p>

<h3>So what have you been doing all this time?</h3>

<p><img src="http://blog.mikebourgeous.com/images/2013/03/13/new-app-nitrogen-logic-pc-remote/n2l_pc_remote.png"></p>

<p>I&#8217;m pleased to announce the release of version 1.0 of a new application, the
<a href="http://www.nitrogenlogic.com/products/pc_remote.html">Nitrogen Logic PC Remote</a>.  This application allows you to run commands on
any Java-enabled PC (Linux, Mac, or Windows) in response to zone events from one
or more <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controllers</a>.<!-- more -->  Don&#8217;t worry, you can still
disable the Java plugin in your browser.</p>

<p>I wrote this application to allow the Depth Camera Controller to interface with
home automation systems that use PC command lines to deliver events to the
automation software.  One example of such a system is <a href="http://www.ihousehomeautomation.com/phpBB/index.php">iHouse Home Automation</a>.
Thanks to a dedicated user&#8217;s feature requests and beta testing, this
application is now available for the benefit of all Nitrogen Logic users.</p>

<h3>What can I do with the Nitrogen Logic PC Remote?</h3>

<p>The application allows the creation of conditional &#8220;triggers&#8221;, or command lines
that will be executed in response to a certain parameter (such as whether a zone
is occupied, or a zone&#8217;s surface area) reaching a defined value.  The command
line&#8217;s parameters may include the controller address, zone name, parameter name,
and parameter value that triggered the command line, through the use of
substitution variables (e.g. <code>%ipercent%</code> anywhere in a command&#8217;s argument will
be substitued with the triggering parameter&#8217;s value as a percentage of its
defined range, rounded to the nearest integer).</p>

<p>By building a list of triggers for the desired zones and parameters, you can
control a command-line-based automation system using a Depth Camera Controller.
In addition to controlling an automation system, you can also do things like
start a video player when someone walks into a zone, shut down a computer when
someone leaves a zone (if you are running the application as a user with
shutdown rights), run custom scripts on the PC in response to changes in the
room&#8217;s ambient light level &#8211; basically anything you can do from a PC&#8217;s command
line can be triggered by zone events from a <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a>.</p>

<p>The Nitrogen Logic PC Remote is also designed with security in mind.  It uses
user-defined command lines and connects directly to a Depth Camera Controller
(instead of the other way around) to minimize the risk of commands being run by
any malicious device or application that finds its way onto your private
network.</p>

<h3>Where do I get it?</h3>

<p>The <a href="http://www.nitrogenlogic.com/products/pc_remote.html">Nitrogen Logic PC Remote</a> can be <a href="http://www.nitrogenlogic.com/products/pc_remote.html#download">downloaded for free from its product page</a>.
If you find any interesting uses, bugs, or cool ideas for the Nitrogen Logic PC Remote,
please be sure to <a href="http://www.nitrogenlogic.com/contact.html">get in touch</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Coming soon: Depth Camera Controller retail micro-launch, Philips Hue support]]></title>
    <link href="http://blog.mikebourgeous.com/2013/01/11/coming-soon-depth-camera-controller-retail-mi/" />
    <updated>2013-01-11T19:44:00-07:00</updated>
    <id>http://blog.mikebourgeous.com/2013/01/11/coming-soon-depth-camera-controller-retail-mi</id>
    <content type="html"><![CDATA[<p>The next few weeks will be exciting for fans of <a href="http://www.nitrogenlogic.com/" title="Nitrogen Logic automation systems">Nitrogen Logic</a>.  First of all, I&#8217;ve been working on adding seamless support for the <a href="http://www.meethue.com/">Philips Hue</a> lighting system to the <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a>.  Soon you will be able to control your Hue lights with a Depth Camera Controller and a Kinect camera, without requiring a separate automation system.  This new Hue support will be available to all purchasers of the Depth Camera Controller via a free firmware update.<!-- more -->  Here&#8217;s a sneak peek at the new web interface:</p>
<div class="p_embed p_image_embed">
<img alt="Knc_hue_2" height="328" src="http://blog.mikebourgeous.com/images/2013/01/11/coming-soon-depth-camera-controller-retail-mi/46778905-knc_hue_2.png" width="500">
</div>
Secondly, the Depth Camera Controller has reached the point where it&#8217;s no longer appropriately described as a &#8220;prototype.&#8221;  A test with a very small initial online retail release will begin soon. If you&#8217;ve been waiting for an &#8220;official&#8221; release of the Depth Camera Controller before purchasing, your wait will soon be over:
<p></p>
<div class="p_embed p_image_embed">
<img alt="Depth_camera_new_box_front_perspective_alpha" height="340" src="http://blog.mikebourgeous.com/images/2013/01/11/coming-soon-depth-camera-controller-retail-mi/46779063-depth_camera_new_box_front_perspective_alpha.png" width="500">
</div>

<p>Customers who purchased a &#8220;prototype&#8221; Depth Camera Controller can  install the latest firmware update, build 31, to get exactly the same  software and features as the retail Depth Camera Controller.  Click the &#8220;Check for updates&#8221; link on your controller&#8217;s Settings page, or <a href="http://www.nitrogenlogic.com/contact.html">contact Nitrogen Logic</a>, to obtain this new firmware version.</p>
<hr>
<h2>new in build 31</h2>
<ul>
<li>Very minor improvements to web interface layout.</li>
<li>Fixed slow loading times in the experimental WebGL view (accessible from a link in the Depth Camera Controller&#8217;s main setup page footer).</li>
<li>Event log is preserved across controller reboots.</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Looking Forward to a New Year]]></title>
    <link href="http://blog.mikebourgeous.com/2013/01/02/looking-forward-to-a-new-year/" />
    <updated>2013-01-02T13:55:00-07:00</updated>
    <id>http://blog.mikebourgeous.com/2013/01/02/looking-forward-to-a-new-year</id>
    <content type="html"><![CDATA[<p>Happy new year!</p>
<p>Things to look forward to in the new year: easier ways to buy a Nitrogen Logic controller, Philips Hue support, and more.</p>
<p>Have a great start to a great year!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Philips Hue support?]]></title>
    <link href="http://blog.mikebourgeous.com/2012/11/19/philips-hue-support/" />
    <updated>2012-11-19T09:17:00-07:00</updated>
    <id>http://blog.mikebourgeous.com/2012/11/19/philips-hue-support</id>
    <content type="html"><![CDATA[<p>If any <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a> customers (or potential customers) would like to control their Philips Hue lights, or for that matter any other hardware, with a Kinect and the <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a> or <a href="http://www.nitrogenlogic.com/products/automation_controller.html">Automation Controller</a>, please <a href="http://www.nitrogenlogic.com/contact.html">get in touch</a> to make arrangements.  Basically it boils down to this:</p>
<ol>
<li>Interested party provides hardware they want to control on a temporary or permanent basis.  Control documentation for the hardware must be available.</li>
<li>Nitrogen Logic makes the necessary changes to the controller firmware.</li>
<li>The new firmware version is released, and temporarily provided hardware is returned.</li>
</ol>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Depth Camera Controller firmware build 23 — brightness sensing, event log]]></title>
    <link href="http://blog.mikebourgeous.com/2012/10/25/depth-camera-controller-firmware-build-23-bri/" />
    <updated>2012-10-25T22:19:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/10/25/depth-camera-controller-firmware-build-23-bri</id>
    <content type="html"><![CDATA[<p>Greetings!  A new version of the <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a> <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a> firmware is now available.  This new version adds <a href="http://blog.mikebourgeous.com/2012/08/16/color-camera-support-ambient-light-detection/">ambient light sensing</a> to xAP and the web interface, visible zones on the Video tab, and an event log.  There are also several <a href="http://blog.mikebourgeous.com/2012/10/12/optimizing-message-parsing-in-the-depth-contr/">performance improvements</a> and <a href="http://blog.mikebourgeous.com/2012/10/05/solving-libfreenect-hangs-in-the-depth-contro/">bug fixes</a>, allowing greater reliability with more zones and more activity.</p>
<!-- more -->
<p>With ambient light values included in xAP messages, customers using HomeSeer, Loxone, and other home automation systems dependent upon the UDP-based xAP protocol can now use relative brightness levels in each zone to trigger automation actions.</p>
<p>The event log provides an overview of recent activity.  You can see camera disconnections and timeouts, zone entry and exit events, xAP status changes, and firmware update attempts.  One great use for the event log is finding the exact XYZ coordinates where a piece of furniture is accidentally activating a zone.</p>
<p>Update instructions will be e-mailed to existing customers.  Read on for a detailed list of changes, complete with pretty pictures!</p>
<hr>
<h2>new in build 23</h2>
<ul>
<li>Ambient light sensing in xAP and the web interface               
<ul>
<li>Ambient light values are now included in the Level field of xAP messages, with an adjustable update rate:<br><div class="p_embed p_image_embed">
<img alt="Knc_xap_brightness" height="406" src="http://blog.mikebourgeous.com/images/2012/10/25/depth-camera-controller-firmware-build-23-bri/45360203-knc_xap_brightness.png" width="500">
</div>
<br>A sample message:
<div class="CodeRay">
  <div class="code"><pre>xap-header
{
v=12
hop=1
uid=FFEDB20A
class=xapbsc.event
source=n2l.depth.theater.cam:Lightbright
}
input.state
{
State=OFF
Level=150/1000
}</pre></div>
</div>

</li>
<li>Ambient light values are displayed in a zone&#8217;s information box on the web interface:<div class="p_embed p_image_embed">
<img alt="Knc_zone_bright" height="172" src="http://blog.mikebourgeous.com/images/2012/10/25/depth-camera-controller-firmware-build-23-bri/45360214-knc_zone_bright.png" width="180">
</div>
</li>
<li>Ambient light sensing zones are visible on the Video tab (browsers without WebGL support will see a black-and-white image).<div class="p_embed p_image_embed">
<img alt="Knc_video_webgl" height="373" src="http://blog.mikebourgeous.com/images/2012/10/25/depth-camera-controller-firmware-build-23-bri/45360213-knc_video_webgl.png" width="500"><img alt="Knc_video_nowebgl" height="373" src="http://blog.mikebourgeous.com/images/2012/10/25/depth-camera-controller-firmware-build-23-bri/45360212-knc_video_nowebgl.png" width="500">
</div>
Note: the video camera has a different field of view from the depth camera, so a zone&#8217;s ambient light sensing and depth sensing do not cover the exact same area of the room.</li>
</ul>
</li>
<li>Event log             
<ul>
<li>The last 100 camera status and zone entry/exit events are visible in the newly added event log:<div class="p_embed p_image_embed">
<img alt="Knc_eventlog" height="322" src="http://blog.mikebourgeous.com/images/2012/10/25/depth-camera-controller-firmware-build-23-bri/45360211-knc_eventlog.png" width="500">
</div>
</li>
<li>The center of gravity listed in zone events can help identify and correct zones experiencing intermittent spurious activation.</li>
</ul>
</li>
<li>Performance improvements and other minor changes<br><ul>
<li>Improvements allow the creation of more zones with more activity, while still maintaining an acceptable frame rate.</li>
<li>The Overhead, Side, and Front views now use a crosshair cursor to indicate that a zone can be created by clicking and dragging.</li>
</ul>
</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Optimizing Message Parsing in the Depth Controller Web UI]]></title>
    <link href="http://blog.mikebourgeous.com/2012/10/12/optimizing-message-parsing-in-the-depth-contr/" />
    <updated>2012-10-12T02:17:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/10/12/optimizing-message-parsing-in-the-depth-contr</id>
    <content type="html"><![CDATA[<p>While preparing for the next revision of the Depth Controller firmware, I found that the web interface would start to show significant lag when a large number of zones were changing.  Some profiling narrowed this down to the interface between the depth camera backend (written in C) and the web frontend (written in Ruby):</p>
<!-- more -->
<table style="font-family: monospace; margin-bottom: 15px;">
<tr>
<td colspan="5"><span style="color: #808080;">Results (267.6715s elapsed):</span></td>
</tr>
<tr>
<td><strong>Zone.new</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">22162</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">110.78</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.005</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">41.39%</span> </td>
</tr>
<tr>
<td><strong>ovh_plot</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">693</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">61.45</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.089</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">22.96%</span> </td>
</tr>
<tr>
<td><strong>ovh_png</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">693</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">53.60</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.077</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">20.03%</span> </td>
</tr>
<tr>
<td><strong>kvp</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">22015</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">48.95</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.002</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">18.29%</span> </td>
</tr>
<tr>
<td><strong>Zone.normalize!</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">22162</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">28.21</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.001</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">10.54%</span> </td>
</tr>
<tr>
<td><strong>get_zones</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">123</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">13.55</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.110</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">5.06%</span>
</td>
</tr>
</table>
<hr>
<h2>analysis</h2>
<p>The Depth Controller web interface uses the same text-based protocol on port 14308 that is made available to users for custom integration.  As such, every time a zone&#8217;s contents change, the web frontend has to parse a line of key-value pairs describing the change.  The <tt>Zone.new</tt> line measures the total amount of time spent parsing zone information from the backend.  This total includes time spent in <tt>kvp</tt>, which is the step of parsing a line of key-value pairs into a Ruby hash, and <tt>Zone.normalize!</tt>, which makes sure all of a zone&#8217;s attributes have the right data type.</p>
<p>The numbers show that, even with the web interface open and watching the overhead view, zone parsing is taking more time than either of the image processing steps for generating the overhead view (41.39% for zone parsing vs. 22.96% and 20.03% for overhead generation and compression)!  This code had already gone through a couple of rounds of optimization before it ever reached the public, but has become a bottleneck once again.  It looks like finding a way to attack both <tt>kvp</tt> and <tt>Zone.normalize!</tt> will knock out almost 29% of that 41% total.  Additionally, the <tt>get_zones</tt> task, which executes rarely but runs for 110ms straight, includes some zone processing, so improving the speed of <tt>Zone.new</tt> will also shorten <tt>get_zones</tt> and cut down on intermittent jitter.</p>
<p>To understand how to remedy the situation, I prepared benchmarks of each of the methods I could use to speed up <tt>kvp</tt>.  In addition to different <tt>kvp</tt> implementations, I tested JSON, YAML, and Ruby&#8217;s eval function, as well as a standalone Zone class that didn&#8217;t rely on hashes at all.  After some testing, I wrote a simple state machine-based version of <tt>kvp</tt> in C that avoided all use of regular expressions.  It also parsed integers, floating point numbers, and strings directly, thus eliminating the need for <tt>Zone.normalize!</tt>.  These are the results on my desktop i7 (ARM is slower, but the proportional relations hold):</p>
<table style="margin-bottom: 15px;">
<tr>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">
<p>Implementation→</p>
<p>↓Task</p>
</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">Baseline kvp: Ruby regex, C unescape</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">Hash-free Zone class</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">kvp 2: C regex, C unescape</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">kvp 3: C state machine, C unescape</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">JSON.parse</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">YAML.load</th>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">Ruby language eval()</th>
</tr>
<tr>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">Parse full<br>zone line</th>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;"><span style="color: #3366ff;">12804/s</span></td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #3366ff;">7191/s</span><br><span style="color: #008080;">(0.56x)</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<p><span style="color: #3366ff;">65832/s</span><br><span style="color: #008080;">(5.14x)</span></p>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #3366ff;">46910/s</span><br><span style="color: #008080;">(3.66x)</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #3366ff;">11707/s</span><br><span style="color: #008080;">(0.91x)</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #3366ff;">24014/s</span><br><span style="color: #008080;">(1.88x)</span><br>
</td>
</tr>
<tr>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">Parse partial<br>zone line</th>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;"><span style="color: #3366ff;">23485/s</span></td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;"> <span style="color: #3366ff;">18003/s</span><br><span style="color: #008080;">(0.77x)</span>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<p><span style="color: #3366ff;">152892/s</span><br><span style="color: #008080;">(6.51x)</span></p>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
</tr>
<tr>
<th style="background: #333; padding: 1px 8px !important; color: #ddd;">Update zone<br>with new data<br>
</th>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #3366ff;">935222/s</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<p><span style="color: #3366ff;"> 83390/s</span><br><span style="color: #008080;">(0.09x)</span></p>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;"><span style="color: #808080;">N/A</span></td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
<td style="background: #333; padding: 1px 8px !important; color: #ddd; text-align: center;">
<span style="color: #808080;">N/A</span><br>
</td>
</tr>
</table>
<hr>
<h2>conclusion</h2>
<p>The C-language state machine-based <tt>kvp</tt> is the clear winner, resulting in as much as a 6.5x speed improvement.  With all overhead accounted for, the new key-value parser can process zone updates 2.4 times faster than the original code.   The final word will come from the results on the controller itself:</p>
<table style="font-family: monospace;">
<tr>
<td colspan="5"><span style="color: #808080;">Results (274.1677s elapsed):</span></td>
</tr>
<tr>
<td><strong>ovh_plot</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">1044</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">74.07</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.071</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">27.02%</span>
</td>
</tr>
<tr>
<td><strong>ovh_png</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">1044</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">60.15</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.058</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">21.94%</span>
</td>
</tr>
<tr>
<td><strong>Zone.new</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">20687</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">38.20</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.002</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">13.93%</span>
</td>
</tr>
<tr>
<td><strong>unpack</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">1049</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">19.26</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.018</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">7.03%</span>
</td>
</tr>
<tr>
<td><strong>kvp</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">21324</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">11.68</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.001</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">4.26%</span>
</td>
</tr>
<tr>
<td><strong>get_zones</strong></td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">count:</span> <span style="color: #3366ff;">131</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">time:</span> <span style="color: #3366ff;">5.89</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">each:</span> <span style="color: #3366ff;">0.045</span>
</td>
<td style="padding: 1px 8px;">
<span style="color: #808080;">overall:</span> <span style="color: #3366ff;">2.15%</span>
</td>
</tr>
</table>
<p>There you have it.  With the new and improved key-value pair parser, <tt>Zone.new</tt> finds its rightful place below the CPU-intensive image processing tasks, and the web UI feels much snappier.  We gained nearly all of our expected 29%.  All this was accomplished without changing the backend protocol.  There are still optimizations that could be made in the new <tt>kvp</tt> code,  but if zone processing becomes a bottleneck again, I will switch to  something like <a href="http://msgpack.org/">MessagePack</a> (initial testing shows a further 2x speedup over the new <tt>kvp</tt>).</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Solving libfreenect hangs in the Depth Controller - gdb saves the day]]></title>
    <link href="http://blog.mikebourgeous.com/2012/10/05/solving-libfreenect-hangs-in-the-depth-contro/" />
    <updated>2012-10-05T10:42:02-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/10/05/solving-libfreenect-hangs-in-the-depth-contro</id>
    <content type="html"><![CDATA[<p><em>This is a technical and lengthy post explaining some of the work involved in the development of the <a href="http://www.nitrogenlogic.com/" title="Nitrogen Logic automation systems">Nitrogen Logic</a> <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a>.  You can follow my thought process and progression through the discovery of a bug, investigating its cause, and implementing a solution.  Executive summary: developer places tongue in cheek, heroically overcomes numerous obstacles, uses stress testing and gdb to find the cause of a bug, and ultimately fixes the problem.<br></em></p>
<!-- more -->
<hr>
<h2>the problem</h2>
<p>Since the <a href="http://blog.mikebourgeous.com/2012/08/16/color-camera-support-ambient-light-detection/" title="Color camera support, ambient light detection added to Depth Camera Controller">introduction of color image support</a> in the Depth Controller, the low-level camera server on the controller has been experiencing occasional hangs.  These hangs could be reproduced quite easily by switching to the Video tab on the controller&#8217;s web interface, then moving or resizing a zone.</p>
<p>The camera server&#8217;s built-in watchdog detects these hangs, resetting the depth camera when they occur.  Every time the camera is reset, there&#8217;s a several second delay while the software and camera reconnect, and sometimes the first few seconds of data from the depth camera are skewed by about half a meter.  With these hangs happening quite often when a zone was adjusted on the Video tab, it was clearly necessary to do something about the problem.</p>
<hr>
<h2>the investigation</h2>
<p>Based on the symptoms, I came up with a few possible explanations:</p>
<ol>
<li>The cause might be within the Kinect itself, that repeatedly stopping and starting its RGB camera was causing it to hang.</li>
<li>A bug in libfreenect was causing an invalid command to be sent to the camera.</li>
<li>The controller didn&#8217;t have enough USB bandwidth or CPU power to keep up with all of the depth and video data, causing data to be lost.  The resulting data loss caused the camera to hang.</li>
<li>A <a href="https://en.wikipedia.org/wiki/Race_condition">race condition</a> between the server&#8217;s network thread and camera processing threads was leading to a <a href="https://en.wikipedia.org/wiki/Deadlock">deadlock</a>.</li>
</ol>
<p>The only way to narrow down the cause was to gather more information.  I started by adding better logging facilities to the camera backend that would also allow me to dump low-level debugging information from libfreenect.  If I could find a common set of events that always happened right before the camera stopped, I would most likely eliminate hypothesis #1.  The massive amount of data generated by the new logging features made  debugging directly on the controller untenable.</p>
<p>Hypothesis #1 seemed unlikely because the bug was associated with  specific behavior on top of video support.  One might also expect to see  USB disconnection messages in the kernel dmesg output; the lack thereof further discredited hypothesis #1.</p>
<p>I upgraded to the latest version of libfreenect, in case the problem was #2, a libfreenect bug that had been solved upstream.  The updated version of libfreenect looked like it supported a 320x240 mode (the libfreenect.h header defines a constant called <a href="https://github.com/OpenKinect/libfreenect/blob/9ab2c20a9b21367b39914a9fa9a04c4ab7ee4c5f/include/libfreenect.h#L79">FREENECT_RESOLUTION_LOW</a>), which would use 25% as much data as 640x480.  I was hoping that by switching to 320x240 the problem would go away, confirming hypothesis #3.  Unfortunately libfreenect doesn&#8217;t actually support a low resolution mode, and there are some claims that the Kinect itself lacks a 320x240 mode (despite the Xbox 360 press indicating that the Kinect&#8217;s launch resolution was 320x240, with a later software update to obtain 640x480).</p>
<p>I reasoned that if I  could reproduce the bug on my desktop PC I would  eliminate hypothesis  #3, so I ran a pair of active USB extension cables  from my desktop to  the Kinect.  At first the bug did not occur on my PC, even when I opened multiple  browsers to the Video tab and thrashed dozens of zones around like a  madman:</p>
<div class="p_embed p_image_embed">
<img alt="Many_zones" height="353" src="http://blog.mikebourgeous.com/images/2012/10/05/solving-libfreenect-hangs-in-the-depth-contro/44896430-many_zones.png" width="480">
</div>

<p>I tried using valgrind&#8217;s thread checking tools to identify the problem, but they made the camera server run <em>so <span style="letter-spacing: 2px;">slowly</span></em> that the watchdog timer fired constantly and the interface was unusable.</p>
<p>Meanwhile, I was still working on further improving performance to allow more zones to be created and monitored, trying to get the Depth Camera software working on the Raspberry Pi, and looking for other ways of reducing USB bandwidth requirements.  In every case I ran into a dead end.  The performance &#8220;improvements&#8221; turned out to be neutral, I found the <a href="http://blog.mikebourgeous.com/2012/10/02/the-ideal-arm-platform/">Raspberry Pi is incapable of working with the Kinect</a>, and as mentioned before, 320x240 support was out of the question.</p>
<p>All this discouragement over several days was getting rather annoying, so I spent quite a few hours playing the awesome <a href="http://www.blackmesasource.com/">Black Mesa Mod</a> to clear my mind and get a fresh perspective.</p>
<hr>
<h2>the cause</h2>
<p>I kept thinking about hypothesis #4 — if indeed there was a race condition on the controller under a certain amount of stress, maybe I could trigger the same condition on my PC by running a stress test.  Since the hang would occur while simultaneously watching the Video tab and moving a zone, I opened my browser to the Video tab, then ran the following command to simulate rapidly changing a zone:</p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<p><code><span style="color: #686868;">$</span> (while true; do echo 'setzone 34,xmin,-1.589'; done) | nc localhost 14308</code></p>
</blockquote>
<p>Success!  In less than a minute the hang was triggered.  Hypothesis #3 was eliminated.  But wait, I forgot to enable the detailed logging features!  I produced a debug build, set the appropriate environment variable to enable ultra-verbose logging, and started gdb (the low-level camera backend process is called knd):</p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<p><code><span style="color: #686868;">$</span> KND_LOG_LEVEL=10 gdb ./knd</code></p>
</blockquote>
<p>In order to get an exact snapshot of the program at the time of the hang, I set a breakpoint in the watchdog callback, automatically printing a stack trace of each thread at the instant the watchdog fires (there are five threads in the camera server):</p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<p><code><span style="color: #686868;">(gdb)</span> break watchdog_callback<br><span style="color: #686868;">(gdb)</span> commands<br><span style="color: #686868;">Type commands for breakpoint(s) 1, one per line.<br>End with a line saying just "end".<br>&gt;</span> info threads<br><span style="color: #686868;">&gt;</span> thread 1<br><span style="color: #686868;">&gt;</span> bt<br><span style="color: #686868;">&gt;</span> thread 2<br><span style="color: #686868;">&gt;</span> bt<br><span style="color: #686868;">&gt;</span> thread 3<br><span style="color: #686868;">&gt;</span> bt<br><span style="color: #686868;">&gt;</span> thread 4<br><span style="color: #686868;">&gt;</span> bt<br><span style="color: #686868;">&gt;</span> thread 5<br><span style="color: #686868;">&gt;</span> bt<br><span style="color: #686868;">&gt;</span> end</code></p>
</blockquote>
<p>Then I launched the camera server with the <code>run</code> command, reloaded the Video tab in my web browser, and started my stress test.  Within minutes, I had logs and stack traces for several hangs.  It was time to look for a pattern.</p>
<div style="margin: 0 auto;">
<p><em>Side note: as an example of how measuring a system can change its behavior, I added an additional field to the logging output after generating five traces.  With this one additional field, the hang became much more rare, having to wait several minutes for a single event.  Tricky timing bugs are tricky.</em></p>
</div>
<p>Every trace was the same, with the obvious exception of timestamps and thread IDs.  Here are the first few lines from a trace (manually colored for clarity and visual appeal):</p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<p><code><span style="color: #686868;">2012-10-05 03:53:00.992642 -0600 - main_thread -</span> Camera spew: Got video frame of size 307200/307200, 162/162 packets arrived, TS a5ffa17f<br><span style="color: #686868;">2012-10-05 03:53:00.993029 -0600 - video_thread - </span>Camera debug: Write Reg 0x0005  <span style="color: #686868;">2012-10-05 03:53:01.941985 -0600 - watchdog_thread - </span>knd.c:89: watchdog_callback():  Timed out: at least 0.949313668s since last update.<br><span style="color: #686868;">[Switching to Thread 0x7ffff6934700 (LWP 9212)]</span><br><br> Breakpoint 1, watchdog_callback (data=<optimized out>, interval=0x7ffff6933e80) at knd.c:91<br> 91              <span style="color: #617ed0;">if</span>(info-&gt;stop) {<br><span style="color: #686868;">   Id   Target Id                                        Frame</span> <br>   <span style="color: #5f85a0;">5    <span style="color: #7f5acd;">Thread 0x7ffff5004700 (LWP 9215) "<strong>kndsrv_thread</strong>"</span></span> <span style="color: #99cc00;">__lll_lock_wait ()</span> at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:136<br>   <span style="color: #5f85a0;">4</span>    <span style="color: #7f5acd;">Thread 0x7ffff5805700 (LWP 9214) "<strong>video_thread</strong>"</span> <span style="color: #99cc00;">pthread_cond_timedwait@@GLIBC_2.3.2 ()</span><br>     at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:216<br>   <span style="color: #5f85a0;">3</span>    <span style="color: #7f5acd;">Thread 0x7ffff6006700 (LWP 9213) "<strong>depth_thread</strong>"</span> <span style="color: #99cc00;">sem_wait ()</span> at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86<br><span style="color: #5f85a0;"><strong>*</strong> 2</span>    <span style="color: #7f5acd;">Thread 0x7ffff6934700 (LWP 9212) "<strong>watchdog_thread</strong>"</span> <span style="color: #99cc00;">watchdog_callback (data=<optimized out>, interval=0x7ffff6933e80)</optimized></span> at knd.c:91<br>   <span style="color: #5f85a0;">1</span>    <span style="color: #7f5acd;">Thread 0x7ffff7fbd720 (LWP 9211) "<strong>main_thread</strong>"</span> <span style="color: #99cc00;">sem_wait ()</span> at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86</optimized></code></p>
</blockquote>
<p>Every single hang was preceded by the same event, a write of 0x00 to register 0x0005 on the camera.  According to the <a href="http://openkinect.org/wiki/Protocol_Documentation#Control_Commands">OpenKinect.org Protocol Documentation</a>, writing 0x00 to register 0x0005 disables the RGB camera stream.  It seems there&#8217;s a problem at the point of disabling the video feed after taking a snapshot.</p>
<p>It&#8217;s also notable that each thread is in the same function every time, and apart from the watchdog thread, they are all lock-related functions.  Hypothesis #4 grows ever stronger.  The next step is to identify which locks are held by which threads (Java makes this <em>much</em> easier than C, but this isn&#8217;t Java).  We will pay particular attention to the <span style="color: #7f5acd;">main</span> and <span style="color: #7f5acd;">video</span> threads, which were the last two threads to print any data.</p>
<p>We&#8217;ll need to compare the stack trace from each thread to look for common ancestors, then read the source code near each entry to identify mutexes and semaphores waited for or held by each thread.  Here are the traces, manually colored and annotated with lock information:</p>
<p><strong><span style="font-size: medium;">Thread 1 — <span style="color: #7f5acd;">main_thread</span></span></strong></p>
<p><span style="color: #ff0000;"><em>Holds something in libusb.<br>Waiting for the video_empty semaphore.</em></span></p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<table style="" width="100%">
<tr>
<td><code><span style="color: #686868;">#0  <br></span></code></td>
<td><code><span style="color: #99cc00;"><strong>sem_wait</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#1</span></code></td>
<td><code><span style="color: #99cc00;"><strong>video_callback</strong></span> (dev=<optimized out>, videobuf=0x644880, timestamp=2784993663) <span style="color: #00ffff;"><em>[waits for the video_empty semaphore, locks the video_in_use mutex, posts the video_full semaphore]</em></span></optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#2</span></code></td>
<td><code><span style="color: #99cc00;"><strong>iso_callback</strong></span> (xfer=0x641ee8)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#3</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#4</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#5</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#6</span></code></td>
<td><code><span style="color: #99cc00;"><strong>libusb_handle_events_timeout</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#7</span></code></td>
<td><code><span style="color: #99cc00;"><strong>freenect_process_events_timeout</strong></span> (ctx=0x63b750, timeout=<optimized out>)</optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#8</span></code></td>
<td><code><span style="color: #99cc00;"><strong>freenect_process_events</strong></span> (ctx=<optimized out>)</optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#9</span></code></td>
<td><code><span style="color: #99cc00;"><strong>vidproc_doevents</strong></span> (info=0x63b580)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#10</span></code></td>
<td><code><span style="color: #99cc00;"><strong>main</strong></span> (argc=<optimized out>, argv=<optimized out>)</optimized></optimized></code></td>
</tr>
</table>
</blockquote>
<p><strong><span style="font-size: medium;">Thread 2 — <span style="color: #7f5acd;">watchdog_thread</span></span></strong></p>
<p><em>Happy as a clam.</em></p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<table width="100%">
<tr>
<td><code><span style="color: #686868;">#0  <br></span></code></td>
<td><code><span style="color: #99cc00;"><strong>watchdog_callback</strong></span> (data=<optimized out>, interval=0x7ffff6933e80)</optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#1</span></code></td>
<td><code><span style="color: #99cc00;"><strong>watchdog_thread</strong></span> (d=0x63b3e0)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#2</span></code></td>
<td><code><span style="color: #99cc00;"><strong>start_thread</strong></span> (arg=0x7ffff6934700)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#3</span></code></td>
<td><code><span style="color: #99cc00;"><strong>clone</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#4</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
</table>
</blockquote>
<p><strong><span style="font-size: medium;">Thread 3 — <span style="color: #7f5acd;">depth_thread</span></span></strong></p>
<p><em>Holds the depth_empty semaphore.</em><br><em>Waiting for the depth_full semaphore.</em></p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<table width="100%">
<tr>
<td><code><span style="color: #686868;">#0  <br></span></code></td>
<td><code><span style="color: #99cc00;"><strong>sem_wait</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#1</span></code></td>
<td><code><span style="color: #99cc00;"><strong>depth_thread</strong></span> (d=0x63b580) <span style="color: #00ffff;"><em>[waits for the depth_full semaphore, locks the depth_in_use mutex, posts the depth_empty semaphore]</em></span></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#2</span></code></td>
<td><code><span style="color: #99cc00;"><strong>start_thread</strong></span> (arg=0x7ffff6006700)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#3</span></code></td>
<td><code><span style="color: #99cc00;"><strong>clone</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#4</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
</table>
</blockquote>
<p><strong><span style="font-size: medium;">Thread 4 — <span style="color: #7f5acd;">video_thread</span></span></strong></p>
<p><em>Holds the video_in_use mutex.<br><span style="color: #ff0000;">Holds the video_empty semaphore.</span><br><span style="color: #ff0000;">Waiting for something in libusb.</span><br></em></p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<table width="100%">
<tr>
<td><code><span style="color: #686868;">#0  <br></span></code></td>
<td><code><span style="color: #99cc00;"><strong>pthread_cond_timedwait@@GLIBC_2.3.2</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#1</span></code></td>
<td><code><span style="color: #99cc00;"><strong>libusb_wait_for_event</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#2</span></code></td>
<td><code><span style="color: #99cc00;"><strong>libusb_handle_events_timeout</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#3</span></code></td>
<td><code><span style="color: #99cc00;"><strong>libusb_handle_events</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#4</span></code></td>
<td><code><span style="color: #99cc00;"><strong>libusb_control_transfer</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#5</span></code></td>
<td><code><span style="color: #99cc00;"><strong>fnusb_control</strong></span> (dev=<optimized out>, bmRequestType=<optimized out>, bRequest=<optimized out>, wValue=<optimized out>, wIndex=<optimized out>, data=<optimized out>, wLength=12)</optimized></optimized></optimized></optimized></optimized></optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#6</span></code></td>
<td><code><span style="color: #99cc00;"><strong>send_cmd</strong></span> (dev=0x63ba00, cmd=3, cmdbuf=<optimized out>, cmd_len=4, replybuf=0x7ffff5804e30, reply_len=4)</optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#7</span></code></td>
<td><code><span style="color: #99cc00;"><strong>write_register</strong></span> (dev=0x63ba00, reg=<optimized out>, data=<optimized out>)</optimized></optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#8</span></code></td>
<td><code><span style="color: #99cc00;"><strong>freenect_stop_video</strong></span> (dev=0x63ba00)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#9</span></code></td>
<td><code><span style="color: #99cc00;"><strong>video_thread</strong></span> (d=0x63b580) <span style="color: #00ffff;"><em>[waits for the video_full semaphore, locks the video_in_use mutex, posts the video_empty semaphore]</em></span></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#10</span></code></td>
<td><code><span style="color: #99cc00;"><strong>start_thread</strong></span> (arg=0x7ffff5805700)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#11</span></code></td>
<td><code><span style="color: #99cc00;"><strong>clone</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#12</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
</table>
</blockquote>
<p><strong><span style="font-size: medium;">Thread 5 — <span style="color: #7f5acd;">kndsrv_thread</span></span></strong></p>
<p><em>Waiting for the video_in_use mutex.</em></p>
<blockquote style="font-size: 9pt; font-family: monospaced;">
<table width="100%">
<tr>
<td><code><span style="color: #686868;">#0  <br></span></code></td>
<td><code><span style="color: #99cc00;"><strong>__lll_lock_wait</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#1</span></code></td>
<td><code><span style="color: #99cc00;"><strong>_L_lock_883</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#2</span></code></td>
<td><code><span style="color: #99cc00;"><strong>__pthread_mutex_lock</strong></span> (mutex=0x63b670)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#3</span></code></td>
<td><code><span style="color: #99cc00;"><strong>request_video</strong></span> (info=0x63b580) <span style="color: #00ffff;"><em>[locks the video_in_use mutex]</em></span><br></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#4</span></code></td>
<td><code><span style="color: #99cc00;"><strong>getbright_func</strong></span> (client=0x7ffff7e07010, command=<optimized out>, argc=<optimized out>, args=<optimized out>)</optimized></optimized></optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#5</span></code></td>
<td><code><span style="color: #99cc00;"><strong>parse_line</strong></span> (line=0x7ffff7e1f4ed "getbright", client=0x7ffff7e07010)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#6</span></code></td>
<td><code><span style="color: #99cc00;"><strong>parse_buffer</strong></span> (count=131072, client=0x7ffff7e07010)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#7</span></code></td>
<td><code><span style="color: #99cc00;"><strong>knd_read</strong></span> (arg=0x7ffff7e07010, buf_event=<optimized out>)</optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#8</span></code></td>
<td><code><span style="color: #99cc00;"><strong>knd_read</strong></span> (buf_event=<optimized out>, arg=0x7ffff7e07010)</optimized></code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#9</span></code></td>
<td><code><span style="color: #99cc00;"><strong>bufferevent_readcb</strong></span> (fd=19, event=2, arg=0x643ab0)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#10</span></code></td>
<td><code><span style="color: #99cc00;"><strong>event_process_active</strong></span> (base=0x63a8f0)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#11</span></code></td>
<td><code><span style="color: #99cc00;"><strong>event_base_loop</strong></span> (base=0x63a8f0, flags=0)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#12</span></code></td>
<td><code><span style="color: #99cc00;"><strong>event_base_dispatch</strong></span> (event_base=0x63a8f0)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#13</span></code></td>
<td><code><span style="color: #99cc00;"><strong>kndsrv_thread</strong></span> (d=0x61a1a0)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#14</span></code></td>
<td><code><span style="color: #99cc00;"><strong>start_thread</strong></span> (arg=0x7ffff5004700)</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#15</span></code></td>
<td><code><span style="color: #99cc00;"><strong>clone</strong></span> ()</code></td>
</tr>
<tr>
<td><code><span style="color: #686868;">#16</span></code></td>
<td><code><span style="color: #99cc00;"><strong>??</strong></span> ()</code></td>
</tr>
</table>
</blockquote>
<p>Even though the traces always have the same functions at the top of the stack, the final trace differs occasionally in the exact call stack.  Specifically, most of the time the <span style="color: #7f5acd;">kndsrv</span> thread was processing a video image for the <code>getvideo</code> command, but sometimes it is handling a <code>getbright</code> command instead.  Both commands need to access video imagery.</p>
<p>Also interesting is the fact that two threads have <span style="color: #99cc00;">libusb_handle_events_timeout()</span> in their call stack; one under <span style="color: #99cc00;">freenect_process_events()</span> where you might expect it, and another under <span style="color: #99cc00;">freenect_stop_video()</span>.  You may recall that every hang happens right after the camera is told to stop the video stream.</p>
<p>Anyway, as you can see, we have a classic deadlock: Thread 4 (<span style="color: #7f5acd;">video</span>) holds video_empty, needs something in libusb.  Thread 1 (<span style="color: #7f5acd;">main</span>) holds something in libusb, needs video_empty.  The other threads are operating as expected, waiting for work that will never come.  Hypothesis #4 is confirmed.</p>
<hr>
<h2>the solution</h2>
<p>When working with third-party libraries in threaded code, it&#8217;s easy to run into concurrency issues where they aren&#8217;t expected.  It is clear that libfreenect is not reentrant.  One solution would be wrapping all access to libfreenect in a mutex, to ensure that only one thread at a time tries to access libusb.  But this is rather like fighting fire with fire — you have to plan very carefully to ensure your fire breaks are in the right place.  Better to avoid concurrent and recursive access altogether, in this case by moving all calls to <span style="color: #99cc00;">freenect_*()</span> functions into a single thread, outside of any libfreenect callbacks.</p>
<p>After building and uploading a new firmware image with the new changes and reconnecting the Kinect to a Depth Camera Controller, video support is fully functional and the hangs are nowhere to be found.  Mission accomplished.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The ideal ARM platform]]></title>
    <link href="http://blog.mikebourgeous.com/2012/10/02/the-ideal-arm-platform/" />
    <updated>2012-10-02T19:20:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/10/02/the-ideal-arm-platform</id>
    <content type="html"><![CDATA[<p>The ideal ARM platform for a next-generation <a href="http://www.nitrogenlogic.com/" title="Nitrogen Logic automation systems">Nitrogen  Logic</a> controller would feature a fast CPU, a GPU with included drivers,  reliable USB port(s), and gigabit Ethernet, ideally for ~$100 or less.  A GPU would allow implementation of features like data smoothing, rotatable zones, custom shaped zones, and more.</p>
<!-- more -->
<p>The SheevaPlug has a fast enough CPU, excellent USB support, and gigabit Ethernet, but no GPU.</p>
<p>The  D2Plug includes a GPU (with unknown driver availability), but costs too  much.</p>
<p>The older Beagleboard had good enough USB support, but the USB bus sometimes died on Rev.C3 boards, it has no network interface, a slower CPU,  difficult GPU drivers, and a higher price than the SheevaPlug.</p>
<p>The Raspberry Pi has a slower CPU, but a good GPU and a great price.  Unfortunately it only has 100mbit Ethernet attached via USB and terrible USB support (can&#8217;t even get a single coherent frame from the Kinect).</p>
<p>The Odroid-X has loads of CPU power and a reasonable price for what it provides, but USB-based 100mbit Ethernet.</p>
<p>The BeagleBone looks promising, but I wasn&#8217;t able to find GPU drivers as easily as for the PandaBoard or Raspberry Pi.  It also requires a separate power supply.</p>
<p>It seems the platforms with good I/O (e.g. the Marvell platforms with gigabit Ethernet, good USB support, eSATA, and even PCI express) either lack GPUs or are priced too high, and the platforms with good GPUs lack drivers and satisfactory I/O (e.g. Raspberry Pi).  <strong>Someone <em>please</em> make a low-cost ARM system with <em><span style="font-family: mceinline;">real</span></em> (not USB-connected) Ethernet, solid USB 2.0 or 3.0 support, an enclosure, and a GPU with easily accessible drivers!</strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A vision for the future - From Kinect hack to bootstrapped startup]]></title>
    <link href="http://blog.mikebourgeous.com/2012/09/18/a-vision-for-the-future-from-kinect-hack-to-b/" />
    <updated>2012-09-18T23:15:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/09/18/a-vision-for-the-future-from-kinect-hack-to-b</id>
    <content type="html"><![CDATA[<p>I have a vision for the future.  I have a vision of a world where technology becomes so robust, it disappears into the background.  A world in which automated systems control lights, climate, and media, anticipating your every need, becoming an effortless extension of your mind and body.  I envision a future in which technology respects its users&#8217; privacy while providing all the benefits imagined by science fiction writers since Jules Verne.  When the time was right, I embarked on a journey to share this vision with the world.</p>
<!-- more -->
<p>I began this journey in May of 2009, when I left school and started down what would be the most enlightening, and most terrifying path I&#8217;ve ever traveled. I&#8217;ve had the excitement of seeing satisfied users putting my products to amazing uses.  I&#8217;ve felt the pain of trying (but always succeeding) to make ends meet during leaner times.  Last year, what was meant to be a one-off hack with the Kinect turned into 15 minutes of fame and, a few months later, my primary product line.  I&#8217;ve put everything I&#8217;ve got into this vision. Nitrogen Logic is my brainchild, my baby.</p>
<p>I have learned and built a lot during this time.  I&#8217;ve learned that working with a team can significantly amplify one&#8217;s potential.  I&#8217;ve learned what it&#8217;s like to have an unexpected publicity breakthrough, only to fade back into the shadows.  Most importantly, I&#8217;ve learned that there&#8217;s a big difference between having a vision, and communicating it.  In other words, I am not a salesman.</p>
<p>Now, over three years down the road less traveled, I come to a fork.  When I started working on Nitrogen Logic, consumer automation appeared to be stagnant. Since then, products and services like IFTTT (If This, Then That) and Belkin&#8217;s WeMo, and Kickstarter projects like Ubi and SmartThings have filled some of the niches I set out to address.  Additionally, home security firms and ISPs are jumping on the home automation bandwagon.  I find myself running into the limits of the processing power and USB bandwidth available on low-power controllers.  Meanwhile, there are recruiters e-mailing, companies growing, and opportunities knocking.  The temptation to rejoin the ranks of the well-paid, salaried workers with strange and unfamiliar benefits like &#8220;dental insurance&#8221; grows.</p>
<p>As each month goes by, one question looms ever larger in my mind: Do I continue with Nitrogen Logic, seeking new customers and partners to keep the vision going?  Or do I move on, put Nitrogen Logic on the back burner, and look for another way to make my vision a reality?  The answer to this question may lie with you, dear readers, customers, and fans.  Should I shut everything down? Switch to selling software?  Go open source?</p>
<p>Have you been inspired by my Kinect hacks?  Are you a current or future customer of Nitrogen Logic?  Do you work for a company interested in adding automation logic to your products?  As I ponder the future of Nitrogen Logic, I welcome your opinions and advice.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Color camera support, ambient light detection added to Depth Camera Controller]]></title>
    <link href="http://blog.mikebourgeous.com/2012/08/16/color-camera-support-ambient-light-detection/" />
    <updated>2012-08-16T20:19:16-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/08/16/color-camera-support-ambient-light-detection</id>
    <content type="html"><![CDATA[<p>Hello everyone!  I&#8217;ve added full-color video image support to the Nitrogen Logic <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a> firmware, as well as ambient light detection within zones.  The controller&#8217;s web interface now includes a Video tab, with ~2fps color video from the camera (browsers that lack WebGL support will show a black-and-white Bayer-encoded image).  So far, ambient light support is only available through the text-based interface on TCP/IP port 14308.</p>
<!-- more -->
<p>Video support has been a long time coming, mostly due to potential privacy concerns.  To help mitigate privacy issues, this firmware version makes use of the Kinect camera&#8217;s LED to indicate whether images are being captured.  If the LED is green, the system is in standard control mode.  If the LED is yellow or red, depth or video images are being accessed, either through the web interface on port 8089 or through the low-level backend on port 14308.  If this is insufficient, future versions may add access control.</p>
<p>Support for ambient light sensing in the Automation Controller and xAP interfaces is on the way.  Existing customers should contact Nitrogen Logic to receive this firmware update.</p>
<p>Finally, I will be announcing an important change to the Nitrogen Logic product lineup in the near future.</p>
<hr>
<h2>new in build 20</h2>
<ul>
<li>Video image support:   
<ul>
<li>Ability to retrieve raw Bayer images from the controller backend on port 14308.
<div class="CodeRay">
  <div class="code"><pre>help
...
getbright - Asynchronously returns the approximate brightness within each zone.
getvideo - Grabs a single video image.
...</pre></div>
</div>

</li>
<li>Ability to retrieve PNG-compressed Bayer images from the web interface on port 8089, at <strong><em>[controller-name.local]</em>/video.png</strong>.</li>
<li>Ability to view full-color, demosaiced images in the Video tab of the web interface (browsers that do not support WebGL will see the raw Bayer image).</li>
</ul>
</li>
<li>Ambient light sensing:   
<ul>
<li>Non-photometric brightness for each zone is available from the controller backend on port 14308.<p></p> <strong>Example with lights off:</strong>
<div class="CodeRay">
  <div class="code"><pre>getbright
OK - Requested brightness for each zone
BRIGHT - bright=4 name="Captains_Chair"
BRIGHT - bright=3 name="Projector"
BRIGHT - bright=4 name="Office_Door"
BRIGHT - bright=4 name="Theater"
BRIGHT - bright=4 name="Theater2"
BRIGHT - bright=4 name="Theater3"
BRIGHT - bright=5 name="Stairs"
BRIGHT - bright=4 name="Laundry"
BRIGHT - bright=4 name="Touchscreen"
BRIGHT - bright=4 name="Theater_Bright"
BRIGHT - bright=4 name="xAP_Stress"
BRIGHT - bright=3 name="Lightbright"</pre></div>
</div>

<strong>Example with lights on:</strong>
<div class="CodeRay">
  <div class="code"><pre>getbright
OK - Requested brightness for each zone
BRIGHT - bright=398 name="Captains_Chair"
BRIGHT - bright=378 name="Projector"
BRIGHT - bright=557 name="Office_Door"
BRIGHT - bright=420 name="Theater"
BRIGHT - bright=400 name="Theater2"
BRIGHT - bright=240 name="Theater3"
BRIGHT - bright=240 name="Stairs"
BRIGHT - bright=221 name="Laundry"
BRIGHT - bright=392 name="Touchscreen"
BRIGHT - bright=480 name="Theater_Bright"
BRIGHT - bright=376 name="xAP_Stress"
BRIGHT - bright=643 name="Lightbright"</pre></div>
</div>

</li>
</ul>
</li>
<li>Kinect LED indicates image capture mode:   
<ul>
<li>Green indicates normal zone detection mode.</li>
<li>Yellow indicates depth images are being accessed.</li>
<li>Red indicates video images are being accessed.</li>
</ul>
</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Curiosity's View of Mars in Pseudocolor 3D]]></title>
    <link href="http://blog.mikebourgeous.com/2012/08/06/curiositys-view-of-mars-in-pseudocolor-3d/" />
    <updated>2012-08-06T14:42:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/08/06/curiositys-view-of-mars-in-pseudocolor-3d</id>
    <content type="html"><![CDATA[<p><a href="http://www.gimp.org">GIMP</a> and I spent a little quality time with the <a href="http://mars.jpl.nasa.gov/msl/multimedia/raw/">earliest full-size images from the Curiosity rover on Mars</a> (artistic license was taken; <em>this is not how the Martian sky actually looks — I know it&#8217;s not blue</em>):</p>
<p><a href="http://imgur.com/oRCVX"><img title="Hosted by imgur.com" src="http://i.imgur.com/oRCVX.jpg" alt="View on Mars from Curiosity's Hazcam" style="height: auto;"></a></p>
<p>To view in 3D, zoom out using your browser&#8217;s zoom feature, then look <em>through</em> your monitor (<em>not</em> cross-eyed) until the red dots align, or you start to see 3D, sort of like a <a href="https://en.wikipedia.org/wiki/Random_dot_stereogram">random dot stereogram</a>.</p>
<!-- more -->
<hr>
<h2>how it was made</h2>
<p><em><strong>Update:</strong></em> The Curiosity rover has stereo pairs of cameras that help it avoid hazardous obstacles.  I placed the raw images from each stereo camera side by side, applied a partial lens correction distortion, adjusted the image levels, added the red alignment dots, then selected and colorized the sections of the image by hand using the Curves, Levels, Hue/Saturation, Color Balance, and Colorize tools.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Documentation for Nitrogen Logic products]]></title>
    <link href="http://blog.mikebourgeous.com/2012/08/01/documentation-for-nitrogen-logic-products/" />
    <updated>2012-08-01T18:30:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/08/01/documentation-for-nitrogen-logic-products</id>
    <content type="html"><![CDATA[<p>I&#8217;ve put some basic public documentation on the Nitrogen Logic web site.  If you have a Nitrogen Logic controller and want to make the most of it, or you&#8217;d like to know more about how the controllers work, check it out at <a href="http://www.nitrogenlogic.com/docs/" title="Nitrogen Logic documentation">nitrogenlogic.com/docs</a>.  More stuff may find its way onto the documentation pages in the future.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[New Firmware for Nitrogen Logic Automation and Depth Controllers]]></title>
    <link href="http://blog.mikebourgeous.com/2012/07/21/new-firmware-for-automation-controller-and-de/" />
    <updated>2012-07-21T00:21:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/07/21/new-firmware-for-automation-controller-and-de</id>
    <content type="html"><![CDATA[<p>I&#8217;m pleased to announce new firmware versions available for both the <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a> <a href="http://www.nitrogenlogic.com/products/automation_controller.html">Automation Controller</a> and <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Controller</a>.  As usual, newly ordered controllers will receive the latest firmware, while existing controller owners can obtain the firmware update by e-mailing me directly, or using the contact form on the Nitrogen Logic web site.</p>
<!-- more -->
<p><strike>As an aside, I will be looking for a new blogging platform soon</strike>, as Posterous has become increasingly unreliable since their acquisition by Twitter.  For example, the media upload and link creation interfaces in the post editor no longer work for me.  The embedded YouTube videos also seem to be missing from my older posts.  I welcome any suggestions.</p>
<p>Here are some of the changes in these new firmware versions:</p>
<hr>
<h2>automation controller v0.9.2-7</h2>
<p>The Automation Controller firmware includes enhancements to existing logic objects, as well as the addition of one new processing object. There are also minor changes to the controller&#8217;s web status page on port 4567.</p>
<h2>Parameter Control object</h2>
<p><img src="http://i.imgur.com/xO94T.png" alt=""></p>
<ul>
<li>The Parameter Control plugin was modified to preserve its exported parameters when its size is changed in Palace Designer.</li>
<li>Added optional Reset input pins to Parameter Control objects, selectable using the Reset Pin parameter.  This permits the use of automation logic to clear out an override value set via parameter, and restores the input pin&#8217;s value on the output pin.</li>
</ul>
<h2>Float Value object</h2>
<ul>
<li>The parameter range of the Float Value plugin was changed from <em>-<a href="https://en.wikipedia.org/wiki/Float.h#float.h" rel="nofollow">FLT_MAX</a>..FLT_MAX</em> to <em>-inf..inf</em>.</li>
</ul>
<h2>Phyiscal Model object</h2>
<p><img src="http://i.imgur.com/C93G7.png" alt=""></p>
<ul>
<li>Added a Physical Model plugin to the Filters category.  This object simulates physical attributes of a point mass on a single axis, such as position, velocity, etc. while moving towards a target value.</li>
<li>The input pins control the target value, while the output pins reflect the current simulated position.  There are limits imposed on the physical attributes (e.g. maximum velocity).</li>
<li>Thus far, velocity is simulated.  Acceleration will be added in the future.</li>
<li>One intended purpose of this object is for light dimmers.  Using a Physical Model object to control light brightness causes fades from very dim to very bright to take a long time, while fades between similar brightness levels happen quickly.</li>
</ul>
<h2>Multi-zone Value object</h2>
<p><img src="http://i.imgur.com/X0txw.png" alt=""></p>
<ul>
<li>Added X Proportion, Y Proportion, and Z Proportion attributes to the Multi-zone Value plugin that interfaces with the Depth Camera Controller.  These attributes result in output pin values between 0.0 and 1.0, based on the zones&#8217; center of gravity in each dimension, regardless of the size of the zone.  The primary use for these attributes is 3D user control interfaces, such as the <a href="https://www.youtube.com/watch?v=x99gHQ-KVcg">Gesture-like Light Control</a> demonstration I released last year.</li>
</ul>
<hr>
<h2>depth controller v19</h2>
<p>Performance improvements have been made both to the controller backend and to the web interface on port 8089.  Some changes were made to the low-level protocol on port 14308.</p>
<h2>Web Interface</h2>
<p><img src="http://i.imgur.com/TXPFC.png" alt=""></p>
<ul>
<li>Coordinate grid and cursor location overlay on Overhead, Side, and Front views.</li>
</ul>
<h2>xAP Support</h2>
<ul>
<li>xAP support is <a href="http://blog.mikebourgeous.com/2012/07/12/ruby-xap-parser-speed-improved-by-28x/">much faster</a>, so the controller will run reliably on a heavily loaded xAP network.</li>
<li>xAP events are generated at the full camera frame rate, up to 30Hz, rather than at a fixed rate of up to 10Hz.</li>
</ul>
<h2>Backend</h2>
<p><img src="http://i.imgur.com/XfUdA.png" alt=""></p>
<ul>
<li>The <tt>sub</tt> command now sends <tt>ADD</tt> and <tt>DEL</tt> events when a zone is added or removed.</li>
<li>There is now a small <a href="https://en.wikipedia.org/wiki/Hysteresis" rel="nofollow">hysteresis</a> used when detecting whether a zone is occupied.</li>
<li>The maximum zone reported by the <tt>zones</tt> command is now selected by surface area instead of pixel count.</li>
<li>Some enhancements were made that should improve frame rates on systems with many zones.</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ruby xAP Parser Speed Improved by 28x]]></title>
    <link href="http://blog.mikebourgeous.com/2012/07/12/ruby-xap-parser-speed-improved-by-28x/" />
    <updated>2012-07-12T08:45:30-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/07/12/ruby-xap-parser-speed-improved-by-28x</id>
    <content type="html"><![CDATA[<p>As I mentioned in a previous blog post, the latset version of the <a href="http://www.nitrogenlogic.com/products/depth_controller.html">Depth Camera Controller</a> firmware has been showing <a href="http://blog.mikebourgeous.com/2012/07/03/tracking-down-performance-problems-in-the-xap/">performance problems in its xAP parser</a>.  Since then I&#8217;ve written a simplified parser that doesn&#8217;t rely on Treetop, which runs over 28 times faster than the Treetop-based parser.<!-- more -->  The new parser is a single method:</p>
<script src="https://gist.github.com/3098541.js?file=gistfile1.rb"></script><p>The complete updated version of <a href="https://github.com/nitrogenlogic/xap_ruby">xap_ruby</a>, including the new parser, is available on Github.  Benchmarks follow.</p>
<hr>
<h2>updated parser - x64</h2>
<div class="CodeRay">
  <div class="code"><pre>$ ./parser_bench.rb 10000
Running 10000 iterations of ParseXap.simple_parse
10000 iterations: cpu=0.360000 clock=(0.363838)
27484.72689933285 per second

Running 10000 iterations of ParseXap.parse
10000 iterations: cpu=10.640000 clock=(10.647138)
939.2195243898797 per second

Running 10000 iterations of node.to_hash
10000 iterations: cpu=0.280000 clock=(0.279407)
35790.08087596572 per second</pre></div>
</div>

<hr>
<h2>updated parser - ARM</h2>
<div class="CodeRay">
  <div class="code"><pre>$ ./parser_bench.rb 1000
Running 1000 iterations of ParseXap.simple_parse
1000 iterations: cpu=0.800000 clock=(1.048829)
953.4446317047145 per second

Running 1000 iterations of ParseXap.parse
1000 iterations: cpu=21.990000 clock=(29.733424)
33.63218476814936 per second

Running 1000 iterations of node.to_hash
1000 iterations: cpu=0.720000 clock=(0.837403)
1194.1684162215195 per second</pre></div>
</div>

<hr>
<h2>conclusion</h2>
<p>It appears that using a generic parser backend like Treetop is disadvantageous for simple parsing tasks like the xAP protocol.  The upside of the Treetop-based parser is that it provides full validation of the message syntax, with better error messages for invalid xAP messages.  This new parser will allow development of the Depth Camera Controller&#8217;s web interface to continue.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Solving slowdowns in the Depth Controller web interface]]></title>
    <link href="http://blog.mikebourgeous.com/2012/07/03/tracking-down-performance-problems-in-the-xap/" />
    <updated>2012-07-03T17:56:00-06:00</updated>
    <id>http://blog.mikebourgeous.com/2012/07/03/tracking-down-performance-problems-in-the-xap</id>
    <content type="html"><![CDATA[<p>Lately I&#8217;ve been working on adding some new features to the Depth Camera Controller.  Unfortunately, I found that with these new features and xAP enabled, the controller&#8217;s frame rate would gradually decrease, its responses would become significantly delayed, and eventually the entire system would grind to a halt.</p>
<p>With a bit of profiling I discovered that the controller&#8217;s web server was spending all its time in the xAP support code, specifically the <a>Treetop-based xAP parser</a>.</p>
<!-- more -->
<hr>
<h2>xAP</h2>
<p>First, a bit of background on xAP.  <a href="http://www.xapautomation.org/" rel="nofollow">xAP</a> is a horribly inefficient protocol for smart home devices that just happens to be supported by a lot of DIY home automation platforms.  Reasons why xAP is inefficient:</p>
<ol>
<li>Everything is all broadcast, all the time.  Each xAP message is sent via UDP broadcast to the entire network, so all xAP devices and applications have to deal with every single xAP message on the network, even messages destined for other devices.</li>
<li>xAP messages are text-based.  Parsing values from text can be slow.</li>
<li>xAP <a href="http://www.xapautomation.org/index.php?title=Basic_Status_and_Control_Schema" rel="nofollow">Basic Status and Control</a>, the schema used by the Depth Camera Controller and supported by automation packages like HomeSeer, sends only a single binary and/or numeric value in each packet.  That&#8217;s 100+ bytes just to send a single bit.</li>
<li>xAP has some unusual multi-device address wildcarding, which can be time consuming to process.</li>
</ol>
<p>Reason number 1 is the probably the most significant factor in the Depth Camera Controller&#8217;s performance problems—every message we send, we also receive and have to process.  However, we can&#8217;t be sure until we&#8217;ve actually tested the parser&#8217;s performance.  So, I threw together a quick benchmark of just the xAP parser, and tested it on my PC and a controller:</p>
<hr>
<h2>original parser - x64</h2>
<div class="CodeRay">
  <div class="code"><pre>$ ./parser_bench.rb 10000
Running 10000 iterations of ParseXap.parse
10000 iterations: cpu=9.690000 clock=(9.696733)
1031.2751730063692 per second

Running 10000 iterations of node.to_hash
10000 iterations: cpu=0.280000 clock=(0.275799)
36258.3475033779 per second</pre></div>
</div>

<p>For whatever reason, the benchmark ran significantly slower when run with realtime priority via <tt>chrt</tt> or <tt>schedtool</tt> (perhaps something to examine some other day).  Here are the numbers for the controller itself:</p>
<hr>
<h2>original parser - ARM</h2>
<div class="CodeRay">
  <div class="code"><pre>$ ./parser_bench.rb 1000
Running 1000 iterations of ParseXap.parse
1000 iterations: cpu=19.690000 clock=(25.032248)
39.94846963781098 per second

Running 1000 iterations of node.to_hash
1000 iterations: cpu=0.660000 clock=(0.733073)
1364.121077297844 per second</pre></div>
</div>

<p>Yikes!  Some of the new features I&#8217;m working on, which were designed to reduce average CPU usage and response delays, could generate 300 (30fps times 10 zones) xAP messages per second or more.  Obviously the frame rate will drop as CPU usage increases, but if we&#8217;re only parsing 40 messages per second at 80% CPU usage, it&#8217;s no wonder the system is getting bogged down.  The EventMachine event queue in the controller&#8217;s web server is filling up with unprocessed xAP packets faster than it&#8217;s being emptied by the parser.</p>
<hr>
<h2>
<span style="text-decoration: line-through;">to be continued</span> aftermath</h2>
<p><span style="text-decoration: line-through;">With the problem identified, I have some optimizing to do.  I&#8217;ll write a followup post detailing how I resolve the performance problem with the xAP parser.</span></p>
<p><em><strong>Update Jul. 12, 2012:</strong></em> I have <a href="http://blog.mikebourgeous.com/2012/07/12/ruby-xap-parser-speed-improved-by-28x/">written a new trivial parser for xAP messages</a> that improves performance by a factor of 28 or more.  Details are in my next blog post (linked in the previous sentence).</p>
]]></content>
  </entry>
  
</feed>
