MoreRSS

site iconYuanxuan Wang修改

住在湾区,爱好:智能家居、星际争霸、摄影。复旦大学软件工程硕士,Ted翻译。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Yuanxuan Wang的 RSS 预览

组装一台家用服务器机架

2020-06-27 09:36:00

最近因为新冠病毒长期宅在家里,决定开始一个很早就想做的项目:搭一个服务器机架。第一次搭经验不足,买错过几次零件,只能重新下单,前前后后花了不少时间。于是写了这篇博客介绍下用到的设备和配件,给有兴趣自己搭一个的朋友做参考。

机架

我选择的机架是 Raising 的 15U 机架。这个机架优点是够结实,深度可变,价格也比 StarTech 的便宜一点。如果预算足够可以考虑买 StarTech 的机架(12U, 25U)。这里 U 是用来衡量机架中组件高度的单位,1U 约等于 43.66 毫米。机架上每个 U 的高度都会对应的三个孔,如下图所示。

因为我有不少没法直接固定在机架上的设备,得把它们放在隔板上。我一共买了四块隔板:

此外出于美观考虑还可以买挡板,StarTech 的 1U 挡板就挺好。

网线

配线架(Patch Panel)可以让前面板的网线看起来干净清爽。它的背面连接各种设备的背部网线口,正面用短网线连接路由器和其他网线口在正面的设备。网上大多数的配线架都是一面连 CAT 5/6 网线,另一面是打线柱,很少有两面都是网线口的配线架。于是我买了两条 TRENDnet 1U 24 口空白网络配线架,加上 48 个两端都是网线口的 Keystone。这个 Keystone 从用户评论来看,以太网供电(PoE)和网速都不会受到影响。

过长的网线用在前面板也不好看,我先试了 1ft (30cm) 的 Monoprice 网线,装上以后还是觉得网线太长。后来换成了 0.5ft (15cm) 的 网线,看起来干净好多。

设备

设备选择方面,我只是把原有的监控设备和服务器搬了过来,放在了层板上。犹豫过要不要买一个机架式服务器,但是考虑到机架式服务器的耗电量,加上已经有了视频监控机和独立 NAS,最后还是买了个翻新的 HP EliteDesk i7-4785T 用来跑智能家居服务和 Unifi Controller。除了 HP 以外,Dell 和 Lenovo 都有类似的微主机,买一个二手的很适合当智能家居服务器。另外推荐使用 Intel T 系列的 CPU,专门为了省电设计。

机架上的一些其他设备:

  • StarTech 1U 条形插座:带过载保护,单一开关控制所有插口。
  • Netgear 16 口交换机 (JGS516PE):其中 8 个口支持 PoE,配合 Unifi 的无线路由。用了三年了,非常稳定。
  • Unifi 安全网关:配合服务器上跑的 Unifi Controller,可以远程配置 / 监控家庭网络。
  • Samsung SmartThings 中控:我买的第一个智能家居中控,现在主要用 Home Assistant,但是部分智能家居设备还是通过 SmartThings 中控 + MQTT 的方式连接刀 Home Assistant 上。
  • Mac mini (2010 年中):曾经的智能家居中控,买了 EliteDesk 后 Mac mini 处于闲置状态。
  • LaView 监控录像机:买了一整套监控录像机 + 摄像头。它的风扇噪音有点大,是目前机架的主要噪音来源。
  • Qnap TS-853 NAS:最多可以放八个硬盘。数据备份中心,同时跑了 Owncloud 同步服务和 Plex 视频播放。如果没买这个 NAS 的话我可能会直接上机架式服务器。
  • Arlo 视频监控机:另外一套视频监控设备。Arlo 的好处是可以选择用电池不连电源。

具体的智能家居和监控的使用这篇文章就不细谈了,对它们感兴趣的朋友,可以参考我的另外两篇博文:

DIY 洗衣机完成通知

2019-07-22 11:54:27

