<?xml version="1.0" standalone="yes"?>
<?xml-stylesheet type="text/css" href="css/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>CSK.Blog - 电子电路</title><link>http://www.csksoft.net/blog/</link><description>Make something different. - </description><generator>RainbowSoft Studio Z-Blog 1.7 Laputa Build 70216</generator><language>zh-CN</language><copyright>Copyright Shikai Chen 2000-2012.</copyright><pubDate>Sun, 03 May 2026 02:12:13 +0800</pubDate><item><title>Intel Galileo Gen 2开发板的性能评估、使用技巧和实现分析</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/306.html</link><pubDate>Mon, 23 Feb 2015 20:39:55 +0800</pubDate><guid>http://www.csksoft.net/blog/post/306.html</guid><description><![CDATA[<div class="quote">本文最早刊登于2014.12和2015.1月的《无线电》杂志上，对Galileo Gen2的内部实现做了分析。</div>
<div class="quote">转载请注明原文出处：CSK.Blog : <a href="http://www.csksoft.net/blog/">http://www.csksoft.net/blog/</a></div>
<p><strong>请点击文章标题进入阅读全文</strong></p>
<p>&nbsp;在Intel发布首款兼容Arduino开发接口风格的x86开发板Galileo的不到一年内，推出了它的升级版本Intel Galileo Gen2。顾名思义，Gen2即英文Generation 2(第二代)的缩写。从一个简单的照片对比中，我们就可以感受到两者的不同：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/001.jpg" /></p>
<p align="center">图：Intel Galileo一代（左）与二代（右）的对比图</p>
<p>从开发板实物的直接对比上，我们可以看到Galileo Gen2的左侧布置了不少小芯片，似乎比前一代复杂了不少。那么它到底与前一代的主要区别在哪里？到底哪些地方得到了提升呢？</p>
<p>当然，这些问题的答案一部分Intel已经为我们解答了：在Intel的官方网站中给出了Galileo Gen2相比前一代的硬件配置的变化。但仅仅硬件配置的不同却远不足以解答以上的这些问题。这些硬件配置具体带来了那些实际的性能和特性改变？在底层设计上，Galileo Gen2具体是怎么做的？</p>
<p>为了将这些问题弄清楚，在没有更多现成资料的情况下，最直接的手段就是亲自去实践了。</p>
<p>同时，我们知道，Intel Galileo虽然是一块兼容Arduino规范的开发板，但其背后基于x86的平台特性又不断地在提醒我们：这又不仅仅只是一块Arduino兼容系统而已。那么，隐藏在兼容Arduino接口规范外表下的Galileo的真实实力又该如何充分展现出来呢？在本文的上一篇《Intel Galileo 开发板的体验、分析和应用》[1]当中，我已向大家简单的介绍了Intel Galileo的底层实现、基于yocto环境的Linux系统开发等话题。在这篇文章中，我将继续深入这些话题。向大家分享Intel Galileo不仅仅作为一个简单的Arduino板的那些功能。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/002.jpg" /></p>
<p align="center">图：在Intel Galileo中安装Debian Linux发行版，运行图形桌面</p>
<p>&emsp;<br />
</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/003.jpg" /></p>
<p align="center">图：Galileo Gen2与上一代的对比</p>
<p align="center">&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/010.jpg" /></p>
<p style="text-align: center">图：相比前一代Galileo对IO的实现（A），Galileo Gen2的实现（B）令软硬件的设计复杂了不少</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/014.jpg" /></p>
<p style="text-align: center">图：示波器中观测到的IO口产生的信号波形</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/023.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/032.jpg" /></p>
<p style="text-align: center">图：Galileo Gen2原理图中进行IO信号电平转换的部分<br />
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/037.jpg" /></p>
<p style="text-align: center">图：Quark SoC数据手册[8]中描绘的硬件框图，可发现有2种GPIO设备<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/050.jpg" /></p>
<p style="text-align: center">图：通过串口调试器看到的本例子输出</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/intel_galileo_gen2/056.jpg" /></p>
<p style="text-align: center">图：使用Hob简化Yocto的使用过程</p>
]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/306.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=306</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=306&amp;key=1522672f</trackback:ping></item><item><title>聊聊几个特殊的显示屏：EL和单色等离子工业屏的浅析与使用</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/el_and_plasma_disp.html</link><pubDate>Sun, 15 Dec 2013 07:09:54 +0800</pubDate><guid>http://www.csksoft.net/blog/post/el_and_plasma_disp.html</guid><description><![CDATA[<div class="quote">
<p>又是许久没有更新自己Blog了。虽然在微博上一直更新自己近况。不过好的内容还需要Blog写文章积淀。</p>
</div>
<p><strong>点击文章标题浏览全文</strong></p>
<p>作为一名电子爱好者，我一直喜欢收集各种类型的屏幕，尤其是那些具有特殊显示效果或者有一定历史且目前很难见到的。虽然不敢说真的收集的有多全有多高级，但也一度被大家戏称为&ldquo;屏幕控&rdquo;。<br />
近期因为各种机缘巧合得到了几块并不多见的EL和等离子工业显示屏。这些屏幕对于电子爱好者来说非常少见，主要应用在工业和航天、军工领域。但显示效果别具一格，因此写了本文向大家分享他们的特点以及使用方式。<br />
虽然这些屏幕并不是大家都会用到的，但相信其中的一些使用理念，尤其是在缺少厂家资料情况下，通过电路分析寻找驱动方法的思路，会对大家有所帮助。</p>
<p align="center"><br />
<img alt="" src="/data/pic/eldispimg/001.jpg" /></p>
<p align="center">图：单色等离子屏（左）与EL屏（右）的显示效果 </p>
<p align="center"><br />
<img alt="" src="/data/pic/eldispimg/020.jpg" /></p>
<p align="center">图：用EL显示屏展示RoboPeak机器人控制界面（PLANAR 640x400）</p>
<p align="center">&nbsp;</p>
<p align="center"><img alt="" src="/data/pic/eldispimg/021.jpg" /></p>
<p align="center">图：PLANAR 320x240 EL显示屏</p>
]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/el_and_plasma_disp.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=303</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=303&amp;key=937823a1</trackback:ping></item><item><title>对Wowwee Rovio机器人的拆解和扩展可能性探讨</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/289.html</link><pubDate>Thu, 06 Sep 2012 19:19:34 +0800</pubDate><guid>http://www.csksoft.net/blog/post/289.html</guid><description><![CDATA[<div class="quote">
<p>最近网上发现有一批很低价的rovio出售，于是入手一台，拆开后发现是正品。一直对他的机械系统和定位系统着迷，于是我就在拿到手第一时间完全拆解。</p>
<p>初步分析下来rovio还是蛮适合做二次扩展或者hack的。不过自己恐怕没时间搞，于是写成此文权当给大家一个抛砖引玉的启发吧，期待今后有不少神级的hack/mod出现:-) </p>
</div>
<h1 class="std_h1">
<p>简介</p>
</h1>
<p>Wowwee Rovio[1] 是一款使用WIFI信号控制的视频小车，主要的应用诸如远程监控家里情况、远程视频会议等。相比普通的wifi摄像头，它具备行动能力，操作者可以遥控它对任何可以到达的地点进行观察。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/roviohacks/theproduct.jpg" /></p>
<p align="center">Rovio在dock上充电的画面，图片来自于[2]</p>
<p>不过它的功能还不止wifi小车和摄像头那么简单。从上图即可看到他的机械设计上也有独特之处：使用了3组万向轮。这样的设计使得Rovio可以很灵活的直接向着任意方向平移，而不用事先转向到目标角度。</p>
<p>这样的机械结构对于机器人来说很容易控制，在Robocup机器人足球比赛中，多采用这样的结构：</p>
<p>&nbsp;</p>
<p align="center"><img alt="" width="400" height="367" src="/data/pic/roviohacks/robot_2005.jpg" /></p>
<p align="center">图：Robocup比赛机器人使用的万向轮，图片来自[3]</p>
<p align="left">对于做过机器人的朋友来说，这样的机械底盘一般售价不低，但性能非常好。Rovio的这个机械地盘非常值得利用</p>
<p>另外一个特点是Rovio具有记录当前位置和自动返航回dock充电的功能，这得益于它装备的NorthStar[4]导航系统。这是一个基于红外成像三角定位原理的导航算法。据他的开发者Evolution Robotics称，其导航精度最高可达4cm/4deg[5]，而在后面的我的拆解分析中，也可以看到Rovio的NorthStar模块可以被直接拿来使用的可能性也很大。另外值得注意的是，市面上的一款拖地机器人mimt也是采用了northstar定位方案。</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/northstar_mechanism.jpg" /></p>
<p align="center">图：Evolution Robotics网站中对NorthStar定位原理的示意图[4]</p>
<p align="left">下面给出Rovio的大体配置：</p>
<ol>
    <li>
    <div align="left">ARM9 200Mhz CPU</div>
    </li>
    <li>
    <div align="left">使用eCos RealTime OS</div>
    </li>
    <li>
    <div align="left">三组万向轮电机，带有里程计</div>
    </li>
    <li>
    <div align="left">NorthStar II 定位模块</div>
    </li>
    <li>
    <div align="left">头部一组红外障碍物检测</div>
    </li>
    <li>
    <div align="left">Speaker和Mic</div>
    </li>
</ol>
<h2 class="std_h2">
<p align="left">拆解后我的基本观点：</p>
</h2>
<ol>
    <li>
    <div align="left">驱动电路和上层电路层次明显，很适合二次扩展</div>
    </li>
    <li>
    <div align="left">可将ARM9的控制电路取出，使用WR703等设备配合OpenWRT替换，通过自行开发固件可以达到一样的功能</div>
    </li>
    <li>
    <div align="left">NothStar模块可以直接驱动（如使用arduino）的可能性很高，可尝试用于其它地方</div>
    </li>
