Ardupilot入口分析

2024-06-12 14:38
文章标签 分析 ardupilot 入口

本文主要是介绍Ardupilot入口分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

▉<=1=>▉---------------------------------------------------------------->>>>>>
入口函数分析
▉<=1=>▉---------------------------------------------------------------->>>>>>

 

ArduCopter.cpp 文件的最后一行为整个代码入口main,展开之后
int main(int argc, char *const argv[]);
int main(int argc, char *const argv[]) 
{
hal.run(argc, argv, &copter);
return 0;
}
    分两部分分析:<1>.copter,<2>. hal.run(...)

<1>.这里的 copter 对象实例化 在Copter.cpp 文件中:
Copter copter;
Copter 从 Callbacks抽象类公有派生而来:
struct Callbacks {// Callbacks 成员
virtual void setup() = 0; // callbacks 纯虚函数成员方法
virtual void loop() = 0;  // claabacks 纯虚函数成员方法
}; 

class Copter : public AP_HAL::HAL::Callbacks {
public:
......
// HAL::Callbacks implementation.
void setup() override; // 该方法具体实现在ArduCopter.cpp
void loop() override;  // 该方法具体实现在ArduCopter.cpp
......
};
其中:
A:
void Copter::setup() 
{
cliSerial = hal.console;


// 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(); // 包含整个ardupilot系统的初始化


// initialise the main loop scheduler
// 初始化 Auducopter.cpp 开头的 scheduler_tasks 所有任务数组
scheduler.init(&scheduler_tasks[0], ARRAY_SIZE(scheduler_tasks));


// setup initial performance counters
perf_info_reset();
fast_loopTimer = AP_HAL::micros();
}
B:
void Copter::loop()
{
// wait for an INS sample
ins.wait_for_sample();


uint32_t timer = micros();


// check loop time
perf_info_check_loop_time(timer - fast_loopTimer);


// used by PI Loops
G_Dt = (float)(timer - fast_loopTimer) / 1000000.0f;
fast_loopTimer = timer;


// for mainloop failure monitoring
mainLoop_count++;


// Execute the fast loop
// ---------------------
fast_loop();


// tell the scheduler one tick has passed
scheduler.tick();


// run all the tasks that are due to run. Note that we only
// have to call this once per loop, as the tasks are scheduled
// in multiples of the main loop tick. So if they don't run on
// the first call to the scheduler they won't run on a later
// call until scheduler.tick() is called again
uint32_t time_available = (timer + MAIN_LOOP_MICROS) - micros();
scheduler.run(time_available > MAIN_LOOP_MICROS ? 0u : time_available);
}

<2>.这里的 hal 对象实例化在 Copter.cpp 文件中:
const AP_HAL::HAL& hal = AP_HAL::get_HAL();
A. 其中 AP_HAL 为 namespace, 
namespace AP_HAL {
/* Toplevel pure virtual class Hal.顶层纯虚类HAL*/ 
class HAL;


/* Toplevel class names for drivers: 顶层驱动相关类*/
class UARTDriver;
class I2CDevice;
class I2CDeviceManager;
class Device;


class SPIDevice;
class SPIDeviceDriver;
class SPIDeviceManager;


class AnalogSource;
class AnalogIn;
class Storage;
class DigitalSource;
class GPIO;
class RCInput;
class RCOutput;
class Scheduler;
class Semaphore;
class OpticalFlow;


class Util;


/* Utility Classes 通用实用的类*/
class Print;
class Stream;
class BetterStream;


/* Typdefs for function pointers (Procedure, Member Procedure)
  函数指针类型定义
  For member functions(成员函数) we use the FastDelegate delegates(代表) class
  which allows us to encapculate(封装) a member function as a type
*/
typedef void(*Proc)(void);
FUNCTOR_TYPEDEF(MemberProc, void);


/**
* Global names for all of the existing(已有的) SPI devices on all platforms.
*/


enum SPIDeviceType {
// Devices using AP_HAL::SPIDevice abstraction(抽象)
SPIDevice_Type = -1,
};


// Must be implemented(执行)by the concrete(具体的) HALs.
const HAL& get_HAL();
}