家里用的是三星的洗衣机和烘干机,买的时候为了完成时有提醒特地挑了带有「智能监控」功能的机型。然而对应的三星洗衣机的 app 几乎没法用,推送和状态更新都有问题。于是我打算自己实现一个类似的功能。

因为洗衣机和烘干机用电量比较大,通过监控用电量很容易判断出设备当前的运行状态,于是我决定用智能插座来实现这个功能。现在很多智能插座都有电量检测的功能,选择的时候要注意插座支持的最大电量,我用了 TP-Link 的 HS110,支持最多 1500 瓦的设备,对于一般的洗衣机和烘干机来说绰绰有余。和智能插座对接的系统依然是 Home Assistant,它对 HS110 的支持很好,可以方便地读出设备当前用电量。

接下来是 Home Assistant 的配置部分,主要分状态定义和自动化脚本。

为了简化我只用两种状态(空闲和运转)描述洗衣机和烘干机的状态(代码只给出了洗衣机部分,烘干机部分几乎一样):

input_select:
  washer_status:
    name: Washer Status
    options:
      - Idle
      - Running
    initial: Idle

为什么要定义状态而不是直接通过用电量判断呢?因为这些机器运转过程里会有几次几乎不用电的阶段,如果只通过用电量很容易产生错误信号,用电量配合状态持续时间才能做出更精准的判断。

接下来定义虚拟的洗衣机传感器,我们会通过自动化脚本更新这个传感器的值:

sensor:
  - platform: template
    sensors:
      washer_status:
        value_template: '{{ states.input_select.washer_status.state}}'
        friendly_name: 'Washer Status'

自动化脚本分两块,一块是检测到电量后的更新洗衣机状态为运转。这里我用了 10 瓦作为运转开始的阈值。

automation:
  - alias: Set washer active when power detected
    trigger:
    - platform: numeric_state
      entity_id: switch.hs110_washer
      value_template: '{{ state.attributes.current_power_w }}'
      above: 10
    condition:
      condition: or
      conditions:
        - condition: state
          entity_id: sensor.washer_status
          state: Idle
    action:
    - service: input_select.select_option
      data:
        entity_id: input_select.washer_status
        option: Running

另一块是设备停止运转的检测,根据不同的设备可能要进行微调。我这里设置了洗衣机用电低于 3 瓦且超过 1 分钟以上后,把状态切换成空置并通过 Twilio 发送短信通知。

automation:
  - alias: Set washer inactive
    trigger:
    - platform: numeric_state
      entity_id: switch.hs110_washer
      value_template: '{{ state.attributes.current_power_w }}'
      below: 3
      for:
        minutes: 1
    condition:
      condition: or
      conditions:
        - condition: state
          entity_id: sensor.washer_status
          state: Running
    action:
    - service: input_select.select_option
      data:
        entity_id: input_select.washer_status
        option: Idle
    - service: notify.twilio_sms
      data:
        message: Washer finished at {{ now() }}
        target:
          - 15555555555

这个脚本用了一个多月没出现误报,虽然一开始折腾一点,最后还是省了我们不少时间。

关于智能家居和 Home Assistant 的更多信息,可以参考我写的其他文章

3D 目标检测之鸟瞰图检测 (Pixor / HDNet)

2019-03-30 07:03:45

随着无人驾驶的兴起,激光雷达数据的目标检测成为了这几年的研究热点之一。常见的 3D 检测模型可以分成两类,一类是用 3D 小方格代表所有的激光点数据,每个小方格包含了这个方格内的特征,例如 VoxelNetVote3deep 。另一类则是先把三维信息投射到一个二维平面,通常是鸟瞰图 (BEV, Bird Eye View) 或是正视图 (Range View),生成二维特征图后再用传统的二维目标模型检测图中的物体,例如 MV3DFaF

无人驾驶场景中的大多数的目标物体都处在同一地面上,非常适合 BEV。相比正视图,BEV 中的目标在不同位置大小固定,我们可以用已知的常见物体大小优化检测效果。对于 BEV 模型来说,主要的问题在于如何选择最终图像的特征,如何生成的图像中做出精确的检测。此文旨在介绍 BEV 检测相关的模型 Pixor 和 HDNet。