</ol>
<p>&nbsp;</p>
<h1 class="std_h1">拆解与分析</h1>
<h2 class="std_h2">
<p>底盘总体布局</p>
</h2>
<p>下图为拆开后的总体布局，所有机械和驱动控制电路部分都位于底盘。这样的布局对希望直接使用小车底盘的应用很有帮助。</p>
<p>不过遗憾的是Rovio使用的是玩具用电机，虽然成本便宜，但使用过程中就可发现这种电机的诸多缺点，如扭矩低、噪音大、精度差等</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_001.jpg" /></p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_002.jpg" /></p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>供电和充电管理</p>
</h2>
<p>这部分在一块单独的PCB上完成，包含了负责稳定电池电压的DCDC模块以及给电池充电的模块。</p>
<p>PCB上一共3组线路：<strike>电池输入、稳压输出以及充电输入</strike>。(<strong>此处有误，感谢网友gzhuli指正：电源板的3pin插座不是供电输出，是电量检测和充电检测，CS=电池电压检测，CPC=充电控制，CPS=充电状态检测。)</strong>可以方便的被再次利用。</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_004.jpg" /></p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_005.jpg" /></p>
<p align="center">&nbsp;</p>
<h2 class="std_h2">
<p>外设驱动模块</p>
</h2>
<p>Rovio将所有外部设备（电机、LED、编码器、红外检测等）完全通过一块PCB管理，该PCB从ARM控制板接受控制信号。因此这部分也可以被利用，通过测量控制信号逻辑，应该不难被arduino等驱动起来。</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_011.jpg" /></p>
<p align="left">图中的一系列黑色的三极管应该是实现电机驱动的H桥。这里也比较遗憾，可能是为了降低成本才如此设计，但三极管相比较MOSFET来说，驱动效率较低，也不能通过过大电流。但从配备的玩具电机上看，的确也没必要使用较好的手段。不过这里也就可以作为爱好者hack的一个入手点，可以使用大功率的H桥替代。</p>
<p align="left">&nbsp;</p>
<h2 class="std_h2">
<p>电机和编码器</p>
</h2>
<p>虽然使用了玩具电机，但rovio给每个电机配置的编码器精度应该还不错。可以用于实现里程计，达到一定精度的航迹推算（Deadreckon）。再另外选配合理的传感器，爱好者应该可以基于Rovio完成SLAM等高级的机器人应用</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_007.jpg" /></p>
<h2 class="std_h2">
<p>红外障碍传感器和Speaker</p>
</h2>
<p>Rovio采用一体化红外接受头作为障碍物检测。这点和我们RoboPeak团队的RPMini一样，但Rovio只有前方一组传感器。使用一体化接受头也意味着发射的红外信号时经过调制的。这样可以有效避免环境光对红外障碍检测的干扰。图中最左侧的就是红外发射LED，中间为白色的照明用LED。至于他们的驱动使用，相信有经验的电子爱好者都可以轻松搞定。</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_010.jpg" /></p>
<p align="center">&nbsp;</p>
<h2 class="std_h2">
<p align="left">LED装饰灯驱动部分</p>
</h2>
<p align="left">位于顶板的装饰用LED，Rovio用了额外的一块驱动PCB，其原理很容易从画面中猜到：经典的三极管扩流方式。这部分如果要自己驱动也非常容易。</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_mech_012.jpg" /></p>
<h2 class="std_h2">
<p align="left">ARM控制核心</p>
</h2>
<p align="left">在拆解中一直没看到Rovio的控制核心，而驱动模块和机械部件的选型也让人觉得这完全就是一款中低端玩具。但实际上Rovio的最核心部件是隐藏在安装摄像头的可伸缩头部的。打开这部分的外壳，就可以看到ARM控制板以及上方的定位模块。这部分的做功就比之前的驱动电路精细一点。当相比我拆解的设备而言（可以参考我之前拆的XV11机器人），做工还是显的粗糙。</p>
<p align="left">&nbsp;</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_ctl_001.jpg" /></p>
<p align="left">PCB的正面可以看到使用的ARM芯片以及后面的WIFI模块，反面有一块声卡的DAC芯片以及ROM。这部分的电路对于希望修改rovio的人来说意义不大。因为Rovio的代码并没有公开。可以考虑将其用其他控制器替换。</p>
<p align="left">图中的ARM芯片型号有误，应为：（由gzhuli指正）</p>
<div class="quote">
<p align="left">CPU是Winbond的W99702，不是PXA270，下面的W99100DG不是ROM而是51核单片机，控制W99702 ISP时序的，进入ISP模式时（先插USB再上电就进入ISP模式）通过一个模拟开关切换接管USB口。</p>
</div>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_ctl_002.jpg" /></p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_ctl_003.jpg" /></p>
<p align="left">&nbsp;</p>
<h2 class="std_h2">
<p align="left">NorthStar定位模块</p>
</h2>
<p align="left">这部分是我认为Rovio真正有价值且区分与一个简单的wifi视频小车的部分。不过这个定位模块并非Rovio所开发，而是由Evolution Robotics提供的模块。但对于爱好者来说这是一个福音。因为这个模块的接口是标准串口！不过由于时间关系我并没有去采集其中的信号。但按照Evolution Robotics的介绍[5]，模块是直接输出定位的坐标信息的。在画面中也可以辨认出串口信号的迹象</p>
<p align="left">&nbsp;</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_nav_004.jpg" /></p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_nav_005.jpg" /></p>
<p align="left">我拆解过程中把该模块从PCB上拆下，这里展现了它的内部构造，可见还是比较精巧的。我想这样的画面对于一些专业领域的朋友来说大致就能知道他的定位原理了。这部分我就不细说了。大家可以先尝试将此模块驱动起来。</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_nav_006.jpg" /></p>
<p align="left">我同时也采用了特殊的摄像机拍摄Rovio底座投射出来的红外光斑，这部分画面用普通摄像头和人肉眼是无法观测的。可以看出光斑与Evolution Robotics的原理描述上一致。不过值得注意的是要投射这样亮度的光斑，投射灯的发射功率不低。当我直接拍摄投射器发出的光斑是，因为光强过大，红外相机的中心感光部分直接出现里&ldquo;溢出&rdquo;现象。虽然人肉眼无法看到红外线，但如此强度的功率，恐怕还是会对视网膜造成损害。</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_nav_007.jpg" /></p>
<p align="center">投射到天花板的2个红外光斑</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/teardown_nav_008.jpg" /></p>
<p align="center">&nbsp;投射器发出的强烈光线（肉眼不可见）</p>
<p align="left">到这里拆解的部分就结束了，我后来将小车原样装回，运行正常。</p>
<h1 class="std_h1">
<p>扩展开发和hack的思路</p>
</h1>
<p>写这篇文章的目的就是希望能起到抛砖引玉的作用，希望大家一起来做扩充。这里就列出我经过分析得出的一些想法给各位借鉴。因为我自己也没尝试过，一些思路未必正确，也欢迎大家通过实践验证不可行时给出回复:-)</p>
<p>对于扩展，有几种途径：</p>
<ol>
    <li>不修改硬件、尝试修改固件扩充 </li>
    <li>不修改硬件和固件、在PC上二次开发 </li>
    <li>保留驱动部分电路，替换逻辑控制电路 </li>
    <li>完全替换所有电路，使用机械平台 </li>
    <li>仅使用NorthStar定位模块 </li>