B. HAL 类头文件 hal.h
class AP_HAL::HAL {
public:
HAL(AP_HAL::UARTDriver* _uartA, // console
AP_HAL::UARTDriver* _uartB, // 1st GPS
AP_HAL::UARTDriver* _uartC, // telem1
AP_HAL::UARTDriver* _uartD, // telem2
AP_HAL::UARTDriver* _uartE, // 2nd GPS
AP_HAL::UARTDriver* _uartF, // extra1
AP_HAL::I2CDeviceManager* _i2c_mgr,
AP_HAL::SPIDeviceManager* _spi,
AP_HAL::AnalogIn*   _analogin,
AP_HAL::Storage*    _storage,
AP_HAL::UARTDriver* _console,
AP_HAL::GPIO*       _gpio,
AP_HAL::RCInput*    _rcin,
AP_HAL::RCOutput*   _rcout,
AP_HAL::Scheduler*  _scheduler,
AP_HAL::Util*       _util,
AP_HAL::OpticalFlow *_opticalflow)
:
uartA(_uartA),
uartB(_uartB),
uartC(_uartC),
uartD(_uartD),
uartE(_uartE),
uartF(_uartF),
i2c_mgr(_i2c_mgr),
spi(_spi),
analogin(_analogin),
storage(_storage),
console(_console),
gpio(_gpio),
rcin(_rcin),
rcout(_rcout),
scheduler(_scheduler),
util(_util),
opticalflow(_opticalflow)
{
AP_HAL::init(); //AP_HAL 构造函数
}


struct Callbacks {// Callbacks 成员
virtual void setup() = 0; // callbacks 纯虚函数成员方法
virtual void loop() = 0;  // callbacks 纯虚函数成员方法
};


struct FunCallbacks : public Callbacks { // FunCallbacks 成员派生自callbacks
FunCallbacks(void (*setup_fun)(void), void (*loop_fun)(void));


void setup() override { _setup(); }
void loop() override { _loop(); }


private:
void (*_setup)(void);
void (*_loop)(void);
};
// 纯虚函数成员方法 run
virtual void run(int argc, char * const argv[], Callbacks* callbacks) const = 0; 
 
AP_HAL::UARTDriver* uartA; 
AP_HAL::UARTDriver* uartB;
AP_HAL::UARTDriver* uartC;
AP_HAL::UARTDriver* uartD;
AP_HAL::UARTDriver* uartE;
AP_HAL::UARTDriver* uartF;
AP_HAL::I2CDeviceManager* i2c_mgr;
AP_HAL::SPIDeviceManager* spi;
AP_HAL::AnalogIn*   analogin;
AP_HAL::Storage*    storage;
AP_HAL::UARTDriver* console;
AP_HAL::GPIO*       gpio;
AP_HAL::RCInput*    rcin;
AP_HAL::RCOutput*   rcout;
AP_HAL::Scheduler*  scheduler;
AP_HAL::Util        *util;
AP_HAL::OpticalFlow *opticalflow;
};


C. 而get_HAL一共6个函数, 尚不知系统如何选择,这里暂时选择 HAL_PX4_Class.cpp 文件的:
const AP_HAL::HAL& AP_HAL::get_HAL() {
static const HAL_PX4 hal_px4;
return hal_px4;
}
这里,实例化了一个HAL_PX4 对象 hal_px4, 并返回其引用;
而 HAL_PX4 由 AP_HAL 名字空间中的 HAL 抽象类派生而来
class HAL_PX4 : public AP_HAL::HAL {
public:
   HAL_PX4();
// 被派生类重写override的虚函数run
   void run(int argc, char* const argv[], Callbacks* callbacks) const override; 
};
这里返回了一个派生类对象给基类,应该是:通过指向派生类对象的基类指针调用派生类的虚函数而多态。