Pixor

Pixor 是 Uber ATG 的 Bin Yang 等人在 CVPR 18 上提出的 BEV 检测模型。在特征生成方面,Pixor 把整个点云切成了 L x W x H 个小方格,每个小方格用 0 或 1 表示这个方格内是否有激光点存在,接着沿高度方向把三维特征压缩到一个二维平面,每个压缩后的二维方格就有了 H 个特征表示这个方格上的不同高度是否有点存在。此外 Pixor 还计算了落在每个方格中激光点的平均强度作为额外的特征,最终拿到了一个分辨率为 L x W、包含 H + 1 个特征通道的图像。

Pixor 结构
Pixor 结构

检测方面,Pixor 采用了基于 RetinaNet 的 one-stage 的结构,如上图所示(这里用了海报上的截图,和论文中的有一些细小的差别)。网络里面用了 ResNet 和类似 FPN 的结构。FPN 结构输出的特征图经过一个头部网络后,直接生成对每个像素点的分类和 bounding box 的回归结果。

优化目标方面,分类目标用了 RetinaNet 中的 focal loss,回归目标用了 smoooth L1。论文中回归目标有笔误,按照海报和 FAQ 的说法应该是 \(\{ \cos 2\theta, \sin 2\theta, dx, dy, \log W, \log L \}\)。这里巧妙的用了 \(2 \theta\) 的三角函数作为车头朝向的回归目标,因为车辆是往前还是往后开这个问题会在 tracker 中处理,在检测的时候只要知道车身线的偏离角度就行了,至于这个角度是 5° 还是 185° 影响不大。

整个网络的运行速度非常快,在 Titan XP 上可以在 35 毫秒内完成。除此之外论文还测试了不同 backbone 网络和头部网络特征层共享的不同选择,做了模型简化测试 (ablation study),感兴趣的朋友可以细读。

HDNet

Pixor 沿高度方向把整个点云切成不同的高度区间,例如 Kitti 数据集上 -2.5 到 1 米之间的点会被分成 35 片,这个区间之外的点会被忽略。当地面坡度较大时,远处的点很容易被排除在外。为了解决这个问题,Bin Yang 等人提出了把高精地图作为额外特征的方案,发表在 CoRL 18 上。

HDNet 中的地图信息
HDNet 中的地图信息

如图所示,HDNet 的核心思路在于引入了高精地图信息,从而可以把地面「摊平」(图 b),并提供道路语义信息帮助检测(图 d)。网络结构和 Pixor 非常相似,采用了 FPN,并把 Pixor 中的反卷积层换成了更高效的双线性插值层。

HDNet 结构
HDNet 结构

为了提高模型的稳定性,确保在缺失地图信息或者地图不准确的情况下仍然有较好的检测结果,作者会在训练模型时随机去除地图信息,并提出了通过 Lidar 扫描结果在线生成地图的方案。

小结

本文介绍了两篇近期的基于纯激光雷达数据的 BEV 检测论文。基于纯激光雷达的模型非常适合车辆的检测,但对于行人检测的精度并不理想,往往需要借助图像提供额外的信息。在接下来的博客中我会和大家一起分享更多的相关研究,同时也欢迎各位提出不同的意见。

最后做一个小广告,我目前在 Ike 做无人卡车视觉的相关工作。我们公司在旧金山,最近拿到了 5200 万 A 轮融资,正在招人中。如果你对无人卡车感兴趣,欢迎联系我。

绿卡终于批了

2018-10-31 12:35:07

来美国五年后绿卡终于批了,没有太大曲折,不过也干等了好久,中间还找了议员催绿。总结下流程,希望给后来的朋友有帮助。