</ol>
<p>&nbsp;</p>
<p>这里我将基于我玩机器人的经验，依次给出他们的一些实施思路和相关资源。</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>不修改硬件、尝试修改固件扩充</p>
</h2>
<p>这点至少在理论上是完全可行的，因为Rovio自身就支持固件更新。因此可以像目前路由器烧录openwrt的模式来支持自己写的第三方固件。但目前Rovio并没有宣称他们开放了源代码。并且Rovio的固件采用了eCos RTOS[7]，而非Linux操作系统。这对于普通爱好者来说挑战不小。</p>
<p>&nbsp;</p>
<p>但如果真要走这条路，那有如下资源可用</p>
<p>a) 有渠道声称官方提供了部分的源代码[8]</p>
<p>b) eCOS是类似GPL的开源授权，OS代码可搞定</p>
<p>c) WIFI模块是mavell的芯片，这部分的驱动代码可以获取</p>
<p>d) 外设的驱动逻辑比较简单</p>
<p>&nbsp;</p>
<p>不过这样做是难度最大的，差不多是完全重写了固件。这样还不如直接替换逻辑控制电路，采用其他方案，比如使用703N+Linux。</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>不修改硬件和固件、在PC上二次开发</p>
</h2>
<p>这应该是一种最可行也是目前资源最多的办法。毕竟已经有第三方的控制终端出现，也有不少朋友说Rovio支持CGI方式的外部控制。但这也是灵活度最低的一种方式。首先无法修改固件的总总问题，也无法获得NorthStar的定位信号</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>保留驱动部分电路，替换逻辑控制电路</p>
</h2>
<p>这是我推崇的一种做法。前面的分析大家应该只到了rovio的驱动电路和控制电路是2个独立的模块。而驱动部分其实无非就是一系列的IO控制信号或者PWM信号（控制电机）。做过机器人的朋友都会对此很熟悉。那么只要搞清楚如何使用驱动模块，就可以在任何其他控制板（arduino、STM32开发板、WR703、MK802、Atom主板...)来驱动Rovio。</p>
<p>这里的实施办法是去使用多通道的逻辑分析仪或者示波器或者万用表，在控制Rovio运行时，对每个IO的电平进行测量。很容易就知道每条控制信号的含义以及如何驱动其对应的设备。</p>
<p>随后找一个自己熟悉的控制板，编写控制逻辑即可。对于可以用的控制板，我有几个推荐方案：</p>
<p><strong>1) WR703N + Arduino</strong></p>
<p>WR703N是TPLink出的一款袖珍无线AP。但有了OpenWRT支持后，可以利用它做更多的事情。加我weibo的朋友应该知道我之前给它写过超频的补丁。网上也有不少人基于他实现wifi摄像头小车。本质上，有了OpenWRT提供的BSP，这就是一个廉价高性能的WIFI MIPS的linux开发板。并且400Mhz的主频和32Mb内存是足够开发rovio的应用了。</p>
<p>但是WR703没有足够的IO口用于Rovio的驱动板通讯，此时可以考虑通过usb串口与一个arduino控制板连接，由arduino完成与rovio驱动板的通讯，甚至可以直接用arduino来接收对所有硬件的控制。arduino可与WR703中的linux程序用串口交互</p>
<p>而在视频传输上，可以用mjpg-streamer轻松实现wifi视频的能力，这部分网上有不少资料，就不再罗嗦了。</p>
<p><strong>2) MK802 + Arduino</strong></p>
<p>这其实与WR703类似，但好处是MK802的运算能力强大很多，这可以允许诸如计算机视觉、SLAM定位地图构建、人物识别和语音交互这类高级应用可以直接运行在Rovio上。但相比较我把这个列为第二推荐的方案。主要是因为MK802的功耗相比703N高了太多。这会影响待机时间。而MK802的高运算速度此处其实不是非常必要。一方面WR703的400Mhz已经足以胜任很多高级算法，即使是跑OpenCV，简单的视觉识别算法也是可以完成的。另外真正复杂的计算，MK802也显得力不从心，此时可以利用wifi摄像头的功能，在无线的另一头使用高性能的PC处理器来完成复杂的视觉计算。</p>
<p><strong>3) Raspiberry-PI (树莓派)</strong></p>
<p>自然树莓派也能做这些事情，并且它直接有GPIO输出，可以将arduino省略。这也是一种不错的方案，并且正好是上述2个方案的折中。</p>
<p>&nbsp;</p>
<p>对于熟悉这类开发板或者其它类似开发平台的朋友来说，在rovio上实现基本控制、视频传输等应该都是比较方便的。但对于自主返回充电和坐标记录就有一定实现困难。这里就需要将Rovio的NorhStar定位模块驱动起来，这部分的思路我将在后面介绍。</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>完全替换所有电路，使用机械平台</p>
</h2>
<p>这部分的过程其实就很简单，前面的拆解分析可以看到rovio的机械部分都是很普通的设备，电机、LED等。这些均能使用arduino驱动器来。如果要这样做，其实就等于购买了一个小车底盘。</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>&nbsp;仅使用NorthStar定位模块</p>
</h2>
<p>对于Rovio最有价值的NorthStar定位模块这里将额外介绍一下。我相信对于做机器人的朋友来说都遇到一个问题就是如何在室内进行定位。在室外有GPS可用，而室内却不行。此时就需要有几种手段</p>
<p>1) 航迹推算</p>
<p>完全使用里程计（电机的编码器）以及惯性导航设备（如陀螺仪，但Rovio没有）来估算出机器人的运动轨迹。这种方式实现起来比较简单，但实际中航迹推算就像人在沙漠中行走，如果缺乏外部的观测设备，就容易走偏方向，因为无论运行还是测量都是由误差的。航迹推算的问题就是误差会越来越大。</p>
<p>这部分的过程有一篇经典的论文推荐WhereamI[9]。</p>
<p>2) 使用激光雷达等高级传感器</p>
<p>如果有这类的设备，室内定位问题很容易解决。目前市面有很成熟的SLAM算法如ICP-SLAM可以解决。</p>
<p>3) 视觉定位法</p>
<p>如RoboPeak使用的全局视觉定位给RPmini提供定位服务：</p>
<p align="center"><img alt="" src="/data/pic/roviohacks/cv-rpmini.jpg" /></p>
<p>这类方法需要架设或者投射一些视觉符号给机器人使用。而这里的NorthStar定位也属于这种方式。</p>
<p>Northstar的思路正好与传统的视觉定位相反：它将视觉定位的标记符号（红外光斑）投射到了天花板，而在机器人上采用视觉传感器（Northstar通过简化算法，仅使用了几块感光器件）感受标记符号的光信号，并进而进行几何分析，计算出机器人在一定坐标系下的坐标和方向角。</p>
<p>有了这个概念后，大家应该明白NorthStar大概是用来做什么的了吧？并且前文我提到厂家对于他的定位性能给出的数据还是很具有诱惑力的：最差也可以保障30cm的误差。</p>
<p>这里说下如何使用其这个模块，因为我自己没有尝试，这里的只是可行的思路，如果大家进行了验证，不妨回复本文说明下情况</p>
<p>前面分析中可知NorthStar使用串口通讯，<strong>自然可以做的第一件事情就是将串口信号连接PC观察它输出了什么</strong>。而一般串口的波特率无法使9600 115200这些常用的。可以逐个尝试。另外就是如果幸运的话，串口的协议大多是基于文本的，这样含义很容易被理解。</p>
<p>当然，这样的思路也有不管用的可能，或者就是输出的数据难以被猜出含义。此时就可以找官方的网站寻找资料了。</p>
<h1 class="std_h1">
<p>小结</p>
</h1>
<p>不小心又扯了那么多，本文我给了几个基于自己经验的对Rovio进行扩展开发的可信手段，希望能对大家有所帮助:-)</p>
<h1 class="std_h1">
<p>参考资料</p>
</h1>
<p>[1] Wowwee Rovio公司主页</p>
<p><a href="http://www.wowwee.com/en/products/tech/telepresence/rovio/rovio"><u>http://www.wowwee.com/en/products/tech/telepresence/rovio/rovio</u></a></p>
<p>&nbsp;</p>
<p>[2] 【視象測試報告】試玩 Wowwee Rovio：識行識走識攝錄的「火星曱甴」！</p>
<p><a href="http://amanda_hoic.mysinablog.com/index.php?op=ViewArticle&amp;articleId=2041357"><u>http://amanda_hoic.mysinablog.com/index.php?op=ViewArticle&amp;articleId=2041357</u></a></p>
<p>&nbsp;</p>
<p>[3] Welcome to Cornell Robocup</p>
<p><a href="http://www.cis.cornell.edu/boom/2005/ProjectArchive/robocup/"><u>http://www.cis.cornell.edu/boom/2005/ProjectArchive/robocup/</u></a></p>
<p>&nbsp;</p>
<p>[4] NorthStar</p>
<p><a href="http://www.evolution.com/products/northstar/"><u>http://www.evolution.com/products/northstar/</u></a></p>
<p>&nbsp;</p>
<p>[5]&nbsp;NorthStar's Specifications</p>
<a href="http://www.evolution.com/products/northstar/spec.masn"><u>http://www.evolution.com/products/northstar/spec.masn</u></a>
<p>&nbsp;</p>
<p>[6] Mint Cleaner</p>
<p><a href="http://mintcleaner.com/howitworks/northstar/"><u>http://mintcleaner.com/howitworks/northstar/</u></a></p>
<p>&nbsp;</p>
<p>[7] eCos RTOS</p>
<p><a href="http://ecos.sourceware.org/"><u>http://ecos.sourceware.org/</u></a></p>
<p>&nbsp;</p>
<p>[8] 外界声称的部分Rovio官方源代码</p>
<p><a href="http://www.robocommunity.com/download/17502/Rovio-eCos-Code/">http://www.robocommunity.com/download/17502/Rovio-eCos-Code/</a></p>
<p>&nbsp;</p>
<p>[9] Where am I?&quot; --Systems and Methods for Mobile Robot Positioning</p>
<a href="http://www-personal.umich.edu/~johannb/position.htm"><u>http://www-personal.umich.edu/~johannb/position.htm</u></a>
<p>&nbsp;</p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/289.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=289</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=289&amp;key=dfcfe49f</trackback:ping></item><item><title>给MK802(USB大小的Android4.0小PC)引出串口信号，变成ARM开发版</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/288.html</link><pubDate>Wed, 27 Jun 2012 08:51:06 +0800</pubDate><guid>http://www.csksoft.net/blog/post/288.html</guid><description><![CDATA[<div class="quote">最近忙各类事情，blog写的不系统，见谅。</div>
<p>这几天搞到了前不久被媒体宣传过的只有U盘大小的Android 4.0小PC。他的样子如下，使用HDMI接口连接显示器再外接一个usb键盘鼠标就能作为PC用了。</p>
<p align="center"><img alt="" src="http://www.blogcdn.com/www.engadget.com/media/2012/06/mk802herohandsonyeh.jpg" /></p>
<p>托朋友买了台，试用了下果然还不错，虽然是Mali 400MP + Cortex-A8 的配置，不过感觉播放1080p媒体很流畅，3D渲染没怎么测试，不过依照我以前接触mali 400的经验看，不会差到哪里，但也好不到哪里。</p>
<p>硬件上他使用了全智(Allwinner)的A10 CPU，实际为Cortex-A8 + Mali400 MP GPU。1G DDR以及集成的usb WIFI和一个usb host以及一个usb OTG。仅支持HDMI输出音视频。一些内部照片贴在这：</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_internal_001.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_internal_002.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_internal_003.jpg" /></p>
<p>如果就想把它当作一台小pc来用，那么就应该到此收手，安心的用了。但相信也有不少朋友和我一样，不满足于这些功能，想完全发挥出这么小巧的arm主板的性能，那还需要做几件事情</p>
<p>1. 拿到kernel source以及相关的driver code。业内称为BSP(board support package)</p>
<p>2. 获得串口调试信息</p>
<p>第一件事情我们已经不用操心了，网上已经有针对A10的kernel code，且可以用于MK802的机器。对于第二件事情，我之前并没在网上看到有人说明如何在MK802上引出串口，但其实看了内部PCB也不难发现办法。在介绍前，我先和不明白引出串口信号的朋友介绍下这样做的目的：</p>
<p>一般做linux kenrel（其实是所有kernel层次）的开发，没有VC IDE debugger这种好用的工具，就连gdb server很多时候都不管用。最常见的办法就是通过printf把日志从串口打印出来调试。（当然如果正在开发串口驱动，那只好通过点亮几个LED灯来调试了，这听上去很疯狂，但这是事实）。虽然也有ICE/JTAG这类硬件调试器，但对于linux kernel这类OS的调试，硬件调试器就显得很不直观，而且很多time critical的逻辑无法通过下断点复现。因此，一般做硬件/kernel/驱动层次开发，有一个用于打印printk信息的串口是非常必要的。</p>
<p>估计又有人问，这和现在有什么关系？我们只是使用MK802，又不是做开发。呵呵，这里我们就是希望做一些&ldquo;开发&rdquo;。比如从简单的控制MK802上几个IO（就像arduino那样）到修改usb驱动、优化GPU驱动等等，都是hacker喜欢做的事情。那么，没有串口调试怎么行？</p>
<p>不扯开了，其实串口信号很好引出，具体见下图：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_serial_raw.jpg" /></p>
<p>PCB上其实有对应的测试点，但是没有丝印标出信号含义，但其实很容易猜到：右起第二个肉眼就能看出是GND。最右侧通过万用表测量横定是3V3。那自然是VCC。左边2个自然有很大嫌疑是TXD和RXD的TTL电平的串口信号。那么怎么确定那个是TX哪个是RX? 注意左起第二个有一个上拉电阻。一般输入信号才要上拉/下拉。那很可能就是RX。用示波器看了下，果然最左侧有信号发出。果断焊上线路，启动putty，看到了熟悉的uboot画面和kernel dmesg。可惜厂家把tty给禁用了，没法登陆console。但没关系，反正有kernel source，自己编一个即可。从dmesg中也可看出，厂家对系统的优化基本没做，很多内部调试log都还在:-P</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_serial_screenonly.jpg" /></p>
<p align="center">Uboot和Kernel启动log</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_serial_screen.jpg" /></p>
<p align="center">使用putty连接usb串口</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_serial_exported.jpg" /></p>
<p align="center">将引出的串口信号连接usb转串口适配器</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/mk802/mk802_serial_exported_and_fix.jpg" /></p>
<p align="center">用热熔胶保护，防止短路</p>
<p>最后提醒看的手痒的朋友一声：焊盘间距比较小，小心短路。</p>
<p><a href="http://www.csksoft.net/data/code/mk802_log.txt">http://www.csksoft.net/data/code/mk802_log.txt</a></p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/288.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=288</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=288&amp;key=f5c0b506</trackback:ping></item><item><title>自制低成本3D激光扫描测距仪(3D激光雷达)，第二部分</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html</link><pubDate>Tue, 29 Nov 2011 08:25:44 +0800</pubDate><guid>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html</guid><description><![CDATA[<div class="quote">
<p>这是本系列文章的第二部分，着重介绍我自制3D激光雷达的制作、校正过程。</p>
<p>对于其中的原理，请参考前一篇文章：</p>
<p>&nbsp;</p>
<p><strong>目前本制作已经开源，代码托管于google code。请访问项目页面下载</strong></p>
<p><a href="http://code.google.com/p/rp-3d-scanner"><u>http://code.google.com/p/rp-3d- scanner</u></a></p>
</div>
<h2 class="std_h2">自制低成本3D激光扫描测距仪(3D激光雷达)，第一部分</h2>
<p><a href="http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html">http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html</a></p>
<div class="quote">
<p>版权信息：</p>
<p>本文采用<a target="_blank" href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/"><font color="#0066ff">CreativeCommons2.5</font></a>授权许可，欢迎转载，但请保留原始作者信息以及原文链接。 </p>
</div>
<h1 class="std_h1">1. 设备设计<a name="mainpart"></a></h1>
<h2 class="std_h2">核心元件原型</h2>
<p>在第一篇文章的原理介绍[1]中，已经大致提到了本次制作的核心元件：摄像头、激光器以及进行扫描的伺服电机的 选型要求。</p>
<p>对于我期望的精度和性能，一般市面常见的USB VGA摄像头即可满足要求。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/camera_used.jpg" /></p>
<p align="center">图：本制作使用的USB摄像头(已经拆除外壳)</p>
<p>对于激光器的选择，主要是考虑他的发射波长和功率。由于我的制作并不用像产品那样考虑激光器功率安全[2]问题 ，因此，采用了200mW的红外一字线激光器。较大功率的优势是可以通过缩短摄像机曝光速率，从而从画面上过滤到环 境光的干扰，同时也可以扫描较远的距离。当然，200mW的激光器功率的确有点太大了，<strong>在使用时注意不能用 眼睛直视，并且红外激光器人肉眼不可见，所以需要额外的当心</strong>。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/irlaser.jpg" /></p>
<p align="center">图：制作所使用的红外一字线激光器</p>
<p>在使用了红外激光器后，可以通过给摄像头加装红外滤光片。它可以将肉眼可见光过滤，仅允许激光器发出的红外 光进入摄像头。从而有效地过滤环境光带来的干扰。对于红外滤光片，最佳的选择是使用与激光器发射波长相匹配的滤 光片，比如如果使用的是808nm的激光器，那么滤光片选择808nm的窄带滤光片最合适，这样做可以最大程度的降低干扰 。因为现实中，日光、白炽灯、遥控器也都会发出红外光谱。</p>
<p>但是这样的滤光片一般价格偏贵，在本制作中，我使用了800nm截至的低通滤光片。它允许任何波长低于800nm的红 外光通过。不过实际效果还是不错的。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/ir_filter.jpg" /></p>
<p align="center">图：本制作采用的低通红外光滤光片</p>
<p>对于用于扫描的伺服电机，由于摄像头的帧率是30fps。扫描速度不需要很快，因此这里使用了普通的标准舵机。他 的优势是可以直接控制定位到特定角度，驱动也相对容易。不过精度不高，对于0.3度的角度定位，已经有些吃力了。 这也是值得改进的地方。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/servo_sel.jpg" /></p>
<p align="center">图：本制作选用的舵机</p>
<p>这里统一列出他们的参数：</p>
<div class="quote">
<p>摄像头：VGA画质的USB摄像头，30fps (市面普遍可以购买的型号)。非广角</p>
<p>激光器：50mW 红外一字线激光 808nm</p>
<p>滤光片：10mm直径红外低通滤光片</p>
<p>舵机：HS-322hd 43g标准舵机</p>
</div>
<h2 class="std_h2">安装考虑</h2>
<p>这里主要针对原理[1]中提到的几个参数的选择，决定激光器、摄像头的安装方式。在[1]中，我提到了摄像头焦距 和摄像头-激光器距离(s)的乘积f*s应当满足：</p>
<div class="quote">fs&gt;=700</div>
<p>一般市面USB非广角镜头的摄像头的焦距在4.5mm左右，因此，s一般选择160mm左右。也就是说，摄像头和激光器的 间距在160mm或者以上。当然，如果觉得这间距太大了，也可以稍微缩小，正如[1]提到的，目前摄像头的像素尺寸一般 比较小。</p>
<p>另外一个在安装中要考虑的参数是激光器夹角beta。[1]中同样提到他的值在83deg左右。对此，安装的时候不必也 不能死板的测量角度并安装，这是因为除非使用了工业精工级别的激光器，否则激光器发出的激光射线也存在夹角。 </p>
<p>beta角度可以在安装完成后进行多次修正，保证在较远处，画面中仍然可以看到激光轨迹，再进行固定。</p>
<h1 class="std_h1">2. 机械和结构部分</h1>
<h2 class="std_h2">对摄像头的改装</h2>
<p>由于我们使用了红外激光器，因此需要对摄像头做一些修改。</p>
<p>首先是要移除摄像头镜片中的红外截止滤光片。该滤光片的作用与前文提到的红外滤光片功能恰好相反：它将红外 光谱过滤。一般摄像头内都会含有这种滤光片。如果不移除，则只能够感受到很微弱的红外信号。（题外话，可以用拆 除截至滤光片的摄像头观察kinect投射出来的红外图案)</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/ir-cutoff_on_the_len.jpg" /></p>
<p align="center">图：位于摄像头镜头中的红外截止滤光片</p>
<p align="left">其次就是将前面提到的红外低通/带通滤光片安装到摄像头中，这里采用比较山寨的组装方式:用胶布固 定在镜头前面，不过效果也可以接受。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/camera_with_irf.jpg" /></p>
<p align="center">图：将红外低通滤光片安装在摄像头上</p>
<h2 class="std_h2">制作激光器、摄像头的固定平台</h2>
<p>这里使用了轻质的木板来安装摄像头和激光器。选择它的主要原因是容易加工。如果有条件，可以考虑使用热缩涨 比率小的金属或者塑料材料来固定。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/org_woodenbar.jpg" /></p>
<p align="center">图：使用木板作为固定摄像头、激光器的材料</p>
<p align="left">在木板上打孔，保证激光器和摄像头能正好装入，2个孔之间的距离是前文提到的160mm左右。不过不必 很精确，因为它的精确数值可以通过校正得到。这样安装的时候就比较省心。在给激光器打孔的时候要注意角度的问题 。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/mounted_wooden_01.jpg" /></p>
<p align="center">图：木板打孔后，将摄像头和激光器装入</p>
<p align="left">&nbsp;</p>
<p align="center">&nbsp;<img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/mounted_wooden_02.jpg" /></p>
<p align="center">图：在木板底部打孔，安装螺丝柱，用于固定在舵机转盘上</p>
<h2 class="std_h2">底座和舵机安装</h2>
<p>我是用了用于安装仪器的塑料盒子作为扫描仪的底座，这类盒子可以在taobao上找到。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/raw_case_and_servo.jpg" /></p>
<p align="center">图：选用的塑料盒子和舵机</p>
<p>将盒子顶板开孔，使得舵机能够放进去：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/case_with_the_hole.jpg" /></p>
<p align="center">图：将盒子开孔</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/case_with_servo.jpg" /></p>
<p align="center">图：将舵机嵌入盒子顶板</p>
<p align="left">最后将之前的摄像头固定支架安装于舵机上：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/allmounted_woodenbar.jpg" /></p>
<p align="left">&nbsp;</p>
<h1 class="std_h1" align="left">3. 电子系统制作</h1>
<p>这里的电子系统主要功能是从PC接受指令并控制舵机转到指定角度的。由于摄像头已经是USB接口了，所以这里的电 子系统不用去处理摄像头的信号。</p>
<p>目前PC外设使用USB几乎已经成为了一种标准，为了使得设备使用尽可能方便，如果能做到免驱动，那就更加完美了 。</p>
<p>这里我才用了我们RoboPeak机器人团队设计的一款AVR开源控制版：<a target="_blank" href="http://www.robopeak.net/blog/?p=133">RoboPeak Usb Connector</a>[2]来实现这部分功能。它使用单片AVR(Atmega88)芯片通过软 件方式模拟出USB协议栈，并且使用了HID协议使得无需在PC上安装驱动程序。对于这部分的细节属于固件实现部分，将 在后文提到。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/blog/upload/release_ver(1).jpg" /></p>
<p align="center">图: 我们RoboPeak团队的开源USB方案：RP USB Connector（蓝色PCB）</p>
<p>这里列出本制作中电子系统所实现的功能</p>
<div class="quote">
<p>实现了一个HID类的USB设备，无需第三方驱动程序支持</p>
<p>支持通过USB接受指令，控制舵机运转到指定角度</p>
<p>可通过USB指令，开启/关闭激光器</p>
<p>通过一个双米字LED显示屏，显示当前舵机的角度</p>
<p>支持用户通过设备上按钮手工设置舵机角度</p>
</div>
<p>对于USB设备的实现、接收处理USB指令等属于固件范畴的职责，这里将不做讨论。这里使用了RP USB Connector， 因此其固件已经支持了此部分的基础操作，也可以在他的介绍页面[2]查看详情。</p>
<h2 class="std_h2">米字LED数码管的驱动</h2>
<p>由于2个米字形LED含有16多个独立的LED需要独立控制，RP USB Connector上并没有如此多空闲IO口。因此这里的做 法是很传统的采用74595串行转并行输出芯片。RP USB Connector上通过SPI总线进行控制。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/led_disp.jpg" /></p>
<p align="center">图：使用2个74595芯片驱动双米字LED数码管</p>
<h2 class="std_h2">扩充RP Usb Connector</h2>
<p align="left">由于RP Usb Connector主要功能是做为AVR芯片编程器和通用USB开发版的，上面并没有舵机控制和激光 器控制功能（需要三极管扩流）。因此需要做一块额外的电路扩充它的功能。电路比较简单，这里就不介绍了，可以参 考本章节模块给出的电路图。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/rpbridge_used_01.jpg" /></p>
<p align="center">图：在RP USB Connector基础上做扩充电路</p>
<h2 class="std_h2">制作角度手工控制面板</h2>
<p align="left">这部分做的比较粗糙，主要就是在塑料盒子外边加装按钮，就不多介绍了，给一些制作的照片。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/switch_installed.jpg" /></p>
<p align="center">图：按钮(正面)</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/switch_installed_back.jpg" /></p>
<p align="center">图：按钮(背面)</p>
<h2 class="std_h2">总装</h2>
<p align="left">最后将所有线路连接起来，并关闭盒子，设备的安装就大功告成。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/asm/rpbridge_used_02.jpg" /></p>
<p align="left">这里给出一个早期的视频：</p>
<p align="center"><embed height="400" type="application/x-shockwave-flash" width="480" src="http://www.tudou.com/v/EB_VaIjklCo/&amp;rpid=70789997/v.swf" quality="1" menu="menu" loop="loop" scale="ShowAll" allowscriptaccess="always" allowfullscreen="true" wmode="opaque"></embed></p>
<p align="left">&nbsp;</p>
<h2 class="std_h2">电子系统电路原理图：</h2>
<p align="left">RoboPeak USB Connector电路图：</p>
<div class="quote">这部分请访问位于google code托管的开源项目：<a href="http://code.google.com/p/rp-usb-connector/"><u><font color="#0066cc">http://code.google.com/p/rp-usb-connector/</font></u></a></div>
<p align="left">扩展电路/LED驱动电路原理图：</p>
<div class="quote">
<p>目前本制作的所有源代码和电路也已经托管于Googe code, 请访问如下地址下载：</p>
<p><a href="http://code.google.com/p/rp-3d-scanner"><u>http://code.google.com/p/rp-3d- scanner</u></a></p>
</div>
<h1 class="std_h1">4. 固件以及PC通讯</h1>
<p>这里的固件自然就是运行在RoboPeak USB Connector AVR芯片上的固件代码了。这里只大致列出实现的思路和原理 。具体的细节以及基础知识不做介绍。源代码可以在本制作的google code项目页面[3]上找到。</p>
<h2 class="std_h2">
<p>固件实现的功能</p>
</h2>
<p>如前文所述，固件实现了：</p>
<ol>
    <li>通过软件方式模拟出USB1.1协议栈(使用了v-usb库[4]) </li>
    <li>实现了HID(Human Input Device)类的USB设备进行通讯，在PC上无需外驱动 </li>
    <li>控制舵机角度 </li>
    <li>驱动LED数码管显示 </li>
