ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

四目鱼眼无人机全向感知:从硬件选型到避障算法实战

四目鱼眼无人机全向感知:从硬件选型到避障算法实战 1. 四目鱼眼方案为什么突然成了无人机感知的香饽饽第一次把四目鱼眼相机装到自研的四轴机上试飞是在一个空旷的郊外场地。那天风不大飞机悬停稳定我盯着地面站屏幕上拼接出来的全景画面心里其实挺忐忑——因为在此之前我用过单目、双目甚至试过把三个普通镜头硬凑在一起做环视效果都不太理想。单目视野窄稍微侧向的障碍物根本看不到双目虽然能测距但视场角有限一旦目标偏离中心区域深度信息就急剧退化三目拼接又存在大量盲区和畸变校正的麻烦。四目鱼眼这套方案是我在踩了无数坑之后认为目前最平衡的一种全向感知硬件形态。所谓四目鱼眼相机简单说就是用四个大广角鱼眼镜头分别朝向机体的前、后、左、右四个方向安装每个镜头覆盖大约180度甚至更大的视场四个镜头组合起来就能拼出一个完整的360度无死角球面视野。它解决的核心问题就是无人机在复杂环境下的全向感知——不管是向前飞、侧移、倒退还是原地旋转周围有没有障碍物、障碍物在哪个方位、距离大概多远都能实时掌握。这套东西适合谁看如果你是做无人机飞控、视觉感知、嵌入式硬件或者算法落地的工程师尤其是正在折腾避障、室内导航、自主飞行这些场景那这篇内容应该能给你不少可直接参考的东西。我写这篇东西的出发点很简单网上讲鱼眼相机标定的文章很多讲无人机避障的也不少但把四目鱼眼从硬件选型、安装布局、标定拼接、深度估计到算法部署这一整条链路串起来讲清楚的真不多。而这条链路里任何一个环节出问题最后出来的感知效果都会大打折扣。所以我想按我自己实际做项目的顺序把每个环节的关键点、踩过的坑、以及为什么这么选都摊开来讲一遍。2. 整体方案设计与核心思路拆解2.1 为什么是四目而不是单目、双目或三目先说说为什么最终锁定四目方案。单目相机做全向感知理论上可以通过旋转或者超广角镜头来实现但旋转有机械延迟超广角单镜头畸变太大边缘区域的有效像素少得可怜深度估计基本靠猜。双目立体视觉在正前方区域精度不错但视场角通常只有60到90度要覆盖360度就得靠机械旋转或者多组双目成本和复杂度直接起飞。三目方案我试过把三个鱼眼镜头按120度间隔布置理论上也能拼出360度但实际标定和拼接时相邻镜头之间的重叠区域处理起来非常别扭而且三个镜头的对称性不如四个镜头直观后续做深度估计时基线组合也少。四目方案的好处在于对称性极好。前后左右各一个相邻镜头之间都有充足的重叠区域用来做特征匹配和拼接对向镜头之间还能构成大基线的立体视觉对用于中远距离的深度估计。更重要的是四个镜头的数据可以两两组合形成多组基线深度估计的鲁棒性比双目强不少。你可以把它理解成双目是一把尺子四目是四把尺子交叉着量哪个方向有障碍物都能量到。2.2 鱼眼镜头的选型逻辑与关键参数鱼眼镜头的选型我主要看几个硬指标视场角、分辨率、光圈、接口和重量。视场角方面我选的是水平和对角线都超过180度的型号实际有效视场大概在190度左右这样相邻镜头之间能有30到40度的重叠足够做拼接和匹配。分辨率我用的是一千两百万像素的全局快门传感器为什么强调全局快门因为无人机在飞行时振动大卷帘快门会产生果冻效应图像几何失真严重标定参数直接失效。全局快门虽然贵一点、功耗高一点但在这个场景下是刚需。光圈我选的是F2.0左右不算特别大但配合良好的曝光控制室内外都能用。接口方面我用的是MIPI CSI-2因为要接嵌入式平台做实时处理带宽和延迟都比USB方案好。重量是容易被忽略的一点四个镜头加支架加线缆如果每个镜头超过50克四个就是200克对小型无人机来说是不小的负担。所以我最后选的镜头模组单个控制在30克以内支架用碳纤维板加工整体控制在150克左右。这里有个经验鱼眼镜头的畸变模型和普通镜头完全不同选型时一定要确认厂家能提供准确的畸变系数或者至少能提供原始图像让你自己标定。有些便宜模组给的参数根本不准标定出来的结果误差很大后面深度估计全是错的。2.3 硬件平台与算力分配四目鱼眼的数据量是很大的。四个一千两百万像素的相机如果每个都跑30帧原始数据带宽就是4×12M×30×10bit大概1.4Gbps以上。所以硬件平台必须支持多路MIPI输入并且有足够的算力做实时处理。我用的平台是带GPU和DSP的嵌入式SoC具体型号就不说了反正选型逻辑是至少支持四路MIPI CSI-2输入GPU算力在1TOPS以上功耗控制在10瓦以内。算力分配上我把任务分成三块图像预处理去畸变、拼接、校正跑在DSP上深度估计和障碍物检测跑在GPU上飞控接口和通信跑在CPU上。这样分工的好处是各司其职不会互相抢资源。实测下来四路图像去畸变加拼接DSP大概占用60%的负载深度估计网络推理GPU大概占用70%CPU主要负责调度和通信负载不到30%。整体延迟控制在80毫秒以内对于飞行速度不超过5米每秒的场景这个延迟是可以接受的。2.4 安装布局与结构设计要点四个镜头的安装布局我试过两种方案一种是水平安装四个镜头光轴在同一水平面上另一种是稍微向下倾斜让镜头光轴与水平面成10到15度夹角。第一种方案的好处是拼接简单水平方向的重叠区域规整第二种方案的好处是能兼顾下方视野对起降和低空避障更友好。最后我选了第二种倾斜12度实测下来对拼接影响不大但下方盲区明显减小。结构设计上镜头支架的刚性非常重要。无人机振动会导致镜头之间发生微小位移哪怕只有0.1毫米标定参数就会漂移拼接画面就会出现错位。我用的是2毫米厚的碳纤维板做支架镜头用螺丝加螺纹胶固定线缆用扎带固定避免拉扯。另外镜头之间的相对位置在标定后要尽量保持不变所以支架设计时要考虑可重复拆装每次拆装后不需要重新标定或者至少标定参数变化很小。3. 核心细节解析与实操要点3.1 鱼眼图像去畸变的原理与参数计算鱼眼图像的畸变模型最常用的是等距投影模型。简单说就是图像上某一点到中心的距离r与入射光线和光轴的夹角θ成正比即r f·θ。这个模型和普通镜头的r f·tanθ不同所以去畸变的方法也不一样。实际标定时我用的是OpenCV的fisheye模块它支持等距投影模型并且能同时标定内参和畸变系数。标定过程是这样的用一块棋盘格标定板在四个镜头前分别拍摄20到30张不同角度的图像确保棋盘格覆盖图像的各个区域尤其是边缘。然后调用cv2.fisheye.calibrate函数输入图像尺寸、棋盘格角点、内参初值和畸变系数初值迭代优化得到最终参数。这里有个坑鱼眼镜头的畸变系数初值如果给得不准优化容易陷入局部最优标定结果误差很大。我的做法是先用厂家提供的参数作为初值如果没有就用经验值k1到k4大概在-0.1到0.1之间多试几次取重投影误差最小的那组。去畸变时我用的方法是先计算去畸变后的图像映射表然后用remap函数做重映射。映射表的计算需要指定去畸变后的图像尺寸和焦距。这里有个权衡去畸变后的图像如果太大边缘区域会被拉伸得很厉害有效像素反而减少如果太小又会丢失视野。我一般把去畸变后的焦距设为原始焦距的0.8倍左右这样视野和像素利用率比较平衡。3.2 四目拼接的标定与融合策略四目拼接的核心是找到相邻镜头之间的空间变换关系。我用的方法是先分别标定四个镜头的内参和畸变系数然后利用相邻镜头重叠区域的特征点匹配计算它们之间的旋转和平移矩阵。具体来说在重叠区域提取ORB特征点用RANSAC剔除误匹配然后求解本质矩阵分解得到旋转和平移。由于四个镜头是刚性连接平移向量理论上应该很小主要优化旋转矩阵。拼接时我先把四个去畸变后的图像投影到一个虚拟球面上然后根据旋转矩阵把球面图像对齐最后用多频段融合或者简单的加权平均融合。加权平均融合的权重根据像素到重叠区域中心的距离来定距离越近权重越大。实测下来这种融合方式在重叠区域过渡自然不会出现明显的拼接缝。这里有个经验拼接的精度很大程度上取决于标定的精度。如果四个镜头的标定参数有误差拼接后会出现重影或者错位。我的做法是标定完成后用一组测试图像检查拼接效果如果发现某个区域错位明显就重新标定那个镜头或者微调旋转矩阵。另外拼接后的全景图像分辨率很高如果直接用于后续处理计算量很大所以我一般会降采样到原始分辨率的四分之一左右再做深度估计和障碍物检测。3.3 基于四目鱼眼的深度估计方法深度估计是四目鱼眼方案的核心价值之一。我用的方法有两种一种是传统的立体匹配另一种是基于深度学习的端到端估计。传统方法是在相邻镜头之间做立体匹配计算视差图然后根据基线长度和焦距换算深度。由于鱼眼图像畸变大直接做立体匹配效果不好所以我先在去畸变后的图像上做匹配然后再把视差图投影回鱼眼图像。这种方法在纹理丰富的区域效果不错但在弱纹理区域比如白墙、地面容易失效。深度学习方法我试过几种网络结构最后选的是一个轻量级的编码器-解码器网络输入是四目拼接后的全景图像输出是深度图。训练数据用的是仿真环境生成的合成数据加上少量真实场景的标注数据。为什么用仿真数据为主因为真实场景的四目鱼眼深度标注太难获取了用激光雷达或者结构光标定成本很高而仿真环境可以批量生成精确的深度真值。实测下来仿真数据训练的模型在真实场景中也能有不错的表现尤其是在室内和结构化环境中。这里有个关键点四目鱼眼的深度估计不能只依赖单对镜头。我的做法是把四对相邻镜头的视差图融合起来用卡尔曼滤波或者简单的加权平均得到更鲁棒的深度估计。对向镜头之间的大基线可以用于远距离估计相邻镜头的小基线用于近距离估计这样远近都能覆盖。3.4 全向障碍物检测与避障逻辑有了全景图像和深度图障碍物检测就相对直接了。我的做法是先把深度图转换成三维点云然后在机体坐标系下划分若干个扇区比如前、后、左、右、上、下各60度每个扇区内计算最近障碍物的距离。如果某个扇区的距离小于安全阈值就触发避障逻辑。避障逻辑我用的是一种简单的势场法障碍物产生斥力目标点产生引力合力方向就是避障方向。势场法的好处是计算简单实时性好缺点是容易陷入局部最优比如遇到凹形障碍物时可能来回震荡。为了解决局部最优问题我在势场法的基础上加了一个记忆机制如果无人机在某个位置反复震荡超过一定次数就切换到沿墙走或者随机探索模式直到脱离震荡区域。实测下来这种组合策略在室内走廊、树林等场景中表现不错没有出现过卡死的情况。这里有个注意事项避障逻辑的响应速度必须快否则无人机在高速飞行时来不及反应。我的做法是把障碍物检测和避障逻辑放在同一个控制循环里循环频率100Hz检测延迟控制在20毫秒以内。另外安全阈值不能设得太小否则容易撞也不能设得太大否则无人机在狭窄空间里根本没法飞。我一般设成无人机半径的1.5倍左右具体根据飞行速度和制动距离调整。4. 实操过程与核心环节实现4.1 硬件组装与镜头安装的实操记录硬件组装这一步看起来简单实际上很容易出问题。我先把四个镜头模组固定在碳纤维支架上支架是提前用CNC加工好的四个安装孔的位置精度控制在0.05毫米以内。镜头安装时先用螺丝轻轻固定不要拧紧然后用一个自制的对准工具其实就是一块带十字线的透明板检查四个镜头的光轴是否指向正确的方向。确认无误后再拧紧螺丝并涂上螺纹胶防止松动。线缆连接是个麻烦事。四路MIPI线缆比较硬弯曲半径不能太小否则信号质量会下降。我用的线缆长度是15厘米刚好够从镜头走到主板再长就会增加信号衰减的风险。线缆用扎带固定在支架上避免飞行时晃动。另外MIPI连接器的插拔次数有限一般只有几十次所以调试时尽量用延长线不要反复插拔主板上的连接器。供电方面四个镜头模组加主板总电流大概在2安培左右我用的是一个5伏3安培的稳压模块从无人机电池直接取电。这里要注意稳压模块的纹波不能太大否则会影响图像质量。我实测过纹波超过50毫伏时图像上会出现横向条纹所以选稳压模块时一定要看纹波指标最好在20毫伏以内。4.2 四目相机标定的完整流程与参数标定是整个方案里最耗时但也最重要的环节。我的标定流程是这样的第一步准备一块高精度的棋盘格标定板我用的是10×7的棋盘格方格边长30毫米打印在哑光纸上贴在平整的铝板上。第二步把无人机固定在一个稳定的支架上确保标定过程中相机不会移动。第三步依次对四个镜头进行标定每个镜头拍摄25张不同角度的棋盘格图像覆盖图像的各个区域。拍摄时有个技巧棋盘格不要只放在图像中心要尽量放到边缘和角落因为鱼眼镜头的畸变在边缘最严重如果边缘区域没有标定数据去畸变后边缘会失真。另外拍摄时要注意光照均匀避免反光或者阴影否则角点检测会失败。标定完成后我会检查重投影误差。一般来说误差在0.5像素以内算合格超过1像素就需要重新标定。四个镜头的标定参数分别保存包括内参矩阵、畸变系数、图像尺寸。然后进行外参标定也就是计算四个镜头之间的旋转和平移矩阵。外参标定用的是相邻镜头重叠区域的特征点匹配我一般会拍摄10组不同场景的图像每组图像中四个镜头同时曝光确保特征点匹配的准确性。4.3 图像拼接与全景生成的代码实现图像拼接的代码实现我分成几个模块去畸变模块、投影模块、对齐模块和融合模块。去畸变模块用OpenCV的fisheye模块先计算映射表然后用remap做重映射。投影模块把去畸变后的图像投影到虚拟球面上球面的半径设为1投影公式是x sinθ·cosφy sinθ·sinφz cosθ其中θ是入射角φ是方位角。对齐模块根据外参标定得到的旋转矩阵把四个球面图像对齐。融合模块用加权平均权重根据像素到重叠区域中心的距离计算。这里贴一段核心代码展示去畸变和投影的过程import cv2 import numpy as np # 读取标定参数 K np.load(camera_matrix.npy) D np.load(dist_coeffs.npy) img cv2.imread(fisheye_image.jpg) h, w img.shape[:2] # 计算去畸变映射表 new_K cv2.fisheye.estimateNewCameraMatrixForUndistortRectify( K, D, (w, h), np.eye(3), balance0.8) map1, map2 cv2.fisheye.initUndistortRectifyMap( K, D, np.eye(3), new_K, (w, h), cv2.CV_16SC2) # 去畸变 undistorted cv2.remap(img, map1, map2, interpolationcv2.INTER_LINEAR) # 投影到球面 theta np.arccos(np.clip(undistorted[:,:,2], -1, 1)) phi np.arctan2(undistorted[:,:,1], undistorted[:,:,0]) # 后续根据theta和phi生成球面图像这段代码的关键是balance参数它控制去畸变后图像的有效视野和像素利用率。balance0时去畸变后图像只保留原始图像中有效的部分视野最小但像素利用率最高balance1时去畸变后图像保留全部视野但边缘区域会被拉伸。我一般用0.8兼顾视野和像素利用率。4.4 深度估计网络的训练与部署深度估计网络我选的是一个轻量级的U-Net变体输入是四目拼接后的全景图像分辨率降采样到512×256输出是同分辨率的深度图。网络结构上编码器用MobileNetV3的前几层解码器用反卷积加跳跃连接。损失函数用的是尺度不变损失加上平滑损失尺度不变损失解决深度估计的尺度模糊问题平滑损失让深度图在平坦区域更平滑。训练数据方面我用的是仿真环境生成的合成数据大概5万张图像覆盖室内、室外、树林、走廊等多种场景。仿真环境的优势是深度真值精确而且可以批量生成。真实数据我标注了大概2000张用激光雷达点云投影得到稀疏深度然后用插值生成稠密深度。训练时先用仿真数据预训练再用真实数据微调这样收敛更快泛化能力也更好。部署时我把训练好的模型转换成ONNX格式然后用TensorRT做推理加速。在嵌入式平台上推理一帧512×256的深度图大概需要15毫秒加上预处理和后处理总共25毫秒左右。这个速度对于30帧的实时处理是够用的。这里有个经验TensorRT的精度设置要选FP16不要选INT8因为深度估计对精度比较敏感INT8量化后深度图的噪声会明显增大。5. 常见问题与排查技巧实录5.1 标定失败或重投影误差过大的排查思路标定失败是新手最容易遇到的问题。常见原因有几个一是棋盘格图像质量差比如模糊、反光、角点检测不到二是棋盘格姿态变化不够所有图像都是同一个角度导致参数优化不充分三是镜头畸变太大初值给得不准优化陷入局部最优。我的排查步骤是这样的先检查图像质量用OpenCV的findChessboardCorners函数检测角点如果检测不到就调整光照或者换一块对比度更高的标定板。然后检查棋盘格姿态确保有正面、侧面、倾斜等多种角度。如果还是不行就手动调整畸变系数初值多试几组取重投影误差最小的。实测下来只要图像质量没问题姿态覆盖足够标定成功率在90%以上。5.2 拼接错位与重影的常见原因拼接错位通常是因为外参标定不准。可能的原因包括特征点匹配错误、旋转矩阵优化不充分、镜头之间发生了位移。我的排查方法是先用一组测试图像检查拼接效果如果某个区域错位明显就检查那个区域对应的两个镜头的特征点匹配情况。如果匹配点太少或者误匹配太多就重新拍摄标定图像增加纹理丰富的场景。另一个常见原因是镜头松动。无人机飞行时的振动可能导致镜头位移标定参数失效。我的做法是定期检查镜头固定情况每次飞行前用手轻轻晃动镜头确认没有松动。如果发现松动重新拧紧后需要重新标定。为了减少重新标定的频率我在支架设计时加了定位销镜头拆装后能回到原来的位置标定参数变化很小。5.3 深度图噪声大或缺失的解决方法深度图噪声大通常是因为立体匹配在弱纹理区域失效或者光照变化导致图像亮度不一致。我的解决方法有几个一是增加平滑损失让网络在弱纹理区域输出更平滑的深度二是用多帧融合把连续几帧的深度图做时域滤波减少随机噪声三是用对向镜头的大基线做补充大基线在远距离估计上更准可以弥补相邻镜头小基线的不足。深度图缺失通常是因为某个镜头被遮挡或者曝光过度。我的做法是检查四个镜头的图像如果某个镜头图像异常就用另外三个镜头的深度图做插值。另外曝光控制也很重要我用的自动曝光算法会根据四个镜头的平均亮度调整曝光时间避免个别镜头过曝或欠曝。5.4 避障逻辑误触发或反应迟钝的调试技巧避障逻辑误触发通常是因为深度图噪声导致障碍物距离估计偏小。我的解决方法是加一个时域滤波连续几帧都检测到障碍物才触发避障单帧的噪声不会导致误触发。另外安全阈值可以设成动态的根据飞行速度调整速度越快阈值越大给制动留出更多距离。反应迟钝通常是因为检测延迟太大或者控制循环频率太低。我的做法是把检测和控制放在同一个循环里循环频率100Hz检测延迟控制在20毫秒以内。另外避障逻辑的计算量要小势场法比采样法快很多适合实时性要求高的场景。问题现象可能原因排查方法解决方案标定重投影误差大图像质量差、姿态单一、初值不准检查角点检测、姿态覆盖、初值重拍图像、调整初值、多组优化拼接错位外参不准、镜头松动检查特征点匹配、镜头固定重新标定、加定位销深度图噪声大弱纹理、光照变化检查图像纹理、曝光加平滑损失、多帧融合避障误触发深度噪声、阈值过小检查深度图、阈值设置时域滤波、动态阈值避障反应慢检测延迟大、循环频率低检查延迟、循环频率提高频率、优化算法5.5 飞行测试中的实战避坑经验飞行测试是最容易出问题的环节。我踩过的坑包括镜头线缆在飞行中松动导致图像丢失、支架振动导致标定参数漂移、电池电压下降导致镜头供电不足图像变暗。这些问题在实验室里很难发现只有实际飞行才会暴露。我的经验是飞行测试要循序渐进先在室内悬停测试确认图像和深度图正常再到室外空旷场地做低速飞行最后才做高速避障测试。每次飞行前检查线缆固定、镜头紧固、电池电量。飞行中记录所有传感器数据事后分析异常。另外备用一套镜头和支架万一炸机可以快速更换不耽误调试进度。6. 算法与硬件的协同优化方向6.1 硬件层面的优化空间硬件层面我觉得还有不少优化空间。一是镜头模组的集成度目前四个镜头是分开的线缆多、重量大如果能做成一体化的四目模组重量和体积都能降不少。二是接口带宽MIPI CSI-2的带宽有限如果未来要上更高分辨率的传感器可能需要换用GMSL或者FPD-Link等车载级接口带宽更大、抗干扰能力更强。三是算力平台目前的嵌入式SoC算力还是偏紧如果要做更复杂的深度网络或者多传感器融合可能需要上更高算力的平台但功耗和散热又是新的挑战。另外镜头的安装精度还可以进一步提升。目前用的是机械定位精度在0.05毫米左右如果改用光学定位或者主动对准精度可以到0.01毫米标定参数会更稳定。不过成本也会上去看具体应用场景是否值得。6.2 算法层面的改进思路算法层面我觉得有几个方向值得尝试。一是把深度估计和障碍物检测合并成一个网络端到端输出障碍物距离和方位减少中间环节的误差累积。二是引入时序信息用RNN或者Transformer处理连续帧提高深度估计的稳定性和避障的预测能力。三是用自监督学习减少对标注数据的依赖利用飞行过程中的图像序列自己学习深度。还有一个方向是多传感器融合把四目鱼眼和超声波、激光雷达、IMU的数据融合起来互相补充。鱼眼相机在弱纹理区域和远距离估计上不如激光雷达但在近距离和纹理丰富区域有优势融合之后整体感知能力会更强。不过融合的难度也大时间同步、坐标变换、数据关联都是麻烦事。6.3 实际项目中的取舍与平衡实际项目中最重要的不是追求极致性能而是找到性能、成本、功耗、开发周期之间的平衡。四目鱼眼方案虽然好但成本和复杂度比单目、双目高不少。如果应用场景只是简单的前方避障双目就够了没必要上四目。如果场景是室内全向避障或者复杂环境自主飞行四目鱼眼的价值才能体现出来。我在项目中的取舍是镜头选中等分辨率、全局快门、重量轻的型号不追求最高像素算力平台选功耗低、接口多的嵌入式SoC不追求最高算力算法选轻量级网络加传统方法结合不追求端到端深度学习。这样整体方案的成本和功耗可控开发周期也短适合快速迭代。最后再分享一个小技巧四目鱼眼的标定参数我建议每次飞行前都做一次快速检查用一块小标定板在镜头前晃一下看拼接画面有没有明显错位。如果有就重新标定如果没有就直接飞。这个检查只要一分钟但能避免很多因为标定漂移导致的飞行事故。踩过几次坑之后我现在已经养成习惯了每次飞行前必查。
返回列表