1. 光流模块选型避坑指南
第一次接触室内定点飞行时,我和团队踩过不少硬件选型的坑。记得当时采购的PX4Flow模块,标称精度0.1m/s,实际测试时数据跳变像心电图。后来发现这个老牌模块对光照异常敏感,窗帘缝隙透过的阳光都能让数据漂移30%。更糟的是超声波在1.5米以上就失效,导致无人机在办公桌高度频繁坠机。
转机出现在发现优象LC-302这款国产模块时。实测在60lux照度下(相当于昏暗会议室),它的位移分辨率能达到0.02m/s。我拆解过它的光学结构——采用全局快门CMOS配合自适应光照算法,这点在从窗户到走廊的明暗过渡区域特别明显。安装时要注意:模块的"OK"标志必须严格对准机头方向,偏差超过15°就会引起Yaw轴耦合误差。
激光雷达选型更有意思。最初用气压计定高,结果办公室空调一开,高度数据就像过山车。换成北醒TFmini Plus后,发现它对反光地板特别敏感。有次在地砖环境测试,1.2米高度突然报出3.4米的鬼数据。后来和厂家沟通才知道,他们的DSP芯片对高反射率表面做了特殊滤波算法,升级固件后问题解决。这里分享个技巧:安装时让雷达与地面呈5°倾角,能有效避免镜面反射干扰。
2. 硬件集成实战技巧
光流模块的安装位置直接影响数据质量。我们尝试过三种布局:机腹居中、起落架外侧和云台下方。实测发现距重心20cm范围内最佳,太远会引入机体振动噪声。有个反直觉的现象:装在减震球上反而不好,因为低频晃动会导致特征点追踪失效。
TFmini Plus的接线要注意I2C地址冲突问题。有次同时接光流和雷达,地址0x10撞车导致数据乱码。解决方法是在init.d脚本里添加:
# 修改雷达I2C地址 tfmini start -a 0x11电源干扰也是常见坑点。某次测试时光流数据周期性跳变,最后发现是图传发射器与光流共用了5V电源。推荐使用LC滤波电路,我们在PCB上加了100μF钽电容配合磁珠后,噪声RMS值从±0.3m降到±0.05m。
校准环节最容易被忽视。建议制作简易校准台:在A3纸上打印棋盘格图案,用支架固定模块距地面80cm。通过QGC的"光流校准"页面,观察x/y_offset参数应小于0.1。有个快速验证方法:手动移动无人机30cm,光流输出的位移误差应小于3%。
3. 数据读取与预处理
优象光流的串口协议解析有讲究。它的数据包格式是:
0xAA 0xAF [x速度低字节][x速度高字节][y速度低字节][y速度高字节]...0x55但实际测试发现要加超时判断,否则可能收到半包数据。我们的处理代码加了状态机:
enum { WAIT_HEADER1, WAIT_HEADER2, RECEIVING_DATA } flow_state; if(rx_char == 0xAA && flow_state == WAIT_HEADER1){ flow_state = WAIT_HEADER2; } else if(rx_char == 0xAF && flow_state == WAIT_HEADER2){ flow_state = RECEIVING_DATA; buffer_index = 0; } //...完整包校验逻辑激光雷达的数据校验更复杂。TFmini Plus的I2C读取要注意时序:
// 先写寄存器地址 i2c_msg[0] = TFminiPlus_TAKE_RANGE_REG; i2c_transfer(fd, &msg, 1); // 延迟至少5ms usleep(5000); // 再读取数据 i2c_read(fd, buf, 6);常见错误是连续读取不延迟,会导致传感器内部ADC未完成转换。我们封装了带超时重试的读取函数,稳定性提升明显。
4. PID位置控制算法实现
纯位置PID的实现关键在于误差计算。我们采用移动窗口积分法处理光流速度:
position_x = 0 window_size = 5 velocity_queue = [] def update_position(vx, dt): velocity_queue.append(vx) if len(velocity_queue) > window_size: velocity_queue.pop(0) position_x += sum(velocity_queue)/len(velocity_queue) * dt这种方法比单纯积分更抗抖动,实测在瓷砖地面可将累计误差降低60%。
PID参数整定有个小技巧:先调D再调P。因为光流数据本身带噪声,过大的P会导致高频振荡。我们的经验值是:
Vxkp=0.087 # 每米误差产生8.7%油门 Vxki=0.00052 # 抗静差系数 Vxkd=0.0252 # 阻尼项调试时在地面画1米见方区域,观察无人机从边界回到中心的过程。理想状态是轻微过冲(约10%)后稳定,整个过程不超过3秒。
积分分离是必须的。当误差超过50cm时关闭积分项,防止windup:
if(fabs(vxErro) > 0.5f){ flag_X = 0; //关闭积分 pidVx_iOut = 0; //清零历史积分 } else { flag_X = 1; }这个策略让我们的无人机在遭遇突发气流时,不会因为累积误差而失控。
5. 系统联调与问题排查
第一次室内试飞时遇到个诡异现象:无人机总是往右前方漂移。用USB线连接QGC实时监测,发现光流x/y速度数据正常,但姿态角持续偏转。最终发现是磁罗盘受电机干扰,重做compass校准后问题消失。建议在mission_config中添加:
SYS_AUTOSTART = 4001 # 禁用磁罗盘 EKF2_AID_MASK = 24 # 仅用光流+GPS另一个典型问题是高度保持时的振荡。表现为无人机在目标高度上下0.5米反复波动。通过分析日志发现是激光雷达更新频率(15Hz)与控制器频率(100Hz)不匹配。解决方法是在位置控制器中加入低通滤波:
filtered_alt = 0.9 * filtered_alt + 0.1 * raw_alt最棘手的要数"跳舞现象"——无人机在空中无规律晃动。用高速摄像机拍下运动轨迹后,发现是光流模块的FOV(视场角)太小。当无人机倾斜超过8°时,地面特征点移出视野导致追踪失败。换成广角镜头版LC-302后问题解决。
6. 方案局限性与改进方向
纯PID方案的最大问题是基准漂移。有次测试时无人机被风吹偏2米,PID就把新位置当作原点。我们在日志中发现积分项逐渐累积到饱和值:
[logger] pidVx_iOut=2.49(限幅值)这说明系统缺乏绝对位置参考。临时解决方案是加入视觉标签检测,当识别到AprilTag时重置积分器。
另一个缺陷是动态响应不足。当人为推动无人机时,恢复速度跟不上手动操作。通过伯德图分析发现相位裕度只有30°,于是在PID后加入前馈补偿:
feedforward = 0.3 * desired_velocity; output = pid_output + feedforward;这使跟踪性能提升40%,但会引入高频噪声,需要折中处理。
7. 实战调试记录
去年给某仓库做的巡检方案中,我们记录下一组典型参数:
# 光滑水泥地面 光流参数: flow_qual_min = 120 pos_p = 0.12 pos_d = 0.03 # 花纹地胶地面 光流参数: flow_qual_min = 80 pos_p = 0.08 pos_d = 0.05地面纹理越复杂,需要降低P增益防止振荡。有个诊断技巧:在QGC的"MAVLink Inspector"中观察flow_qual值,低于100时应考虑更换起飞点。
温度影响也值得注意。冬季测试时发现光流数据在早晨和下午差异明显。后来在模块上加贴隔热棉,并用温度补偿公式:
scale_factor = 1.0 + 0.003*(temp - 25)使全天性能波动控制在±5%以内。