</ol>
<p>同时，固件代码采用了我之前写的Arduino-Lite[5]轻量级AVR固件库。因此如果需要使用这里的固件代码，请在 google code上下载并配置Arduino-Lite[6]。</p>
<p>接下来我将跳出一些典型问题介绍</p>
<h2 class="std_h2">
<p>HID-USB设备的模拟及与PC通讯</p>
</h2>
<p>RoboPeak USB Connector使用的是不含有USB接口的AVR芯片。因此，USB通讯支持是采用软件方式进行的。索性目前 v-usb开源库[4]已经提供了很优秀的封装。</p>
<p>软件模拟usb的优势在于可以降低设备成本(带有USB的AVR芯片成本较高），缺点是稳定性和速率上不如硬件实现。 对于本制作，稳定性和速度并不关键。</p>
<p>在使用USB与PC通讯时有一个烦恼的问题是驱动。直接为系统编写驱动程序会提升本制作的难度，同时对于64位 Windows系统，微软要求驱动程序进行签名。目前也有一种可以在用户态实现usb驱动的方案：libusb。但是，同样在64 位Windows系统上，这个做法就不管用了。</p>
<p>这里采用了另一种思路：利用那些OS自带驱动支持的USB类设备。(USB协议中预先定义了几类USB设备的种类，比如 Mass Storage就是平时用的移动硬盘、UVC设备常用于实现摄像头、HID设备用于实现键盘鼠标。OS往往会自带驱动支持 这类设备）。这里我也使用了HID类设备。理由如下：</p>
<ol>
    <li>协议比较简单，通讯单位也是数据包 </li>
    <li>支持USB1.1低速率规范，可以用v-usb实现 </li>
    <li>在Windows、Linux、Mac上均可以通过OS提供的用户态API与HID设备通讯 </li>
</ol>
<p>采用了HID设备后，及时在计算机上第一次使用本扫描仪，OS也能直接识别，不会要求安装驱动或者配置文件。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/screenshot/usbdev.png" /></p>
<p align="center">图：本扫描仪在PC上识别为HID设备</p>
<p align="center">&nbsp;</p>
<p align="left">接下来的问题是如何利用HID设备进行通讯了。这里的做法千差万别。为了提高通讯质量，这里我使用 了带有checksum交验的，基于数据包的通讯协议，将它运行在HID协议之上。因为本固件是基于RP USB Connector固件 的缘故，我直接采用了用于AVR芯片烧录器的STK500v2协议。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/design/protocol_stack.jpg" /></p>
<p align="center">图：本制作的通讯构架</p>
<h2 class="std_h2">
<p align="left">舵机驱动逻辑</p>
</h2>
<p align="left">在AVR上有很多舵机驱动库，这里我使用的是RoboPeak对Arduino自带舵机库的修改版本，该版本使用 Arduino-Lite进行了重写，精度上也较高。但这部分不影响具体效果，因此就不多介绍了。</p>
<h2 class="std_h2">
<p align="left">数码管驱动逻辑</p>
</h2>
<p align="left">在RP USB Connector上引出了SPI总线，因此很自然的我使用SPI协议驱动74595芯片，直接通过AVR控制 数码管的每个LED，从而支持显示任意的图案。</p>
<p align="left">要注意的是，由于双米字管的每个字符上相同位置的LED公用信号线，因此在驱动上需要采用传统的扫 描方式，轮流点亮LED。</p>
<h1 class="std_h1">5. 图像处理和渲染</h1>
<p>图像处理部分就是第一篇文章[1]所介绍的几个步骤：</p>
<ol>
    <li>获取摄像头原始画面 </li>
    <li>通过摄像头校正参数，消除画面扭曲 </li>
    <li>提取和识别激光光斑的位置 </li>
    <li>通过激光光斑的位置，代入距离求解公式，算出对应点真实距离 </li>
</ol>
<p>本制作使用了OpenCV库简化图像计算的开发难度。同时这样也有利于代码的跨平台移植。对于摄像头的校正，会在 后文介绍。</p>
<p>这部分的细节已经在第一篇文章中详细介绍了，因此这里给出程序运作中的截图作为示意：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/screenshot/processing_stages.png" /></p>
<p align="center">图：对摄像头画面进行扭曲校正并识别激光点的过程</p>
<p>&nbsp;</p>
<p>由于采用了红外激光器，在加装滤光片后，背景光干扰被有效的去处。画面上除了激光光斑外，几乎看不到别的内 容。红外激光在摄像头中以偏紫色的色彩显示。</p>
<p>上图中显示了画面中心点的激光中心坐标值。这样做的目的是用于后期进行测距参数的校正。而使用中心点的原因 在第一篇文章中已经介绍。</p>
<h2 class="std_h2">
<p>渲染点云</p>
</h2>
<p>在视频中看到了实时扫描并显示点云的画面。在明白了扫描原理后，这点就没什么特别的了。基本上都是基本的3D 渲染得技巧。我使用了Irrlicht[7]开源3D引擎简化了这部分的实现工作。</p>
<p>除了自行编写软件外，也有很多工具可以用来查看3D点云。比如开源的MeshLab[8]，Blender[9]以及Matlab。在后 文我将给出可以在Meshlab中观看的点云数据。</p>
<p>要产生可被这类软件读取的文件很容易，像MeshLab支持如下格式的文本点云数据</p>
<div class="quote">
<p><font face="Courier New">x1,y1,z1</font></p>
<p><font face="Courier New">x2,y2,z2</font></p>
<p><font face="Courier New">...</font></p>
<p><font face="Courier New">xn,yn,zn</font></p>
</div>
<p>&nbsp;</p>
<h1 class="std_h1">6. 校正</h1>
<p>当完成所有部分制作和PC端软件后，就可以进行校正工作了。校正主要分为：相机校正和测距校正。</p>
<h2 class="std_h2">
<p>相机校正</p>
</h2>
<p>我使用自己打印的Chessboard图案，分别在不同距离和位置下拍摄了不同画面。校正工具使用了matlab的Camera Calibration Toolbox。它的信息请参考第一篇文章的参考文献[10]。OpenCV也包含了相机校正功能，也可以直接使用 。</p>
<p align="center"><img alt="" src="http://secure.csksoft.net/data/pic/3dscanner/calibration/calib_cam_chessboard_array.png" /></p>
<p align="center">图：用棋盘图在不同位置下拍摄画面</p>
<p align="center"><img alt="" src="http://secure.csksoft.net/data/pic/3dscanner/calibration/calib_cam_chessboard_01.png" /></p>
<p align="center">图：使用matlab进行校正时识别出的Inner Corner</p>
<p align="center"><img alt="" src="http://secure.csksoft.net/data/pic/3dscanner/calibration/calib_cam_ext_result.png" /></p>
<p align="center">图：校正计算的外部参数(对本制作无用)</p>
<p align="left">在完成校正后，将得到如下的校正参数：</p>
<div class="quote">
<p><font face="Courier New">Calibration results (with uncertainties):</font></p>
<p><font face="Courier New">Focal Length:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fc = [ 935.44200&nbsp;&nbsp; 929.73860 ] ? [ 11.29945&nbsp;&nbsp; 10.64268 ]<br />
Principal point:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cc = [ 149.00014&nbsp;&nbsp; 233.25474 ] ? [ 17.13538&nbsp;&nbsp; 11.11605 ] <br />
Skew:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alpha_c = [ 0.00000 ] ? [ 0.00000&nbsp; ]&nbsp;&nbsp; =&gt; angle of pixel axes = 90.00000 ? 0.00000 degrees<br />
Distortion:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kc = [ - 0.13196&nbsp;&nbsp; -0.05787&nbsp;&nbsp; -0.00358&nbsp;&nbsp; -0.01149&nbsp; 0.00000 ] ? [ 0.04542&nbsp;&nbsp; 0.12717&nbsp;&nbsp; 0.00195&nbsp;&nbsp; 0.00565&nbsp; 0.00000 ]<br />
Pixel error:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = [ 0.24198&nbsp;&nbsp; 0.25338 ] </font></p>
<p><font face="Courier New">Note: The numerical errors are approximately three times the standard deviations (for reference).<br />
</font></p>
</div>
<p>对于这里的应用，之需要关心Focal Length、Principal point、Distortion的几组参数。可以使用OpenCV的 cvInitUndistortMap/cvRemap读取校正参数并<font face="Verdana">完成画面扭曲消除。</font></p>
<font face="Verdana">
<h2 class="std_h2">
<p align="left"><font face="Verdana">测距参数校正</font></p>
</h2>
<p align="left">&nbsp;</p>
<p align="left"><font face="Verdana">需要校正的参数请参考前一篇原理文章。要开始测距校正，首先要求PC客户端软 件已经能够得到激光光斑中心位置了。这里给出对画面中心位置激光光斑测距参数校正的过程。至于这样做的理由，已 经在第一篇文章中详细介绍了。其他的参数可以用相同的思路进行。</font></p>
<p align="left"><font face="Verdana">理想的校正环境是比较空旷的区域，前方有垂直的白墙用于反射激光光斑。并配 备高精度的测距仪器参考。我没有这样的条件，也没有必要如此，因此采用了比较山寨的参考设备：卷尺。 </font></p>
<p align="center"><img alt="" src="http://secure.csksoft.net/data/pic/3dscanner/calibration/perform_ranger_calib.jpg" /></p>
<p align="center">图:进行测距参数校正</p>
<p align="left"><font face="Verdana">上图正是在制作本测距仪时进行校正所拍摄的照片。所需要的设备就是一把卷尺 ，当然最好能够足够长，有5-6m。这样可以校正到较远的距离。一般校正到5米是必须的。</font></p>
<p align="left">校正至少需要采集2个参数：实际的距离值，激光光斑中心点位置。校正采集到的数据自然是越多也好 ，但一般6个以上的点即可。</p>
<p align="left">如下是本制作校正采集的数据：</p>
<div class="quote">
<p align="left"><font face="CourierNew">Dist&nbsp;X<br />
146.8&nbsp;14.79<br />
246.8&nbsp;259.63<br />
346.8&nbsp;356.72<br />
446.8&nbsp;420.24<br />
5 46.8&nbsp;457.9<br />
746.8&nbsp;503.58<br />
946.8&nbsp;528.9<br />
1146.8&nbsp;546.71<br />
1546.8&nbsp;567.54<br />
1846.8&nbsp;576.87<br />
2246.8&nbsp;586.08<br />
3046.8&nbsp;597.04<br />
4046.8&nbsp;604.6<br />
5546.8&nbsp;611.9 </font></p>
</div>
<p align="left">在完成了数据采集后，可以在matlab等工具帮助下，进行曲线拟合。拟合的曲线公式正式前一篇文章提 到的式(4)。可以看出采集的数据和理论曲线非常吻合：</p>
<p align="center"><img alt="" src="http://secure.csksoft.net/data/pic/3dscanner/calibration/final_fit.gif" /></p>
<p align="center">图：对校正数据进行的拟合</p>
<p align="left">&nbsp;</p>
<h1 class="std_h1">7. 结果和讨论</h1>
<p>本制作的结果在文章开始的时候已经给出了，简单说，就是达到了我的预期:-)</p>
<p>指标如下：</p>
<div class="quote">
<p>绝对测距精度：1m内-/+10mm与实际值的偏差，5m处最大80mm与实际值的偏差<br />
扫描角度: 0-180度<br />
最小步进 ：0.3度<br />
扫描分辨率: 480 points per sample<br />
扫描速度：30 samples per sec (180度，1度步进需时6秒)<br />
成本：~￥150</p>
</div>
<p>这里给出前面图像和视频中出现的我的扫描像的点云数据，可以在MeshLab中导入察看：</p>
<div class="quote">
<p><a href="http://www.csksoft.net/data/pic/3dscanner/sample/face_scan.zip">http://www.csksoft.net/data/pic/3d scanner/sample/face_scan.zip</a></p>
</div>
<p>同时也给出一些额外的图片和视频：</p>
<p align="center"><a href="http://www.csksoft.net/data/pic/3dscanner/sample/sample_in_matlab.jpg"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/sample/sample_in_matlab_s.jpg" /></a></p>
<p align="center">图：在Matlab中查看点云(点击查看原始图像)</p>
<p align="center"><embed height="400" type="application/x-shockwave-flash" width="480" src="http://player.youku.com/player.php/sid/XMzE4NzY1Nzcy/v.swf" allowscriptaccess="always" quality="high" allowfullscreen="true" scale="ShowAll" loop="loop" menu="menu" wmode="Window"></embed></p>
<p align="center">视频：另一段实时扫面渲染</p>
<p align="center"><embed height="400" type="application/x-shockwave-flash" align="9" width="480" src="http://player.youku.com/player.php/sid/XMzE4MTA0MzMy/v.swf" allowscriptaccess="sameDomain" quality="high" scale="ShowAll" loop="loop" menu="menu" wmode="Window"></embed></p>
<p align="center">视频：matlab中观察点云</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>性能分析</p>
</h2>
<p>这里主要看看扫描精度实现的情况。如果之前校正用的基准数据没有任何误差（实际不可能），激光光点提取算法没有问题，那么实际工作时刻的误差主要就体现在拟合的曲线与实际的函数曲线的差距。换句话说，就是拟合得到的参数于实际正确的参数（我们并不知道）。</p>
<p>当然，上面2个假设实际都是不成立的，不过，我们先加设他们都没有误差，先来分析校正曲线与实际曲线的误差：</p>
<p>&nbsp;</p>
<div class="quote">
<p><font face="Courier New">Dist&nbsp;&nbsp; X&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Diff<br />
146.8&nbsp; 14.79&nbsp; 123.3103843&nbsp;23.48961566<br />
246.8&nbsp; 259.63&nbsp;231.8752505&nbsp;14.92474953<br />
346.8&nbsp; 356.72&nbsp;328.8075565&nbsp;17.99244355<br />
446.8&nbsp; 420.24&nbsp;440.8004392&nbsp;5.99956081<br />
546.8&nbsp; 457.9&nbsp; 546.254414&nbsp; 0.545586001<br />
746.8&nbsp; 503.58&nbsp;758.5428124&nbsp;-11.74281238<br />
946.8&nbsp; 528.9&nbsp; 958.9149139&nbsp;-12.11491386<br />
1146.8&nbsp;546.71&nbsp;1172.910412&nbsp;-26.11041169<br />
1546.8&nbsp;567.54&nbsp;1578.227294&nbsp;-31.42729368<br />
1846.8&nbsp;576.87&nbsp;1862.988106&nbsp;-16.18810582<br />
2246.8&nbsp;586.08&nbsp;2262.96604&nbsp; -16.16604012<br />
3046.8&nbsp;597.04&nbsp;3030.93851&nbsp; 15.86149048<br />
4046.8&nbsp;604.6&nbsp; 3948.153444&nbsp;98.64655635<br />
5546.8&nbsp;611.9&nbsp; 5564.223928&nbsp;-17.42392847</font></p>
</div>
<p>上表是在之前校正中收集的数据基础上得到的，其中Calc列的数据是通过校正后的拟合曲线，通过式(4)的计算得到的测距数据，而Diff就是计算得到的距离和真实距离(Dist)的差值。这里的单位除了X列外都是毫米。</p>
<p>从数据上很直观的可以看到在4046mm处进行测距时，计算结果和实际值相差了98.64mm。相比这个，对于近距离的数据，误差也比较大。对于第二个现象，在前一篇文章的文献[3]猜测这是由于镜头扭曲造成的。但是，大家可能会有疑问了，我的实现不是已经做过相机校正了吗？为何还会有镜头扭曲？这里给出几个可能的解释</p>
<ol>
    <li>相机校正结果存在误差，造成仍旧有细微扭曲</li>
    <li>相机校正也是基于实现设计出来的数学模型，实际情况有很多其他因素均能导致画面扭曲，但他们无法通过目前的校正修正</li>
    <li>红外光的折射率与自然光不同，校正是针对自然光频率范围进行的，因此对于红外光，扭曲依然存在</li>
</ol>
<p>实际的情况可能是这些原因中的几种组合。</p>
<p>另外，别忘了我们之前做的2个假设，实际他们也是不成立的。在得到了这个误差表后，接下来的问题是：可否继续校正来弥补这个误差？前一篇文章的文献[3]表示这也是可以做得，至少有了上面的表格后，可以在对应的距离下直接校正出正确结果。不过这样做的有效性有待验证。</p>
<p>&nbsp;</p>
<p>除了测距精度外，这里也提一下扫描的分辨率。在前文中我提到过目前的舵机可以实现0.3度的角度定位精度。但实际上对于近距离物体扫描，这是不够的。目前的设备比较适合进行大范围扫描，这也比较符合他作为激光雷达的用途。</p>
<h1 class="std_h1">8. 下一步工作</h1>
<p>目前本制作已搞一段落。这里说说我的制作动机和下一步打算。</p>
<p>其实动机在前一篇文章中已经点到，就是用于我们RoboPeak团队的机器人，进行SLAM。这也是接下来我即将进行的事情。当然，其实能做的事情还有很多，比如：</p>
<h2 class="std_h2">
<p>进行多视角扫描，并合成为一个全局点云</p>
</h2>
<p>其实商业的扫描仪都会支持这个应用。目前一次3D扫描只能采集物体的一个表面，而他的背面则无法扫描。如果对物体的背面也进行3D扫描，那就能得到完整的3D模型了。</p>
<p>要实现它，可以有2种办法：</p>
<ol>
    <li>旋转物体本身，扫描仪固定</li>
    <li>扫描仪在不同方位扫描目标物体</li>
</ol>
<p>1的实现和原理很简单，2的核心问题是如何将2次扫描的点云对应起来？除了人肉拼接外，实际上也有比较成熟的算法，这类算法成为Surface Registration。如ICP-Slam也是采用了这样的算法。</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>提高扫描精度和速度</p>
</h2>
<p>更高的精度和速度永远是对这个作品的需求，这就不多解释了。我在原理部分也提到了改善性能的方法。</p>
<h2 class="std_h2">
<p>基于3D点云进行物体识别</p>
</h2>
<p>这个应用就很类似于Kinect。其实实现的算法也是相同的。</p>
<p>这里也提一下一个可用的工具和库：PCL (Point Cloud Library)[10]。他也是又机器人公司WillowGarage推出的开源库。其中包含了可以实现上述扩展的基础库。可以尝试。</p>
<p>&nbsp;</p>
<p>好了，这个系列的文章就告一个段落了，感谢能耐住性子看到这里的朋友们:-) 如果你们愿意，可以在我Blog上的本文留个言让我知道:-) 每次写好这类文章，都感慨写文章要比制作复杂漫长，其中要把自己的想法转化成大家能懂得语言，对我这个表达能力较差的人来说还是蛮辛苦的。</p>
<p>时隔几个月，我blog终于迎来一次比较大的更新。希望自己也能坚持下去，不过，业余时间的确也比以前少了些。不知道我下一篇文章是何时发布呢？当然，我业余时间的另一个投入就是我们RoboPeak团队，大家也可今后在我们团队动态中了解我正在做的事情:-)</p>
<h1 class="std_h1">参考文献</h1>
<p>[1] 自制低成本3D激光扫描测距仪(3D激光雷达)，第一部分<br />
<a href="http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html">http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html</a></p>
<p>&nbsp;</p>
<p>[2]: Driverless USB AVR/51 ISP Programmer powered by RoboPeak<br />
<a href="http://code.google.com/p/rp-usb-connector/">http://code.google.com/p/rp-usb-connector/</a></p>
<p>&nbsp;</p>
<p>[3]: 本制作在Google Code的开源项目页面<br />
<a href="http://code.google.com/p/rp-3d-scanner">http://code.google.com/p/rp-3d-scanner</a></p>
<p>&nbsp;</p>
<p>[4]: V-USB, Virtual USB port for AVR microcontrollers<br />
<a href="http://www.obdev.at/products/vusb/index.html">http://www.obdev.at/products/vusb/index.html</a></p>
<p>&nbsp;</p>
<p>[5]: Arduino-Lite, Lightweight AVR library developed by RoboPeak<br />
<a href="http://www.robopeak.net/blog/?p=131">http://www.robopeak.net/blog/?p=131</a></p>
<p>&nbsp;</p>
<p>[6]: Arduino-Lite Project<br />
<a href="http://code.google.com/p/arduino-lite/">http://code.google.com/p/arduino-lite/</a></p>
<p>&nbsp;</p>
<p>[7]: Irrlicht Engine - A free open source 3d engine<br />
<a href="http://irrlicht.sourceforge.net/">http://irrlicht.sourceforge.net/</a></p>
<p>&nbsp;</p>
<p>[8]: MeshLab OpenSource Project<br />
<a href="http://meshlab.sourceforge.net/">http://meshlab.sourceforge.net/</a></p>
<p>&nbsp;</p>
<p>[9]: Blender OpenSource Project<br />
<a href="http://www.blender.org/">http://www.blender.org/</a></p>
<p>&nbsp;</p>
<p>[10]: PCL - Point Cloud Library<br />
<a href="http://pointclouds.org/">http://pointclouds.org/</a></p>
<p>&nbsp;</p>
</font>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=283</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=283&amp;key=ba4ba216</trackback:ping></item><item><title>自制低成本3D激光扫描测距仪(3D激光雷达)，第一部分</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html</link><pubDate>Wed, 23 Nov 2011 08:41:39 +0800</pubDate><guid>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html</guid><description><![CDATA[<div class="quote">本文介绍我从今年十一假期开始制作的激光3D扫描测距仪的相关原理和制作细节。对于先前提到的激光键盘制作将会在后续文章中详细介绍，不过他们的核心原理是相同的。 </div>
<div class="quote">这是本系列的第一部分，第二部分请访问<br />
<strong>自制低成本3D激光扫描测距仪(3D激光雷达)，第二部分<br />
</strong><a href="http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html"><u>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html</u></a></div>
<div class="quote">
<p>版权信息：</p>
<p>本文采用<a target="_blank" href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/">CreativeCommons2.5</a>授权许可，欢迎转载，但请保留原始作者信息以及原文链接。 </p>
</div>
<p>在开始介绍原理前，先给出一些扫描得到的3D模型以及演示视频，给大家一个直观的认识。</p>
<p align="center"><embed height="400" type="application/x-shockwave-flash" width="480" src="http://www.tudou.com/v/HXPLjJCpWi4/v.swf" quality="1" menu="menu" loop="loop" scale="ShowAll" allowscriptaccess="always" allowfullscreen="true" wmode="opaque"></embed></p>
<h2 class="std_h2">相关的图片：</h2>
<p>&nbsp;</p>
<p align="center"><a href="http://www.csksoft.net/data/pic/3dscanner/sample/sample_inapp.png"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/sample/sample_inapp_s.jpg" /></a></p>
<p align="center">扫描得到的房间一角(点击查看原始尺寸)</p>
<p align="center"><a href="http://www.csksoft.net/data/pic/3dscanner/sample/sample_self.png"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/sample/sample_self_s.png" /></a></p>
<p align="center">扫描的我(点击查看原始尺寸)</p>
<p align="center"><img alt="扫描仪实物图" src="http://www.csksoft.net/data/pic/3dscanner/asm/final_effect.jpg" /></p>
<p align="center">扫描仪实物</p>
<p>&nbsp;</p>
<h2 class="std_h2">
<p>本文结构</p>
</h2>
<ol>
    <li>简单介绍了激光雷达产品的现状 </li>
    <li>激光三角测距原理 </li>
    <li>线状激光进行截面测距原理 </li>
    <li>3D激光扫描仪的制作考虑 </li>
    <li>参考文献 </li>
</ol>
<h1 class="std_h1">简介-激光扫描仪/雷达</h1>
<p>这里所说的激光扫描测距仪的实质就是3D激光雷达。如上面视频中展现的那样，扫描仪可以获取各转角情况下目标物体扫描截面到扫描仪的距离，由于这类数据在可视化后看起来像是由很多小点组成的云团，因此常被称之为：<strong>点云(Point Clould)。</strong></p>
<p>在获得扫描的点云后，可以在计算机中重现扫描物体/场景的三维信息。</p>
<p>这类设备往往用于如下几个方面：</p>
<p>1) 机器人定位导航 </p>
<p>目前机器人的SLAM算法中最理想的设备仍旧是激光雷达(虽然目前可以使用kinect，但他无法再室外使用且精度相对较低)。机器人通过激光扫描得到的所处环境的2D/3D点云，从而可以进行诸如SLAM等定位算法。确定自身在环境当中的位置以及同时创建出所处环境的地图。这也是我制作他的主要目 的之一。</p>
<p>2) 零部件和物体的3D模型重建</p>
<p>3) 地图测绘</p>
<h2 class="std_h2">现状</h2>
<p>目前市面上单点的激光测距仪已经比较常见，并且价格也相对低廉。但是它只能测量目标上特定点的距离。当然，如果将这类测距仪安装在一个旋转平台上，旋转扫描一周，就变成了2D激光雷达 （LIDAR）。相比激光测距仪，市面上激光雷达产品的价格就要高许多：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/3rd/hokuyo.jpg" /></p>
<p align="center">图片: Hokuyo 2D激光雷达</p>
<p>上图为Hokuyo这家公司生产的2D激光雷达产品，这类产品的售价都是上万元的水平。其昂贵的原因之一在于他们往往采用了高速的光学振镜进行大角度范围(180-270)的激光扫描，并且测距使用了计算发射/反射激光束相位差的手段进行。当然他们的性能也是很强的，一般扫描的频率都在10Hz以上，精度也在几个毫米的级别。</p>
<p>2D激光雷达使用单束点状激光进行扫描，因此只能采集一个截面的距离信息。如果要测量3D的数据 ，就需要使用如下2种方式进行扩充：</p>
<ol>
    <li>采用线状激光器 </li>
    <li>使用一个2D激光雷达扫描，同时在另一个轴进行旋转。从而扫描出3D信息。 </li>
