pixhawk ArduPilot_main启动与运行分析

2023-05-16

上节分析2个系统启动脚本,一个是ardupilot/mk/PX4/ROMFS/init.d里的rcS,另一个是rc.APM,这个脚本在rcS里得到了调用,也就是说,rcS就是为Nuttx的启动文件。

查看rc.APM的最低端,调用ArduPilot_main

echo Starting ArduPilot $deviceA$deviceC$deviceD
if ArduPilot -d $deviceA -d2 $deviceC -d3 $deviceD start
then
    echo ArduPilot started OK
else
    sh /etc/init.d/rc.error
fi

其中ArduPilot是一个内嵌的应用程序,由编译生成的ardupilot/modules/PX4Firmware/Build/px4fmu-v2_APM.build/builtin_commands.c可知,这个应用程序的入口地址就是ArduPilot_main。其实也只有这个ArduPilot_main应用是APM编写的,其余的应用基本上都是px4底层自带的。

{"ArduPilot",SCHED_PRIORITY_DEFAULT,4096,ArduPilot_main},
{"px4flow",SCHED_PRIORITY_DEFAULT,CONFIG_PTHREAD_STACK_DEFAULT,px4flow_main},

ArduPilot_main的内容是什么呢?ArduCopter.cpp实际上是多旋翼飞行器的主程序,那么该文件中找ArduPilot_main

我们看源代码的时候,特别喜欢从main函数开始,顺着思路开始往下理。下面我就以ArduCopter工程里的px4-v2编译目标为例子,一步一步剖析main函数。
总的来说,这里的main函数就是ArduCopter.cpp里的AP_HAL_MAIN_CALLBACKS(&copter);,它实际上是一个宏定义,传进来的参数为类对象的引用,通过在AP_HAL_Main.h里的定义可知原型为:

#define AP_HAL_MAIN_CALLBACKS(CALLBACKS)extern "C" { \
   int AP_MAIN(int argc, char* const argv[]); \
   int AP_MAIN(int argc, char* const argv[]) { \
       hal.run(argc, argv, CALLBACKS); \
       return 0; \
    }\
    }

而这里的AP_MAIN也是一个宏,如下:

#if CONFIG_HAL_BOARD == HAL_BOARD_PX4 ||CONFIG_HAL_BOARD == HAL_BOARD_VRBRAIN
#define AP_MAIN __EXPORT ArduPilot_main
#endif

所以它实际上是这样的:

#define AP_HAL_MAIN_CALLBACKS(CALLBACKS)extern "C" { \
    int__EXPORT ArduPilot_main(int argc, char* const argv[]); \
   int __EXPORT ArduPilot_main(int argc, char* const argv[]) { \
       hal.run(argc, argv, CALLBACKS); \
       return 0; \
    }\
    }

将这个宏替换到ArduCopter.cpp里的AP_HAL_MAIN_CALLBACKS(&copter);它就变成了:

int __EXPORT ArduPilot_main(int argc, char*const argv[]);
int __EXPORT ArduPilot_main(int argc, char*const argv[]) {
       hal.run(argc, argv, &copter);
       return 0;
    }

因此实际上这个工程的main函数就是ArduCopter.cpp里的ArduPilot_main函数。在这个main函数所在的CPP文件创建了不同的线程以供调用。

 

题外话builtin_commands.c是怎么生成的?这样的命令有很多,在rcS里就开始调用的比如rgbled就是的。至于这些内置的命令是怎么生成的,就要了解PX4原生的编译过程了,查看px4_targes.mk

PX4_MAKE =$(v)+ GIT_SUBMODULES_ARE_EVIL=1 ARDUPILOT_BUILD=1 $(MAKE) -C $(SKETCHBOOK) -f $(PX4_ROOT)/Makefile.make EXTRADEFINES="$(SKETCHFLAGS)$(WARNFLAGS)$(OPTFLAGS) "'$(EXTRAFLAGS)'APM_MODULE_DIR=$(SKETCHBOOK)SKETCHBOOK=$(SKETCHBOOK)CCACHE=$(CCACHE)PX4_ROOT=$(PX4_ROOT)NUTTX_SRC=$(NUTTX_SRC)MAXOPTIMIZATION="-Os"UAVCAN_DIR=$(UAVCAN_DIR)