时间线

  • 2013 年 10 月入职,2014 年初提交 I-140 (EB-2),排期 (PD) 在 2014 年 3 月。
  • 2015 年中换了工作,重新提交 PERM,排期不变。
  • 2017 年 5 月 EB-3 排期赶超了 EB-2,我的 PD 在 EB-3 下已经 current。于是提交了 EB-3 I-140 的申请,同时提交了 I-485 / I-765 / I-131。I-485 回执日期 (RD) 在 2017 年 5 月。
  • 2017 年 7 月中收到 EAD / AP 卡。
  • 2018 年 3 月中 EB-3 I-140 审核通过。
  • 2018 年 4 月收到 case 转移的通知。
  • 2018 年 6 月初面试,面试后被通知体检过期,重新办了以后月底寄出。
  • 2018 年 7 月 EB-3 的排期倒退,我的 PD 不再 current,由于当时 EB-2 还是 current 的,就让律师 interfile EB-2。
  • 2018 年 8 月初联系议员催绿,月中得到消息说我的 case 还在审核中,最起码要等 45 天。
  • 2018 年 9 月底再次联系议员,三天后得到消息说 USCIS 还在解决我 case 中的一些问题。
  • 2018 年 10 月底查询网站更新状态为「New Card Is Being Produced」,两天后变成「Case Was Approved」,又过了两天变成了「Card Was Mailed To Me」。

整个过程中 EB-3 的 I-140 拖了好久,因为律师说加急需要 9089 原件,而我的原件已经在第一份 I-140 申请中提交了,没法再次加急。另外比较后悔的一件事就是绿卡面试前没有再去准备一份体检卡。面试通知上写着体检要求「valid within last year」,我以为只要是前一年办过体检就行,律师也建议面试完了再看要不要补办。等重新做体检提交,第二个月正好排期倒退了。

另外一个经验就是即使绿卡面试完了,也得催律师重新申请 EAD / AP。我的律师觉得绿卡马上拿到了就没急着帮我重新申 AP,导致我在绿卡迟迟没下来加上 Visa 过期的情况下,年底出游计划受限不少,如果有一张 AP 就可以放心安排出国计划了。

议员催绿

催绿方面,我们研究过参议员和众议员两个方案。两者效果应该差不多,都是通过官方问一下进度,以免你的 case 堆积在某个角落没人管。我们只联系了众议员,具体的流程如下:

  1. https://www.house.gov/htbin/findrep 上输入你的区号找到对应区的议员,可能会要求输入具体地址进一步筛选。
  2. 在议员的主页上找到电话联系方式,负责我的区域的是议员 Jackie,她的联系方式在这个页面
  3. 接下来的步骤不同议员可能会有所区别,具体可以看主页上的说明。对于我所在区的议员,打电话后选移民相关问题,会转接给负责的工作人员。
  4. 工作人员要了我的邮箱地址后给我寄了一份隐私授权书,因为他们向 USCIS 查询我的情况时可能会涉及我的隐私,填完表格后扫描回复即可。一般等几天才会收到 USCIS 的答复。

整个过程没等多久,而且工作人员态度很好,之后发邮件问都是一刻钟内会有回复。

后记

拿到绿卡后似乎还要去更新下 SSN,去掉上面的工作限制。另外就是可以办 Global Entry 啦。

祝愿等绿卡的各位早日顺利拿到绿卡。

SLAM 公开课笔记 4:定位

2018-08-07 15:56:13

最后一周讲定位 (localization),也就是 SLAM 里面的 L。主要包括粒子滤波和迭代最近点。

里程计定位 (Odometry)

里程计定位法直接从设备里读取信息,更新当前的位置状态。例如要跟踪车子的位置状态,可以在车轮上安装计数器记录车轮转动的次数,从而了解车子前进了多少。对于转弯的情况,可以从内外轮子的计数差得到转弯的角度。假设内轮转了 \(e_i\) 圈,外轮转了 \(e_o\) 圈,内轮半径 \(r_i\),外轮半径 \(r_o\),则有 \[ e_i = \theta r_i \\ e_o = \theta r_o \] 这里 \(\theta\) 就是车子转动的角度,上面的方程可以解得 \[ \theta = \frac{e_o - e_i}{r_o - r_i} \] 然后就能根据转动角度更新车辆当前的位置了。