</ol>
<p>第一种方式是改变激光器的输出模式，由原先的一个点变成一条线型光。扫描仪通过测量这束线型光在待测目标物体上的反射从而一次性获得一个扫描截面的数据。这样做的好处是扫描速度可以很快 ，精度也比较高。但缺点是由于激光变成了一条线段，其亮度(强度)将随着距离大幅衰减，因此测距范围很有限。对于近距离(&lt;10m)的测距扫描而言，这种方式还是很有效并且极具性价比的，本文介绍的激光雷达也使用这种方式，</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/linear_laser.jpg" /></p>
<p align="center">图：一字线红色激光器</p>
<p>&nbsp;</p>
<p>对于第二种方式，优点是可以很容易用2D激光雷达进行改造，相对第一种做法来说，他在相同的激光器输出功率下扫描距离更远。当然，由于需要控制额外自由度的转轴，其误差可能较大，同时扫描速度也略低。</p>
<p>这类激光雷达产品目前在各类实验室、工业应用场景中出现的比较多，但对于个人爱好着或者家用 设备中，他们的价格实在是太高了。当然，目前也有了一个替代方案，那就是kinect，不过他的成像 分辨率和测距精度相比激光雷达而言低了不少，同时无法在室外使用。</p>
<h2 class="std_h2">低成本的方案</h2>
<p>造成激光雷达设备高成本的因素为</p>
<ol>
    <li>使用测量激光相位差/传播时间差测距 </li>
    <li>高速振镜的高成本 </li>
    <li>矫正算法和矫正人工成本 </li>