综上:hal.run() 实际执行 hal_px4.run(argc, argv, &copter);
下面是最终调用的run函数:
HAL_PX4_Class.cpp (ardupilot\libraries\ap_hal_px4)
这里,copter 派生类指针被隐式转化为基类指针Callbacks*,即 多态 行为
void HAL_PX4::run(int argc, char * const argv[], Callbacks* callbacks) const
{
int i;
const char *deviceA = UARTA_DEFAULT_DEVICE;
const char *deviceC = UARTC_DEFAULT_DEVICE;
const char *deviceD = UARTD_DEFAULT_DEVICE;
const char *deviceE = UARTE_DEFAULT_DEVICE;


if (argc < 1) {
printf("%s: missing command (try '%s start')", 
  SKETCHNAME, SKETCHNAME);
usage();
exit(1);
}


assert(callbacks);
// 定义在 HAL_PX4_Class.cpp (ardupilot\libraries\ap_hal_px4)
   // static AP_HAL::HAL::Callbacks* g_callbacks;
g_callbacks = callbacks;  // &copter 被其基类指针 Callbacks* 所指向。


for (i=0; i<argc; i++) {
if (strcmp(argv[i], "start") == 0) {
if (thread_running) {
printf("%s already running\n", SKETCHNAME);
/* this is not an error */
exit(0);
}


uartADriver.set_device_path(deviceA);
uartCDriver.set_device_path(deviceC);
uartDDriver.set_device_path(deviceD);
uartEDriver.set_device_path(deviceE);
printf("Starting %s uartA=%s uartC=%s uartD=%s uartE=%s\n", 
  SKETCHNAME, deviceA, deviceC, deviceD, deviceE);


_px4_thread_should_exit = false;
//创建守护进程
daemon_task = px4_task_spawn_cmd(SKETCHNAME,
SCHED_FIFO,
APM_MAIN_PRIORITY,
APM_MAIN_THREAD_STACK_SIZE,
main_loop, // 主循环,后面分析------------------------->
NULL);
exit(0);
}


if (strcmp(argv[i], "stop") == 0) {
_px4_thread_should_exit = true;
exit(0);
}
 
if (strcmp(argv[i], "status") == 0) {
if (_px4_thread_should_exit && thread_running) {
printf("\t%s is exiting\n", SKETCHNAME);
} else if (thread_running) {
printf("\t%s is running\n", SKETCHNAME);
} else {
printf("\t%s is not started\n", SKETCHNAME);
}
exit(0);
}


if (strcmp(argv[i], "-d") == 0) {
// set terminal device
if (argc > i + 1) {
deviceA = strdup(argv[i+1]);
} else {
printf("missing parameter to -d DEVICE\n");
usage();
exit(1);
}
}


if (strcmp(argv[i], "-d2") == 0) {
// set uartC terminal device
if (argc > i + 1) {
deviceC = strdup(argv[i+1]);
} else {
printf("missing parameter to -d2 DEVICE\n");
usage();
exit(1);
}
}


if (strcmp(argv[i], "-d3") == 0) {
// set uartD terminal device
if (argc > i + 1) {
deviceD = strdup(argv[i+1]);
} else {
printf("missing parameter to -d3 DEVICE\n");
usage();
exit(1);
}
}


if (strcmp(argv[i], "-d4") == 0) {
// set uartE 2nd GPS device
if (argc > i + 1) {
deviceE = strdup(argv[i+1]);
} else {
printf("missing parameter to -d4 DEVICE\n");
usage();
exit(1);
}
}
}
 
usage();
exit(1);
}
接上,分析main_loop
static int main_loop(int argc, char **argv)
{
hal.uartA->begin(115200);
hal.uartB->begin(38400);
hal.uartC->begin(57600);
hal.uartD->begin(57600);
hal.uartE->begin(57600);
hal.scheduler->init();
hal.rcin->init();
hal.rcout->init();
hal.analogin->init();
hal.gpio->init();

//  run setup() at low priority to ensure CLI(command line interface) does not hang the
//  system, and to allow initial sensor read loops to run

hal_px4_set_priority(APM_STARTUP_PRIORITY);


schedulerInstance.hal_initialized();

// 多态调用,基类Callbacks指针调用派生类Copter的重写的虚函数setup,
// 在前面<1>.A ---> ArduCopter.cpp (ardupilot\arducopter)
g_callbacks->setup();
hal.scheduler->system_initialized();


perf_counter_t perf_loop = perf_alloc(PC_ELAPSED, "APM_loop");
perf_counter_t perf_overrun = perf_alloc(PC_COUNT, "APM_overrun");
struct hrt_call loop_overtime_call;

// 定义static bool thread_running = false;        /**< Daemon status flag */
thread_running = true;


/*
 switch to high priority for main loop
*/
hal_px4_set_priority(APM_MAIN_PRIORITY);

/*****************************************
* 整个飞控系统的主循环while:
*****************************************/
while (!_px4_thread_should_exit) { // 定义 bool _px4_thread_should_exit = false;        /**< Daemon exit flag */
perf_begin(perf_loop);

/*
 this ensures a tight(紧凑的) loop waiting on a lower priority driver
 will eventually give up some time for the driver to run. It
 will only ever be called if a loop() call runs for more than
 0.1 second
*/
hrt_call_after(&loop_overtime_call, 100000, (hrt_callout)loop_overtime, NULL);

// 多态调用,基类Callbacks指针调用派生类Copter的重写的虚函数loop,
// 在前面<1>.B ---> ArduCopter.cpp (ardupilot\arducopter)
g_callbacks->loop();

if (px4_ran_overtime) {
/*
 we ran over 1s in loop(), and our priority was lowered
 to let a driver run. Set it back to high priority now.
*/
hal_px4_set_priority(APM_MAIN_PRIORITY);
perf_count(perf_overrun);
px4_ran_overtime = false;
}


perf_end(perf_loop);


/*
 give up 250 microseconds of time, to ensure drivers get a
 chance to run. This relies on the accurate semaphore wait
 using hrt(high resolution timer) in semaphore.cpp
*/
hal.scheduler->delay_microseconds(250);
}
thread_running = false;
return 0;
}

 

 

 

 

 

 

这篇关于Ardupilot入口分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054498

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师,爱吃土豆。如有需要技术交流或者需要方案帮助、需求:以下为联系方式—V 方案1:通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通过IO+EXIT中断的方式进行霍尔传感器数据的读取。将IO口配置为上升沿+下降沿中断触发的方式。当霍尔传感器信号发生发生信号的变化就会触发中断在中断

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据