这种方法用车辆本身的坐标系统记录位置,虽然实现起来简单但是测量精度非常局限于测量误差。例如上例中轮子打滑或事漂移都会导致结果不准确。更成熟的方案需要结合地图信息。

地图定位 (Map Registration)

可以用下面三张图来来介绍地图定位问题,左图是当前的区域地图,中间是激光测距传感器得到的结果,地图定位的目的就是根据传感器返回的结果判断机器人当前坐标和朝向,右图就是一个理想的结果。

配合第三周讲的占据栅格地图障碍物的概率 \(m(x, y)\),我们可以定义最佳定位结果应该满足 \[ \max_p \sum_r \delta(p_x + r\cos(p_{\theta} + r_{\theta}), p_y + r\sin(p_{\theta} + r_{\theta})) \cdot{m(x,y)} \] 接下来介绍两种解决地图定位的方法。

粒子滤波 (Particle Filters)

粒子滤波(有没有觉得这个术语的中文翻译很科幻)又称为序列蒙特卡洛 (Sequential Monte Carlo),是一种非参数 (non-parametric) 模型。它用一系列样本(粒子)表示可能性分布。每一个粒子都是方差接近于 0 的高斯分布,这种分布又被称为狄拉克δ函数 (Dirac Delta),采用这个分布好处之一是可以把连续数学中的工具应用到离散的结果中。

在地图定位问题中,粒子的状态代表位置和朝向,同时每个粒子分别有自己的权重。初始状态的粒子滤波分布由一开始的假设决定,可能是均匀分布,也可能是以某个点为中心的高斯分布。初始化完成后,重复以下步骤更新粒子的分布:

  1. 根据里程计的信息更新粒子的状态。
  2. 由于里程计本事有不确定,更新每个粒子状态的时候可以加入里程计带入的噪音,通常也是一个高斯分布。
  3. 从每个粒子更新后带噪音的分布中采样。
  4. 根据距离传感器得到的信息,更新每个粒子的权重(例如由传感器得知前方近距离有障碍物,而某个粒子并没有,那么这个粒子的权重都会大幅降低)。
  5. 这样得到的结果可能会有有效粒子过少的问题,需要重新采样。有效粒子的数量可以用 \(n_{effective} = \frac{(\sum_i w_i)^2}{\sum_i w_i^2}\) 表示。
  6. 重新采样的方法就是根据权重重新从粒子集中独立抽取同样数量的粒子,注意这里高权重的粒子可能会被多次抽取。重复抽取的粒子会在下一轮更新时因为里程计噪音再次分散。
  7. 重复步骤,直到粒子集中在某一状态。

迭代最近点 (Iterative Closest Point)

粒子滤波的缺点之一在于高维度中,需要大量的粒子才能保证理想的分布。ICP 算法可以更好的适应高维度的场景。

如图所示,ICP 的目的在于已知测量结果和地图,要求出左侧测量结果如何旋转移动后,可以和右侧的地图局部吻合。这里主要有两个问题,一是旋转和移动矩阵,二是测量点和地图点的对应关系。具体的 ICP 算法可以参考这篇论文,它的大致思路和第一周提到的解高斯混合模型的 EM 算法很接近:

  1. 初始化旋转 (R) 和移动 (t) 矩阵。
  2. 固定 R 和 t,优化点的对应关系:\(y_i = \argmin_{y_j \in Y} \Vert x_i - y_j \Vert\)
  3. 固定点的对应关系,优化 R 和 t:\(R, t = \argmin \sum_{x_i, y_i \in C} \Vert d(x_i, y_i) \Vert ^2\)
  4. 重复 2 和 3,直到稳定。

作业

这次的作业是实现一个粒子滤波,应该是整个课程最麻烦的一次了。问题本身不算难,尤其简化了动力学模型之后。但是调参比较麻烦,尤其是最后提交的那个地图,容易卡在某个转角跑不出来。