</ol>
<p>对于个人DIY而言，第三个因素可以排除，所谓知识就是力量这里就能体现了:-) 对于前2个因素，如果要实现完全一样的精度和性能，那恐怕成本是无法降低的。但是，如果我们对精度、性能要求稍 微降低，那么成本将可以大幅的下降。</p>
<p>首先要明确的是投入的物料成本与能达成的性能之间并非线型比例的关系，当对性能要求下降到一 定水平后，成本将大幅下降。对于第一个因素，可以使用本文将介绍的三角测距方式来进行。而对于 扫锚用振镜，则可以使用普通的电机机构驱动激光器来替代。</p>
<p>本文介绍的低成本3D激光扫描仪实现了如下的成本/性能：</p>
<div class="quote">
<p>成本：~￥150</p>
<p>测量范围：最远6m</p>
<p>测量精度：（测量距离与实际距离的误差）最远6m出最大80mm误差，近距离(&lt;1m)，误差水平在 5mm以内</p>
<p>扫描范围：180度</p>
<p>扫描速度：30 samples/sec (比如以1度角度增量扫描180度，耗时6秒)</p>
</div>
<p>对于精度而言，这个低成本方案足以超过kinect，不过扫描速度比较慢，但是对于一般业余用途而言已经足够。不过，该扫描速度是很容易提升的，本文将在分析其制约因素后介绍提高扫描速度的方 法。</p>
<h1 class="std_h1">原理和算法</h1>
<p>这里先介绍测量目标上一个点所涉及的算法。3D扫描将采用类似的方式进行扩充。</p>
<h2 class="std_h2">使用单点激光进行三角测距</h2>
<p>&nbsp;</p>
<p>除了使用相位差和时间差进行TOF测距外，另一种测距方式就是三角测距。这也是实现低成本激光测距的关键，因为这种方式不需要具备其他测距方式所要求的特殊硬件。并且，在一定距离范围内， 三角测距也可以达到与TOF测距媲美的测量精度和分辨率。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/single_dot_concept.gif" /></p>
<p align="center">图片(来源自[3]): 激光三角测距原理</p>
<p align="left">目前有不少爱好者[1][2]基于激光三角测距制作了激光雷达或者测距仪，本制作也采用了这个方式。除了本文外，参考论文[3]也给出了较多的细节。（该论文的作者所在的公司正是将低成本激光雷达用于家用机器人XV-11的开发商，这里就不扯开了:-)</p>
<p align="left">这里摘录了论文中的示意图，要进行激光三角测距，所需的设备很简单：<strong> 点状激光器、摄像头</strong>。因此，能做到多少的成本大家现在应该比较清楚了。</p>
<p align="left">图中展现了测量对象Object距离激光器的距离d的示意图。图中的Imager部分是对摄 像头的一种抽象表达(针孔摄像机模型)。标有s的线段实际可以是一个固定摄像头和激光器的平面。摄像头成像平面与该固定平面平行，而激光器发出的射线与该平面夹角beta仅存在于图中的视图中。 </p>
<p align="left">要测量距离d，首先要求激光射线射到了Object上，他的反射光在摄像头的感光平面上成像。对于不同远近的物体，当被测距激光照射后，摄像头上的成像光点的x值将变化。这里涉及到如下几个参数</p>
<div class="quote">
<p align="left">Beta:激光器夹角</p>
<p align="left">s:激光器中心与摄像头中心点距离</p>
<p align="left">f:摄像头的焦距</p>
</div>
<p align="left">如果这些参数在测距设备安装后不再改变（固定）且数值已知，则物体距离激光器距离可由如下公式求得：</p>
<div class="quote">
<p align="left"><font face="Courier New">q=fs/x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .... (1)</font></p>
<p align="left"><font face="Courier New">d=q/sin(beta) .... (2)</font></p>
</div>
<p align="left">其中，x是测量中唯一需要获得的变量。它的含义是待测物体上激光光点在摄像头感光元件(如CMOS)上的成像到一侧边缘的距离。该距离可以通过在摄像头画面中查找并计算激光点中心位置的像素坐标来求得。对于示意图</p>
<p align="left">式(1)求出了目标物体与摄像头-激光器平面的垂直距离(实际上对于大尺度测距，该值可以近似认为是实际距离)。这一步就是三角测距的所有内容了，非常简单。</p>
<p align="left">&nbsp;</p>
<p align="left">不过，在实际操作中，上述公式仍旧需要扩充。首先时对于变量x的求解，假设我们已经通过算法求出了画面中激光光点的像素坐标(px,py)，要求出公式中需要的x，首先需要将像素单位的坐标变换到实际的距离值。为了计算方便，在安装时，可以令摄像头画面的一个坐标轴与上图线 段s平行，这样做的好处是我们只需要通过光点像素坐标中的一个参量(px或者py)来求出实际投影距离 x。这里假设我们只用到了px。</p>
<p align="left">那么，变量x可以由如下公式计算:</p>
<div class="quote"><font face="Courier New">x=PixelSize*px+offset .... (3)</font></div>
<p align="left">式(3)由引入了两个参数，PixelSize以及offset。其中PixelSize是摄像头感光部件上单个像素感光单元的尺寸，offset是通过像素点计算的投影距离和实际投影距离x的偏差量。这个偏 差量是由如下2个因素引入的：</p>
<ol>
    <li>
    <div align="left">x变量的原点（示意图中与激光射线平息的虚线和成像平面焦点）的位置未必在成像感光阵列的第一列（或排）上（实际上在第一排的概率非常低）</div>
    </li>
    <li>
    <div align="left">通过摄像头主光轴的光线在画面中的像素坐标未必是画面中点。</div>
    </li>
