码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • PX4模块设计之十七:ModuleBase模块


    PX4模块设计之十七:ModuleBase模块

    • 1. ModuleBase模块介绍
    • 2. ModuleBase类介绍
    • 3. ModuleBase类功能介绍
      • 3.1 模块入口
      • 3.2 模块启动
      • 3.3 模块停止
      • 3.4 状态查询
      • 3.5 任务回调
      • 3.6 辅助函数
    • 4. 总结
    • 5. 参考资料

    1. ModuleBase模块介绍

    ModuleBase模块是一个基础类,主要完成各个模块需要的基础功能,比如:start, stop, status命令,但是目前尚不支持多实例(类似mavlink模块多实例应用)。

    当继承自该类的模块:

    • 必须完成以下函数实现:
    1. static int task_spawn(int argc, char *argv[])
    2. static T *instantiate(int argc, char *argv[])
    3. static int custom_command(int argc, char *argv[])
    4. static int print_usage(const char *reason = nullptr)
    • 根据情况重构以下函数实现:
    1. virtual int print_status()
    2. virtual void run()
    3. virtual void request_stop()

    2. ModuleBase类介绍

    这是一个UML绘图工具绘制的ModuleBase类定义(给出一个整体的picture)。

    ModuleBase类 UML图
    注:由于PX4的代码已经都完成了实现,从代码上逆向回来的UML图,所以感觉很细(很具体化);设计上的一些内容(注释,考虑,场景分析等)看不太出来。如果自上而下的UML设计,会注意到有非常多的描述。这里只是用了UML画个图,做个整体的了解。知道这个类有哪些函数、参量,以及public/protected/private属性。所以不再去考虑和分析设计这个类的时候设计人员的想法(也无从得知)。

    3. ModuleBase类功能介绍

    3.1 模块入口

    ModuleBase::main
     ├──> 
     │   └──> return T::print_usage();                                //【必须实现】的函数
     ├──> <命令参数 "start">
     │   └──> return start_command_base(argc - 1, argv + 1);
     ├──> <命令参数 "status">
     │   └──> return status_command();
     ├──> <命令参数 "stop">
     │   └──> return stop_command();
     ├──> lock_module(); // Lock here, as the method could access _object.
     ├──> int ret = T::custom_command(argc - 1, argv + 1);            //【必须实现】的函数
     └──> unlock_module();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在PX4飞控系统代码中模块入口采用的是_main来作为app应用入口的。这里只是ModuleBase::main,在实际符号链接之前要做转换。我们以logger模块为例:

    int logger_main(int argc, char *argv[])
    {
    	// logger currently assumes little endian
    	int num = 1;
    
    	if (*(char *)&num != 1) {
    		PX4_ERR("Logger only works on little endian!\n");
    		return 1;
    	}
    
    	return Logger::main(argc, argv);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此时logger_main是logger模块的应用入口,然后【PX4模块设计之十一:Built-In框架】通过CMakelist将logger模块的应用入口编译和链接到系统中。

    注:main的写法与【Linux应用程序之Helloworld入门】里面的入口main一致,符合常规习惯。

    3.2 模块启动

    检查是否已在运行,如果尚未运行,则调用T::task_spawn()。

    ModuleBase::start_command_base
     ├──> lock_module();
     ├──> 
     │   └──> PX4_ERR("Task already running");
     ├──> 
     │   └──> ret = T::task_spawn(argc, argv);                    //【必须实现】的函数
     └──> unlock_module();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.3 模块停止

    检查模块是否正在运行,如果正在运行,则请求模块停止并等待任务完成。

    ModuleBase::stop_command
     ├──> lock_module();
     ├──> 
     │   ├──> T *object = _object.load();
     │   ├──> 
     │   │   ├──> object->request_stop();  // 发布stop应用指令
     │   │   └──> do {} while (_task_id != -1);
     │   │       ├──> unlock_module();
     │   │       ├──> px4_usleep(10000); // 10 ms, 定期循环查询_task_id是否==-1(满足条件表明模块自己已经优雅退出)
     │   │       ├──> lock_module();
     │   │       └──> <++i > 500 && _task_id != -1>  // wait at most 5 sec
     │   │           ├──> PX4_ERR("timeout, forcing stop");
     │   │           ├──> <_task_id != task_id_is_work_queue>  // 如果已经创建task,需要强制删除任务
     │   │           │   └──> px4_task_delete(_task_id);
     │   │           ├──> _task_id = -1;
     │   │           ├──> delete _object.load();
     │   │           ├──> _object.store(nullptr);
     │   │           └──> break
     │   └──> 
     │       └──> _task_id = -1;
     └──> unlock_module();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.4 状态查询

    检查是否正在运行,如果正在运行,则调用print_status()。

    ModuleBase::status_command
     ├──> lock_module();
     ├──> 
     │   ├──> T *object = _object.load();
     │   └──> ret = object->print_status();
     ├──> 
     │   └──> PX4_ERR("failed to instantiate object");
     └──> unlock_module();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.5 任务回调

    创建任务以后,ModuleBase通过px4_task_spawn_cmd封装了任务入口函数run_trampoline。

    ModuleBase::run_trampoline
     ├──> T *object = T::instantiate(argc, argv);                //【必须实现】的函数
     ├──> _object.store(object);
     ├──> 
     │   └──> object->run();
     ├──> 
     │   └──> PX4_ERR("failed to instantiate object");
     └──> exit_and_cleanup
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.6 辅助函数

    static bool is_running()                                       //判断模块是否已经启动
    bool should_exit()                                             //判断模块是否需要退出
    static void exit_and_cleanup()                                 //清除当前模块对象(清空指针)
    static int wait_until_running(int timeout_ms = 1000)           //等待实例初始化完成,可以在task_spawn最初阶段
    static T *get_instance()                                       // 获取当前模块实例
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4. 总结

    ModuleBase类总体上看类似一个简单封装,将模块设计的基本框架搭建好了,完成最为基本的start/stop/status功能。关于具体是否创建任务(线程),还是使用工作队列,ModuleBase类都没有具体给出。

    关于模块是否采用任务(T::task_spawn内部实现),还是采用WorkQueue(继承WorkItem实现),在后续章节中再做深入。

    5. 参考资料

    【1】PX4开源软件框架简明简介
    【2】Linux应用程序之Helloworld入门
    【3】PX4模块设计之十一:Built-In框架
    【4】PX4模块设计之十三:WorkQueue设计

  • 相关阅读:
    Leetcode—142.环形链表II【中等】
    Sketch for mac v98.2最新版 修复了打开某些文档时导致 Sketch 崩溃的错误
    基于Python开发的DIY字符画程序(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)
    跨平台编译QScintilla、安装QScintilla(Windows、Linux、MacOS环境下编译与安装)
    平年,闰年 质数 有效日期
    智慧家庭解决方案-最新全套文件
    手机通用便签APP哪个比较好用?
    GrapeCity Documents for Excel:GcExcel 5.1.0
    《bug记录》在利用TCP协议创建【服务器-客户端交互程序】中出现的一些问题
    npm 如何更新项目最新依赖包
  • 原文地址:https://blog.csdn.net/lida2003/article/details/126173134
    • 最新文章
    • 沪漂五周年了:我越来越迷茫了
      Agentic Skill Routing 实战:别再把所有 Skill 塞进 AI Agent 上下文
      MySQL-Seconds_behind_master的精度误差
      [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间
      AI的至暗历史:从万众期待到被政府撤资,AI的两次死亡徘徊
      Agent OS :五种驯服不确定性的范式
      PortSwigger SQL注入LAB11
      数据库即时编译JIT
      [Begin]AI Learn Data Day 0
      深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    小工具 小游戏
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

    京公网安备 11010502049817号