动力学模型方面,我一开始假设机器人位置和朝向的变化量和前一次接近,移动一次粒子之后再添加噪音。这个方法在机器人变向的时候容易位置偏离过多导致粒子失效,后来注意到作业的 Tips 里面建议假设机器人不动,利用高斯噪音移动粒子,这样的话相当于就不需要针对动力学模型做任何操作了。

计算每个例子的得分时,一种做法是用上一周的作业中用到的 bresenham 函数计算发出点到障碍物中间所经历的空白格,然后对每个空白格计算加权,但是这个做法实在太慢了,我最后计算得分时只用了障碍物所在格的状态。

关于粒子的数量,我看到网上有一种做法是设置一个得分的阈值(例如 70% 的障碍物要正好打到墙上),如果所有的粒子都没法超过这个阈值,就重新再跑一次。这么做容易在测量不准时卡死,而且和书中的实现有出入,在现实中会导致粒子滤波每次估计位置时使用的时间不稳定。比较好的做法还是把粒子的数量和高斯分布的参数放在一起调,跑偏了可以看看是因为粒子不够还是分布参数有问题。

作业里其实有两个地图,样例地图比较容易过(可能是参数变化不大)。提交用的地图调参要不少时间,我看了自己的输出以后,发现有几个点的运动变化很大,有可能是这几个点的测量本身也不精确。另外两个地图用来标记墙和空白方格的数值也是不一样的。

小结

至此 Robotics Estimation and Learning 这门课就上完了。课程设置不错,但是讲解不够详细,尤其是第二周和第四周,这小哥讲得太简单了,slides 上还有不少错误。推荐《Probabilistic Robotics》这本书,在上课的时候参考了里面一部分章节,写得很详细,作者 Thrun 也是机器人领域的大神。

全课程的笔记链接

SLAM 公开课笔记 3:地图

2018-08-01 15:07:22

这一周的内容和地图有关,最后的作业就是通过传感器的数据创建一个地图。

地图类型

常见的题目类型有三种:

  1. 度量地图 (Metric Map):地点用坐标表示,例如用经纬度表示地点的世界地图。
  2. 拓扑地图 (Topological Map):表示地点之间的逻辑关系,例如图论中图的概念,以及地铁图。
  3. 语义地图 (Semantic Map):用标签描述的地图,通过位置关系描述被标记的地点,例如景点游览图。

在现实中绘制地图有几个难点,一是测量误差会导致坐标不精确,二是设备本身需要不断地移动才能绘制,三是地图本身是对现实世界的反应,会不断的变化。

占据栅格地图 (Occupancy Grid Map)

栅格地图用二维栅格表示整个环境,每个栅格都有一个概率值表示这个栅格是否有物体存在。绘制栅格地图常用的设备之一是测距传感器,通过发出激光并测量接受反射所用的时间,传感器可以了解前方障碍物的大致距离。

测距传感器
测距传感器

如图所示,传感器本身测量存在误差,我们只能认为在传感器正前方给定距离处有一定几率存在障碍物。对于这种测量有误差的环境,我们再次引入贝叶斯模型描述。记 \(p(m_{x, y})\) 为 (x, y) 格中存在障碍物的概率的先验知识,根据测量的设备模型我们可以得到条件概率 \(p(z | m_{x,y})\)\(p(z=1|m_{x,y}=1)\) 就代表栅格中有障碍物,且检测成功的概率,而 \(p(z=1|m_{x,y}=0)\) 则代表栅格中不存在障碍物,但是却检测到障碍的概率(假阳性)。