</ol>
<p align="left">对于PixelSize，可以通过摄像头感光元件手册来确定其数值。对于offset，要在安 装上消除offset或者直接测量，在业余条件下几乎是不可能的，因此，需要通过后面介绍的矫正步骤求出。</p>
<p align="left">到这里，我们得出了通过激光点像素坐标(pX)来求出对应光点实际距离的公式： </p>
<div class="quote"><font face="Courier New">d=fs/(PixelSize*px+offset)/sin(beta) .... (4)</font></div>
<p align="left">&nbsp;</p>
<p align="left">接下来的问题就是如何确定这些参数了。不过，实际操作中，还需要考虑性能指标问题：要达到某种精度要求，究竟需要怎样的摄像头，上述各类参数如何选择呢？</p>
<h2 class="std_h2">决定单点激光测距性能的因素</h2>
<p align="left">有公式(3)可知，参数px是一个离散量(虽然有算法可以求出连续的px,后文将介绍) 。因此，得到的距离数值也将会发生一定的跳变。该跳变的程度反映了测距的分辨率以及精度。</p>
<p align="left">如果将式(1)改写为x=fs/q并按q进行求导，可以得出：dx/dq=-fs/(q^2)，或者写为 ：</p>
<div class="quote"><font face="Courier New">dq/dx=-q^2/fs .... (5)</font></div>
<p align="left">式(5)的含义是，变量x每发生一次跳变，通过我们三角测距公式求出的距离值q跳变大小与当前实际待测距离的关系。可以看出，当待测距离边远后，从摄像机获得的像素点每移动一个单位距离，求出的距离值得跳变会大幅增大。<strong>也就是说：三角测距的精度和分辨率均随着距 离增加而变差</strong>。</p>
<p align="left">因此，要决定我们希望实现的指标，只需要明确：</p>
<div class="quote">
<p align="left">希望测距的最大距离</p>
<p align="left">在最大距离下，分辨率(式(5))的数值</p>
</div>
<p align="left">在论文[3]中给出了他的选取规则，这里直接给出一个结论，具体过程就不重复了： </p>
<p align="left"><strong>假设对于激光光点定位能做到0.1个次像素单位，单位像素尺寸为6um。并要求在6m处分辨率(dq/dx)&lt;=30mm。</strong>则要求：</p>
<div class="quote"><font face="Courier New">fs&gt;=700</font></div>
<p align="left">在我们制作过程中，这个要求还是很容易做到的。另外目前的CMOS摄像头往往具有更小的单位像素尺寸（在同样大小的芯片上做出了更高的分辨率），因此实际fs的取值下限可以更低 。</p>
<p align="left">而对于摄像头分辨率、激光器夹角beta，则决定了测距的范围（最近/最远距离）。 这里也同样不再重复了，可以参考[3]。对于使用pX进行测距的摄像头，其分辨率480x640即可做出比较好的效果，更高的分辨率更好（当然后文会提到缺点）。beta一般在83deg左右。</p>
<p align="left">&nbsp;</p>
<h2 class="std_h2">2D激光雷达的原理和性能制约因素</h2>
<p align="left">在实现了单点激光测距后，进行2D激光扫描就非常容易：进行旋转。这里讨论的他的性能问题：扫描速度。</p>
<p align="left">对于采用三角测距的方式，从摄像头画面上识别出激光点到计算出实际距离对于目前的桌面计算机而言，几乎可以认为不需要时间。那么，制约扫描速度的因素就在于摄像头的祯率了 。对于目前市面常见的usb摄像头，其工作在640x480分辨率的模式下最高帧率都在30fps，那么，扫描速度就是30samples/sec。换言之就是每秒钟进行30次的测距计算。</p>
<p align="left">对于一个180度范围的激光雷达，如果按照每1度进行一次测距计算，最短需要6秒。 </p>
<p align="left">如果要提高扫描速度，很自然的就是提高祯率。对于usb摄像头，有PS eye摄像头可 以做到60fps。但这也只能实现3秒180度扫描。需要更加高的速率，也就意味着更快的传输速度，对于USB2.0而言，保证640x480的分辨率，fps很难有所提升。在论文[3]中，他们采用了高速摄像芯片+DSP 的方式实现了1200fps的帧率。</p>
<p align="left">由于本制作不需要很高的扫描速度，因此我仍旧采用了30fps的摄像头。</p>
<h2 class="std_h2">
<p align="left">3D激光扫描的原理</p>
</h2>
<p align="left">由前文已经指出，这里采用了线状激光器一次对一条线而非单点的目标物体进行扫描测距。将扫描器进行旋转，从而可以实现3D扫描。下图展示了他的工作画面和捕获到的摄像头画面 ：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/effect_red.jpg" /></p>
<p align="center">图：本制作早期使用的红色一字线激光器的工作画面</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/screenshot/camview_red.jpg" /></p>
<p align="center">图：采用红色一字线激光器捕捉到的画面</p>
<p align="left">对于线状激光器进行测距的问题，可以将它转化为前面单点激光测距的计算问题。 对于上图中的激光线条，算法将按照Y轴依次计算出当前Y轴高度下，激光光斑的X坐标值pX。并尝试通过先前的算法求处该点的距离。</p>
<p align="left">为了简化问题，我们先考虑对于一个与摄像头感光面平行的平面上激光光斑各点的 距离问题：</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/concept01.png" /></p>
<p align="center">图：激光线条光斑在平行平面上各点的距离问题抽象</p>
<p align="left">如上图所示，远处平面为目标待测平面，上面有一条紫色的激光光斑。近处的平面 是摄像头的感光成像平面，经过了翻折后，他可以看作是目标平面到摄像头成像中心点组成的棱锥的一个截面。</p>
<p align="left"><strong>图中的P1点位于摄像头投影画面高度的中点，按照针孔摄像机的定义，该点在画面上的投影P1'距离摄像头中心Camera Center的距离应当为摄像头的焦距F。因此，对于P1，可以直接带入式(4)求出实际距离</strong>。</p>
<p align="left">现在的问题是，对于其他高度上的点，如P2，是否可以通过式(4)求得？</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/concept02.png" /></p>
<p align="center">图：3D测距的原理</p>
<p align="left">答案自然是肯定的，不过这里涉及到了额外的参数。如上图所示，设P2的投影点P2' 到摄像头中心距离为f'，则P2到baseline垂线距离d'可由如下公式得到:</p>
<div class="quote"><font face="Courier New">d'=f'baseline/x .... (6)</font></div>
<p align="left">而很容易知道，f'可以通过f求出：</p>
<div class="quote"><font face="Courier New">f'=f/cos(arctan((P2'.y-P1'.y)/f)) .... (7) </font></div>
<p align="left">其中的P2'.y以及P1'.y分别是点P2',P1'在成像元件上的实际高度，他们可由各自点像素坐标pY乘以像素高度求出。</p>
<p align="left"><font face="Arial">在求出了垂线距离d'后，需要转化成实际的距离D，此时需要 知道P2-RotationCenter以及Baseline组成的夹角theta。该角度可以由立体几何知识通过激光器与 Baseline的夹角beta求出。具体的求解公式可以参考本制作配套源代码的计算部分。</font></p>
<p align="left"><font face="Arial">在求出了平行平面上激光光斑任意点的坐标后，可以将问题一 般化，对于3D空间任意激光投影点，可以先构造出该点所在的一个平行平面，然后利用上述算法求解 。</font></p>
<p align="left"><font face="Arial">对于每次测距采样，上述算法将产生一个数组dist[n]。其中 dist[i]为对应画面不同高度像素坐标i下激光点的距离。对于采用640x480分辨率的摄像头，n的取值 为480。</font></p>
<font face="Arial">
<div class="quote"><font face="Arial">如果进行180度，步进为1度的3D扫描，则可得到分辨率为 180x480的点云阵列。</font></div>
<div class="quote">如果采用0.3度步进，扫描180度，则得到600x480的点云阵列</div>
</font>
<h2 class="std_h2">激光光点像素坐标确定和求解</h2>
<p align="left">这里讨论如何从摄像头画面中计算出光点的坐标信息，具体来说，要解决如下几个 问题：</p>
<ol>
    <li>
    <div align="left">识别并确定激光光点，排除干扰</div>
    </li>
    <li>
    <div align="left">确定光点中心的精确位置</div>
    </li>
