精华内容
下载资源
问答
  • px4飞控
    2021-12-25 15:09:36

    接触PX4飞控代码一年多了,代码都是模块化 开发起来比APM的方便,使用过程中也出现过各种怪异问题,用的硬件是V5 nano 和V5+,测试的代码版本是1.9和1.10。今天总结一下遇到过的问题及解决方法。
    1、飞行过程中切返航 飞机直接无动力掉下来 出现概率不高 这是1.9版本的BUG 后续版本已经修复
    2、有SD卡的时候 会出现上传任务失败 出现概率低
    3、任务起飞 飞机只解锁 却不飞任务 出现概率比较低
    4、飞机上电后 参数重置 这个问题可以从硬件上解决 也可以在软件上解决
    5、无法远程上传固件,升级固件很麻烦必须插USB,虽然boot loader也支持串口,但需要比较好的串口工具 而且成功率低,这需要从软件上去解决

    后续会更新具体的解决方案……

    更多相关内容
  • px4飞控源码

    2018-04-09 14:37:42
    px4飞控源码,来自github。。。。。。。。。。。。。。。。
  • PX4飞控中利用EKF估计姿态角代码详解
  • px4飞控磁罗盘校准算法理论与代码结合解读,有分析图解,有代码注释,有理论有实践
  • PX4飞控介绍

    2015-11-05 22:05:17
    Pixhawk是一种先进的自动驾驶仪,由PX4开放硬件项目设计和3D机器人制造。它具有来自ST公司先进的处理器和传感器技术,以及NuttX实时操作系统,能够实现惊人的性能,灵活性和可靠性控制任何自主飞行器。 Pixhawk系统...
  • 3D Robotics 的开源飞控技术解决方案 APM:Copter,带有高级组织形式的个人自动导航仪技术,能够为飞行器带 来易用的自主飞行能力。本手册可以带领您进行第一次的设置、调参和飞行活动。
  • PX4飞控系统的流程图

    2018-06-25 20:34:33
    飞控系统流程图.rar,飞控系统流程图,Pixhawk姿态解算流程.pdf,Pixhawk位置解算之LPE .pdf,Pixhawk姿态控制流程图.pdf,Pixhawk位置控制流程图.pdf
  • pixhawk/PX4飞控固件代码,包括bootloader
  • 电子-PX4飞控开发笔记第五章PWMPPMS.bus与DSM2.pdf,综合电子技术四轴飞行器|飞控
  • PX4FMU 与 PX4IO 的组装 1) 首先将 PX4 套件中 PX4IO 板上的 9x3 针的接插件焊接在板子右侧(这是舵机 连接接插件——译者注),那边有“PX4 autupilot”(应该是 SERVOS——译者 注)的字样。 注意:接插件...
  • 修改px4飞控的系统时间

    1.在platforms/nuttx/src/px4/stm/stm32_common/hrt/hrt.c文件中自定义一个时间偏移量,并添加到系统时间计算之后。

    2.在src/drivers/drv_hrt.h文件中声明一下。

     

     3.在自己需要用的地方再声明一下。

     4.便可以自己喜欢的位置编写算法,修改abs_time_offset。这个abs_time_offset能影响到系统时间。

    展开全文
  • PX4飞控原理图

    2015-12-07 09:03:16
    这是官网下载的PX4飞控原理图包括AltiumDesiner的工程
  • Pixracer 飞控的原理图 pcb图,PX4飞控 Mini版硬件资料 Autopilot固件。穿越机硬件原理图,pcb图 飞控介绍:http://www.rcgroups.com/forums/showthread.php?t=2576614
  • px4则是一款常见的开源飞控固件,是自主无人机系统开发中非常常用的飞控固件。但是其对应的硬件往往都比较贵,即使是早期的pixhawk版本也要600+。 如果要开发一款廉价自主无人机系统,那么采用F4/F7/H7飞控硬件...

    前言

    穿越机F4/F7/H7飞控是一系列采用stm32系列F4xx和F7xx处理器的飞控的统称,是目前穿越机爱好者非常喜欢使用的飞控硬件,其价格也非常便宜180~410。

    而px4则是一款常见的开源飞控固件,是自主无人机系统开发中非常常用的飞控固件。但是其对应的硬件往往都比较贵,即使是早期的pixhawk版本也要600+。

    如果要开发一款廉价自主无人机系统,那么采用F4/F7/H7飞控硬件配合px4飞控固件是一种非常好的组合,但是需要很多的修改才能实现。

    本系列文章将一步一步的通过修改F4/F7/H7飞控硬件和px4飞控固件、并搭载一些必要的设备,搭建一套廉价自主无人机系统。


    飞控硬件选择

    生产F4/F7/H7飞控硬件的厂家很多,也有一些自制的硬件。不论是F4、F7还是H7飞控,他们的处理器一般都是stm32f4xx和stm32f7xx。而px4固件本身除支持标准的pixhawk系列外,还支持一些其他厂家的飞控固件,其中F4系列中被比较好支持的是omnibus f4 sd系列, F7和H7系列中支持比较好的是holybro的kakute F7和H7系列飞控。

    对于F7和H7,目前F7只能买到F7 mini(300+),H7则都可以买到(400+),推荐买H7系列。

    对于F4,选择则非常多,但是也有很多坑。

    首先,购买时一定要看是否是omnibus F4,否则不保证能成功。

    而对于支持omnibus F4的飞控中,还要避开的大坑就是传感器。很多商家卖的F4飞控版本非常多,常见的有:F4 pro v2,F4 v3,F4 v3s, F4 v3 plus。其实版本不是很重要,但是重要是以下两点:1. IMU,2. 气压计。

    IMU

    这个是个巨坑!购买时千万不要只看网页说明,要问店家要实物图片看。F4支持的IMU很多,包括:MPU6050,L3G4200D,MPU3050,L3GD20,MPU6000,MPU6500,MPU9250,ICM20601,ICM20602,ICM20608G,ICM20649,ICM20689,ICM42605,ICM42688P,BMI160,BMI270,LSM6DSO。而px4的omnibus f4固件支持的IMU则包括:MPU6000,ICM20602,ICM20608G,ICM42670,ICM42605,ICM42688P等。可以看到,交集挺多,但是目前我只遇到这MPU6000和ICM20608g/IC268g这两种px4固件支持且F4常用的IMU。尤其注意F4 V3 plus这个版本,一定要和店家确认用的是不是mpu6000,我买的用的都看不出来是哪款IMU,估计是bmi280,px4不支持!!!

    气压计

    许多F4飞控没有气压计!!!这个一定要注意!

    主要看硬件参数就可以,F4常用的气压计型号为bmp280。所以只要包含这个,就有气压计。

    GPS和电子罗盘

    另外,要实现自主飞行,F4/F7/H7系列还缺少的就是电子罗盘,而常见的解决方案就是北天GPS出品的BN880模块,该模块既有GPS还有一个常见的电子罗盘芯片HMC5883。有了这两个,就可以实现有GPS下使用auto mission进行飞行了。

    推荐购买:

    目前淘宝上能买到的可用的是F4 pro V2这个版本的飞控(截止2022年5月10日),这个搭载的IMU是IC268g(ICM20608g);holybro的kakute H7/H7 mini以及F7 mini,搭载MPU6000。


    固件更新

    一般F4/F7/H7购买时都可以选择刷好了固件,但是可选的固件是不包含px4的。这里推荐选择让店家默认刷betaflight的固件,也就是BF固件。

    然后就可以利用betaflight configurator来实现刷px4固件了。

    betaflight configurator的下载链接如下:

    https://github.com/betaflight/betaflight-configurator/releases/latesthttps://github.com/betaflight/betaflight-configurator/releases/latest

    下载后,为了刷px4固件,则需要先给飞控刷上bootloader。这里可以先刷上官方的bootloader,链接为:

    https://github.com/PX4/PX4-user_guide/tree/master/assets/flight_controller/omnibus_f4_sdhttps://github.com/PX4/PX4-user_guide/tree/master/assets/flight_controller/omnibus_f4_sd

    由于这个bootloader很老了,所以如果默认用这个,在后期修改px4固件代码并编译后再刷固件后,可能会在Qgroundcontrol上遇到以下错误:

    Fail: No CPU load information

    这是因为bootloader和px4固件不匹配的原因,方法也很简单,就是更新bootloader。


    F4/F7飞控更新bootloader

    对于F4飞控的bootloader刷机的方法如下:

    https://docs.px4.io/master/en/advanced_config/bootloader_update_from_betaflight.htmlhttps://docs.px4.io/master/en/advanced_config/bootloader_update_from_betaflight.html首先就是下载bootloader的代码:

    git clone --recursive  https://github.com/PX4/Bootloader.git
    cd Bootloader
    make <target> upload # For example: omnibusf4sd_bl or kakutef7_bl

    完成编译后,可利用betaflight configurator进行bootloader的刷机。


    H7飞控更新bootloader

    对于H7飞控的bootloader刷机的方法如下:

    https://docs.px4.io/master/en/advanced_config/bootloader_update.htmlhttps://docs.px4.io/master/en/advanced_config/bootloader_update.html直接在飞控固件里进行编译,并利用QGroundcontrol进行bootloader的更新即可。


    利用以上方法更新bootloader后,接可以编译固件了。固件的下载地址为:

    https://github.com/PX4/PX4-Autopilot.githttps://github.com/PX4/PX4-Autopilot.git默认编译和上传如下:

    make omnibus_f4sd_default upload

    如果更新bootloader和固件后,仍然有no cpu load information的提示,也可以用暴力的方法解决。

    这个问题的核心就是preflight check里需要保证飞控的cpu负载不要过高,默认设置是90%以下才能解锁。所以暴力的方法就是不让飞控检查cpu负载即可。方法如下:

    在QGroundControl里的vehicle setup里,在parameters下面搜索COM_CPU_MAX,并把这个值设置为-1,即为不检查cpu的负载了。

    如此设置后,无人机就不会继续报no cpu load information的错误了。


     


    参考链接:

    1. Omnibus F4 SD:https://docs.px4.io/master/zh/flight_controller/omnibus_f4_sd.htmlhttps://docs.px4.io/master/zh/flight_controller/omnibus_f4_sd.html
    2. holybro kakute F7:https://docs.px4.io/master/zh/flight_controller/kakutef7.htmlhttps://docs.px4.io/master/zh/flight_controller/kakutef7.html
    3. holybro kakute H7:https://docs.px4.io/master/zh/flight_controller/kakuteh7.htmlhttps://docs.px4.io/master/zh/flight_controller/kakuteh7.html
    4. bootloader编译:https://docs.px4.io/master/en/advanced_config/bootloader_update.htmlhttps://docs.px4.io/master/en/advanced_config/bootloader_update.html
    5. 刷bootloader:https://docs.px4.io/master/en/advanced_config/bootloader_update_from_betaflight.htmlhttps://docs.px4.io/master/en/advanced_config/bootloader_update_from_betaflight.html以及https://mbot1.blog.csdn.net/article/details/106988811https://mbot1.blog.csdn.net/article/details/106988811
    6. 更新bootloader:https://docs.px4.io/master/en/config/firmware.html#bootloaderhttps://docs.px4.io/master/en/config/firmware.html#bootloader

    展开全文
  • PX4飞控试炼之路

    千次阅读 2020-11-13 11:26:11
    PX4飞控试炼之路一、地面站控制台上显示输出“Hello Sky!” 一、地面站控制台上显示输出“Hello Sky!” 找到目录:Firmware/src/examples/, 并新建一个子目录,可以命为:my_example_app; 在新建的目录下,新建一个 c...

    一、地面站控制台上显示输出“Hello Sky!”

    1. 找到目录:Firmware/src/examples/, 并新建一个子目录,可以命为:my_example_app;
    2. 在新建的目录下,新建一个 c文件,可以命名为:my_example_app.c;
    3. 打开新建的 c文件,并填入以下代码:
    #include <px4_posix.h>//包含了打印信息函数:PX4_INFO
    __EXPORT int my_example_app_main(int argc, char *argv[]);
    int my_example_app_main(int argc, char *argv[])
    {
    PX4_INFO("Hello Sky!");
    return 0;
    }
    

    my_example_app是飞控运行过程中的一个指令,可在地面站端口输入,调用该条指令时,打印信息Hello Sky。需要注意的是主函数命名方式为 C文件的名称 + _main, 这样在控制台输入命令时,就可以从该入口进入函数;

    1. 仍在该目录下,新建一个 txt文件,名为:CMakeLists.txt,该文件用于编译,必不可少,里面写入以下代码:
    px4_add_module(
    	MODULE examples__my_example_app
    	MAIN my_example_app
    	STACK_MAIN 2000
    	SRCS
    		my_example_app.c
    	DEPENDS
    	)
    
    1. 如果想从仿真中查看的话,需要进入文件夹:Firmware/boards/px4/sitl/, 并打开文件:default.cmake,如果想从飞控中查看,需要进入文件夹:Firmware/boards/px4/fmu-v2/并打开文件:default.cmake, 在EXAMPLES类中添加my_example_app
      在这里插入图片描述该cmake文件中的命令,如果在使用过程中不需要可以注释掉,这样编译过程会更快;
      然后进入Firmware目录下的终端,输入指令:make px4_fmu-v2_default编译固件,输入指令:make px4_sitl_default gazebo打开gazebo仿真:
      在这里插入图片描述

    接着在该终端中输入my_example_app,终端输出“Hello Sky!”
    在这里插入图片描述
    gazebo仿真界面如下图,中心位置出现一辆无人机。
    在这里插入图片描述

    二、利用飞控计算加法

    1. PX4中的任何一个功能模块或者说一个进程基本模式如下图所示:
      在这里插入图片描述要想用飞控实现两个数字的加法,需在控制台输入两个数字a和b,然后经飞控计算后,再返回控制台。按照上图的进程模式指令应包括:进程启动、进程停止、进程状态、进程帮助以及用户操作指令。
      用户的操作指令格式为:my_example_app test -a num1 -b num2,其中my_example_app 是指令的名称, -a num1 -b num2均是指令参数。例如,一个正常指令为:
    my_example_app test -a 100 -b 2
    
    1. 考虑到源码主要使用C++进行变成,这里我们将.c文件改为.cpp文件,首先创建一个类,里面包含需要实现各个指令的公有公式和用于运算与状态标记的变量。
      对参数的提取主要利用了头文件#include <px4_getopt.h>中的int PX4_getopt(int argc, char *argv[], const char *options, int *myoptind, const char **myoptarg)函数。完整代码如下:
    #include <px4_posix.h>//包含了打印信息函数:PX4_INFO
    #include <px4_defines.h>//含有OK等定义
    #include <px4_getopt.h>//用于解析指令
    #include <stdlib.h>//基本函数库,如字符串转浮点数据的函数: atof
    #include <string.h>//用于字符串处理
    
    extern "C" __EXPORT int my_example_app_main(int argc, char *argv[]);
    
    class AddtionCall
    {
    public:
    	/**
    	* Constructor
    	*/
    	AddtionCall();//构造函数
    
    	/**
    	* Destructor, also kills task.
    	*/
    	~AddtionCall();//析构函数
    
    	int start();
    	int stop();
    	void status();
    	void help();
    	void my_example_app(int argc, char *argv[]);
    
    private:
    	float _num1 ;//加数
    	float _num2;//被加数
    	float _result ;//结果
    	bool _status; //状态标志
    };
    //构造函数
    AddtionCall::AddtionCall():
    
    _num1(0.0f),
    _num2(0.0f),
    _result(0.0f),
    _status(false)
    {
    	;
    }
    //析构函数
    AddtionCall::~AddtionCall()
    {
    _num1= 0.0f;
    _num2= 0.0f;
    _result = 0.0f;
    _status=false;
    }
    //开始函数
    int AddtionCall::start()
    {
    	if (_status)
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app");
    	}
    	else
    	{
    		_status=true;
    		PX4_INFO("Task start successful!");
    	}
    	return 1;
    }
    //终止函数
    int AddtionCall::stop()
    {
    	_status=false;
    	PX4_INFO("Task has been stopped!");
    	return 1;
    }
    //状态函数
    void AddtionCall::status()
    {
    	if (!_status)
    	{
    		PX4_INFO("Task is is not running, please start it first ");
    	}
    	else
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app!");
    	}
    }
    //帮助函数
    void AddtionCall::help()
    {
    	PX4_INFO("This is my_example_app module, using for addition opreation. You can use the following command:");
    	PX4_INFO(" my_example_app start //---- start the module");
    	PX4_INFO(" my_example_app stop //---- stop the module");
    	PX4_INFO(" my_example_app status //---- show the current state of the module");
    	PX4_INFO("my_example_app help //---- show what you can do in this module");
    	PX4_INFO("my_example_app test -a num1 -b num2 //----caculate your data, There is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation.");
    }
    //运算函数
    void AddtionCall::my_example_app(int argc, char *argv[])
    {
    	bool error_flag=false;
    	int myoptind = 1;
    	int ch;
    	const char *myoptarg = nullptr;
    
    	while ((ch = px4_getopt(argc, argv, "a:b:", &myoptind, &myoptarg)) != EOF)
    	{
    		switch (ch) {
    		case 'a':
    			_num1= atof(myoptarg);
    			break;
    		case 'b':
    			_num2 = atof(myoptarg);
    			break;
    		default:
    			error_flag = true;
    			break;
    					}
    	}
    	if (error_flag)
    	{
    		PX4_WARN("unrecognized flag");
    	}
    	else
    	{
    		if (_num1<=10000&&_num1>=-10000&&_num2<=10000&&_num2>=-10000)
    			{
    				_result=_num1+_num2;
    				PX4_INFO("The result is: %f",(double)_result);
    			}
    		else
    			{
    				PX4_WARN("Your data is beyond the limitation!");
    			}
    	}
    }
    //入口函数
    int my_example_app_main(int argc, char *argv[])
    {
    	//PX4_INFO("Hello Sky!");
    	//static bool module_start=false;
    	static AddtionCall add_num;
    	if (argc < 2)
    		{
    			PX4_WARN( "AddtionCall: my_example_app {start|stop|status|help|test -a num1 -b num2}");
    		}
    	if (!strcmp(argv[1], "start")&&argc==2)
    		{
    			//if(!module_start)
    			{
    				add_num.start();
    			}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "stop")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.stop();
    			// delete add_num;
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "status")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.status();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "help")&&argc==2)
    		{
    		//if (add_num!=NULL)
    		{
    			add_num.help();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "test")&&argc>2)
    	{
    		//if (add_num!=NULL)
    		{
    			add_num.my_example_app(argc, argv);
    		}
    		_exit(0);
    	}
    	else
    	{
    		PX4_INFO("This is my_example_app module, using for addition opreation. You can use the following command:");
    		PX4_INFO(" my_example_app start //---- start the module");
    		PX4_INFO(" my_example_app stop //---- stop the module");
    		PX4_INFO(" my_example_app status //---- show the current state of the module");
    		PX4_INFO("my_example_app help //---- show what you can do in this module");
    		PX4_INFO("my_example_app test -a num1 -b num2 //----caculate your data, there is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation. ");
    	}
    	return OK;
    }
    
    

    编译固件,打开终端输入:make px4_sitl_default gazebo,打开gazebo仿真,在终端继续输入my_example_app test -a 5 -b 5,计算得到两个数的加法。
    也可以通过数据线连接飞控板,打开QGC地面站,在MAVLink Console命令端口输入my_example_app test -a 5 -b 5,也可得到返回的计算结果。
    在这里插入图片描述

    三、飞控按指定频率计数,并将计数结果反馈到控制台

    1. 利用while循环实现计数

    在类中加入void run()函数专门处理计数任务,代码如下:

    void AddtionCall::run()
    {
    	hrt_abstime time_start = hrt_absolute_time();//取出系统当前时刻,时刻函数hrt_absolute_time()位于头文件#include <drivers/drv_hrt.h>中
    	float time_count=0;
    	while (_status)
    		{
    			usleep(WAITING_1S);//宏定义WAITING_1S=1000000,usleep(WAITING_1S)表示休眠1000000us也就是休眠1s
    			time_count=(float)hrt_elapsed_time(&time_start)/WAITING_1S;//计算当前时刻距离time_start时刻的时间间隔
    			PX4_INFO("count from start:%3.6f",(double)time_count);
    		}
    }
    

    start()函数中调用run()函数。
    在原代码中修改得到的完整程序为:

    #include <px4_posix.h>//包含了打印信息函数:PX4_INFO
    #include <px4_defines.h>//含有OK等定义
    #include <px4_getopt.h>//用于解析指令
    #include <stdlib.h>//基本函数库,如字符串转浮点数据的函数: atof
    #include <string.h>//用于字符串处理
    #include <drivers/drv_hrt.h>
    
    extern "C" __EXPORT int my_example_app_main(int argc, char *argv[]);
    
    #define WAITING_1S 1000000
    class AddtionCall
    {
    public:
    	/**
    	* Constructor
    	*/
    	AddtionCall();//构造函数
    
    	/**
    	* Destructor, also kills task.
    	*/
    	~AddtionCall();//析构函数
    
    	int start();
    	int stop();
    	void status();
    	void help();
    	void my_example_app(int argc, char *argv[]);
    	void run();
    
    
    private:
    	float _num1 ;//加数
    	float _num2;//被加数
    	float _result ;//结果
    	bool _status; //状态标志
    	hrt_abstime _time_start;
    };
    //构造函数
    AddtionCall::AddtionCall():
    
    _num1(0.0f),
    _num2(0.0f),
    _result(0.0f),
    _status(false)
    {
    	;
    }
    //析构函数
    AddtionCall::~AddtionCall()
    {
    _num1= 0.0f;
    _num2= 0.0f;
    _result = 0.0f;
    _status=false;
    }
    
    void AddtionCall::run()
    
    {
    	_time_start = hrt_absolute_time();
    	PX4_INFO("Time _start is:%3.6f",(double)_time_start);
    	float time_count=0;
    	while (_status)
    		{
    			usleep(WAITING_1S);//宏定义WAITING_1S=1000000,usleep(WAITING_1S)表示休眠1000000us也就是休眠1s
    			time_count=(float)hrt_elapsed_time(&_time_start)/WAITING_1S;//计算当前时刻距离time_start时刻的时间间隔
    			PX4_INFO("count from start:%3.6f",(double)time_count);
    		}
    
    
    }
    
    //开始函数
    int AddtionCall::start()
    {
    
    	if (_status)
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app");
    	}
    	else
    	{
    		_status=true;
    		PX4_INFO("Task start successful!");
    	}
    	run();
    	return 1;
    
    }
    //终止函数
    int AddtionCall::stop()
    {
    	_status=false;
    	PX4_INFO("Task has been stopped!");
    	return 1;
    }
    //状态函数
    void AddtionCall::status()
    {
    	if (!_status)
    	{
    		PX4_INFO("Task is is not running, please start it first ");
    	}
    	else
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app!");
    	}
    }
    //帮助函数
    void AddtionCall::help()
    {
    	PX4_INFO("This is my_example_app module, using for addition opreation. You can use the following command:");
    	PX4_INFO(" my_example_app start //---- start the module");
    	PX4_INFO(" my_example_app stop //---- stop the module");
    	PX4_INFO(" my_example_app status //---- show the current state of the module");
    	PX4_INFO("my_example_app help //---- show what you can do in this module");
    	PX4_INFO("my_example_app test -a num1 -b num2 //----caculate your data, There is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation.");
    }
    //运算函数
    void AddtionCall::my_example_app(int argc, char *argv[])
    {
    	bool error_flag=false;
    	int myoptind = 1;
    	int ch;
    	const char *myoptarg = nullptr;
    
    	while ((ch = px4_getopt(argc, argv, "a:b:", &myoptind, &myoptarg)) != EOF)
    	{
    		switch (ch) {
    		case 'a':
    			_num1= atof(myoptarg);
    			break;
    		case 'b':
    			_num2 = atof(myoptarg);
    			break;
    		default:
    			error_flag = true;
    			break;
    					}
    	}
    	if (error_flag)
    	{
    		PX4_WARN("unrecognized flag");
    	}
    	else
    	{
    		if (_num1<=10000&&_num1>=-10000&&_num2<=10000&&_num2>=-10000)
    			{
    				_result=_num1+_num2;
    				PX4_INFO("The result is: %f",(double)_result);
    			}
    		else
    			{
    				PX4_WARN("Your data is beyond the limitation!");
    			}
    	}
    }
    //入口函数
    int my_example_app_main(int argc, char *argv[])
    {
    	//PX4_INFO("Hello Sky!");
    	//static bool module_start=false;
    	static AddtionCall add_num;
    	if (argc < 2)
    		{
    			PX4_WARN( "AddtionCall: my_example_app {start|stop|status|help|test -a num1 -b num2}");
    		}
    	if (!strcmp(argv[1], "start")&&argc==2)
    		{
    			//if(!module_start)
    			{
    				add_num.start();
    			}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "stop")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.stop();
    			// delete add_num;
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "status")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.status();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "help")&&argc==2)
    		{
    		//if (add_num!=NULL)
    		{
    			add_num.help();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "test")&&argc>2)
    	{
    		//if (add_num!=NULL)
    		{
    			add_num.my_example_app(argc, argv);
    		}
    		_exit(0);
    	}
    	else
    	{
    		PX4_INFO("This is my_example_app module, using for addition opreation. You can use the following command:");
    		PX4_INFO(" my_example_app start //---- start the module");
    		PX4_INFO(" my_example_app stop //---- stop the module");
    		PX4_INFO(" my_example_app status //---- show the current state of the module");
    		PX4_INFO("my_example_app help //---- show what you can do in this module");
    		PX4_INFO("my_example_app test -a num1 -b num2 //----caculate your data, there is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation. ");
    	}
    	return OK;
    }
    
    

    上传固件到飞控后,在地面站控制台输入my_example_app start,飞控开始计数:
    在这里插入图片描述

    2. 利用hrt_call_every周期回调函数实现

    该函数为:void hrt_call_every(struct hrt_call *entry, hrt_abstime delay, hrt_abstime interval, hrt_callout callout, void *arg)
    位于头文件 #include <drivers/drv_hrt.h>中。其作用是以周期 interval (us) 循环调用函数 callout. 调用时间最多不超过 delay(单位 us,delay 要略大于interval), 且函数callout调用期间禁止中断。传感器 mpu6000的驱动中就使用了该函数,如下:

    hrt_call_every(&_call,
    				1000,
    				_call_interval - MPU6000_TIMER_REDUCTION,
    				(hrt_callout)&MPU6000::measure_trampoline, this);
    

    仍旧在my_example_app原代码中进行修改,得到该部分完整代码。

    3. 飞控创建新线程

    多线程所需要使用的函数在Nuttx中,相关函数的具体说明可参考Nuttx系统Porting Guide
    Nuttx可以运行两种线程:
    tasks: 各线程相互独立,每创建一个tasks都会产生一组新的描述符包括输入、输出和错误,子进程可以自由使用自己的描述符而不影响父进程。
    pthreads: 与父进程共享相同的描述符,子进程的操作将影响到父进程和父进程包含的所有子进程,互相共享资源。

    (1)task控制接口

    task_create函数:

    task_create(char *name, int priority, int stack_size, main_t entry, char *
    const argv[]);
    

    --------------函数说明------------------
    name:/任务名称
    priority:/任务优先级,有:SCHED_PRIORITY_MAX/SCHED_PRIORITY_MAX/
    SCHED_PRIORITY_MIN/SCHED_PRIORITY_IDLE等,具体参考头文件platforms/nuttx/NuttX/nuttx/include/sys/types.h
    stack_size:/栈大小,一般取2048
    entry:/线程主函数入口
    argv[]:/主函数入口参数

    通过创建task_create函数来解决上面无法在控制台打印信息的问题,主要过程如下:
    hrt_call_every函数定时精度较高,我们使用该函数计时,每隔1s,给相应的计时标志位;
    利用task_creat创建的主线程执行while循环任务,检测到计时标志位时(可以理解为中断),调用打印函数将计数信息打印到控制台。

    在类中定义新的打印信息函数和用于标志计数的变量,该变量定义为了静态变量,不能在构造函数内部初始化,只能在外面初始化赋值。

    int AddtionCall::run_info_print(int argc,char *argv[])
    {
    	while(_status)
    	{
    		if(!_tick_arrived)
    		{
    			_tick_arrived = true ;
    					PX4_INFO("count from start: %3.6f",(double)_time_count);
    			usleep(WAITING_1S-50);
    		}
    	}
    	return OK;
    }
    //新布尔变量类内定义
    ...
    static bool _tick_arrived;//注意是静态变量
    ...
    //类外初始化
    bool AddtionCall::_tick_arrived=false;
    
    
    1. start()函数修改:
    //开始函数
    int AddtionCall::start()
    {
    
    	if (_status)
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app");
    		return 0;
    	}
    
    	else
    	{
    		_status=true;
    		PX4_INFO("Task start successful!");
    	}
    	pid_t task_pid=task_create("addtion_call",
    						SCHED_PRIORITY_DEFAULT,
    						2048,
    						run_info_print,
    						NULL);
    	if(task_pid<0)
    	{
    		int errcode =errno;
    		PX4_INFO("ERROR:Failed to start addtion_call: \n");
    		return -errcode;
    	}
    	hrt_cancel(&_call);
    	_call_interval=WAITING_1S;
    	_time_start=hrt_absolute_time();
    
    	hrt_call_every(&_call,WAITING_1S+200,WAITING_1S,(hrt_callout)&AddtionCall::run_trampoline, this);
    
    	return 1;
    
    }
    

    完整程序如下:

    #include <px4_posix.h>//包含了打印信息函数:PX4_INFO
    #include <px4_defines.h>//含有OK等定义
    #include <px4_getopt.h>//用于解析指令
    #include <px4_log.h>
    #include <stdlib.h>//基本函数库,如字符串转浮点数据的函数: atof
    #include <string.h>//用于字符串处理
    #include <drivers/drv_hrt.h>
    #include  <sched.h>
    #include <errno.h>
    
    extern "C" __EXPORT int my_example_app_main(int argc, char *argv[]);
    
    #define WAITING_1S 1000000
    #define RUN_TIMER_REDUCTION 200000
    class AddtionCall
    {
    public:
    	/**
    	* Constructor
    	*/
    	AddtionCall();//构造函数
    
    	/**
    	* Destructor, also kills task.
    	*/
    	~AddtionCall();//析构函数
    
    	int start();
    	int stop();
    	void status();
    	void help();
    	void my_example_app(int argc, char *argv[]);
    	void run();
    	void calculate(int argc,char *argv[]);
    	static void  run_trampoline(void *arg);
    	static int run_info_print(int argc,char *argv[]);
    
    
    private:
    	float _num1 ;//加数
    	float _num2;//被加数
    	float _result ;//结果
    	static bool _status; //状态标志
    
    	struct hrt_call  _call;
    	unsigned   _call_interval;
    	hrt_abstime _time_start;
    	static float _time_count;
    	static bool _tick_arrived;
    
    };
    
    bool AddtionCall::_status=false;
    float AddtionCall::_time_count=0;
    bool AddtionCall::_tick_arrived= false;
    
    //构造函数
    AddtionCall::AddtionCall():
    
    _num1(0.0f),
    _num2(0.0f),
    _result(0.0f),
    //_status(false)
    _call{},
    _call_interval(1000),
    _time_start(0)
    {
    	memset(&_call,0,sizeof(_call));
    }
    //析构函数
    AddtionCall::~AddtionCall()
    {
    _num1= 0.0f;
    _num2= 0.0f;
    _result = 0.0f;
    _status=false;
    }
    
    void AddtionCall::run()
    
    {
    	_time_count=(float)hrt_elapsed_time(&_time_start)/WAITING_1S;
    	_tick_arrived=false;
    }
    void AddtionCall::run_trampoline(void *arg)
    {
    	AddtionCall *dev=(AddtionCall*)arg;
    	dev->run();
    }
    int AddtionCall::run_info_print(int argc,char *argv[])
    {
    	while(_status)
    	{
    		if(!_tick_arrived)
    		{
    			_tick_arrived = true ;
    					PX4_INFO("count from start: %3.6f",(double)_time_count);
    			usleep(WAITING_1S-50);
    		}
    	}
    	return OK;
    }
    //开始函数
    int AddtionCall::start()
    {
    
    	if (_status)
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app");
    		return 0;
    	}
    
    	else
    	{
    		_status=true;
    		PX4_INFO("Task start successful!");
    	}
    	pid_t task_pid=task_create("addtion_call",
    						SCHED_PRIORITY_DEFAULT,
    						2048,
    						run_info_print,
    						NULL);
    	if(task_pid<0)
    	{
    		int errcode =errno;
    		PX4_INFO("ERROR:Failed to start addtion_call: \n");
    		return -errcode;
    	}
    	hrt_cancel(&_call);
    	_call_interval=WAITING_1S;
    	_time_start=hrt_absolute_time();
    
    	hrt_call_every(&_call,WAITING_1S+200,WAITING_1S,(hrt_callout)&AddtionCall::run_trampoline, this);
    
    	return 1;
    
    }
    //终止函数
    int AddtionCall::stop()
    {
    	_status=false;
    	hrt_cancel(&_call);
    	PX4_INFO("Task has been stopped!");
    	return 1;
    }
    //状态函数
    void AddtionCall::status()
    {
    	if (!_status)
    	{
    		PX4_INFO("Task is is not running, please start it first ");
    	}
    	else
    	{
    		PX4_INFO("count from start: %3.6f",(double)_time_count);
    		PX4_INFO("Task is already running, now is waiting for data to calculate!");
    	}
    }
    //帮助函数
    void AddtionCall::help()
    {
    	PX4_INFO("This is calculate module, using for addition opreation. You can use the following command:");
    	PX4_INFO(" calculate start //---- start the module");
    	PX4_INFO(" calculate stop //---- stop the module");
    	PX4_INFO(" calculate status //---- show the current state of the module");
    	PX4_INFO("calculate help //---- show what you can do in this module");
    	PX4_INFO("calculate test -a num1 -b num2 //----caculate your data, There is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation.");
    }
    //运算函数
    void AddtionCall::calculate(int argc, char *argv[])
    {
    	bool error_flag=false;
    	int myoptind = 1;
    	int ch;
    	const char *myoptarg = nullptr;
    
    	while ((ch = px4_getopt(argc, argv, "a:b:", &myoptind, &myoptarg)) != EOF)
    	{
    		switch (ch) {
    		case 'a':
    			_num1= atof(myoptarg);
    			break;
    		case 'b':
    			_num2 = atof(myoptarg);
    			break;
    		default:
    			error_flag = true;
    			break;
    					}
    	}
    	if (error_flag)
    	{
    		PX4_WARN("unrecognized flag");
    	}
    	else
    	{
    		if (_num1<=10000&&_num1>=-10000&&_num2<=10000&&_num2>=-10000)
    			{
    				_result=_num1+_num2;
    				PX4_INFO("The result is: %f",(double)_result);
    			}
    		else
    			{
    				PX4_WARN("Your data is beyond the limitation!");
    			}
    	}
    }
    //入口函数
    int my_example_app_main(int argc, char *argv[])
    {
    	//PX4_INFO("Hello Sky!");
    	//static bool module_start=false;
    	static AddtionCall add_num;
    	if (argc < 2)
    		{
    			PX4_WARN( "AddtionCall: calculate {start|stop|status|help|test -a num1 -b num2}");
    		}
    	if (!strcmp(argv[1], "start")&&argc==2)
    		{
    			//if(!module_start)
    			{
    				add_num.start();
    			}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "stop")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.stop();
    			// delete add_num;
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "status")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.status();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "help")&&argc==2)
    		{
    		//if (add_num!=NULL)
    		{
    			add_num.help();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "test")&&argc>2)
    	{
    		//if (add_num!=NULL)
    		{
    			add_num.calculate(argc, argv);
    		}
    		_exit(0);
    	}
    	else
    	{
    		PX4_INFO("This is calculate module, using for addition opreation. You can use the following command:");
    		PX4_INFO(" calculate start //---- start the module");
    		PX4_INFO(" calculate stop //---- stop the module");
    		PX4_INFO(" calculate status //---- show the current state of the module");
    		PX4_INFO("calculate help //---- show what you can do in this module");
    		PX4_INFO("calculate test -a num1 -b num2 //----caculate your data, there is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation. ");
    	}
    	return OK;
    }
    
    

    运行结果如下,计数可通过my_example_app stop命令结束:
    在这里插入图片描述

    (2)phreads方式创建线程

    该方式以pthread.h文件和线程函数库实现,主要函数有:
    线程操纵函数:pthread_create()创建一个线程,pthread_exit()终止当前线程等;
    线程属性函数:pthread_attr_init()初始化线程属性变量等;
    在tasks线程基础上修改代码,完整程序如下:

    #include <px4_posix.h>//包含了打印信息函数:PX4_INFO
    #include <px4_defines.h>//含有OK等定义
    #include <px4_getopt.h>//用于解析指令
    #include <px4_log.h>
    #include <stdlib.h>//基本函数库,如字符串转浮点数据的函数: atof
    #include <string.h>//用于字符串处理
    #include <drivers/drv_hrt.h>
    #include  <sched.h>
    #include <errno.h>
    #include <pthread.h>
    
    extern "C" __EXPORT int my_example_app_main(int argc, char *argv[]);
    
    #define WAITING_1S 1000000
    #define RUN_TIMER_REDUCTION 200000
    class AddtionCall
    {
    public:
    	/**
    	* Constructor
    	*/
    	AddtionCall();//构造函数
    
    	/**
    	* Destructor, also kills task.
    	*/
    	~AddtionCall();//析构函数
    
    	int start();
    	int stop();
    	void status();
    	void help();
    	void my_example_app(int argc, char *argv[]);
    	void run();
    	void calculate(int argc,char *argv[]);
    	static void  run_trampoline(void *arg);
    	static int run_info_print(int argc,char *argv[]);
    	static void *run_phreads(void *context);
    	static void phreads_define();
    
    
    private:
    	float _num1 ;//加数
    	float _num2;//被加数
    	float _result ;//结果
    	static bool _status; //状态标志
    
    	struct hrt_call  _call;
    	unsigned   _call_interval;
    	hrt_abstime _time_start;
    	static float _time_count;
    	static bool _tick_arrived;
    	static pthread_t _thread;//线程ID
    	static pthread_mutex_t _value_mutex;//互斥锁
    
    };
    
    bool AddtionCall::_status=false;
    float AddtionCall::_time_count=0;
    bool AddtionCall::_tick_arrived= false;
    pthread_t  AddtionCall::_thread = {};
    pthread_mutex_t  AddtionCall::_value_mutex={};
    
    //构造函数
    AddtionCall::AddtionCall():
    
    _num1(0.0f),
    _num2(0.0f),
    _result(0.0f),
    //_status(false)
    _call{},
    _call_interval(1000),
    _time_start(0)
    {
    	memset(&_call,0,sizeof(_call));
    }
    //析构函数
    AddtionCall::~AddtionCall()
    {
    _num1= 0.0f;
    _num2= 0.0f;
    _result = 0.0f;
    _status=false;
    }
    
    void AddtionCall::run()
    
    {
    	_time_count=(float)hrt_elapsed_time(&_time_start)/WAITING_1S;
    	_tick_arrived=false;
    }
    void AddtionCall::run_trampoline(void *arg)
    {
    	AddtionCall *dev=(AddtionCall*)arg;
    	dev->run();
    }
    int AddtionCall::run_info_print(int argc,char *argv[])
    {
    	while(_status)
    	{
    		if(!_tick_arrived)
    		{
    			_tick_arrived = true ;
    					PX4_INFO("count from start1: %3.6f",(double)_time_count);
    			usleep(WAITING_1S-50);
    		}
    	}
    	return OK;
    }
    void  *AddtionCall::run_phreads(void *context)
    {
    	while(_status)
    	{
    		if(!_tick_arrived)
    		{
    			pthread_mutex_lock(&_value_mutex);
    
    			pthread_mutex_unlock(&_value_mutex);
    					PX4_INFO("count from start2: %3.6f",(double)_time_count);
    			usleep(WAITING_1S-50);
    		}
    	}
    	return OK;
    }
    void AddtionCall::phreads_define()
    {
    	//属性设置
    	pthread_attr_t  runloop_attr;
    	pthread_attr_init(&runloop_attr);
    
    	struct sched_param param;
    	(void)pthread_attr_getschedparam(&runloop_attr,&param);
    	param.sched_priority=SCHED_PRIORITY_MAX -100;
    	(void)pthread_attr_setschedparam(&runloop_attr,&param);
    
    	pthread_attr_setstacksize(&runloop_attr,PX4_STACK_ADJUSTED(2840));
    	//创建线程
    	pthread_create(&_thread, &runloop_attr, AddtionCall::run_phreads, NULL);
    
    }
    
    
    
    
    //开始函数
    int AddtionCall::start()
    {
    
    	if (_status)
    	{
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app");
    		return 0;
    	}
    
    	else
    	{
    		_status=true;
    		PX4_INFO("Task start successful!");
    	}
    	pid_t task_pid=task_create("addtion_call",
    						SCHED_PRIORITY_DEFAULT,
    						2048,
    						run_info_print,
    						NULL);
    	if(task_pid<0)
    	{
    		int errcode =errno;
    		PX4_INFO("ERROR:Failed to start addtion_call: \n");
    		return -errcode;
    	}
    	hrt_cancel(&_call);
    	_call_interval=WAITING_1S;
    	_time_start=hrt_absolute_time();
    
    	hrt_call_every(&_call,WAITING_1S+200,WAITING_1S,(hrt_callout)&AddtionCall::run_trampoline, this);
    
    	/* initialize send mutex */
    	pthread_mutex_init(&AddtionCall::_value_mutex, nullptr);
    	phreads_define();
    	return 1;
    
    }
    //终止函数
    int AddtionCall::stop()
    {
    	_status=false;
    	hrt_cancel(&_call);
    	pthread_join(_thread, nullptr);
    	PX4_INFO("Task has been stopped!");
    	return 1;
    }
    //状态函数
    void AddtionCall::status()
    {
    	if (!_status)
    	{
    		PX4_INFO("Task is is not running, please start it first ");
    	}
    	else
    	{
    		PX4_INFO("count from start3: %3.6f",(double)_time_count);
    		PX4_INFO("Task is already running, now is waiting for data to my_example_app!");
    	}
    }
    //帮助函数
    void AddtionCall::help()
    {
    	PX4_INFO("This is my_example_app module, using for addition opreation. You can use the following command:");
    	PX4_INFO(" my_example_app start //---- start the module");
    	PX4_INFO(" my_example_app stop //---- stop the module");
    	PX4_INFO(" my_example_app status //---- show the current state of the module");
    	PX4_INFO("my_example_app help //---- show what you can do in this module");
    	PX4_INFO("my_example_appte test -a num1 -b num2 //----caculate your data, There is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation.");
    }
    //运算函数
    void AddtionCall::calculate(int argc, char *argv[])
    {
    	bool error_flag=false;
    	int myoptind = 1;
    	int ch;
    	const char *myoptarg = nullptr;
    
    	while ((ch = px4_getopt(argc, argv, "a:b:", &myoptind, &myoptarg)) != EOF)
    	{
    		switch (ch) {
    		case 'a':
    			_num1= atof(myoptarg);
    			break;
    		case 'b':
    			_num2 = atof(myoptarg);
    			break;
    		default:
    			error_flag = true;
    			break;
    					}
    	}
    	if (error_flag)
    	{
    		PX4_WARN("unrecognized flag");
    	}
    	else
    	{
    		if (_num1<=10000&&_num1>=-10000&&_num2<=10000&&_num2>=-10000)
    			{
    				_result=_num1+_num2;
    				PX4_INFO("The result is: %f",(double)_result);
    			}
    		else
    			{
    				PX4_WARN("Your data is beyond the limitation!");
    			}
    	}
    }
    //入口函数
    int my_example_app_main(int argc, char *argv[])
    {
    	//PX4_INFO("Hello Sky!");
    	//static bool module_start=false;
    	static AddtionCall add_num;
    	if (argc < 2)
    		{
    			PX4_WARN( "AddtionCall: my_example_app {start|stop|status|help|test -a num1 -b num2}");
    		}
    	if (!strcmp(argv[1], "start")&&argc==2)
    		{
    			//if(!module_start)
    			{
    				add_num.start();
    			}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "stop")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.stop();
    			// delete add_num;
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "status")&&argc==2) {
    		//if (add_num!=NULL)
    		{
    			add_num.status();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "help")&&argc==2)
    		{
    		//if (add_num!=NULL)
    		{
    			add_num.help();
    		}
    		_exit(0);
    		}
    	else if (!strcmp(argv[1], "test")&&argc>2)
    	{
    		//if (add_num!=NULL)
    		{
    			add_num.calculate(argc, argv);
    		}
    		_exit(0);
    	}
    	else
    	{
    		PX4_INFO("This is my_example_app module, using for addition opreation. You can use the following command:");
    		PX4_INFO(" my_example_app start //---- start the module");
    		PX4_INFO(" my_example_app stop //---- stop the module");
    		PX4_INFO(" my_example_app status //---- show the current state of the module");
    		PX4_INFO("my_example_app help //---- show what you can do in this module");
    		PX4_INFO("my_example_app test -a num1 -b num2 //----caculate your data, there is a limit that \"a<=10000 and a>=-10000\", and ’b’ has the same limitation. ");
    	}
    	return OK;
    }
    

    完成程序包含tasks和pthreads两个线程的计数,所以控制台中两个计数进程同时打印计数信息。
    在这里插入图片描述

    四、uORB通信发布和订阅数据

    飞控各个功能模块之间是独立运行的,但对整个系统来说,进程间需要有数据传输,这需要uORB通信机制来实现。
    uORB机制包含两个部分,功能模块订阅和发布;

    • 模块订阅数据:订阅主题、设置订阅数据最小间隔、检查数据更新、拷贝数据;
    • 模块发布数据:公告主题、发布主题数据、取消订阅主题。
      在这里插入图片描述uORB消息A、B、C、D在源码中是预先定义的结构体变量,是由.msg文件编译自动生成的,所有可以订阅或者发布的数据均可以在Firmware/msg/文件夹下找到。这些消息我们可以理解为预先定义好的全局变量,任何功能模块都能去读写,但需要通过特定的订阅和发布过程。
      注意uORB通信不能用于进程内通信,一个功能模块不能既订阅某主题的同时又发布该主题。

    1.模块订阅数据

    1. 订阅数据需要先订阅该数据主题,使用的函数格式为:
    int orb_subscribe(const struct orb_metadata *meta)
    参数:meta:uORB元对象,可以认为是主题id;
    返回值:正确返回一个句柄,句柄是你自己定义的,初始化为-1,
    eg:
    int my_topic_sub=-1;
    int my_topic_sub = orb_subscribe(ORB_ID(my_topic));
    句柄在某种程度上可以理解为订阅主题的地址.
    

    注意:函数都是直接对句柄操作,句柄的初始化放在进程的初始化部分。

    1. 设置订阅数据更新周期
      我们可以自己设定读取的频率,这个类似于多长时间去读一次,也有很多模块不设置就会一直检测。
      eg:orb_set_interval(sensor_sub_fd, 1000);
      参数:handle:orb_subscribe函数返回的句柄;
         interval:间隔时间,单位ms;
      该函数返回OK表示成功;返回ERROR表示错误。

    2. 检查数据更新
      订阅数据后需要知道数据是否更新,检查数据更新的方法有两种:第一是阻塞等待,就是程序卡在此处等着更新;第二种是使用while循环周期性的检查:
      阻塞等待函数格式:

    int poll(struct pollfd fds[], nfds_t nfds, int timeout)
    参数:fds[]:结构类型的数组,进程可以同时等待很多个主题数据,当有数据更新时,判断一下是谁;fd也经常被称为文件描述符
    nfds:用于标记数组fds中的结构体元素的总数量;
    timeout:阻塞时间,单位是ms,即如果timeout=1000,那么就是1000ms=1s。
    eg:
    //定义阻塞等待结构体,下面的定义中实际该结构体只有一个成员
    px4_pollfd_struct_t fds[] =
    {
    	{ .fd = sensor_sub_fd,
     	 .events = POLLIN },//sensor_sub_fd是订阅主题返回的句柄
    };
    //阻塞等待
    int poll_ret = px4_poll(fds, 1, 1000);
    

    timeout是最长等待时间,返回为0表示超过最长等待时间没有等到数据更新;>0就是在时间内收到了数据,<0表示出错。如果正常拿到数据,函数返回的是拿到数据剩下的阻塞时间。
    检查更新函数格式为:

    int orb_check(int handle, bool *updated)
    参数:handle:句柄
        *updated:是否更新的标志位,如果主题数据已经更新了,那么updated会被设置为true。
    eg:下面是一个从订阅到检查更新到拷贝数据到最后关闭订阅的完整过程
    int subsys_sub = orb_subscribe(ORB_ID(subsystem_info));//订阅数据
    	struct subsystem_info_s info;
    	memset(&info, 0, sizeof(info));
    	...
    orb_check(subsys_sub, &updated);//检查数据有没有更新
    	if (updated) {
    		orb_copy(ORB_ID(subsystem_info), subsys_sub, &info);//拷贝数据
    		}
    ...
    //px4_close(subsys_sub);//一般在最后线程退出后,飞控不再工作后才需要
    orb_unsubscribe(subsys_sub);//一般在析构函数里会使用
    

    调用orb_copy函数接收、处理数据后,updated会自动设置为false,所以这种方式在被第一次检测到后,后面再检测时就不再算是新数据了。

    1. 拷贝数据
      函数格式为:
    int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
    参数:meta:消息ID
         handle:句柄
         buffer: 存放拷贝出的数据,是自己事先定义的数据结构类型
    返回值:拷贝成功,返回OK(0)
    eg:
    sensor_combined_s raw ;//结构体变量,和发布主题数据的格式一致
    orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
    
    1. 取消订阅数据
    int orb_unsubscribe(int handle)
    参数:handle:主题句柄;
    返回值:OK表示成功;错误返回ERROR;否则则有根据的去设置errno;
    eg:
    ret = orb_unsubscribe(handle);
    

    2.模块发布数据

    发布数据主要分为公告主题和发布主题两部分:

    1. 公告主题:
    1.orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
    功能:先公告主题,相当于注册,只要一次就行了。meta为公告的消息ID,data为公告的原始数据。
    说明:在发布主题之前是必须的;否则订阅者虽然能订阅,但是得不到数据;
    eg:
    orb_advert_t _to_system_power;
    _to_system_power(nullptr)//一般要先在构造函数中初始化成nullptr
    _to_system_power = orb_advertise(ORB_ID(system_power), &system_power);
    2.orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void
    *data, int *instance,int priority)
    说明:主要用于同一主题的多个数据来源的发布,比如飞控连接了多个超声波传感器,那么可
    以发布到同一主题下;同时,需要订阅的时候,也是用:
    int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)进行订阅。
    eg:_distance_sensor_topic = orb_advertise_multi(ORB_ID(distance_sensor), &ds_report,&_orb_class_instance, ORB_PRIO_LOW);
    
    1. 发布主题数据
    int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
    功能:公告之后就可以发布主题数据。meta为公告的消息ID,handle为公告返回的句柄,这个句柄初始化为null,data为发布的数据。
    
    1. 新建主题
      首先如果我们需要订阅和公告的主题已经存在,通过上面的方式就能完成数据的订阅或发布。否则需要新建这个主题,新建主题的步骤如下:
      在目录Firmware/msg/下,新建文件my_test_data.msg,在其中写入:
    #Date:2020年11月16日
    #File name:my_test_data.msg
    #Author:李俊龙
    #说明:新建一个消息主题
    uint64 timestamp	# time since system start (microseconds)
    uint8  my_test_data     #测试数据   
    

    .msg必须定义时间戳变量,否则无法编译。
    接着在Firmware/msg/下的CMakeList.txt文件中,添加my_test_data.msg
    在这里插入图片描述打开终端编译固件,系统会在Firmware/build/px4_fmu-v3_default/uORB/topics/文件夹中自动生成对应的头文件my_test_data.h
    在这里插入图片描述

    展开全文
  • PX4 飞控源码系统框架介绍 osc_ozmm6ila 2019/12/31 17:19 阅读数 618 一、build_px4fmu-v2_default  编译以后生成的文件:内部主要需要在意的就是topics_temporary_header(所有的任务是要的头文件,在创建...
  • PX4 飞控剖析】03 PX4固件烧录以及QGC初步指南一、加载固件二、加载参数三、校准传感器四、遥控器校准五、飞行模式六、电调校准七、检查参数 一、加载固件 打开电脑QGroundControl 将飞控通过USB线连上电脑,右边...
  • MAVROS接收PX4飞控消息

    千次阅读 2021-01-15 20:38:10
    MAVROS接收PX4飞控消息 使用px4飞控,外接控制器,实现实时读取飞控信息的功能。部分飞控信息已能够通过mavros接收并读取,例如"mavros/local_position/pose",部分飞控信息则没有通过mavros发送。本篇博客针对这...
  • PX4飞控连接Mavros

    2021-09-12 23:38:12
    首先NX开发板与PX4飞控连线正确 进入地面站>>参数>>搜索mav_1_config>>改成telem2 重启飞控,查看Telem2的波特率是否为921600 若是,则在NX开发板终端内输入: roslaunch mavros px4.launch ...
  • PX4学习过程遇到的问题及解决方法一、 安装时遇到的问题二、 添加环境变量 一、 安装时遇到的问题 1.安装时使用amov制作的ubuntu18.04环境包,该系统是通过systemback软件打包好的ubuntu系统,省去了PX4和ros等环境...
  • pi4飞控,地面站数据全部正常,为什么遥控器不能解锁电机,还有就是pi4飞控怎么校准电池已经遥控器
  • px4飞控调试方法

    千次阅读 2020-12-24 09:43:15
    4. 你发的文档我看了,对比 3.3.2 和 3.2.1 版本,确实是 3.3.2 才会发送这个信息。 3.2.1 没有 这个消息。 文档说 “这个是地面站算出来的”是不对的。 这个消息是飞控发出的。 数学上就是磁场采样 值方差超差。 ...
  • 本篇博客介绍如何利用XBee模块实现QGC地面站与飞控的通信
  • 为了实现自主飞行,无人机需要许多的感知设备,而F4/F7/H7所搭载的传感器都很有限,因此需要...本文主要解决如何在F4 pro V2飞控上挂载可与飞控连接的传感器设备,从而实现基于F4 pro V2飞控的基本自主飞行能力。......
  • ubuntu18.04配置px4飞控环境 2020.12.17 环境:VMWare workstation player 16 + ubuntu18.04及以上的系统(强烈不建议16.04) 一、安装、配置git 由于px4在make时会检测.git文件夹的内容,因此务必使用git clone获取...
  • px4+vins+ego单机鲁棒飞行四(PX4飞控日志分析篇)一、FlightPlot安装二、记录日志二、取出日志三、分析日志 一、FlightPlot安装 参考博客 参考视频 二、记录日志 在QGC中参数SDLOG_MODE可以设置什么时候开始记录...
  • PX4飞控的PPM接收机

    千次阅读 2018-07-03 13:10:57
     PX4飞控的PPM输入捕获由协处理器完成,接在A8引脚,对应Timer1的通道1。 (二)PPM协议:  PPM的每一帧数据间隔为20ms,用两个上升沿之间的时间间隔表示一个通道的值,如图所示是一个6通道信号。在每一帧的结束...
  • PX4飞控之导航及任务架构

    千次阅读 2018-03-01 11:27:47
    感谢博主的分享,原文地址:http://blog.csdn.net/zhenglongf/article/details/77775658本文重点介绍PX4飞控的Navigator和mission控制框架和逻辑。Navigator导航部分是无人机自主飞行控制的核心所在,其中包括自主...
  • PX4飞控学习(一)

    千次阅读 2017-09-16 16:04:14
    PX4项目学习(一)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,103
精华内容 841
关键字:

px4飞控

友情链接: read-Access-program.rar