重复项表格高亮重复项晃示了为什么去除不了

&p&文章链接:&a href=&http://link.zhihu.com/?target=https%3A//arxiv.org/pdf/.pdf& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&arxiv.org/pdf/&/span&&span class=&invisible&&2.pdf&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&文章是2016年8月放到arvix上的,看格式应该是投到CVPR2017了,Korea的POSTECH这个团队做的,之前比较有名的还有MDNet和CNN-SVM,相信大家应该不陌生哈。&/p&&p&这篇文章的简称是TCNN(树结构的CNN),是VOT2016的冠军,效果很棒,想法也蛮有新意,下面听我一一道来。&/p&&h2&&b&1. Motivations&/b&&/h2&&p&这篇文章最重要的出发点是Model的可靠性问题(reliability),大部分现有的trackers默认Model是可靠的,就是说模型一直随着目标的变化而稳定变化,这样就有一个问题,当目标被遮挡,或者说在跟丢了情况下,再更新的模型其实已经被污染了,可靠性很低,其实是不能用这样的模型进行后续的跟踪的。&/p&&p&TCNN用了很多个CNN的模型,并构建成一棵树的结构,如图1所示,红色的框越粗说明对应的CNN模型的可靠性(reliability)越高。连接的红色的线越粗,说明两个CNN之间的相关性越高(affinity)。黑色的箭头越粗表示对应的CNN模型对目标估计的权重越高。TCNN还对每一个CNN模型进行了可靠性评估。下面来看看具体是怎么做的。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-4bcab529aa8_b.png& data-rawwidth=&481& data-rawheight=&291& class=&origin_image zh-lightbox-thumb& width=&481& data-original=&https://pic1.zhimg.com/v2-4bcab529aa8_r.jpg&&&/figure&&p&
图1:树形结构示意&/p&&h2&&b&2. TCNN Algorithm&/b&&/h2&&p&&b&2.1 CNN网络结构&/b&&/p&&p&每个CNN的网络结构是一样的,前面的卷积层的参数共享,是来自于事先用imageNet训练好的VGG-M网络,后面的全连接层是作者自己设计加上的,在第一帧的时候随机初始化并进行迭代训练,后面每次更新的时候都只更新全连接层的参数。图2是网络结构示意图。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-8b9aeeacd33c0f42c200_b.png& data-rawwidth=&1191& data-rawheight=&289& class=&origin_image zh-lightbox-thumb& width=&1191& data-original=&https://pic1.zhimg.com/v2-8b9aeeacd33c0f42c200_r.jpg&&&/figure&&p&
图2:网络结构示意图&/p&&p&由于一棵树里每次的active set(定义为最近更新的10个网络)有很多个CNN,那么怎样让计算过程或者说特征提取过程简化一些?每次在detection的时候采样好几百个candidates,每个candidate都要提取特征,这个计算量可想而知。&/p&&p&这里作者是这样做的,对每一个candidate,在用一个CNN提取特征时,前面的卷积层的特征conv3是共享的,每个节点上的CNN其实只需要保存全连接层即可,也即conv3的特征的提取只需要进行一次,所有的CNN都用同样的conv3的特征,不同的是他们的全连接层。&/p&&p&另外,在确定了目标之后,需要将这个目标保存为训练样本,也只需要保存这个conv3特征即可,不需要再重复计算一次。&/p&&p&网络的训练:第一帧以0.001的学习率迭代50次,之后每次更新以学习率0.003迭代10次,用标准的随机梯度下降(SGD)和softmax交叉熵损失。&/p&&p&&b&2.2 树的结构&/b&&/p&&p&树用:&figure&&img src=&https://pic1.zhimg.com/v2-add446b1bd0_b.png& data-rawwidth=&161& data-rawheight=&39& class=&content_image& width=&161&&&/figure&表示。其中V是顶点集,后者是边的集合。&/p&&p&每个顶点v:包含的信息有对应的CNNv,和帧集Fv。&/p&&p&每条边edge的得分:&figure&&img src=&https://pic2.zhimg.com/v2-a92cba1f_b.png& data-rawwidth=&342& data-rawheight=&85& class=&content_image& width=&342&&&/figure&用这个分数来衡量边。&/p&&br&&p&&b&2.3 目标查找(target state estimation)&/b&&/p&&p&目标候选框生成:以上一帧的位置为中心,在(x,y,s)空间由多变量正态分布生成256个候选框,s是尺度scale。&/p&&p&对这些candidates:&/p&&p&&figure&&img src=&https://pic1.zhimg.com/v2-fb5abc8642add53205f44_b.png& data-rawwidth=&179& data-rawheight=&45& class=&content_image& width=&179&&&/figure&计算他们是否为目标的得分:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-fbfbb915e7a34b35d7e1ecc06a73ce5e_b.png& data-rawwidth=&375& data-rawheight=&63& class=&content_image& width=&375&&&/figure&&p&那么目标就确定为:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-9d2badd3feacf358beab9f_b.png& data-rawwidth=&344& data-rawheight=&47& class=&content_image& width=&344&&&/figure&&p&现在需要确定(2)式中的权重系数,就是图一中黑色箭头所代表的量。这个权重从两个量来定义,第一个是:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-09d0f9fb4abc20_b.png& data-rawwidth=&337& data-rawheight=&43& class=&content_image& width=&337&&&/figure&&p&表示的是CNNv和目标的相关性(affinity),用CNNv对所有的candidates的最大分类得分来衡量。第二个是:&/p&&p&&figure&&img src=&https://pic1.zhimg.com/v2-218f0ab1ea694a4aca20_b.png& data-rawwidth=&342& data-rawheight=&43& class=&content_image& width=&342&&&/figure&表示的是CNNv这个网络模型自身的可靠性(reliability)。取得是当前的CNNv与他的父节点相连的边的得分与父节点的reliability中小的那一个。最后的CNNv对于t时刻的candidate的权重是这样定义的:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-a5b8e90c3ef1d95b394a6ee3dfba885b_b.png& data-rawwidth=&375& data-rawheight=&63& class=&content_image& width=&375&&&/figure&&p&这里(3)式确定的位置还要做一次bounding box regression之后才得到这一帧最终的位置。&/p&&br&&p&&b&2.4 整体模型更新(model update)&/b&&/p&&p&采用的策略是每做10次的tracking,创建一个新的CNNn节点。选择这个新的节点的父节点的方式:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-2b9af7a422_b.png& data-rawwidth=&374& data-rawheight=&49& class=&content_image& width=&374&&&/figure&&p&即选择能够使新节点的可靠性最高的节点作为其父节点。这过去的10帧就是新节点对应的帧集Fn。以选择的父节点CNNpv为起点,用其自己的帧集Fn和它的父节点的帧集Fpv对CNNpv的全连接层进行fine-tuning,最后得到的就是CNNn。&/p&&p&每次做tracking的时候保持一个active set,里面是10个最新更新的CNN模型,用这个active set来做跟踪。&/p&&br&&h2&&b&3. Experiment&/b&&/h2&&p&&i&&b&速度是1.5FPS&/b&。&/i&&/p&&p&首先在OTB50上做了自己的对比实验:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-e0dcabdf4dfb54_b.png& data-rawwidth=&482& data-rawheight=&158& class=&origin_image zh-lightbox-thumb& width=&482& data-original=&https://pic1.zhimg.com/v2-e0dcabdf4dfb54_r.jpg&&&/figure&&p&可以看到是使用树的结构,并用加权检测而不是简单平均或者用最大权重的来做检测,都对结果是有贡献的。&/p&&p&最后TCNN的实验结果:&/p&&p&(1)OTB50:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-56a3cda6e6f240d298bed_b.png& data-rawwidth=&712& data-rawheight=&341& class=&origin_image zh-lightbox-thumb& width=&712& data-original=&https://pic2.zhimg.com/v2-56a3cda6e6f240d298bed_r.jpg&&&/figure&&p&(2)OTB100:&/p&&p&&figure&&img src=&https://pic2.zhimg.com/v2-8cf2bc95_b.png& data-rawwidth=&715& data-rawheight=&336& class=&origin_image zh-lightbox-thumb& width=&715& data-original=&https://pic2.zhimg.com/v2-8cf2bc95_r.jpg&&&/figure&(3)VOT2015:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-d45dad3d_b.png& data-rawwidth=&631& data-rawheight=&439& class=&origin_image zh-lightbox-thumb& width=&631& data-original=&https://pic3.zhimg.com/v2-d45dad3d_r.jpg&&&/figure&&p&从上面三个实验可以看到效果是非常好的。不过这个方法是在ECO之前的,所以没有与ECO进行比较,ECO的效果比其更好哈,可以看我的&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&上一篇文章ECO&/a&。&/p&&p&&b&总结一下效果好的原因:&/b&&/p&&p&&b&(1) 使用了多个CNN模型进行检测(10个)&/b&&/p&&p&&b&(2) 使用了树的结构来组织CNN模型,避免它们只对最近的帧过拟合&/b&&/p&&p&&b&(3) CNN会一直有新的模型加进来,并且是经过fine-tuning的&/b&&/p&&p&&b&(4)在确定最终的位置时还做了Bounding Box Regression,进一步提高定位准确性&/b&&/p&
文章链接:文章是2016年8月放到arvix上的,看格式应该是投到CVPR2017了,Korea的POSTECH这个团队做的,之前比较有名的还有MDNet和CNN-SVM,相信大家应该不陌生哈。这篇文章的简称是TCNN(树结构的CNN),是VOT2016的冠军,效果很棒,想…
&blockquote&&p&&b&&i&来源:&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/CarpenterLee/p/5419880.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java ArrayList源码剖析&/a&&/i&&/b&&/p&&p&&b&&i&作者:CarpenterLee(转载已获得原作者许可,如需转载请联系原作者)&/i&&/b&&/p&&/blockquote&&h1&&ul&&li&&b&ArrayList&/b&&br&&/li&&/ul&&br&&/h1&&p&&a href=&https://link.zhihu.com/?target=https%3A//github.com/CarpenterLee/JCFInternals/blob/master/markdown/2-ArrayList.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&本文github地址&/a&&/p&&h1&&ul&&li&&b&总体介绍&/b&&br&&/li&&/ul&&br&&/h1&&i&ArrayList&/i&实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟&i&Vector&/i&大致相同。每个&i&ArrayList&/i&都有一个容量(capacity),表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添加元素时,如果容量不足,容器会自动增大底层数组的大小。前面已经提过,Java泛型只是编译器提供的语法糖,所以这里的数组是一个Object数组,以便能够容纳任何类型的对象。&figure&&img src=&https://pic4.zhimg.com/v2-966f23b07473fbafdb6a_b.jpg& data-rawwidth=&800& data-rawheight=&245& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic4.zhimg.com/v2-966f23b07473fbafdb6a_r.jpg&&&/figure&&p&size(), isEmpty(), get(), set()方法均能在常数时间内完成,add()方法的时间开销跟插入位置有关,addAll()方法的时间开销跟添加元素的个数成正比。其余方法大都是线性时间。&/p&&p&为追求效率,ArrayList没有实现同步(synchronized),如果需要多个线程并发访问,用户可以手动同步,也可使用Vector替代。&/p&&h2&&ul&&li&&b&方法剖析&/b&&/li&&/ul&&/h2&&ul&&ul&&li&&b&set()&/b&&/li&&/ul&&/ul&&br&&p&既然底层是一个数组&em&ArrayList&/em&的set()方法也就变得非常简单,直接对数组的指定位置赋值即可。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&n&&E&/span& &span class=&nf&&set&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&index&/span&&span class=&o&&,&/span& &span class=&n&&E&/span& &span class=&n&&element&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&rangeCheck&/span&&span class=&o&&(&/span&&span class=&n&&index&/span&&span class=&o&&);&/span&&span class=&c1&&//下标越界检查&/span&
&span class=&n&&E&/span& &span class=&n&&oldValue&/span& &span class=&o&&=&/span& &span class=&n&&elementData&/span&&span class=&o&&(&/span&&span class=&n&&index&/span&&span class=&o&&);&/span&
&span class=&n&&elementData&/span&&span class=&o&&[&/span&&span class=&n&&index&/span&&span class=&o&&]&/span& &span class=&o&&=&/span& &span class=&n&&element&/span&&span class=&o&&;&/span&&span class=&c1&&//赋值到指定位置,复制的仅仅是引用&/span&
&span class=&k&&return&/span& &span class=&n&&oldValue&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&ul&&ul&&li&&b&get()&/b&&/li&&/ul&&/ul&&br&&p&get()方法同样很简单,唯一要注意的是由于底层数组是Object[],得到元素后需要进行类型转换。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&n&&E&/span& &span class=&nf&&get&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&index&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&rangeCheck&/span&&span class=&o&&(&/span&&span class=&n&&index&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&o&&(&/span&&span class=&n&&E&/span&&span class=&o&&)&/span& &span class=&n&&elementData&/span&&span class=&o&&[&/span&&span class=&n&&index&/span&&span class=&o&&];&/span&&span class=&c1&&//注意类型转换&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&ul&&ul&&li&&b&add()&/b&&/li&&/ul&&/ul&&br&&p&跟C++ 的&em&vector&/em&不同,&em&ArrayList&/em&没有push_back()方法,对应的方法是add(E e),&em&ArrayList&/em&也没有insert()方法,对应的方法是add(int index, E e)。这两个方法都是向容器中添加新元素,这可能会导致&em&capacity&/em&不足,因此在添加元素之前,都需要进行剩余空间检查,如果需要则自动扩容。扩容操作最终是通过grow()方法完成的。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kr&&private&/span& &span class=&k&&void&/span& &span class=&nx&&grow&/span&&span class=&p&&(&/span&&span class=&kr&&int&/span& &span class=&nx&&minCapacity&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kr&&int&/span& &span class=&nx&&oldCapacity&/span& &span class=&o&&=&/span& &span class=&nx&&elementData&/span&&span class=&p&&.&/span&&span class=&nx&&length&/span&&span class=&p&&;&/span&
&span class=&kr&&int&/span& &span class=&nx&&newCapacity&/span& &span class=&o&&=&/span& &span class=&nx&&oldCapacity&/span& &span class=&o&&+&/span& &span class=&p&&(&/span&&span class=&nx&&oldCapacity&/span& &span class=&o&&&&&/span& &span class=&mi&&1&/span&&span class=&p&&);&/span&&span class=&c1&&//原来的1.5倍&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&nx&&newCapacity&/span& &span class=&o&&-&/span& &span class=&nx&&minCapacity&/span& &span class=&o&&&&/span& &span class=&mi&&0&/span&&span class=&p&&)&/span&
&span class=&nx&&newCapacity&/span& &span class=&o&&=&/span& &span class=&nx&&minCapacity&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&nx&&newCapacity&/span& &span class=&o&&-&/span& &span class=&nx&&MAX_ARRAY_SIZE&/span& &span class=&o&&&&/span& &span class=&mi&&0&/span&&span class=&p&&)&/span&
&span class=&nx&&newCapacity&/span& &span class=&o&&=&/span& &span class=&nx&&hugeCapacity&/span&&span class=&p&&(&/span&&span class=&nx&&minCapacity&/span&&span class=&p&&);&/span&
&span class=&nx&&elementData&/span& &span class=&o&&=&/span& &span class=&nx&&Arrays&/span&&span class=&p&&.&/span&&span class=&nx&&copyOf&/span&&span class=&p&&(&/span&&span class=&nx&&elementData&/span&&span class=&p&&,&/span& &span class=&nx&&newCapacity&/span&&span class=&p&&);&/span&&span class=&c1&&//扩展空间并复制&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&由于Java GC自动管理了内存,这里也就不需要考虑源数组释放的问题。&br&&/p&&p&&figure&&img src=&https://pic1.zhimg.com/v2-7080cbd7ca5fa34ab76d8cd_b.jpg& data-rawwidth=&850& data-rawheight=&458& class=&origin_image zh-lightbox-thumb& width=&850& data-original=&https://pic1.zhimg.com/v2-7080cbd7ca5fa34ab76d8cd_r.jpg&&&/figure&空间的问题解决后,插入过程就显得非常简单。&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-4d43a00a31c3dd8170d3_b.jpg& data-rawwidth=&804& data-rawheight=&806& class=&origin_image zh-lightbox-thumb& width=&804& data-original=&https://pic2.zhimg.com/v2-4d43a00a31c3dd8170d3_r.jpg&&&/figure&&p&add(int index, E e)需要先对元素进行移动,然后完成插入操作,也就意味着该方法有着线性的时间复杂度。&/p&&ul&&ul&&li&&b&addAll()&/b&&/li&&/ul&&/ul&&br&&p&addAll()方法能够一次添加多个元素,根据位置不同也有两个把本,一个是在末尾添加的addAll(Collection&? extends E& c)方法,一个是从指定位置开始插入的addAll(int index, Collection&? extends E& c)方法。跟add()方法类似,在插入之前也需要进行空间检查,如果需要则自动扩容;如果从指定位置插入,也会存在移动元素的情况。&/p&&p&addAll()的时间复杂度不仅跟插入元素的多少有关,也跟插入的位置相关。&/p&&ul&&ul&&li&&b&remove()&/b&&/li&&/ul&&/ul&&br&&p&remove()方法也有两个版本,一个是remove(int index)删除指定位置的元素,另一个是remove(Object o)删除第一个满足o.equals(elementData[index])的元素。删除操作是add()操作的逆过程,需要将删除点之后的元素向前移动一个位置。需要注意的是为了让GC起作用,必须显式的为最后一个位置赋null值。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&n&&E&/span& &span class=&nf&&remove&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&index&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&rangeCheck&/span&&span class=&o&&(&/span&&span class=&n&&index&/span&&span class=&o&&);&/span&
&span class=&n&&modCount&/span&&span class=&o&&++;&/span&
&span class=&n&&E&/span& &span class=&n&&oldValue&/span& &span class=&o&&=&/span& &span class=&n&&elementData&/span&&span class=&o&&(&/span&&span class=&n&&index&/span&&span class=&o&&);&/span&
&span class=&kt&&int&/span& &span class=&n&&numMoved&/span& &span class=&o&&=&/span& &span class=&n&&size&/span& &span class=&o&&-&/span& &span class=&n&&index&/span& &span class=&o&&-&/span& &span class=&mi&&1&/span&&span class=&o&&;&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&numMoved&/span& &span class=&o&&&&/span& &span class=&mi&&0&/span&&span class=&o&&)&/span&
&span class=&n&&System&/span&&span class=&o&&.&/span&&span class=&na&&arraycopy&/span&&span class=&o&&(&/span&&span class=&n&&elementData&/span&&span class=&o&&,&/span& &span class=&n&&index&/span&&span class=&o&&+&/span&&span class=&mi&&1&/span&&span class=&o&&,&/span& &span class=&n&&elementData&/span&&span class=&o&&,&/span& &span class=&n&&index&/span&&span class=&o&&,&/span& &span class=&n&&numMoved&/span&&span class=&o&&);&/span&
&span class=&n&&elementData&/span&&span class=&o&&[--&/span&&span class=&n&&size&/span&&span class=&o&&]&/span& &span class=&o&&=&/span& &span class=&kc&&null&/span&&span class=&o&&;&/span& &span class=&c1&&//清除该位置的引用,让GC起作用&/span&
&span class=&k&&return&/span& &span class=&n&&oldValue&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&关于Java GC这里需要特别说明一下,&strong&有了垃圾收集器并不意味着一定不会有内存泄漏&/strong&。对象能否被GC的依据是是否还有引用指向它,上面代码中如果不手动赋null值,除非对应的位置被其他元素覆盖,否则原来的对象就一直不会被回收。&/p&&h2&&ul&&li&&b&系列回顾&/b&&/li&&/ul&&/h2&&p&&a href=&https://zhuanlan.zhihu.com/p/?refer=dreawer& class=&internal&&【深入理解Java集合框架】Java Collections Framework概览&/a&&br&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/?refer=dreawer& class=&internal&&《深入理解Java集合框架》系列文章&/a&&/p&&p&—————————————————————————————————————————&/p&&p&在学习过程如果有任何疑问,请来极乐网(&a href=&https://link.zhihu.com/?target=http%3A//www.dreawer.com& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&dreawer.com&/span&&span class=&invisible&&&/span&&/a&)提问,或者扫描下方二维码,关注极乐官方微信,在平台下方留言。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-9acba0ed93f79df845880_b.jpg& data-rawwidth=&640& data-rawheight=&320& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic1.zhimg.com/v2-9acba0ed93f79df845880_r.jpg&&&/figure&
来源:作者:CarpenterLee(转载已获得原作者许可,如需转载请联系原作者)ArrayList 总体介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该…
&p&2014年的六月,我在知乎“&a href=&https://www.zhihu.com/question//answer/& class=&internal&&民用小型无人机的销售现状和前景怎么样? - YY硕的回答&/a&”这个问题下面发布了一篇科普多旋翼飞行器技术的回答,在知乎上至今获得了889个赞同、近10万次浏览,并且被几十家媒体和公众号转发。2014年中正是多旋翼飞行器市场爆发前的风口,后来很多朋友告诉我说正是这篇文章吸引他们走入了多旋翼飞行器行业。&/p&&p&两年来,大疆精灵系列更新了两代,飞控技术更新了两代,智能导航技术从无到有,诸多新的软件和硬件产品陆续发布。同时我们也多了很多友商,现在多旋翼飞行器市场火爆,诸多产品琳琅满目,价格千差万别。为了理解这些飞行器的区别,首先要理解这些飞行器上使用的传感器技术。我觉得现在很有必要再发一篇科普文章,定义“智能导航”这个概念,顺便字里行间介绍一下两年来大疆在传感器技术方面的努力。&/p&&br&&p&&b&&u&1. 飞行器的状态&/u&&/b&&/p&&p&客机、多旋翼飞行器等很多载人不载人的飞行器要想稳定飞行,首先最基础的问题是确定自己在空间中的位置和相关的状态。测量这些状态,就需要各种不同的传感器。&/p&&br&&p&世界是三维的,飞行器的三维位置非常重要。比如民航客机飞行的时候,都是用GPS获得自己经度、纬度和高度三维位置。另外GPS还能用多普勒效应测量自己的三维速度。后来GPS民用之后,成本十几块钱的GPS接收机就可以让小型的设备,比如汽车、手机也接收到自己的三维位置和三维速度。&/p&&br&&p&对多旋翼飞行器来说,只知道三维位置和三维速度还不够,因为多旋翼飞行器在空中飞行的时候,是通过调整自己的“姿态”来产生往某个方向的推力的。比如说往侧面飞实际上就是往侧面倾,根据一些物理学的原理,飞行器的一部分升力会推着飞行器往侧面移动。为了能够调整自己的姿态,就必须有办法测量自己的姿态。姿态用三个角度表示,因此也是三维的。与三维位置、三维角度相对应的物理量是三维速度、三维加速度和三维角速度,一共是十五个需要测量的状态。&/p&&figure&&img src=&https://pic3.zhimg.com/50/694927cac6cbda2385f62_b.jpg& data-rawwidth=&1062& data-rawheight=&744& class=&origin_image zh-lightbox-thumb& width=&1062& data-original=&https://pic3.zhimg.com/50/694927cac6cbda2385f62_r.jpg&&&/figure&&p&这十五个状态都对多旋翼飞行器保持稳定飞行有至关重要的作用。拿“悬停”这件看起来是多旋翼飞行器最基本的能力来说,实际上飞行器的控制器在背后做了一系列“串级控制”:在知道自己三维位置的基础上,控制自己的位置始终锁定在悬停位置,这里的控制量是一个目标的悬停速度,当飞行器的位置等于悬停位置时,这个目标悬停速度为0,当飞行器的位置偏离了悬停位置时,飞行器就需要产生一个让自己趋向悬停位置的速度,也就是一个不为零的目标悬停速度;飞行器要想控制自己产生目标悬停速度,就需要根据自己当前的三维速度,产生一个目标加速度;为了实现这个目标加速度,飞机需要知道自己的三维角度,进而调整自己的姿态;为了调整自己的姿态,就需要知道自己的三维角速度,进而调整电机的转速。&/p&&br&&p&读者可能会想哇为什么这么复杂。其实我们身边的许多工程产品都在简单的表现背后藏着复杂的过程。比如汽车的油门也是类似的,踩下油门之后,有传感器测量汽油的流速、控制汽油的流速;然后有传感器测量发动机的转速、控制发动机转速……从踩油门到加速的过程中也有许许多多的传感器在测量汽车的各个状态量,并对这些状态量施加控制。&/p&&br&&p&知道十五个状态量是多旋翼飞行器做任何动作的基础中的基础,但是让飞行器在任何情况下都准确知道这十五个状态量是非常困难的事情,因为现在的科技水平还没有能够实现让一个传感器同时测量这么多的物理量。&b&几十年来,人们发展出了一套复杂的技术,叫做组合导航,用GPS加上惯性测量元件、气压计和地磁指南针来让飞行器测量自己的十五个状态量。&/b&&/p&&br&&p&&b&&u&2. 组合导航&/u&&/b&&/p&&p&惯性测量元件是一种能够测量自身三维加速度和三维角速度的设备(实际上惯性测量元件有两种,一种加速度计,一种角速度计,为了行文方便,我们把这两种元件当做一种,统称为惯性测量元件)。根据物理学原理,加速度的积分是速度,速度的积分是位置,角速度的积分是角度,理论上单靠惯性测量元件,我们就可以知道十五个状态量。&/p&&br&&p&人类的科技水平也的确实现了这一点:GPS还没被发明以前,导弹上通常都装着一个精密的惯性测量元件,导弹打出去以后靠这个装置测量自己的十五个状态量,然后控制自己飞越海洋和大洲。然而这种惯性测量元件会在测量的过程中慢慢累积误差,元件本身的工艺、技术、成本越差,积累误差的速度就越快。导弹上价值几百万的惯性测量元件飞几万公里后会积累十几米到几公里的误差,这种水平的导弹已经非常了不起了,毕竟不是每个国家都可以在背后竖着洲际导弹和国际社会讲道理。&/p&&figure&&img src=&https://pic3.zhimg.com/50/84a0d000f26c9ce6bd3eacba_b.jpg& data-rawwidth=&1227& data-rawheight=&1500& class=&origin_image zh-lightbox-thumb& width=&1227& data-original=&https://pic3.zhimg.com/50/84a0d000f26c9ce6bd3eacba_r.jpg&&&/figure&&p&人体内也有惯性测量元件,人的耳蜗充满液体,人运动的时候这些液体有惯性,可以被耳中的神经感受到,因此测出了运动的加速度。然而人的惯性测量元件非常差,闭上眼睛,也不摸周围的东西,只靠耳蜗感受的移动,人基本没法走直线。&/p&&br&&p&而多旋翼飞行器上用的低成本MEMS惯性测量元件,精度就更差了,它测量的速度和位置在几秒钟内就会发散到几十米开外去,完全没法用来规划控制自己的飞行路线。&/p&&br&&p&此外,惯性测量元件还会受到温度、制造工艺的限制,产生一些测量的偏差,比如说有时温度突然变化之后,一个静止的惯性测量元件会觉得自己转动了起来,虽然它静止着,但是会输出不为零的角速度。这类测量的偏差需要比较仔细的算法进行修正,而且往往不能单靠惯性测量元件自己的测量完全消除。&/p&&br&&p&地磁指南针是一种测量航向的传感器。指南针在人们的生活中作用重大,在未知的环境中,不分南北可能寸步难行。飞行器的机身正方向朝南还是朝北这个状态量用导航的术语来说叫做航向,也就是飞行器姿态的三维角度中的一个,他在组合导航系统中是非常重要的一个状态量。&/p&&br&&p&地磁指南针能够指南指北是因为地球表面空间中有看不见的横贯南北的地磁线,地磁指南针可以测量出穿过自身的地磁强度,从而指出当前自身相对于地磁线的偏转。同样地,这个理论虽然非常简单,但是地磁线的强度非常弱,很容易受到干扰。比如多旋翼飞行器通用的无刷电机,在运转的时候就会产生变化的磁场,和地磁场叠加之后,地磁指南针就找不到正确的方向了。地磁指南针的这个特性非常令人恼火,但是早期的多旋翼飞行器开发人员毫无办法,因为这是唯一的能够确定飞行器在空间中绝对航向的设备。如果不知道这个航向,就基本没办法进行组合导航。&/p&&figure&&img src=&https://pic2.zhimg.com/50/50a2d0c7ba_b.jpg& data-rawwidth=&1000& data-rawheight=&649& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&https://pic2.zhimg.com/50/50a2d0c7ba_r.jpg&&&/figure&&p&气压计的原理最为简单。因为地球表面海拔越高,空气越稀薄,气压越低,因此气压就能够给出飞行器的海拔高度。不过,不出意料的是,尺寸和重量适合在多旋翼飞行器上使用的气压计有很大的缺陷,它的测量值会受到温度、湿度、空气流速、光照、振动等因素的影响,单靠气压计非常难实现对高度的稳定测量。&/p&&br&&p&&b&组合导航技术结合GPS、惯性测量元件、地磁指南针和气压计各自的优缺点,使用电子信号处理领域的很多技术,融合多种传感器的测量值,获得较为准确的飞行器十五个状态量的测量。&/b&前面说惯性测量元件的测量容易发散,这个发散可以通过GPS来抑制:GPS可以获得三维位置也可以获得三维速度,惯性测量元件可以获得三维加速度,加速度的积分也是速度。在通过地磁指南针获得航向的基础上,两种速度的观测就可以融合起来,通过GPS的测量值来发现并抑制惯性测量元件的发散。惯性测量元件的发散被抑制住之后,它也可以更准地测量三维角度和三维加速度。因此GPS和惯性测量元件在这些情况中互相取长补短。除此之外,气压计和GPS互相提高了高度测量的精度,地磁指南针、GPS和惯性测量元件一同提高了航向测量的精度,他们都是利用了相同的融合、“互补”的思想。&/p&&br&&p&组合导航技术中传感器互补的原理直接源于1948年诞生的信息论。克劳德-香农总结归纳出的信息论提出了信息的概念以及如何从数学上度量信息,信息论可以说是现代人类文明的基石之一。解释清楚信息的本质之后,人们才能够用数学表示一个朴素而又深刻的原理:信息可以用来估计状态,越多的信息可以把状态量估计得越准。&/p&&p&&figure&&img src=&https://pic2.zhimg.com/50/fea29fd04e16a86b37f455_b.jpg& data-rawwidth=&800& data-rawheight=&430& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic2.zhimg.com/50/fea29fd04e16a86b37f455_r.jpg&&&/figure&(上图致敬信息论之父,克劳德-香农)&/p&&p&此后,控制论的奠基人诺伯特-维纳与其他一大批工程师和科学家完善了通过信息进行状态估计的线性估计理论,进一步提出了传感器之间“互补滤波”,共同减小误差的理论。在此基础上鲁道夫-卡尔曼提出了卡尔曼滤波器,在通信、控制工程和飞行器状态估计领域广泛使用。&b&卡尔曼滤波器还被实现在了阿波罗飞船的导航计算机当中,使用星座位置和惯性测量元件互补测量阿波罗飞船的十五个状态量。&/b&&/p&&br&&p&信息论、线性估计理论以及卡尔曼滤波器允许人们把多个具有误差的传感器通过数学方程融合起来,利用传感器信息估计特定的状态量,而且越多传感器“互补”,可以获得越好的状态估计。这样,数学给工程学指出了发展方向:造更多牛逼的传感器进行互补,就能获得更好的状态估计能力。&b&大疆飞控总工程师鱼大人也曾经说过:“最牛逼的工程师都是在搞传感器。”传感器技术的重要性可见一斑。&/b&&/p&&br&&p&作为一种位置传感器,GPS具有诸多的问题,GPS信号只有在开阔的空间内才能给出比较好的测量值,因为GPS接收机需要从天上的卫星获得信号,这些信号要从太空传入大气层,这么远的距离,信号已经相对来说很微弱,所以必须要求接收机和卫星之间的连线上没有遮挡,一旦有建筑甚至是树木的遮挡,卫星发下来的信号就有噪声,GPS接收机就不能给出很好的位置和速度观测。在室内环境中,GPS甚至完全不能使用。组合导航技术要想进一步发展,就需要寻找其他能够在GPS不能使用的环境中使用的传感器。&/p&&br&&p&一种较为简单的能够替代GPS测量高度的传感器是小型超声波模块。这种模块通常有一收一发两个探头,一个探头发出超声波,另一个探头测量回波的时间,能够算出导致声波反弹的物体离探头的距离。现在在淘宝上,只要10块钱就可以买到一个能够比较准确测量几米内物体距离的超声波模块,被广泛用在大学生制作的小机器人上。这种10块钱的传感器没有比气压计和MEMS惯性测量元件性能高多少,它发出的声波容易发散,探测到的物体不一定位于探头正前方,另外声波也容易被空气中的水雾、振动所影响,给出完全错误的观测。因此,超声波模块最好的使用场景是对着地面,测量自身和地面的距离。&/p&&figure&&img src=&https://pic3.zhimg.com/50/5c9c1b686a9ae4bcdc6d1f_b.jpg& data-rawwidth=&400& data-rawheight=&400& class=&content_image& width=&400&&&/figure&&figure&&img src=&https://pic1.zhimg.com/50/4d9ea9b2e93f3e8f7c1cf24_b.jpg& data-rawwidth=&450& data-rawheight=&373& class=&origin_image zh-lightbox-thumb& width=&450& data-original=&https://pic1.zhimg.com/50/4d9ea9b2e93f3e8f7c1cf24_r.jpg&&&/figure&&p&&b&&u&3. 视觉感知系统&/u&&/b&&/p&&p&另外一种替代品是视觉感知系统。1970年之后,随着数字成像技术的发展,相机作为一种传感器开始被广泛研究。因为人可以通过自己的视觉估计视野中物体的位置、距离,而相机的原理模拟了人的双眼,所以研究者们模仿人的特点,利用相机的二维图像反推图像中物体的三维信息。这种和二维图像推算三维信息相关的技术和数学理论发展成了一个独立的学科——计算机视觉,也被称作机器视觉。&/p&&br&&p&视觉感知系统是目前世界上最热门的机器人学和机器视觉领域研究课题。其原理是利用一个或者多个相机构成的视觉传感器系统,采用复杂的算法,通过二维的相机图像推算出视野中物体相对与视觉传感器系统的几何中心的运动信息,如果假设这些物体都是静止的,那么相对运动其实代表了视觉传感器本身的运动。理论上,计算机视觉技术能够单凭一个相机就可以准确测量十五个状态量,但是与其他传感器类似,相机也有很多的缺陷,包括无法恢复尺度、成像质量有限、计算量消耗巨大等等。幸好,我们还可以把视觉感知系统和其他传感器结合起来,互相提高测量精度。&/p&&br&&p&聪明的读者肯定能够想到,把视觉感知系统和之前说的所有组合导航中用到的传感器融合起来,GPS信号质量高的时候用GPS组合导航,没GPS的时候用视觉感知系统替代GPS,不就解决问题了吗。这确实正是目前工程师和科学家们正在努力解决的问题,也是精灵4上初步实现的技术。在介绍精灵4是如何结合视觉感知系统和组合导航技术之前,我们先简单介绍两种已经比较成熟的视觉感知系统:光流测速模块和视觉里程计。&/p&&br&&p&光流测速模块顾名思义,只能测速度。通常一个光流测速模块由一个相机、一个惯性测量元件、一个超声波模块构成,它的主要原理是计算机视觉技术中于1981年被发展出来的“光流追踪”算法。&/p&&p&“光流”的概念最早在1950年代由心理学家和生物学家提出,指的是一个观察者和他在观察的事物发生相对运动时,这些事物在他眼前成的像会产生“运动的模式”,人脑利用这种“运动的模式”能够更灵敏地感知周围什么东西在动。比如下图中,读者一看就可以直观理解“光流”的意义。&/p&&figure&&img src=&https://pic2.zhimg.com/50/ea0a846b9da1b6732ff2b_b.jpg& data-rawwidth=&763& data-rawheight=&403& class=&origin_image zh-lightbox-thumb& width=&763& data-original=&https://pic2.zhimg.com/50/ea0a846b9da1b6732ff2b_r.jpg&&&/figure&&p&后来计算机科学家布鲁斯-卢卡斯和金出武雄在1981年发明了Lucas-Kanade算法,通过算法计算出连续拍摄的图片上的光流,并证明了光流可以反解出相对运动的速度。虽然三十多年来,Lucas-Kanade算法始终被公认为最好的“光流追踪”算法,但是它有比较大的局限性,它包含很多假设,比如假设连续图片的平均亮度相同,比如假设图片中的物体只发生平面运动等等。另外,光流算法算出的速度是没有尺度的,因为相机图像的单位是像素,所以光流算法只能给出“你现在的速度是10个像素每秒”,但是没法算出10个像素是1厘米还是1米。恢复尺度的方式是增加一个超声波模块测量平面运动离相机的距离,这样就能够把像素运动转换成真实的运动。最后,如果要让光流测速模块在晃来晃去的多旋翼飞行器上也能使用,通过惯性测量元件找出图像所代表的平面也是必不可少的,这一点需要在算法上进行两种传感器很好的配合。&/p&&br&&p&光流算法原理上只可以测三维速度,不能直接测量三维位置。我们同样可以通过把光流测速模块测出的三维速度积分获得三维位置,但是就像惯性测量元件积分会发散一样,光流测速模块积分得到的位置也会发散。好在它不会天马行空地失去控制,和组合导航技术中除了GPS之外的传感器妥善融合之后,它可以做到悬停时测量的位置不发散。因此可以说光流测速模块只在有限的条件下能够替代GPS。&/p&&br&&p&光流测速模块已经形成了非常标准的解决方案。大疆悟以及精灵3上都装载了自主研发的光流测速模块,另外著名的开源飞控产品Pixhawk中包含了一个叫做PX4Flow的光流测速模块,并且开源了所有的代码和硬件方案。所以光流测速模块目前已经广泛出现在了各大厂商的多旋翼飞行器产品上。&/p&&figure&&img src=&https://pic2.zhimg.com/50/fcddce6cf2be62a72c740ebdca8eb91f_b.jpg& data-rawwidth=&990& data-rawheight=&696& class=&origin_image zh-lightbox-thumb& width=&990& data-original=&https://pic2.zhimg.com/50/fcddce6cf2be62a72c740ebdca8eb91f_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/50/eba280c38e_b.jpg& data-rawwidth=&400& data-rawheight=&367& class=&content_image& width=&400&&&/figure&&br&&p&视觉里程计相比光流测速模块,增加了直接测量位置的能力,所以才叫“里程计”。视觉里程计比光流测速模块能力更强,性能更好。&/p&&br&&p&读者可能会问,为什么听起来视觉里程计和光流测速模块参与的传感器数量差不多(光流测速模块甚至还多一个超声波模块),但是视觉里程计能力反而更强呢。这里的原因不在于传感器硬件,而在软件算法上。前面已经说到光流追踪算法有很多简化的假设,只能测量平面运动,增加其他传感器硬件一定程度上是为了把那些为了计算方便而简化掉的因素重新弥补起来。&/p&&br&&p&而视觉里程计算法则复杂得多,它不仅要通过图像反推出视野中物体的平面运动,还要反推出这些物体的三维位置,并且基于这些物体的三维位置做很多次的优化计算,算法复杂度成倍于光流测速模块。有些视觉里程计的算法甚至包含完整的光流追踪的算法,但是仅仅把计算光流作为预处理图像的步骤。&/p&&br&&p&视觉里程计能够直接测量位置,测量值也比较准确,不会像光流测速模块那样发散。通常比较优秀的视觉里程计飞100米之后只会积累十几厘米到几十厘米的误差,这个测量水平比起导弹上几百万的惯性测量元件还是差了不少,但是考虑到视觉里程计的价格极其低廉,对比起来它的性价比非常高。&/p&&br&&p&视觉里程计有几个不同层次的难度,最简单的是两个相机构成的双目立体视觉系统加惯性测量元件,最难的是一个相机构成的单目视觉系统加惯性测量元件。如果视觉里程计和光流测速模块硬件一致,那么这里的视觉里程计采用的是单目视觉系统。目前,双目立体视觉系统加惯性测量元件实现自身状态观测已经是比较完善的技术,而&b&单目视觉系统则是活跃的研究方向,世界上做这个研究方向较好的大学有美国的宾西法尼亚大学、瑞士的苏黎世联邦理工学院、英国的牛津大学、我国的香港科技大学和其他一些欧美院校。&/b&&/p&&br&&p&单目视觉系统和双目立体视觉系统两者对比起来,他们的算法难度差别很大。视觉里程计的算法关键点是前面说的“通过连续的图像反推出视野中物体的三维位置”。对于和人眼结构类似的双目立体视觉系统,这一点比较容易,因为一个物体同时出现在左右两个相机的视野中时左右视野有视差,视差可以帮助解算物体的位置,只需要用简单的几何关系就可以实现,这已经是非常成熟的技术。&/p&&p&但是对于单目视觉系统,只有一个相机就没有视差,没法做简单的几何关系的解算,所以算法必须能智能地在局部范围内同时估计很多个物体的位置,然后在自身移动过程中通过位置移动产生视差,然后进行多个物体的位置的最大似然估计,从而推算出这些物体比较准确的位置。这个过程包括很多个环节,大部分环节在学术界都没有公认最优的方案,因此还没有成熟的技术。&/p&&br&&p&因为原理相对简单,所以双目立体视觉系统构成的视觉里程计在三十年前就开始被研究了。1980年代早期,NASA工程师、著名机器人学家汉斯-莫拉维克就已经制造出了这种状态测量系统。关于汉斯-莫拉维克的另一个故事,我在知乎问题中“&a href=&https://www.zhihu.com/question//answer/& class=&internal&&有哪些与控制、机器人等相关的 quotes? - YY硕的回答&/a&”也有提到。&/p&&p&&figure&&img src=&https://pic3.zhimg.com/50/3fedf5afca253d4b15d5_b.jpg& data-rawwidth=&500& data-rawheight=&561& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&https://pic3.zhimg.com/50/3fedf5afca253d4b15d5_r.jpg&&&/figure&(上图致敬汉斯-莫拉维克)&/p&&p&在经年累月的优化之后,&b&2004年,NASA成功把视觉里程计和惯性测量元件构成的视觉定位系统装在“机遇号”和“勇气号”火星车主频仅有20MHz的特制芯片上,送上了火星&/b&,它可以帮助火星车通过一对双目相机非常准确地记录自己走过的路线。2007年,参与火星探测任务的计算机科学家和工程师们把这个激动人心的过程写成了一篇论文《计算机视觉在火星》(Computer Vision on Mars),这篇文章吸引了很多计算机视觉研究人员投身视觉里程计的研究,也极大推动了视觉里程计在机器人学中的应用。&/p&&br&&p&&b&&u&4. 精灵4的传感器方案&/u&&/b&&/p&&p&大疆在精灵4上实现了双目立体视觉系统加惯性测量元件构成的视觉里程计,飞机上装了两套双目立体视觉系统,一套向前看,一套向下看,一共是四个相机。&/p&&figure&&img src=&https://pic4.zhimg.com/50/63e8cb01ca6eadbeaf04d5_b.jpg& data-rawwidth=&266& data-rawheight=&249& class=&content_image& width=&266&&&/figure&&figure&&img src=&https://pic2.zhimg.com/50/cd80f87f9cf_b.jpg& data-rawwidth=&1024& data-rawheight=&684& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/50/cd80f87f9cf_r.jpg&&&/figure&&p&两套双目立体视觉系统都参与视觉里程计的计算。通常情况下以向下看的双目立体视觉系统为主,如果向下看的相机对着一些特征不明显的环境(比如纯色的地板、海面等等),感受不到什么图像变化,视觉里程计会自动切换到向前看的立体视觉系统做测量计算。虽然精灵4采用的都是较为成熟的机器视觉技术,但是由于精灵4上机载的计算量非常有限,大疆还是下了相当久的苦功去优化算法,并使用了Movidius公司制作的图像算法处理专用芯片,结合Movidius公司的图像处理算法库优化四路图像处理的性能。值得一提的是,不久就会面世的Google Project Tango也使用了Movidius公司的这款芯片。不过因为Movidius公司的芯片不包含视觉里程计的算法,所以Google的这款产品中视觉里程计的算法应该与精灵4的算法有较大差别。&/p&&br&&p&两套双目立体视觉系统还带来了视觉里程计之外的两个好处:1. 向下看的一套双目立体视觉系统可以探测下方地面上物体的三维位置,从而知道地面的距离;2. 向前看的一套双目立体视觉系统可以用来探测前方场景中物体的深度,产生深度图进行障碍感知。深度图还可以用于重建一个飞行器周围的局部地图,以进行精细的运动规划,这就是精灵4指点飞行的基础,在这篇文章中不详细介绍了。&/p&&figure&&img src=&https://pic3.zhimg.com/50/190d7d82fda_b.jpg& data-rawwidth=&428& data-rawheight=&324& class=&origin_image zh-lightbox-thumb& width=&428& data-original=&https://pic3.zhimg.com/50/190d7d82fda_r.jpg&&&/figure&&p&除了增加视觉里程计之外,精灵4上还增加了内置的超声波模块。&b&所以精灵&/b&&b&4上一共有GPS+惯性测量元件+气压计+地磁指南针+超声波模块+双目视觉系统六种传感器。其中双目视觉系统有两套,共4个相机;惯性测量元件有两个,实现双冗余备份;地磁指南针也有两个,同样双冗余。&/b&当工作中的惯性测量元件或者地磁指南针受到严重干扰的时候,系统会自动进行备份切换,切换到另一个传感器上。这些传感器的数量、功能和特性总结如下表:&/p&&p&&figure&&img src=&https://pic4.zhimg.com/50/373e5a07de765c691a77aa4add242c8d_b.jpg& data-rawwidth=&653& data-rawheight=&388& class=&origin_image zh-lightbox-thumb& width=&653& data-original=&https://pic4.zhimg.com/50/373e5a07de765c691a77aa4add242c8d_r.jpg&&&/figure&有了这些传感器以后,组合导航系统升级成为了智能导航系统。智能导航技术极大拓展了飞行器可以活动的空间,当有GPS的时候,系统可以通过GPS为主进行十五个状态量的测量,视觉里程计依然可以继续运作,提供额外的速度和位置的测量值进一步提高精度;GPS信号不好的时候,视觉里程计可以接替GPS为整个系统提供稳定的观测。智能导航系统中有三种确定高度的传感器:超声波、气压计、双目立体视觉,这三种传感器几乎可以覆盖所有让传统多旋翼飞行器头疼的定高场景:树丛上方、室内、靠近建筑的位置、大风环境等等。&br&&/p&&br&&p&地磁指南针的冗余设计可以很大程度上减小外部磁干扰带来的指南针故障。另外视觉里程计也能给出航向的观测,两者互补能够提高航向的观测精度。在以前的飞行器上,因为地磁指南针受到干扰造成的炸机问题比较多,在精灵4上因为有了多重保护措施,地磁指南针被干扰导致问题的概率大大降低。&/p&&br&&p&有了智能导航系统之后,还需要有一套强有力的软件系统去组织导航算法和飞行控制算法。精灵4的飞控和最新推出的A3飞控类似,都是大疆第三代飞行控制器。大疆第一代飞控性能已经很不错了,然后飞控组在过去的几年里做了两次比较大的飞控软件系统的重构,以支持更多的传感器和功能。2014年底推出的第二代飞控里加入了光流测速模块支持、SDK、限飞区和新手模式等功能,2016年初开发完成的第三代飞控里加入了冗余传感器、双目立体视觉支持、避障功能和智能返航等功能。因为每一次重构都对整个软件系统做了很大规模的调整,增加了很多的软件模块和新的软件架构,所以分了三代。&b&别人刚开始做飞控的时候,大疆已经自己重构了两次代码,这一点是大疆最引以自豪的地方之一。&/b&&/p&&br&&p&智能导航系统让精灵4在任何状态下都可以准确测量自身的三维位置和三维速度,这对实现多种功能都有非常重要的意义。&/p&&br&&p&近年来,业界有很多关于避障应该使用双目立体视觉还是激光雷达传感器等传感器的争论。在大疆内部,选择什么样的传感器放入智能导航系统用来避障,工程师团队也进行了旷日持久的探讨,最后还是选择了双目立体视觉的方案。我相信随着科技的发展,在未来会不断有更多更好的新传感器诞生,很可能会有其他传感器代替双目立体视觉,但是实现稳定避障的关键不在于避障所使用的传感器。避障这个事件发生前后,飞行器机体一定会发生急刹车,整体会经历很大的姿态变化和加速度,在这种状态下,飞行器是否还能稳定地测量出自己的十五个状态量,才是最影响安全性的问题。&/p&&br&&p&如果系统急刹车之后,整体的位置观测甚至速度观测都发散了,这时候飞行器有可能左右飘出去,还是会发生炸机。就算不炸机,避障之后飞机前后左右摇晃,也会给用户心理上造成不安全的感受,带来很差的用户体验。精灵4在很多严苛的情况下发生避障动作时,飞行器会自动锁定位置、速度迅速减为0的状态,很快就可以从高速机动恢复到完全不动,非常稳定地悬停,避免了在障碍附近不稳定活动引起炸机。&/p&&br&&p&精灵4还能处理很多看似很简单,但是对传感器系统要求非常高的飞行场景。比如在十几层楼的窗口把飞行器从室内飞到室外悬停。这种场景下,从窗口穿出时,向下看的传感器几乎马上全部失效,由于有建筑的遮挡,GPS也不会立刻生效,因此传感器系统不够稳健的飞行器有可能因为失去速度和位置的测量而飘到建筑上造成高空炸机。而精灵4则能够通过前视双目视觉系统的观测,在向下看的传感器都暂时失效时继续运行视觉里程计,及时提供辅助的速度和位置观测,避免造成无法控制速度和位置导致炸机的情况出现。&/p&&br&&p&实际上,由于前面说的过GPS容易被遮挡导致没有足够的信号做观测的情况在航拍的场景中其实常常遇到。比如在树木茂密的峡谷里航拍,经常出现的情况是飞行器放在地面上时接收不到GPS信号,如果稳定飞到几十米的高度就可以接收到了。在这些临界情况下起飞和降落非常危险,如果要保证飞行器在升降过程中都能保持稳定的状态,飞行器必须能够在GPS和视觉里程计之间无缝转换,这样才能让用户放心地起降。如果用户从高处下降到低处GPS突然没有了,而视觉里程计没有及时补上,飞机失去位置和速度观测之后就变得非常难操控,就有可能撞在树丛上。&/p&&br&&p&读者可能问,在这些情况下光流测速模块效果是不是也一样呢。我们前面说过光流测速模块的算法有很多简化的假设,尤其是被观测的物体必须处于同一个平面这样的假设,使得光流测速模块在树丛上方、地势变化较大的空间上方,都表现非常糟糕,并不能满足户外航拍的需求。虽然视觉里程计计算量庞大,但它是比光流测速模块更加实用有效的方案。&/p&&br&&p&另外值得一提的是,第二代的大疆飞控使用的是遥控器杆量转化成飞行器的加速度指令,而第三代的大疆飞控在精灵4上变成了遥控器杆量转化成飞行器的速度指令。在精灵3、大疆的前代飞行器以及很多无人机产品上,如果你推遥控器满杆前进,飞行器会以一个固定的角度加速飞出去,直到加速度被空气阻力抵消,这样控制并不直观,所以新手很难操作飞行器;而在精灵4上,如果你推遥控器满杆前进,飞行器会自己调整到一个固定的速度上,直接操控速度显得非常直接,非常容易操控。以往,让飞行器保持匀速飞行是只有专业飞手才能做到的事情,现在则真真正正地让普通人也能触手可得。这一个修改看似简单,但是提供了更好的操作手感,而且让飞行器飞行的状态更加稳定。&/p&&br&&p&对于航拍操作手来说,所有的花哨功能都不如悬停得稳、飞得稳这一点重要,因为飞机晃得太厉害,总会给用户造成一种“我的飞机真的没出问题吗”的感受,用户体验极其不好。我们去西藏青海或者其他很美的地方开车玩,肯定是希望平稳、慢慢地开,这样才能专心看美景;如果开着一部油门轻轻一点就加速到200公里的赛车,坐在车里一会儿被推背,一会儿过弯时左右甩,人还有心情欣赏路上的美景吗?&/p&&br&&p&遥控器杆量改动也显示了大疆对自己智能导航系统提供的稳定的三维速度测量的信心。目前我没有见过其他哪家公司的飞行器控制系统采用的是遥控器杆量转化成飞行器的速度指令。&/p&&br&&p&&b&&u&5. 当我在谈论无人机的时候,我在谈论什么&/u&&/b&&/p&&p&在这篇文章里,到现在我都没有提过“无人机”三个字。我觉得&b&,就像一辆合格的汽车必须有安全带、安全气囊、后视镜、阻燃内饰、各种仪表盘等等安全措施才能称为汽车一样,一部合格的多旋翼飞行器也必须有惯性测量元件、GPS&/b&&b&、视觉里程计、避障系统、气压计和超声波等传感器构成的智能导航系统才能被称为无人机&/b&。多旋翼飞行器不是玩具,汽车以高速撞人会造成人体严重的伤害,多旋翼飞行器甚至都不需要高速运动就可以用螺旋桨造成人体严重的伤害,因此多旋翼飞行器传感器必须有很强的安全性和稳定性。&/p&&br&&p&2014年的时候,大疆飞控组有一个白板,上面写着:“竞争对手” 下面只用小字写了几个业内竞争品牌的名字,但是用大大的字写了“波音“。几年来,大疆飞控的梦想都是能让便宜低价的多旋翼飞行器像波音的民航客机那样,只有五百万分之一的致死事故发生率。随着传感器技术的提升和飞行控制品质的提升,&b&截止2016年5月底,精灵4核心传感器系统出现故障的概率约为每两百万次起降仅有一次发生严重故障&/b&。虽然相比起载人的飞行器来说,大疆还有很多地方需要努力,但是在无人的多旋翼飞行器行业中,大疆是行业中飞行器整体故障率最低的企业。很多其他的企业,可能都无法计算出事故概率是百万分之多少,甚至是万分之多少。&br&&/p&&br&&p&很多其他公司也出了不少多旋翼飞行器产品,但是大部分只做了个组合导航的皮毛,加上一个光流测速模块,然后动一些歪脑筋,就开始标榜自己的安全性。就好比造个了汽车,说“啊我这个安全性很好的因为我方向盘手感很好,还装了个车载GPS”,但他车里连安全气囊和后视镜都没有。&/p&&p&还有的公司以飞行器上有新型传感器为卖点。&b&但是一套完整、可靠的传感器系统是一点一滴积累起来的,新传感器必须和已有的组合导航系统在硬件和软件上仔细融合,才能真正发挥作用。&/b&面对很多号称采用激光、红外线、“人眼级别的智能”的传感器,读者们只要去问这些厂商:“你的传感器能和GPS无缝切换吗?”“你的传感器解决室内掉高问题吗”“你的传感器在急刹车的时候还能保持位置观测吗”,就可以看出他们都是堆砌出来的空中楼阁。&/p&&br&&p&有些厂商的宣传语是“无人机不是土豪的玩具”。如果把他们所有宣传语中的“无人机”一词换成“汽车”,那么这类宣传逻辑和它们引导的消费观念显得极其错误。对汽车来说,有些汽车价格昂贵是因为提供了更好的倒车雷达和车身周围的传感器系统,这种增加汽车售价的行为提高了驾驶的体验,是理所应当的;另一方面,要求汽车变得更便宜,不应该要求去除这些安全传感器,而是应该从车身材料、内饰等方面去入手降成本。&/p&&br&&p&大疆极其反感这类行为,并不是想打击这些竞争对手以占领市场,而是希望所有厂商能够沉住气,把飞行器的传感器做完善。多旋翼飞行器不是手机一类的消费电子,而是和汽车、客机一样具有一定危险性的载具,不能一味打价格战或者标新立异。我们希望市场上能出现带着全套智能导航系统和算法,依然售价2999的飞行器。&b&我们坚信只有实现了完善的智能导航系统,才能造出真正安全的无人机产品,否则让不达标的飞行器进入市场,损害的是全体厂商的利益,也危害了整个社会的安全。&/b&&/p&
2014年的六月,我在知乎“”这个问题下面发布了一篇科普多旋翼飞行器技术的回答,在知乎上至今获得了889个赞同、近10万次浏览,并且被几十家媒体和公众号转发。2014年中正是多旋翼飞行器市场爆发前的风…
&figure&&img src=&https://pic2.zhimg.com/v2-8e2beceb046_b.jpg& data-rawwidth=&700& data-rawheight=&700& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&https://pic2.zhimg.com/v2-8e2beceb046_r.jpg&&&/figure&修真院CSS任务第一个,就是做一个九宫格,然后要支持手机访问,这样就难倒了一大片人。&p&在我的期望中,我说了要支持手机访问,你就应该去想办法,怎么样能让手机访问一个网页?第一件事,就是要知道怎么能把一个网页发布出去。&/p&&p&搜一下“怎么样能让手机访问一个网页”,第二页,百度经验上写着Apache。&/p&&p&&figure&&img src=&https://pic3.zhimg.com/v2-b498c7b091cc69590ddf18ad57bcaf36_b.png& data-rawwidth=&818& data-rawheight=&332& class=&origin_image zh-lightbox-thumb& width=&818& data-original=&https://pic3.zhimg.com/v2-b498c7b091cc69590ddf18ad57bcaf36_r.jpg&&&/figure&点开去看的话,&a href=&http://link.zhihu.com/?target=http%3A//jingyan.baidu.com/article/48b37f8d032d861a.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&jingyan.baidu.com/artic&/span&&span class=&invisible&&le/48b37f8d032d861a.html&/span&&span class=&ellipsis&&&/span&&/a&,介绍的还算详细,按照步骤来的话,基本上已经可以做得到吧?&/p&&br&&p&如果做不到的话,至少知道了,嗯,有Apache这个东西,这个东西可以让我本地的网页发布出去。那么,Apache又是一个什么鬼?&/p&&p&继续搜apache,百度的搜索联想给出几个关键的字,如图所示。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-403d9b76e20dd8a186d4ee47afa35c5c_b.png& data-rawwidth=&785& data-rawheight=&339& class=&origin_image zh-lightbox-thumb& width=&785& data-original=&https://pic1.zhimg.com/v2-403d9b76e20dd8a186d4ee47afa35c5c_r.jpg&&&/figure&&br&&p&第一个是Tomcat,这个是什么东西,可以稍后再去搜索。&/p&&p&第二个是下载,不用想,说明很多人想去下载Apache。&/p&&p&第三个是http,如果对http不熟悉,这个时候可以去跳转继续查找什么是http.&/p&&p&第四个是配置,说明这个东西是需要下载之后配置一下的。&/p&&p&第五个提到了虚拟主机,至少证明Apache和虚拟主机有关联,什么是虚拟主机呢?把它继续列入自己下一个搜索的词里面。&/p&&p&剩下的可以不用怎么看。&/p&&br&&p&再看搜索结果,广告不用管,排名靠前的如下。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-f249cb83b5d1b9daf27351ff01cfc5eb_b.png& data-rawwidth=&905& data-rawheight=&487& class=&origin_image zh-lightbox-thumb& width=&905& data-original=&https://pic4.zhimg.com/v2-f249cb83b5d1b9daf27351ff01cfc5eb_r.jpg&&&/figure&&br&&p&第一个是官网,百度的官网两个字写的很清楚,眼不瞎的话,应该是能看得到的吧?英文网站不懂可以不管。&/p&&p&第二个是百度百科,这是仅次于百度外卖的百度重量级产品,百科的内容,很多时候还是挺靠谱的。&/p&&p&第三个是Apache的一个项目介绍,也可以暂时不管。&/p&&br&&p&所以可以直接点开看Apache的百度百科。如下所示:&/p&&p&&b& Apache是世界使用排名第一的Web&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/899.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&服务器&/a&软件。它可以运行在几乎所有广泛使用的&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/2269685.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&计算机平台&/a&上,由于其&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/469855.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&跨平台&/a&和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充,将&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/46614.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Perl&/a&/&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/21087.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python&/a&等&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/592974.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&解释器&/a&编译到服务器中。同时Apache音译为&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/19261.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&阿帕奇&/a&,是北美印第安人的一个部落,叫阿帕奇族,在美国的西南部。也是一个基金会的名称、一种&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/subview/5788.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&武装直升机&/a&等等。&/b&&br&&/p&&br&&p& 这段解释,其实看不太明白。接着往下看。如下所示:&/p&&br&&br&&b&Apache HTTP &a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/488131.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Server&/a&(简称&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/subview/2.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Apache&/a&)是&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/7044910.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Apache软件基金会&/a&的一个开放源码的网页服务器,可以在大多数计算机操作系统中运行,由于其多平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩展,将Perl/Python等解释器编译到服务器中。[2]&/b&&br&&b&Apache HTTP服务器是一个模块化的服务器,源于NCSAhttpd服务器,经过多次修改,成为世界使用排名第一的&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/460250.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Web服务器&/a&软件。&/b&&br&&br&&br&&br&
世界使用排名第一的WEB服务器,什么叫WEB服务器?于是你可以直接点开WEB服务器的百度百科。如下所示:&br&&br&&b&Web服务器一般指网站服务器,是指驻留于&a href=&http://link.zhihu.com/?target=http%3A//baike.baidu.com/view/1706.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&因特网&/a&上某种类型计算机的程序,可以向浏览器等Web客户端提供文档,[1] 也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个Web服务器是Apache Nginx IIS。&/b&&br&&br&&br&&br&&br&原来WEB服务器就是可以把网站文件发布到因特网上,可以让全世界浏览的~而且还提到了另外两个,一个是Apache,一个是Nginx,一个IIS。&br&&br&正常来讲,应该再看一下Nginx是什么,IIS是什么。假设你已经自己学会去查看什么是Nginx了,那么接下来应该做什么?&br&&br&应该去对比一下Apache和Nginx有什么区别。&br&&br&所以你应该这个时候在百度里打上 Apache和Nginx的区别,别慌,这个时候你发现,百度提示已经出来很多Apache和Nginx的区别了,有图为证。&br&&br&&figure&&img src=&https://pic3.zhimg.com/v2-a98b78f576fb3d1225bfc7f_b.png& data-rawwidth=&852& data-rawheight=&383& class=&origin_image zh-lightbox-thumb& width=&852& data-original=&https://pic3.zhimg.com/v2-a98b78f576fb3d1225bfc7f_r.jpg&&&/figure&&br&这说明什么呢?说明你搜索的方向是对的。如果换一个,比如说,我们想搜Apache和IT修真院的区别,你会发现没有任何提示,这说明并没有太多人去搜这些问题。如下图所示:&br&&figure&&img src=&https://pic1.zhimg.com/v2-f2e87aa790_b.png& data-rawwidth=&745& data-rawheight=&431& class=&origin_image zh-lightbox-thumb& width=&745& data-original=&https://pic1.zhimg.com/v2-f2e87aa790_r.jpg&&&/figure&&br& 一般情况下来说,你不会是第一个遇到问题的人,在你之前百度没有给出任何结果,基本上证明Apache和IT修真院没有任何的关系。&br&&br&继续看Apache和Nginx的区别,如下图所示:&br&&figure&&img src=&https://pic2.zhimg.com/v2-ef6f85466b6edee4ac27db9_b.png& data-rawwidth=&795& data-rawheight=&586& class=&origin_image zh-lightbox-thumb& width=&795& data-original=&https://pic2.zhimg.com/v2-ef6f85466b6edee4ac27db9_r.jpg&&&/figure&博客园,对于技术人员来讲,能写博客的,基本上还是能靠的住的,所以可以点开这个,稍后再看。&br&百度知道,简单的问题有点帮助,稍微深度一些的问题,绝对不会有正确答案。所以看不看无所谓。&br&知乎,很严谨的问答社区,特别是有一些装逼的人爱维护秩序,你回答的问题不粘边了,很快有人点没有帮助,所以大部分的答案还是有用的。可以点开,稍后再看。&br&51CTO,跟博客园差不太多,可以参考,也是稍后点开。&br&&br&随便点开一看,大概会有很多术语弄不太懂。比如说:&br&&br&&br&&figure&&img src=&https://pic4.zhimg.com/v2-afe722c5dbf8ba3b786e77_b.png& data-rawwidth=&797& data-rawheight=&527& class=&origin_image zh-lightbox-thumb& width=&797& data-original=&https://pic4.zhimg.com/v2-afe722c5dbf8ba3b786e77_r.jpg&&&/figure&&br&&br&反正也看不太懂。但是下面有结论。大概意思就是要性能和不要性能,那就是差别不大~&br&&br&剩下的什么Rewrite,Bug,SSL 这些,有兴趣可以随便看看,没兴趣,对于Apache和Nginx的了解可以到此为止了。&br&&br&&br&所以,我们在任务1里写了要支持手机访问,然后找到了Apache,然后找到了WEB服务器,找到了三款WEB服务器,又看了一下Apache和Nginx的对比。&br&&br&这是不是你自己在百度过程学会的东西?&br&&br&&br&整个过程不会超过半个小时吧?半个小时之内,你从一个什么都不太懂的人,已经开始有点像一个专业的程序员的样子了。&br&然而大多数学员都不是这个样子。&br&&br&他们第一句话会问:“不会做啊,有没有教程?”&br&我往往会回答:教程你妹啊?不能自己去百度?&br&他们第二句话会说:“你直接告诉我不是更快吗?”&br&我去你大爷的,根本无法交流。&br&&br&&br&然后还会有人说:视频在哪里?&br&我会说:“看视频的都是SB。”&br&他们就会说:“前期看书太慢,没基础,看视频速度前期速度更快。”&br&我去你大爷的,根本无法交流。&br&&br&我其实对视频并不是完全抵触,我反感的是无脑看视频。&br&而且对于快和慢的概念根本没办法和他们在一个频道上。&br&&br&半个小时能学完的东西,看视频至少要半天。视频的坏处不仅仅是拖沓,更重要的是封闭,不开放。&br&看完就忘,太多人看了N多视频,上手写代码的时候一行代码都写不出来了。&br&&br&这次先不扯为什么不看视频,继续说百度的事儿。&br&以我的性子,写一句支持手机访问,支持自适应就好了。怎么做,自己去找对应的方法。&br&后来看到脑残的人太多,没办法只好加上:&br&&br&&figure&&img src=&https://pic2.zhimg.com/v2-165a82dae71e_b.png& data-rawwidth=&1012& data-rawheight=&278& class=&origin_image zh-lightbox-thumb& width=&1012& data-original=&https://pic2.zhimg.com/v2-165a82dae71e_r.jpg&&&/figure&&br&
第一步,请下载九宫格的图片,第二步,请写出来一个页面,跟图片一个样子。第三步,请使用Nginx,配置好了,这样能够直接访问网页了。&br&&br&然后,大家的反应就是:&br&Nginx是什么东西?&br&为什么要用它?&br&我不是要写代码吗?&br&不用它行不行?&br&怎么配置?&br&教程在哪里?&br&&br&我去你大爷的,根本无法交流。&br&&br&其实这些问题很正常,但是这些问题不该问我,而是应该问百度,对不对?&br&如果你带着这些问题去百度查,多好。&br&&br&因为SB太多,所以没办法,只好再加上参考资料。&br&&figure&&img src=&https://pic2.zhimg.com/v2-676f9fbbe05_b.png& data-rawwidth=&683& data-rawheight=&318& class=&origin_image zh-lightbox-thumb& width=&683& data-original=&https://pic2.zhimg.com/v2-676f9fbbe05_r.jpg&&&/figure&&br&&br&其实心都在滴血。我倒底需要不需要把这些资料送到你们面前,还是应该坚持让你们改变自己的学习方式,改变自己的心态,改变自己的习惯?&br&&br&&br&抛开这个问题不谈,就算把这些攻略摆在了他们的面前,还是会有这样的问题:&br&1.我按照攻畋一步步做的,怎么就是不能显示?&br&2.为什么我出来的是IIS的界面?&br&3.Nginx怎么关闭?&br&4.在哪下载Nginx?&br&5.我倒底为什么要用Nginx?这么麻烦,用它干嘛,好难,好难,我还是去看幕课吧。&br&&br&我去你大爷的,根本无法交流。&br&这些问题其实也很正常,可是真的必须要有一个人来24小时伺候着,随叫随答吗?&br&&br&其实你们不知道,程序员最好的伴侣就是问题,从来都是不经意见遇到一堆问题,在各种烦燥中孤独的和问题自由的相处,每天想着问题,念着问题,恨不得一口把问题全吃掉,而一旦征服了她,成就感胜过上了3个漂亮妹子。&br&&br&好吧,我承认其实比不上跟妹子一起玩儿。但是,无论你是刚学2个小时的新人,还是工作十年的老人,你总是会面对问题。遇到问题,解决问题,总结方案是程序员的终身伴侣,根本扔不掉。&br&&br&等你和一个又一个的问题相识相知分手之后再重逢内心平静没有一点波澜,你已经成长了。&br&&br&那么,再回到标题。&b&当你遇到问题时,你为什么不先去百度?&/b&&br&&br&&br&修真院最早是希望指明方向,明确路线,提供环境,做好辅导。这是传统培训机构拉一个从来没做过项目人当讲师的方式远远无法提供的内容。&br&而修真院在一年半里培养出来的学员,也证明了修真院是活好钱少的典范。&br&&br&可是最近才发现,修真院更可贵的是,给你一个改变自己的机会。&br&&br&也许你之前没读过大学,也许你之前喜欢24小时玩游戏,也许你之前从来没动过脑子因为它早就退休了。&br&也许你之前没有自信,也许你根本不懂什么叫做主动,也许你也不明白什么叫做坚持。&br&&br&但是修真院就是提供了这么一个近似于苛刻的环境。&br&看起来,修真院的任务有难度,然而有没有想过,真正找工作的时候,会更难。&br&看起来,修真院几乎是纯自学,很少有讲座有辅导,然而有没有想过,哪个程序员是辅导出来的?&br&&br&能力 & 知识&br&&br&特别是在你还没有能力的时候,所以,从现在做起,改变自己好么?&br&&b&让自己变的更主动,让自己变的更有耐心,让自己变的更严谨,让自己学会遵守流程,让自己学会尊重规范,让自己学会解决问题,让自己通过一件一件真真正正的事情来积累自信。&/b&&br&&br&这比你研究JQuery有用的多。&br&&br&&br&最后。给出几个搜索的小技巧。&br&&br&1.搜索的时候,尽量搜索名词。&br&2.词和词之间用空格分开,不要加语气助词。百度识别不了“为什么我的电脑打不开,是中毒了吗?”这种语句,也许再过10年就可以-前提是把百度外卖的投入放到语义识别上。&br&3.有报错信息,尽量搜报错信息,不要太长,堆栈异常的话,去找典型错误。&br&4.搜索的内容尽量准确,不要选特别通用的场景,比如说,“Nginx无法启动”这种问题就是撞运气,因为有太多原因会造成他无法启动了。&br&5.搜索出来的内容,并不全部是有用的。一般来说,知乎,百科,博客是比较靠谱的,其他的,看一眼就算。&br&6.多比较几个搜索出来结果,毕竟网上信息多,内容杂,出错的可能性非常大。&br&7.搜索一个词的时候,多个心眼,想一想,你搜索出来的结果,是不是跟你想要的答案有一些接近,如果完全不搭边,换个搜索关键字吧。&br&8.正常情况下,解决一个问题。换3~5个关键字是比较正常的,换10个关键字也不例外。&br&9.可以刷StackOverflow,基本上都能解决问题。&br&10.搜索结果中,永远先看官网,找Reference,找5Min教程。&br&11.英文词,请用Google或者是Bing,不要相信百度的英文搜索。&br&12.查找知识点的时候,往往会从一个词,找到另一个跟这个词接近的关键字。记着这些关键字,也许很快你就能找到答案。&br&13.搜索的时候不要太过发散,记着你只是一个小菜鸟,不可能把所有的知识点都解决。&br&14.一般来说,搜索结果都会在前3页里。很少的情况下,会在后面几页。&br&15.实在搜索不出来结果,学会整理好自己的问题,自己的解决思路,再去请教别人。&br&&br&&br&&p&对了。本来想介绍一下CSS任务,为什么这么设计,然而天色已晚~&/p&
修真院CSS任务第一个,就是做一个九宫格,然后要支持手机访问,这样就难倒了一大片人。在我的期望中,我说了要支持手机访问,你就应该去想办法,怎么样能让手机访问一个网页?第一件事,就是要知道怎么能把一个网页发布出去。搜一下“怎么样能让手机访问一…
&p&市场上讲:php做中小型企业网站比较合适,性价比高,java偏大型。&/p&&p&性价比:很简单的php空间一年才几百块钱,而java空间一个月就得几百。&/p&&p&语言方面:当然php和java都各领风骚,最主要看自己最擅长哪一种语言了,我也用过php一段时间,发现确实很难习惯其语法,所以最代码也是用java开发的。&/p&&p&开发周期:java和php我觉得效率上php会好,但性能上java会比php会更占优势,当然这不是绝对的,只能说玩的好的语言不是问题。&/p&&p&其他方面:如果客户坚持让你用php或java,那你还有的挑么?&/p&&p&对于java web开发框架,主要有:&/p&&p&1.S2SH(struts2+spring+hibernate)&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/1680.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&基于Struts2+Spring3+Hibernate4开发java Web企业应用开源框架s2jh源码分享&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/5552.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&spring+hibernate+struts2开发OA企业办公管理系统源码分享&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/8592.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Struts2+Hibernate3+Spring三大框架技术实现MySQL数据分页&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/8448.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring+struts2+hibernate+easyui基础权限管理框架&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/5888.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring+Struts2+Hibernate三大框架开发企业人力资源管理系统源代码下载&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/0736.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring mvc+struts2+Hibernate整合实例代码(注解详解)&/a&&/p&&p&2.S2SM(struts2+spring+mybatis)&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/6928.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring+Struts2+mybatis手动配置三大框架整合源代码下载&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/6736.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Struts2+mybatis开发音乐分享系统&/a&&/p&&p&3.SSH(spring mvc+spring+hibernate或struts+spring+hibernate)&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/7344.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring MVC+Spring+Hibrenarte实现的简单的CRUD项目实例&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/0544.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&springMVC注解与hibernate完美结合完成基本的增删改查demo源码下载&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/8480.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&springmvc+hibernate+spring+easyui开发bsalse进销存后台管理系统源代码下载&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/0752.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&spring 3.0+spring MVC+Hibernate框架搭建教程(附:springMVC文件上传功能)&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/3216.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&spring+struts2+Hibernate三大框架开发某制药厂管理系统源代码下载&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/0736.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring mvc+struts2+Hibernate整合实例代码(注解详解)&/a&&/p&&p&4.SSM(spring mvc+spring+mybatis)&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/9888.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SpringMVC+Mybatis整合实现简单权限控制系统代码&/a&&/p&&p&5.JSJ(javabean+servlet+jsp)&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/1920.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&jsp+servlet+javabean编写的一个java开源免费简易电子商城系统源码,适合初学者&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/8688.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JSP Servlet开发博客天空源代码下载&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/share/6576.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JSP+servlet开发在线投票统计管理系统源代码下载&/a&&/p&&p&原文:&a href=&//link.zhihu.com/?target=http%3A//www.zuidaima.com/question/0944.htm& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&zuidaima.com/question/1&/span&&span class=&invisible&&944.htm&/span&&span class=&ellipsis&&&/span&&/a&&/p&
市场上讲:php做中小型企业网站比较合适,性价比高,java偏大型。性价比:很简单的php空间一年才几百块钱,而java空间一个月就得几百。语言方面:当然php和java都各领风骚,最主要看自己最擅长哪一种语言了,我也用过php一段时间,发现确实很难习惯其语法,…
&figure&&img src=&https://pic1.zhimg.com/v2-c8bf17c79024_b.jpg& data-rawwidth=&1816& data-rawheight=&1018& class=&origin_image zh-lightbox-thumb& width=&1816& data-original=&https://pic1.zhimg.com/v2-c8bf17c79024_r.jpg&&&/figure&&p&昨天刷了一天微博,不敢蓝瘦香菇了,会被打断腿的。其他人都装逼,为什么只打我一个人。&/p&&p&想写个装逼点的入门教程,可是要先有工具环境,接着就有了 这篇文章了,正所谓工欲善其事,必先利其器嘛~
-------------请关注我&a href=&https://www.zhihu.com/people/10983bbd4ca4fd85daf2c04& data-hash=&10983bbd4ca4fd85daf2c04& class=&member_mention& data-editable=&true& data-title=&@小萧ovo& data-hovercard=&p$b$10983bbd4ca4fd85daf2c04&&@小萧ovo&/a&,一起学习、交流、分享。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f18d335bb2c05741bac92b_b.jpg& data-rawwidth=&168& data-rawheight=&220& class=&content_image& width=&168&&&/figure&&br&&p&开发工具webstorm。是在windows环境下的。&/p&&p&webstorm官网下载:&a href=&https://link.zhihu.com/?target=http%3A//www.jetbrains.com/webstorm/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&WebStorm: The Smartest JavaScript IDE&/a& 下载后安装,直接下一步,安装在哪里自己喜欢。&/p&&br&&p&购买服务或自行百度xx方法。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-8b7266cce45f65c8dff6f0c431c562ce_b.jpg& data-rawwidth=&639& data-rawheight=&398& class=&origin_image zh-lightbox-thumb& width=&639& data-original=&https://pic1.zhimg.com/v2-8b7266cce45f65c8dff6f0c431c562ce_r.jpg&&&/figure&&br&&br&&p&到这里,你可以愉快的使用webstorm了。&/p&&br&&blockquote&&p&这部分可以忽略(不怎么

我要回帖

更多关于 高亮重复项 的文章

 

随机推荐