</ol>
<p align="left">先来看问题一，这个问题看似简单，不过实际会有很多问题，比如下面的几幅实际操作中遇到的画面：</p>
<p align="left">&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/dot_samples.jpg" /></p>
<p align="center">图：不同环境和配置下摄像头捕获的画面</p>
<p align="left">&nbsp;</p>
<p align="left">上面3幅图像分别是在使用红色激光器摄像头所拍摄到的。(a)的图像比较理想，在于画面中除了激光光点外没有别的内容，虽然可以看到上方有光电发射发出的干扰点，但激光光点仍旧可以通过求出画面中最亮点的方式获取。</p>
<p align="left">(b)画面中出现了日光灯，由于日光灯亮度也较高，从画面上看与激光点中心亮度一致（均为纯白)，对于这个图像，一种办法是同时判断临近像素的色彩，红色激光点的外围均为红色。 </p>
<p align="left">(c)画面中，除了激光点外，出现了其他的红色物体，并且部分高光区域也在图像中表现为纯白，此时，上述通过色彩判断的算法也将失效。因此需要有另外的办法。</p>
<p align="left">完美的激光提取算法几乎是不存在的，一个例子就是当画面中出现了2个类似的激光点（另一个来自别的测距仪或者激光笔)，此时单从一副图像上很难做出判断哪个才是正确的光点。 </p>
<p align="left">同时，较准确的识别光点也需要硬件设备以及光学设备的合作，具体的细节超过了本文的范畴。这里列举几种可行的办法：</p>
<p align="left"><strong>1. 加装滤光片</strong></p>
<p align="left">在文献[3]和文献[4]中均提及使用滤光片的做法，仅保留激光器发射波长的光线进入，从而可以一定程度的避免光线干扰。</p>
<p align="left"><strong>2. 调整摄像头曝光时间</strong></p>
<p align="left">调整摄像机曝光率也可以有效去除画面的干扰，例如上图(b)和(c)，对于5mW的激光器，一定距离内其单位光照强度仍旧比日光强[3](人肉眼可以在室外识别出激光笔照射在地面的光点) ，因此，只要将摄像头曝光率调整的足够短，完全由可能将画面中除了激光点之外的内容剔除。</p>
<p align="left"><strong>3. 采用非可见光激光器</strong></p>
<p align="left">例如使用红外激光器，这个做法与遥控器使用红外LED理由一样，在人造环境中少有红外光干扰。配合红外滤光片，可以有效滤除来自诸如日光灯等的干扰。但是，对于日光和白炽灯， 其中也含有足够强的红外光，无法单纯采用此法。</p>
<p align="left"><strong>4. 增加激光器功率</strong></p>
<p align="left">配合曝光率控制，增加激光器发射功率也足以使得画面中仅保留光点，但这样也有危险性，尤其采用点状激光时。</p>
<p align="left">本制作采用了上述的所有方法，将在后文具体介绍。</p>
<p align="left">&nbsp;</p>
<p align="left">对于问题(2)，最简单的做法是直接找出光电中最亮的像素的坐标。但是由于前面公式得知，这样的得到的pX值是整数，计算得到的q将会有比较大的跳变。因此这里介绍如何将pX变为更 加精确的&quot;次像素&quot;级别。</p>
<p align="left">对于这个问题，学术界已有不少的研究，这里推荐参考论文[5]，其中介绍了几种次像素激光光点定位算法的介绍以及分析了他们的优劣。这里也不再重复了。</p>
<p align="left">简单来说，可以认为激光光点的亮度是一个二维的Gauss函数经过了一次采样得到了画面上的激光点。那么，可以通过拟合或者简单的线性插值/求质心的手段，估计出光点的中心。</p>
<p align="left">本制作使用了简单的质心法求取次像素的激光中心点。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/dot_loc.jpg" /></p>
<p align="center">图：采用滤光片后，从白色日光灯画面(右上图)中识别并计算出激光光点中心坐 标</p>
<p align="left">可能有人会问这样的估算精确有效吗？一般而言，精确到0.1个像素单位是比较可靠的，也有文献指出他们做到了0.01个像素的可靠定位。</p>
<p align="left"><strong>对于线状激光器的求解过程与点状激光类似，区别在于将按照图像的每行（或者每列）分别找出激光光斑的中心。</strong>可参考文献[6]，文献[7]给出了一个针对线状激光 更优的光点中心提取算法。</p>
<h2 class="std_h2">摄像头校正</h2>
<p align="left">进行激光测距的基本原理非常简单，但在实现中却有很多制约因素。除了前文提到的进行三角测距求解公式中的那些参数需要确定之外，校正摄像头从而得到理想的针孔摄像机模型下的图像也是很重要的环节。</p>
<p align="left">首先要回答的一个问题是：为何要校正摄像头？校正什么参数？</p>
<p align="left">校正的主要理由是实际上目前使用的摄像头并非是前文所提到的针孔摄像机模型。 所谓针孔摄像机，简单说原理就和小孔成像类似：光线通过一个小孔后再背后的感光部件上成像。但大家知道，现实的摄像机都是采用光学透镜聚光成像的，并且所用的透镜并非是抛物面的（很难加工 ），同时，感光芯片也透镜之间也非严格平行[8]。总之，现实就是产生的画面实际上存在扭曲和偏移 的。如果直接使用原始摄像机的画面进行测距，势必造成误差。因此需要进行相机的校正，通过校正 后获取消除上述画面扭曲和偏移的图像，再用来进行激光测距的相关操作。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/3dscanner/concept/chessboard_calib.jpg" /></p>
<p align="center">图: 摄像头原始画面和经过相机校正后的修正画面</p>
<p align="left">上图左侧图片是一种摄像头拍摄到的原始画面，可以明显看出图像存在着扭曲，对相机校正后，我们可以校正后的参数修正扭曲的画面，得到右侧图像的效果。</p>
<p align="left">对于摄像机校正的具体原理、算法和过程超过了本文的介绍范围，具体信息可以参考如下的文献和教程:[8][9][10]。在本文后续的制作部分，也会介绍本次制作的校正过程和结果。 </p>
<h2 class="std_h2">校正和求解三角测距所用参数</h2>
<p align="left">前文介绍的三角测距公式中涉及了如下的参数：</p>
<div class="quote">
<p align="left">Beta:激光器夹角</p>
<p align="left">s:激光器中心与摄像头中心点距离</p>
<p align="left">f:摄像头的焦距</p>
<p align="left">pixelSize:感光部件单位像素尺寸</p>
<p align="left">offset:激光点成像位置补偿值</p>
</div>
<p align="left">这些参数有些很难通过实际测量求出，有些很难再安装时就控制好精度。他们数值 的精确度会对测距精度有着非常大的影响。例如pixelSize一般都是微米级别的数值，很小的误差即可导致最终测距的偏差。</p>
<p align="left">对于他们的求解，我们将在测距仪制作完成后进行的校正环节求出。这里的校正， 实际过程是在实现测量好的距离下采集出测距公式中用到的pX数值。然后通过曲线拟合的方式确定参 数。</p>
<p align="left">这部分的具体操作将在后文的制作/校正过程中具体介绍。</p>
<p align="left">&nbsp;</p>
<h1 class="std_h1">
<p align="left">制作低成本的3D激光雷达</p>
</h1>
<p>这部分的内容请访问</p>
<h2 class="std_h2">自制低成本3D激光扫描测距仪(3D激光雷达)，第二部分<br />
</h2>
<p><a href="http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html">http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_2.html</a><br />
&nbsp;</p>
<h1 class="std_h1">
<p>参考文献</p>
</h1>
<p>[1] <strong>Details of the Laser Range finder</strong></p>
<p><a href="http://www.eng.buffalo.edu/ubr/ff03laser.php">http://www.eng.buffalo.edu/ubr/ff03laser.php</a></p>
<p>&nbsp;</p>
<p>[2] <strong>Webcam Based DIY Laser Rangefinder</strong></p>
<a href="http://sites.google.com/site/todddanko/home/webcam_laser_ranger">http://sites.google.com/site/todddanko/home/webcam_laser_ranger</a>
<p>&nbsp;</p>
<p>[3] K. Konolige, J. Augenbraun, N. Donaldson, C. Fiebig, and P. Shah. <strong>A low-cost laser distance sensor.</strong> In Int. Conference on Robotics and Automation (ICRA), 2008.</p>
<p>&nbsp;</p>
<p>[4] Kenneth Maxon. <strong>A Real-time Laser Range Finding Vision System</strong></p>
<p><a href="http://www.seattlerobotics.org/encoder/200110/vision.htm"><u>http://www.seattlerobotics.org/encoder/200110/vision.htm</u></a></p>
<p>&nbsp;</p>
<p>[5] Fisher, R. B. and D. K. Naidu. <strong>A Comparison of Algorithms for Subpixel Peak Detection</strong>. Springer-Verlag, Heidelberg, 1996.</p>
<p>&nbsp;</p>
<p>[6] Mertz, C., J. Kozar, J.R. Miller, and C. Thorpe. <strong>Eye-safe Laser Line Striper for Outside Use.</strong> Intelligent Vehicle Symposium, 2002.</p>
<p>&nbsp;</p>
<p>[7] J. Forest, J. Salvi, E. Cabruja, C. Pous, <strong>Laser stripe peak detector for 3D scanners. A FIR filter approach</strong>, in: International Conference on Pattern Recognition, Cambridge, August 2004, pp. 646&ndash;649</p>
<p>&nbsp;</p>
<p>[8] <strong><em>Learning OpenCV: Computer Vision with OpenCV Library</em></strong>, Gary Bradski and Adrian Kachlev, first edition , 2008 O&rsquo;Reilly, ISBN 978-0-569-51613.</p>
<p>&nbsp;</p>
<p>[9] 分享一些OpenCV实现立体视觉的经验<br />
<a href="http://blog.csdn.net/scyscyao/article/details/5443341">http://blog.csdn.net/scyscyao/article/details/5443341</a></p>
<p>&nbsp;</p>
<p>[10] Camera Calibration Toolbox for Matlab<br />
<a href="http://www.vision.caltech.edu/bouguetj/calib_doc/">http://www.vision.caltech.edu/bouguetj/calib_doc/</a></p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/lowcost_3d_laser_ranger_1.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=282</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=282&amp;key=9ff40821</trackback:ping></item><item><title>XV-11拆解和部件使用</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/276.html</link><pubDate>Sat, 19 Mar 2011 07:38:48 +0800</pubDate><guid>http://www.csksoft.net/blog/post/276.html</guid><description><![CDATA[<p>详细的拆解照片就不发出来了，放出一小部分给大家看看，但不作解释:-)</p>
<p>XV-11国外已有不少开源项目利用起了这个硬件设备，蛮不错的。</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/xv11_td_01.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/xv11_td_02.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/xv11_td_03.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/xv11_td_04.jpg" /></p>
<p align="left">最后来段视频：<a href="http://www.tudou.com/programs/view/1iMA0Tc3y1k/"><u><font color="#800080">http://www.tudou.com/programs/view/1iMA0Tc3y1k/</font></u></a></p>
<p align="center"><embed height="400" type="application/x-shockwave-flash" width="480" src="http://www.tudou.com/v/1iMA0Tc3y1k/&amp;uid=70789997/v.swf" wmode="opaque" allowfullscreen="true" allowscriptaccess="always" scale="ShowAll" loop="loop" menu="menu" quality="1"></embed></p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/276.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=276</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=276&amp;key=ead74275</trackback:ping></item><item><title>RoboPeak Stage2 Basic Feature Demo</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/272.html</link><pubDate>Thu, 18 Nov 2010 18:41:31 +0800</pubDate><guid>http://www.csksoft.net/blog/post/272.html</guid><description><![CDATA[<p>放出一段演示我们机器人基本功能的演示视频，具体介绍就不提供了。视频内有必要的说明。</p>
<p>视频仅展示了手动控制机器人的相关功能，而真正强大的部分还没有太多展示。</p>
<p>视频地址：<a href="http://www.tudou.com/programs/view/mZcWNvUj6NM/">http://www.tudou.com/programs/view/mZcWNvUj6NM/</a></p>
<div align="center"><embed height="400" type="application/x-shockwave-flash" width="480" src="http://www.tudou.com/v/mZcWNvUj6NM" wmode="opaque" allowfullscreen="true" allowscriptaccess="always"></embed></div>
<p>&nbsp;</p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/272.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=272</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=272&amp;key=ce6fec01</trackback:ping></item><item><title>RoboPeak: the 1st Release Soon!</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/271.html</link><pubDate>Thu, 11 Nov 2010 07:58:10 +0800</pubDate><guid>http://www.csksoft.net/blog/post/271.html</guid><description><![CDATA[<p>业余时间和朋友们做了一年多的机器人项目，RoboPeak Project。快要接近第一次公开发布了~</p>
<p>&nbsp;</p>
<p>很好很强大。我Blog将在正式发布后做更多详细介绍，敬请期待:-) 这里也感谢各位忙里抽空的朋友们，大家辛苦啦。</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/rp_pub_pic_front.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/rp_pub_pic_end.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/rp_pub_pic_console.jpg" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/271.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=271</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=271&amp;key=7d238d79</trackback:ping></item><item><title>自制蓝牙GPS</title><author>csk@live.com (csk)</author><link>http://www.csksoft.net/blog/post/270.html</link><pubDate>Sat, 28 Aug 2010 08:01:22 +0800</pubDate><guid>http://www.csksoft.net/blog/post/270.html</guid><description><![CDATA[<p>最近买了一些GPS模块打算用在我们的机器人上，就顺便花了一个下午用一个蓝牙串口模块配合，做了一个可以给带蓝牙的智能机使用的蓝牙GPS。效果不错，就和大家分享下制作过程吧。</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_final_001.jpg" /></p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_final_002.jpg" /></p>
<p>&nbsp;</p>
<p>上图就是成品的外观，我使用了DVmini磁带壳作为这个GPS的外壳，样子有点山寨，不过平时使用是会放在包里的，问题不大。以下是这个制作所实现的功能和配置情况：</p>
<p>&nbsp;</p>
<p>1. 基于SiRF III芯片的GPS模块</p>
<p>2. 蓝牙通讯功能</p>
<p>3. 900mAh锂电池，单次充电可达7小时工作时间</p>
<p>4. Mini-USB口充电</p>
<p>5. 低电压充电提醒</p>
<p>&nbsp;</p>
<p>在介绍制作前先给出我的HTC S1连接他的效果吧:-)</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_ss01.jpg" /></p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_ss02.jpg" /></p>
<p>&nbsp;</p>
<p>实际测试中，在室外环境下通电（冷启动）到完成3D定位仅需20秒不到的时间。性能很不错。</p>
<h2 class="std_h2">制作原理&nbsp;</h2>
<p>目前GPS通讯协议有相关规范，一般都是通过串口进行数据发送的，市面上可以买到的GPS模块元件也基本都是直接串口输出。所以只要简单的和市面上可以找到的蓝牙转串口模块相连即可实现出一个蓝牙GPS设备了。</p>
<p>&nbsp;</p>
<p>需要做的额外工作是如何给GPS和蓝牙供电、充电。一般蓝牙设备需要3.3V的稳压供电，所以要有LDO元件，这里要选择专供电池设备使用的低压差的LDO，我用的是PAM3101系列的LDO。</p>
<p>&nbsp;</p>
<p>另外为了防止锂电池过放电导致报废，这里设计了一个低压提醒电路。我使用TL431基准源对当前电池电压比较，如果低于3.3V后，会点亮一个红色LED提醒该给电池充电了，如下图所示：</p>
<p>&nbsp;</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_final_lowpower.jpg" /></p>
<p>&nbsp;</p>
<p>对于锂电池充电部分，这里仍旧使用了偷懒办法，从USB口取电后经过1N4148二极管的正向压降后大致可以得到4.2V左右的电压给锂电池充电，如果实际电压不幸高于了4.2V，就依靠电池内部的保护电路动作了... <strong>这个是比较危险的设计，需要有人看守着进行充电。</strong></p>
<p>&nbsp;</p>
<p>电路原理图我就不介绍了，很简单，大家打开这个pdf看看即可：</p>
<p><a href="http://www.csksoft.net/data/GPS_bluetooth.pdf">http://www.csksoft.net/data/GPS_bluetooth.pdf</a></p>
<p>&nbsp;</p>
<p>我尽可能的使用了贴片元件来制作，这样可以保证较小的尺寸好放进这个磁带盒中，虽然焊的比较费时:-) 下面是制作过程中拍摄的几张照片给大家参考</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_prog_001.jpg" /></p>
<p align="center">万用版上挖出凹槽部分放置蓝牙模块的天线</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_prog_002.jpg" /></p>
<p align="center">成品电路</p>
<p align="center"><img alt="" src="http://www.csksoft.net/data/pic/btgps_prog_003.jpg" /></p>
<p align="center">所有组件连接就绪</p>
<p>&nbsp;</p>]]></description><category>电子电路</category><comments>http://www.csksoft.net/blog/post/270.html#comment</comments><wfw:comment>http://www.csksoft.net/blog/</wfw:comment><wfw:commentRss>http://www.csksoft.net/blog/sydication.asp?cmt=270</wfw:commentRss><trackback:ping>http://www.csksoft.net/blog/cmd.asp?act=tb&amp;id=270&amp;key=385fe92e</trackback:ping></item></channel></rss>
