文章目录
2.1 void Copter::init_ardupilot()
3.1 void Copter::init_rangefinder(void)
4.1 void RangeFinder::init(enum Rotation orientation_default)
4.2 void RangeFinder::detect_instance(uint8_t instance, uint8_t& serial_instance)
5.1 hal.i2c_mgr->get_device(i, params[instance].address)
6.1 AP_RangeFinder_Backend *AP_RangeFinder_VL53L3CX::detect(...)
6.2 bool AP_RangeFinder_VL53L3CX::check_id(void)
6.3 bool AP_RangeFinder_VL53L3CX::init()
6.4 void AP_RangeFinder_VL53L3CX::timer(void)
6.5 SCHED_TASK(read_rangefinder, 20, 100)
6.6 void Copter::read_rangefinder(void)
6.7 void AP_RangeFinder_VL53L3CX::update(void)
前言
故事的开始,要从参数 RNGFND1_TYPE 说起。
RNGFND1_TYPE:测距仪类型
连接的测距仪类型。
Values | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
本文主要梳理,Ardupilot 中测距仪的代码运行流程,以及如何选择相应的测距仪类型。
1 Copter.cpp
1.1 void Copter::setup()
此函数仅在启动时调用一次。用于初始化一些必要的任务。此函数由 HAL 中的 main() 函数调用。
void Copter::setup()
{
// Load the default values of variables listed in var_info[]s
AP_Param::setup_sketch_defaults();
// setup storage layout for copter
StorageManager::set_layout_copter();
init_ardupilot();
// initialise the main loop scheduler
scheduler.init(&scheduler_tasks[0], ARRAY_SIZE(scheduler_tasks), MASK_LOG_PM);
}
2 system.cpp
2.1 void Copter::init_ardupilot()
init_ardupilot() 函数将处理空中重启所需的一切。稍后将确定飞行器是否真的在地面上,并在这种情况下处理地面启动。
void Copter::init_ardupilot()
{
...
// initialise rangefinder
init_rangefinder();
...
}
3 sensors.cpp
3.1 void Copter::init_rangefinder(void)
测距仪初始化。此函数会初始化朝下的测距仪。
void Copter::init_rangefinder(void)
{
#if RANGEFINDER_ENABLED == ENABLED
rangefinder.set_log_rfnd_bit(MASK_LOG_CTUN);
rangefinder.init(ROTATION_PITCH_270);
rangefinder_state.alt_cm_filt.set_cutoff_frequency(RANGEFINDER_WPNAV_FILT_HZ);
rangefinder_state.enabled = rangefinder.has_orientation(ROTATION_PITCH_270);
// upward facing range finder
rangefinder_up_state.alt_cm_filt.set_cutoff_frequency(RANGEFINDER_WPNAV_FILT_HZ);
rangefinder_up_state.enabled = rangefinder.has_orientation(ROTATION_PITCH_90);
#endif
}
3.2 对象rangefinder说明
在 AP_Vehicle.h 文件中,我们用 RangeFinder 类定义了 rangefinder 对象。
// sensor drivers
AP_GPS gps;
AP_Baro barometer;
Compass compass;
AP_InertialSensor ins;
AP_Button button;
RangeFinder rangefinder;
4 RangeFinder.cpp
4.1 void RangeFinder::init(enum Rotation orientation_default)
所以,我们在跳转 init() 这个成员函数的时候,跳转到 RangeFinder 类的 init() 函数。
初始化 RangeFinder 类。我们将在这里检测已连接的测距仪。目前我们还不允许热插拔测距仪。
/*
initialise the RangeFinder class. We do detection of attached range
finders here. For now we won't allow for hot-plugging of
rangefinders.
*/
void RangeFinder::init(enum Rotation orientation_default)
{
if (num_instances != 0) {
// init called a 2nd time?
return;
}
convert_params();
// set orientation defaults
for (uint8_t i=0; i<RANGEFINDER_MAX_INSTANCES; i++) {
params[i].orientation.set_default(orientation_default);
}
for (uint8_t i=0, serial_instance = 0; i<RANGEFINDER_MAX_INSTANCES; i++) {
// serial_instance will be increased inside detect_instance
// if a serial driver is loaded for this instance
detect_instance(i, serial_instance);
if (drivers[i] != nullptr) {
// we loaded a driver for this instance, so it must be
// present (although it may not be healthy)
num_instances = i+1;
}
// initialise status
state[i].status = RangeFinder_NotConnected;
state[i].range_valid_count = 0;
}
}
4.2 void RangeFinder::detect_instance(uint8_t instance, uint8_t& serial_instance)
检测是否连接了测距仪实例。
根据我们在文章开始介绍的 RNGFND1_TYPE 参数,选择不同传感器进行检测。
此处,我们以 RNGFND1_TYPE(16) 中 AP_RangeFinder_VL53L3CX 为例进行介绍。
/*
detect if an instance of a rangefinder is connected.
*/
void RangeFinder::detect_instance(uint8_t instance, uint8_t& serial_instance)
{
enum RangeFinder_Type _type = (enum RangeFinder_Type)params[instance].type.get();
switch (_type) {
case RangeFinder_TYPE_PLI2C:
case RangeFinder_TYPE_PLI2CV3:
case RangeFinder_TYPE_PLI2CV3HP:
FOREACH_I2C(i) {
if (_add_backend(AP_RangeFinder_PulsedLightLRF::detect(i, state[instance], params[instance], _type))) {
break;
}
}
break;
...
case RangeFinder_TYPE_VL53L0X:
FOREACH_I2C(i) {
if (_add_backend(AP_RangeFinder_VL53L0X::detect(state[instance], params[instance],
hal.i2c_mgr->get_device(i, params[instance].address)))) {
break;
}
if (_add_backend(AP_RangeFinder_VL53L1X::detect(state[instance], params[instance],
hal.i2c_mgr->get_device(i, params[instance].address)))) {
break;
}
if (_add_backend(AP_RangeFinder_VL53L3CX::detect(state[instance], params[instance],
hal.i2c_mgr->get_device(i, params[instance].address)))) {
break;
}
}
break;
...
}
5 I2CDevice.cpp
5.1 hal.i2c_mgr->get_device(i, params[instance].address)
如果当前的 bus 没有超过 i2c_bus_desc,会 new 一个新的 I2CDevice 类对象返回。
AP_HAL::OwnPtr<AP_HAL::I2CDevice>
I2CDeviceManager::get_device(uint8_t bus, uint8_t address,
uint32_t bus_clock,
bool use_smbus,
uint32_t timeout_ms)
{
if (bus >= ARRAY_SIZE(i2c_bus_desc)) {
return AP_HAL::OwnPtr<AP_HAL::I2CDevice>(nullptr);
}
auto dev = AP_HAL::OwnPtr<AP_HAL::I2CDevice>(new I2CDevice(bus, address, bus_clock, use_smbus, timeout_ms));
return dev;
}
6 AP_RangeFinder_VL53L3CX.cpp
6.1 AP_RangeFinder_Backend *AP_RangeFinder_VL53L3CX::detect(...)
检测是否连接了 VL53L3CX 测距仪。我们将通过 I2C 读取数据来进行检测。如果得到结果,则表示传感器已连接。
首先会根据传入的参数,new 一个 AP_RangeFinder_VL53L3CX 类对象。
然后读取测距仪固有的产品 ID 是否正确(sensor->check_id()),再对测距仪进行必要的初始化(sensor->init())。
/*
detect if a VL53L3CX rangefinder is connected. We'll detect by
trying to take a reading on I2C. If we get a result the sensor is
there.
*/
AP_RangeFinder_Backend *AP_RangeFinder_VL53L3CX::detect(RangeFinder::RangeFinder_State &_state, AP_RangeFinder_Params &_params, AP_HAL::OwnPtr<AP_HAL::I2CDevice> dev)
{
if (!dev) {
return nullptr;
}
hal.console->printf("VL53L3CX: detect...\n");
AP_RangeFinder_VL53L3CX *sensor = new AP_RangeFinder_VL53L3CX(_state, _params, std::move(dev));
if (!sensor) {
delete sensor;
hal.console->printf("VL53L3CX: delete sensor...\n");
return nullptr;
}
sensor->dev->get_semaphore()->take_blocking();
if (!sensor->check_id() || !sensor->init())
{
sensor->dev->get_semaphore()->give();
delete sensor;
return nullptr;
}
sensor->dev->get_semaphore()->give();
return sensor;
}
6.2 bool AP_RangeFinder_VL53L3CX::check_id(void)
检查测距仪 ID 寄存器。每种类型测距仪的 ID 寄存器都有唯一值。
// check sensor ID registers
bool AP_RangeFinder_VL53L3CX::check_id(void)
{
uint8_t v1 = 0;
uint8_t v2 = 0;
if (!(read_register(0x010F, v1) && read_register(0x0110, v2))) {
hal.console->printf("VL53L3CX: v1=0x%02x v2=0x%02x\n", v1, v2);
return false;
}
if ((v1 != 0xEA) || (v2 != 0xAA)) {
hal.console->printf("VL53L3CX: Not a recognised device.\n");
return false;
}
printf("Detected VL53L3CX on bus 0x%x.\n", dev->get_bus_id());
return true;
}
6.3 bool AP_RangeFinder_VL53L3CX::init()
初始化传感器,并注册测距仪的周期运行函数 timer()。
/*
initialise sensor
*/
bool AP_RangeFinder_VL53L3CX::init()
{
...
通过I2C向传感器寄存器写入初始值。
...
// call timer() every 50ms. We expect new data to be available every 50ms
dev->register_periodic_callback(50000, FUNCTOR_BIND_MEMBER(&AP_RangeFinder_VL53L3CX::timer, void));
return true;
}
6.4 void AP_RangeFinder_VL53L3CX::timer(void)
20Hz 调用一次该函数,读取测距仪的测量值。
/*
timer called at 20Hz
*/
void AP_RangeFinder_VL53L3CX::timer(void)
{
uint16_t range_mm;
if ((get_reading(range_mm)) && (range_mm <= 4000)) {
WITH_SEMAPHORE(_sem);
sum_mm += range_mm;
// printf("Range_mm: %dmm\n", range_mm);
counter++;
}
}
6.5 SCHED_TASK(read_rangefinder, 20, 100)
在 Copter.cpp 文件的周期任务列表中,注册了调用频率为 20Hz 的 read_rangefinder() 函数。
const AP_Scheduler::Task Copter::scheduler_tasks[] = {
...
#if RANGEFINDER_ENABLED == ENABLED
SCHED_TASK(read_rangefinder, 20, 100),
#endif
...
}
6.6 void Copter::read_rangefinder(void)
在 sensors.cpp 文件中,以厘米为单位返回测距仪高度。
// return rangefinder altitude in centimeters
void Copter::read_rangefinder(void)
{
#if RANGEFINDER_ENABLED == ENABLED
rangefinder.update();
...
}
6.7 void AP_RangeFinder_VL53L3CX::update(void)
根据 6.1 中的返回的 AP_RangeFinder_VL53L3CX 对象,调用 AP_RangeFinder_VL53L3CX 类中的 update() 函数。
/*
update the state of the sensor
*/
void AP_RangeFinder_VL53L3CX::update(void)
{
WITH_SEMAPHORE(_sem);
if (counter > 0) {
state.distance_cm = sum_mm / (10*counter);
state.last_reading_ms = AP_HAL::millis();
update_status();
sum_mm = 0;
counter = 0;
// printf("VL53L3CX: %dcm\n", state.distance_cm);
} else if (AP_HAL::millis() - state.last_reading_ms > 200) {
// if no updates for 0.2s set no-data
set_status(RangeFinder::RangeFinder_NoData);
}
}