其中-f $(PX4_ROOT)/Makefile.make显示了makefile使用了PX4项目根目录的Makefile.make文件,拜读这里即可查出真相,真相在根目录下makefiles文件夹里的firmware.mk里。其实px4的代码使用的是Cmake,所以通过查看根目录下的CMakeLists.txt可知,真正产生builtin_commands.c的是px4_impl_nuttx.cmake里的px4_nuttx_generate_builtin_commands函数。同理,nuttx操作系统的ROMFS是由px4_nuttx_add_romfs函数产生的

 

接着继续分析main函数里的一些特征及其所做的事情。

由上面分析可知,main函数及为:ardupilot/Arducopter/Arducopter.cpp

int __EXPORTArduPilot_main(int argc,char*const argv[]) {
       hal.run(argc, argv, &copter);
       return0;
    }

其中hal定义为const AP_HAL::HAL& hal =AP_HAL::get_HAL();

ardupilot/Arducopter/Copter.cpp,而:

const AP_HAL::HAL& AP_HAL::get_HAL() {
    staticconst HAL_PX4 hal_px4;
    return hal_px4;
}

ardupilot/libraries/AP_HAL_PX4/HAL_PX4_Class.cpp

classHAL_PX4:public AP_HAL::HAL {
public:
   HAL_PX4();
    void run(int argc,char*const argv[], Callbacks* callbacks)const override;
};

ardupilot/libraries/AP_HAL_PX4/HAL_PX4_Class.h

hal.run函数即为HAL_PX4里面的run方法,这个main函数主要运行的是这个方法。这个方法能在HAL_PX4_Class.cpp中找到。在这个方法中有:

           

daemon_task =px4_task_spawn_cmd(SKETCHNAME,
                                SCHED_FIFO,
                                APM_MAIN_PRIORITY,
                                APM_MAIN_THREAD_STACK_SIZE,
                                main_loop,
                                NULL);

所以这里又调用了main_loop函数,在main_loop函数中,主要分析两点:

g_callbacks->setup();
while(!_px4_thread_should_exit){
g_callbacks->loop();
}

setup()函数在板子启动的时候被调用一次,它实际的调用来自每块板子的HAL,所有main函数是在HAL里的,其后就是loop()函数的调用,sketch的主要工作体现在loop()函数里。

setuploop函数可以在ArduCopter.cpp中分别找到,其中setup函数里有scheduler.init(&scheduler_tasks[0],ARRAY_SIZE(scheduler_tasks));,这样在这个应用函数里又启动了调度任务:

constAP_Scheduler::TaskCopter::scheduler_tasks[]={
    SCHED_TASK(rc_loop,              100,    130),
    SCHED_TASK(throttle_loop,         50,     75),
    SCHED_TASK(update_GPS,            50,    200),
#if OPTFLOW == ENABLED
    SCHED_TASK(update_optical_flow,  200,    160),
#endif
    SCHED_TASK(update_batt_compass,   10,    120),
    SCHED_TASK(read_aux_switches,     10,     50),
    SCHED_TASK(arm_motors_check,      10,     50),
    SCHED_TASK(auto_disarm_check,     10,     50),
    SCHED_TASK(auto_trim,             10,     75),
    SCHED_TASK(update_altitude,       10,    140),
    SCHED_TASK(run_nav_updates,       50,    100),

所以apm的源码就是在px4的原生代码上以一个应用的接口加入了自己的调度任务,总的来说就是在px4上加了自己的应用。而在loop函数里开展了主要的循环fast_loop函数,如下:

// Main loop - 400hz
voidCopter::fast_loop()
{
 
    // IMU DCM Algorithm
    // --------------------
    read_AHRS();
 
    // run low level rate controllers that only require IMU data
    attitude_control.rate_controller_run();
 
#if FRAME_CONFIG == HELI_FRAME
    update_heli_control_dynamics();
#endif //HELI_FRAME
 
    // send outputs to the motors library
    motors_output();
 
    // Inertial Nav
    // --------------------
    read_inertia();
 
    // check if ekf has reset target heading
    check_ekf_yaw_reset();
 
    // run the attitude controllers
    update_flight_mode();
 
    // update home from EKF if necessary
    update_home_from_EKF();
 
    // check if we've landed or crashed
    update_land_and_crash_detectors();
 
#if MOUNT == ENABLED
    // camera mount's fast update
    camera_mount.update_fast();
#endif
 
    // log sensor health
    if(should_log(MASK_LOG_ANY)){
        Log_Sensor_Health();
    }
}

在这里边进行姿态解算,PID控制等等,那么分析到这里我想完过飞行器的同学就大致清楚了。
在这个工程里有一个重要的类叫Copter,大部分函数都是该类的方法,如voidCopter::arm_motors_check(),以后用的一些全局变量基本上都属于这个类里面的。

下面看一下一些简单的应用,以电机解锁为例子,玩过飞行器的同胞就知道,油门拉杆按右下角几秒就可以解锁,一般都是这样设置的,看看代码都是怎么实现的:
首先解锁的函数为arm_motors_check,调用次数为10hz。代码很简单,从中可以看出,2s后如果检查通过就可以解锁,当飞行器不属于手动控制模式时,拉杆打左下角2s即可上锁。



如果您觉得此文对您的发展有用,请随意打赏。 
您的鼓励将是笔者书写高质量文章的最大动力^_^!!


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pixhawk ArduPilot_main启动与运行分析 的相关文章

随机推荐

  • 当面试官问 promise 的时候,他们希望听到什么(二)

    目录 前言 一 前提知识 1 JS 单线程机制 2 JS 任务队列与事件循环 3 Promise 回顾 二 题目实战 1 开头提到的题目 2 稍有难度 3 挑战升级 前言 上一篇文章 xff0c 当面试官问 promise 的时候 xff0
  • JS 防抖与节流的原理分析和代码手写

    目录 前言 作用 防抖 使用场景 分析原理 手写代码 节流 使用场景 原理分析 手写代码 小补充 前言 前一段时间 xff0c 我学习了 JS 的防抖与节流 xff0c 自认为掌握住了它们 xff0c 当我在做面试题的时候 xff0c 遇到
  • ELK-日志收集系统在Centos上环境安装

    ELK 日志收集系统在Centos上环境安装 文章目录 ELK 日志收集系统在Centos上环境安装 前言安装elastcsearch6 5 4安装准备学习资料启动创建新用户取掉只能本机访问的配置配置跨域访问启动命令测试 安装分词ik安装e
  • Linux环境下下载pydicom

    Linux中只要使用命令即可 sudo pip install pydicom 如果出现sudo xff1a pip xff1a command not found 把sudo去掉 xff0c 再操作一次 因为在执行Linux命令时 xff
  • C语言编程实现汉诺塔问题

    C语言编程实现汉诺塔问题 1 首先解释一下 xff0c 汉诺塔问题 xff1a 古代梵塔内有A B C3个座 xff0c 开始时A座上面有64个盘子 xff0c 盘子大小不等 xff0c 大的在下 xff0c 小的在上 一个老和尚想把64个
  • ORA-28000: the account is locked

    原因 xff1a Oracle账户多次以错误密码登录 xff0c 导致数据库服务器宕机 xff0c 账户被锁定 以系统账户sys 登录Oracle xff0c 查看sql SELECT FROM DBA PROFILES WHERE RES
  • Docker镜像编译方式

    1 普通Dockerfile的缺点 我们通常情况下要编译Spring Boot的Docker镜像 xff0c 一般会写一个下面这样的Dockerfile FROM openjdk span class token operator span
  • Python入门第一章笔记 从安装到编写hello world

    1 下载Python安装包 xff1b 可以到官网下载 xff1a https www python org 但是如果没有翻墙的话 xff0c 下载会很慢 25M安装包 xff0c 需要1个小时以上 如果没有耐心等可以在csdn进行下载 x
  • 养老产业政策链接

    江西省养老政策文件 xff1a 江西省养老服务条例 http mzw ganzhou gov cn gzsmzjy c103172 202201 d238525b35bb47b49b3de312c9b63a60 shtml 南昌市养老服务体
  • 我多变的2013

    我多变的2013 第一篇 xff1a 回顾 回顾工作 首先简单的做个自我介绍吧 xff0c 我是87年的 xff0c 北漂已经是第5个年头了 xff0c 一直都从事java开发工作 前后只换过一家公司 xff0c 第一家待了近两年 xff0
  • 我花1200大洋所学的“元学习课”究竟学了些什么?

    我花1200大洋所学的 元学习课 究竟学了些什么 xff1f 讲课的是台湾的一位大牛名叫Xdite xff0c 以及亿万富豪李笑来 能够跟牛人学习怎么学习我想应该不会有错吧 xff0c 对我来说这次做的应该是一次正确的决定 xff0c 所谓
  • 成长记录-开启我的新生 (2016-12-06)

    真的是很惊险 xff0c 我差一点就错过了 获得新生 的机会 xff0c 我在蜻蜓音频中听到了逻辑思维 xff0c 从逻辑思维中了解到了 得到 xff0c 从 得到 中订阅了吴军博士的 硅谷来信 xff0c 却在过去的好几个月里 xff0c
  • 最新Java电子书

    最新Java电子书 JAVA参考大全 J2SE 5EDITION 世界级程序设计大师作品 Thinking in Java第三版 43 第四版 xff08 中文版 43 习题答案 xff09 Java数据库高级编程宝典 Java核心技术第八
  • ELK-ElasticSearch权威指南笔记

    ELK ElasticSearch笔记 文章目录 ELK ElasticSearch笔记 前言测试工具 语法索引 xff0c 文档和类型文档元数据检索索引里文档数据查看当前节点的所有 Index查看所有index的mapping 映射 查看
  • 关于JAVA中内存溢出的解决办法

    关于JAVA中内存溢出的解决办法 J2ee应用系统是运行在J2EE应用服务器上的 xff0c 而j2ee应用服务器又是运行在JVM上的 xff0c 生成环境中JVM参数的优化和设置对于J2EE应用系统性能有着决定性的作用 要优化系统 xff
  • ireport的使用总结

    ireport的使用总结 截图居然都没显示出来 xff0c 如有需要可以到 xff08 http download csdn net detail czp0608 4140640 xff09 下载 相信很多java程序员们 xff0c 在开
  • 卡尔曼滤波C代码分析

    文章下载地址 xff1a http wenku baidu com view 3c42b7733186bceb18e8bb29
  • 作为一个新人,怎样学习嵌入式Linux?

    作为一个新人 xff0c 怎样学习嵌入式Linux xff1f 被问过太多次 xff0c 特写这篇文章来回答一下 在学习嵌入式Linux之前 xff0c 肯定要有C语言基础 汇编基础有没有无所谓 就那么几条汇编指令 xff0c 用到了一看就
  • pixhawk启动脚本分析

    Nuttx系统启动是由ardupilot mk PX4 ROMFS init d里的rcS和rc APM完成的 笔者阅读了rcS和rc APM xff0c 该脚本类似C语言 xff0c 并做了相关注释 主要是一些设备自检 xff0c 启动各
  • pixhawk ArduPilot_main启动与运行分析

    上节分析 2 个系统启动脚本 xff0c 一个是 ardupilot mk PX4 ROMFS init d 里的 rcS xff0c 另一个是 rc APM xff0c 这个脚本在 rcS 里得到了调用 xff0c 也就是说 xff0c