根据贝叶斯公式,我们可以得到测量之后的后验概率 \[ p(m_{x,y}|z) = \frac{p(z | m_{x,y}) p(m_{x,y})}{p(z)} \] 为了简化计算,引入 \(Odd(X) = \frac{p(X)}{p(\neg{X})}\) ,则有 \[ Odd(m_{x,y} = 1 | z) = \frac{p(m_{x,y} = 1 | z)}{p(m_{x,y} = 0 | z)} = \frac{p(z | m_{x,y} = 1) p(m_{x,y} = 1)}{p(z | m_{x,y} = 0) p(m_{x,y} = 0)} \] 其中最后一步可以代入贝叶斯公式得到。对 \(Odd\) 求对数,则有 \[ \begin{align} \log \frac{p(m_{x,y} = 1 | z)}{p(m_{x,y} = 0 | z)} &= \log \frac{p(z | m_{x,y} = 1) p(m_{x,y} = 1)}{p(z | m_{x,y} = 0) p(m_{x,y} = 0)} \\ &= \log \frac{p(z | m_{x,y} = 1)}{p(z | m_{x,y} = 0)} + \log \frac{p(m_{x,y} = 1)}{p(m_{x,y} = 0)} \end{align} \]\(\log{odd\ meas}\) 表示 \(\log \frac{p(z | m_{x,y} = 1)}{p(z | m_{x,y} = 0)}\) ,上式可以简化为 \[ \log odd(m_{x,y} = 1 | z) = \log{odd\ meas} + \log odd(m_{x,y} = 1) \] 如果用 \(\log{odd}\) 表示栅格的状态,这一状态可以简单的通过加减来维护。当检测到障碍物时,该栅格的 \(\log{odd}\) 增加 \(\frac{p(z=1 | m_{x,y} = 1)}{p(z=1 | m_{x,y} = 0)}\),没有检测到障碍物时,该栅格的 \(\log{odd}\) 减少 \(\frac{p(z=0 | m_{x,y} = 0)}{p(z=0 | m_{x,y} = 1)}\)。初始状态为 0,即 \(odd = 1\)

下图为一个具体的例子,第一个栅格地图为 t1 时刻的状态,做了一次探测后,经过的空闲栅格的 \(\log{odd}\) 减少 0.7(这个值由传感器决定),而最后的障碍物所在格的 \(\log{odd}\) 增加了 0.9。第三个栅格地图为 t2 时刻更新后的状态。

log odd 更新例子
log odd 更新例子

三维地图

常见的三维传感器:

  • 三维测距传感器 (如 Lidar)
  • 双目相机 (Stereo Camera)
  • 深度相机 (Depth Camera)

地图的数据格式也有多个方案:

  • 栅格表示:查询单个栅格的状态非常快,但是占用大量内存,而且因为离散化一部分信息会丢失。
  • 列表表示:节省了内存,也不会因为离散化丢失信息,但是查询时需要线性扫描。
  • 树状表示:查询比列表快 (O(logN)),同时内存占用不大。
  • k-d tree:每次选择一条坐标轴,把空间对半分。查询和维护都能在 O(log n) 内完成。
  • octree:把空间均等分成八块,在存在点的分块中继续递归细分。

作业

这次的作业是根据一组 Lidar 测量结果绘制一个二维地图。输入包含四个参数(这里 K 为扫描总次数,N 为 Lidar 光线数):

  1. t 数组记录每组数据的时间点,大小为 \(1 \times K\)
  2. ranges 数组记录每次测试各条激光线测得的距离,大小为 \(N \times K\)
  3. scanAngels 数组记录每条激光线相对机身的转角,大小为 \(N \times 1\),每次测试时这个转角不会变化。
  4. pose 数组记录每次测试时机器人在地图中的位置,大小为 \(3 \times K\),三行数据分别是坐标 x y 和相对地图的转角。

我实现的方法没有用向量并行,用了两层循环依次处理每次测试的各条光线。在 i7 6700K 上大概 25 秒可以跑完最终测试,测试程序里会提到整个过程可能要五分钟,性能差一点的机器这个时间里面应该也能跑完了。

最后跑地图的时候,注意 example_test.m 里传给 occGridMapping 的参数只取了前 1000 次测量结果,所以要制作完整地图要把这个限制去掉。另外文档里面坐标转换时用了 ceil,我在本地测试时只能拿到 27/30 分,换成 round 就能到满分了。

最终生成的地图
最终生成的地图

全课程的笔记链接