Yannick 发表于 2022-10-24 17:48:04

Ardupilot源码分析(二)setup函数

上一篇文章讲到main_loop函数主要分为三部分:

[*]hal对象持有的部分底层外设的初始化和HAL调度器的初始化
[*]g_callbacks->setup()
[*]g_callbacks->loop()
    这一篇文章分析一下g_callbacks->setup()函数,g_callbacks指针指向的是sub对象,setup函数定义在sub对象的父类AP_Vehicle.cpp中,程序版本不同,定义的位置可能不同,不过都无所谓,不影响程序效果。
//libraries/AP_Vehicle.cpp
void AP_Vehicle::setup()
{
    // load the default values of variables listed in var_info[]
AP_Param::setup_sketch_defaults();

    // initialise serial port
serial_manager.init_console();

hal.console->printf("\n\nInit %s"
"\n\nFree RAM: %u\n",
AP::fwversion().fw_string,
                        (unsigned)hal.util->available_memory());

load_parameters();

   // initialise the main loop scheduler
   //AP调度器的初始化,包含用户任务和通用任务,用户任务数组定义在ArduSub.cpp中,由函数get_scheduler_tasks获取
const AP_Scheduler::Task *tasks;
uint8_t task_count;
uint32_t log_bit;
get_scheduler_tasks(tasks, task_count, log_bit);
AP::scheduler().init(tasks, task_count, log_bit);

    // time per loop - this gets updated in the main loop() based on
    // actual loop rate
G_Dt = scheduler.get_loop_period_s();

    // this is here for Plane; its failsafe_check method requires the
    // RC channels to be set as early as possible for maximum
    // survivability.
set_control_channels();

    // initialise serial manager as early as sensible to get
    // diagnostic output during boot process.We have to initialise
    // the GCS singleton first as it sets the global mavlink system ID
    // which may get used very early on.
gcs().init();

    // initialise serial ports
serial_manager.init();
gcs().setup_console();

    // Register scheduler_delay_cb, which will run anytime you have
    // more than 5ms remaining in your call to hal.scheduler->delay
//在HAL调度器中注册delay callback,在每次调用delay函数时会调用这个callback,用于与地面站的通信
hal.scheduler->register_delay_callback(scheduler_delay_callback, 5);

    // init_ardupilot is where the vehicle does most of its initialisation.
    //板级资源的初始化
init_ardupilot();

    // gyro FFT needs to be initialized really late
#if HAL_GYROFFT_ENABLED
gyro_fft.init(AP::scheduler().get_loop_period_us());
#endif
#if HAL_RUNCAM_ENABLED
runcam.init();
#endif
#if HAL_HOTT_TELEM_ENABLED
hott_telem.init();
#endif
#if HAL_VISUALODOM_ENABLED
    // init library used for visual position estimation
visual_odom.init();
#endif
vtx.init();

#if AP_PARAM_KEY_DUMP
AP_Param::show_all(hal.console, true);
#endif
}
    setup主要实现了AP调度器的初始化和板载资源的初始化,下边分别分析。
AP调度器的初始化

    AP调度器区别于上一篇讲到的HAL调度器,HAL调度器属于OS级调度器,负责管理多线程的启动和delay函数实现以及线程内回调函数的注册等。
    AP调度器中定义的所有任务仅仅是在OS主线程中工作,即只在main函数中轮流运行,并不会“并行”运行,AP调度器调度的任务是在ArduSub.cpp函数中定义的应用层功能函数,如气压计,惯性器件的数据读取,姿态计算等。这些任务是如何轮流工作的,在下一篇文章《g_callbacks->loop()》中分析。
板载资源初始化init_ardupilot

    这个函数对板内外设和板载资源进行初始化,如gpio,电量检测,气压计,遥控器,电子罗盘,惯性器件的初始化。这里有必要说明一下这些设备的初始化方法。
    以惯性导航器件为例,首先完成设备的初始化,然后再定时更新设备数据。由于总线结构问题,可能多个设备共用一条总线,需要给总线通信单独开辟一个OS线程,然后每个设备在这个线程中注册回调函数,以完成自身的定时刷新。
    飞控的应用层程序从上述传感器中取数据,为了使应用层不需要关心设备驱动层,Ardupilot设计了传感器驱动前后端程序结构,应用程序从前端取数据,后端在上述线程中定时刷新,为了兼容每款飞控板使用的不同型号的传感器,又分别根据具体型号对后端程序进行继承。这一部分较复杂,我会在后边一篇文章专门分析。
页: [1]
查看完整版本: Ardupilot源码分析(二)setup函数