AP_RangeFinder的应用的主要用途是用于测量对地距离的,这个与大家通常理解的障碍物避障还是有比较大的差异的。
主要的应用有:
其他应用有:
本次结合代码进行研读,其中也请注意两个应用类型的传感器:upward facing rangefinder和downward facing rangefinder。
启动代码:
Copter::init_ardupilot
└──> Copter::init_rangefinder
└──> rangefinder.init
任务代码:
SCHED_TASK(read_rangefinder, 20, 100, 33),
└──> Copter::read_rangefinder
└──> rangefinder.update
主要作用是对传感器设备进行检测和初始化。
RangeFinder::init
├──> // don't re-init if we've found some sensors already
│ └──> return
├──> // set orientation defaults
│ └──> params[i].orientation.set_default(orientation_default)
├──>
│ │ // serial_instance will be increased inside detect_instance
│ │ // if a serial driver is loaded for this instance
│ ├──> WITH_SEMAPHORE(detect_sem);
│ ├──> detect_instance(i, serial_instance);
│ └──>
│ │ // we loaded a driver for this instance, so it must be
│ │ // present (although it may not be healthy). We use MAX()
│ │ // here as a UAVCAN rangefinder may already have been
│ │ // found
│ └──> num_instances = MAX(num_instances, i+1);
└──> [initialise status]
├──> state[i].status = Status::NotConnected;
└──> state[i].range_valid_count = 0;
以固定的频率进行循环遍历,得到相应的数据更新。
// return rangefinder altitude in centimeters
Copter::read_rangefinder
├──>
│ ├──> [downward facing rangefinder]
│ │ ├──> rangefinder_state.enabled = false;
│ │ ├──> rangefinder_state.alt_healthy = false;
│ │ └──> rangefinder_state.alt_cm = 0;
│ ├──> [upward facing rangefinder]
│ │ ├──> rangefinder_up_state.enabled = false;
│ │ ├──> rangefinder_up_state.alt_healthy = false;
│ │ └──> rangefinder_up_state.alt_cm = 0;
│ └──> return
├──> rangefinder.update();
├──>
│ └──> const float tilt_correction = MAX(0.707f, ahrs.get_rotation_body_to_ned().c.z);
├──>
│ └──> const float tilt_correction = 1.0f;
│
│
│ // iterate through downward and upward facing lidar
│ struct {
│ RangeFinderState &state;
│ enum Rotation orientation;
│ } rngfnd[2] = {{rangefinder_state, ROTATION_PITCH_270}, {rangefinder_up_state, ROTATION_PITCH_90}};
│
└──>
├──> [local variables to make accessing simpler]
│ ├──> RangeFinderState &rf_state = rngfnd[i].state;
│ └──> enum Rotation rf_orient = rngfnd[i].orientation;
├──> [update health]
│ └──> rf_state.alt_healthy = ((rangefinder.status_orient(rf_orient) == RangeFinder::Status::Good) &&
│ (rangefinder.range_valid_count_orient(rf_orient) >= RANGEFINDER_HEALTH_MAX));
├──> [tilt corrected but unfiltered, not glitch protected alt]
│ └──> rf_state.alt_cm = tilt_correction * rangefinder.distance_cm_orient(rf_orient);
├──> [remember inertial alt to allow us to interpolate rangefinder]
│ └──> rf_state.inertial_alt_cm = inertial_nav.get_position_z_up_cm();
├──> [glitch handling]
│ //rangefinder readings more than RANGEFINDER_GLITCH_ALT_CM from the last good reading
│ // are considered a glitch and glitch_count becomes non-zero
│ // glitches clear after RANGEFINDER_GLITCH_NUM_SAMPLES samples in a row.
│ // glitch_cleared_ms is set so surface tracking (or other consumers) can trigger a target reset
│ ├──> const int32_t glitch_cm = rf_state.alt_cm - rf_state.alt_cm_glitch_protected;
│ ├──> bool reset_terrain_offset = false;
│ ├──> = RANGEFINDER_GLITCH_ALT_CM)>
│ │ └──> rf_state.glitch_count = MAX(rf_state.glitch_count+1, 1);
│ ├──>
│ │ └──> rf_state.glitch_count = MIN(rf_state.glitch_count-1, -1);
│ ├──>
│ │ ├──> rf_state.glitch_count = 0;
│ │ └──> rf_state.alt_cm_glitch_protected = rf_state.alt_cm;
│ └──> = RANGEFINDER_GLITCH_NUM_SAMPLES> // clear glitch and record time so consumers (i.e. surface tracking) can reset their target altitudes
│ ├──> rf_state.glitch_count = 0;
│ ├──> rf_state.alt_cm_glitch_protected = rf_state.alt_cm;
│ ├──> rf_state.glitch_cleared_ms = AP_HAL::millis();
│ └──> reset_terrain_offset = true;
├──> [filter rangefinder altitude]
│ ├──> uint32_t now = AP_HAL::millis();
│ ├──> const bool timed_out = now - rf_state.last_healthy_ms > RANGEFINDER_TIMEOUT_MS;
│ ├──>
│ │ ├──>
│ │ │ // reset filter if we haven't used it within the last second
│ │ │ ├──> rf_state.alt_cm_filt.reset(rf_state.alt_cm);
│ │ │ └──> reset_terrain_offset = true;
│ │ └──>
│ │ └──> rf_state.alt_cm_filt.apply(rf_state.alt_cm, 0.05f);
│ └──> rf_state.last_healthy_ms = now;
├──> // handle reset of terrain offset
│ ├──> // upward facing
│ │ └──> rf_state.terrain_offset_cm = rf_state.inertial_alt_cm + rf_state.alt_cm;
│ └──> < else > // assume downward facing
│ └──> rf_state.terrain_offset_cm = rf_state.inertial_alt_cm - rf_state.alt_cm;
└──>
│ // send downward facing lidar altitude and health to the libraries that require it
└──> g2.proximity.set_rangefinder_alt(rangefinder_state.enabled, rangefinder_state.alt_healthy, rangefinder_state.alt_cm_filt.get());
针对当前传感器数据有效性进行状态更新。
RangeFinder::update
├──>
│ └──>
│ ├──> <(Type)params[i].type.get() == Type::NONE> // allow user to disable a rangefinder at runtime
│ │ ├──> state[i].status = Status::NotConnected
│ │ ├──> state[i].range_valid_count = 0
│ │ └──> continue
│ └──> drivers[i]->update()
└──>
└──> Log_RFND()
除了AP_RangeFinder里面使用到的传感器外,衍生阅读可看下360度雷达以及视觉传感,详见Rangefinders (landing page)。
RangeFinder::detect_instance
├──>
│ └──> return
├──> AP_RangeFinder_Backend_Serial *(*serial_create_fn)(RangeFinder::RangeFinder_State&, AP_RangeFinder_Params&) = nullptr;
├──> const Type _type = (Type)params[instance].type.get();
├──>
│ ├──> _add_backend(AP_RangeFinder_PulsedLightLRF::detect
│ └──> break;
├──>
│ ├──> uint8_t addr = AP_RANGE_FINDER_MAXSONARI2CXL_DEFAULT_ADDR;
│ ├──>
│ │ └──> addr = params[instance].address;
│ ├──> _add_backend(AP_RangeFinder_MaxsonarI2CXL::detect
│ └──> break;
├──>
│ ├──> // the LW20 needs a long time to boot up, so we delay 1.5s here
│ │ ├──>
│ │ │ └──> _add_backend(AP_RangeFinder_LightWareI2C::detect
│ │ └──>
│ │ └──> _add_backend(AP_RangeFinder_LightWareI2C::detect
│ └──> break;
├──>
│ ├──>
│ │ └──> __add_backend(AP_RangeFinder_TeraRangerI2C::detect
│ └──> break;
├──>
│ ├──>
│ │ └──> _add_backend(AP_RangeFinder_VL53L0X::detect
│ ├──>
│ │ └──> _add_backend(AP_RangeFinder_VL53L1X::detect
│ └──> break;
├──>
│ ├──> uint8_t addr = TFMINIPLUS_ADDR_DEFAULT;
│ ├──>
│ │ └──> addr = params[instance].address;
│ ├──> _add_backend(AP_RangeFinder_Benewake_TFMiniPlus::detect
│ └──> break;
├──>
│ │ // to ease moving from PX4 to ChibiOS we'll lie a little about
│ │ // the backend driver...
│ ├──>
│ │ └──> _add_backend(new AP_RangeFinder_PWM(state[instance], params[instance], estimated_terrain_height), instance);
│ └──> break;
├──>
│ ├──>
│ │ └──> _add_backend(new AP_RangeFinder_BBB_PRU(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_LightWareSerial::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_LeddarOne::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_USD1_Serial::create;
│ └──> break;
├──>
│ ├──>
│ │ └──> _add_backend(new AP_RangeFinder_Bebop(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──>
│ │ └──> _add_backend(new AP_RangeFinder_MAVLink(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_MaxsonarSerialLV::create;
│ └──> break;
├──>
│ ├──> // note that analog will always come back as present if the pin is valid
│ │ └──> _add_backend(new AP_RangeFinder_analog(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> // note that this will always come back as present if the pin is valid
│ │ └──> _add_backend(new AP_RangeFinder_HC_SR04(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_NMEA::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_Wasp::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_Benewake_TF02::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_Benewake_TFMini::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_Benewake_TF03::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_TeraRanger_Serial::create;
│ └──> break;
├──>
│ ├──>
│ │ └──> _add_backend(new AP_RangeFinder_PWM(state[instance], params[instance], estimated_terrain_height), instance);
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_BLPing::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_Lanbao::create;
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_LeddarVu8::create;
│ └──> break;
├──>
│ │ /*
│ │ the UAVCAN driver gets created when we first receive a
│ │ measurement. We take the instance slot now, even if we don't
│ │ yet have the driver
│ │ */
│ ├──> num_instances = MAX(num_instances, instance+1);
│ └──> break;
├──>
│ ├──> serial_create_fn = AP_RangeFinder_GYUS42v2::create;
│ └──> break;
├──>
│ ├──> _add_backend(new AP_RangeFinder_SITL(state[instance], params[instance], instance), instance);
│ └──> break;
├──>
│ ├──>
│ │ └──> _add_backend(new AP_RangeFinder_MSP(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> _add_backend(new AP_RangeFinder_USD1_CAN(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> _add_backend(new AP_RangeFinder_Benewake_CAN(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> _add_backend(new AP_RangeFinder_Lua(state[instance], params[instance]), instance);
│ └──> break;
├──> ,AP_RANGEFINDER_NOOPLOOP_ENABLED>
│ ├──> serial_create_fn = AP_RangeFinder_NoopLoop::create;
│ └──> break;
├──>
│ ├──> _add_backend(new AP_RangeFinder_TOFSenseP_CAN(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> _add_backend(new AP_RangeFinder_NRA24_CAN(state[instance], params[instance]), instance);
│ └──> break;
├──>
│ ├──> auto *b = serial_create_fn(state[instance], params[instance]);
│ └──>
│ └──> _add_backend(b, instance, serial_instance++);
└──> // if the backend has some local parameters then make those available in the tree
├──> backend_var_info[instance] = state[instance].var_info;
├──> AP_Param::load_object_from_eeprom(drivers[instance], backend_var_info[instance]);
└──> AP_Param::invalidate_count(); // param count could have changed
各传感器设备因设备总线以及协议的差异,存在一定的差异化,在相应的驱动代码中实现,可参考:ArduPilot之开源代码Library&Sketches设计。
作为RangeFinder传感器主要的目的是检测飞机与地面之间的距离
// The RangeFinder_State structure is filled in by the backend driver
struct RangeFinder_State {
float distance_m; // distance in meters
uint16_t voltage_mv; // voltage in millivolts, if applicable, otherwise 0
enum RangeFinder::Status status; // sensor status
uint8_t range_valid_count; // number of consecutive valid readings (maxes out at 10)
uint32_t last_reading_ms; // system time of last successful update from sensor
const struct AP_Param::GroupInfo *var_info;
};
注:不同设备更新频率方面主要在驱动中进行数据采集更新,详见驱动代码的init
方法中如何挂定时回调钩子函数。
【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot飞控启动&运行过程简介
【3】ArduPilot之开源代码Library&Sketches设计