参考链接:PX4 User Guide - Development - Applicaiton/Module Template。
一、基于话题订阅决定运行频率
- 在 Firmware/src/modules 下新建文件夹 mc_self_check,并在里面添加 MulticopterSelfCheck.cpp,MulticopterSelfCheck.hpp 和 CMakeLists.txt 三个文件。
- 按照官方给的模板,也参考PX4源文件 Firmware/src/modules/mc_att_control 中的文件写法,三个文件内容分别如下
MulticopterSelfCheck.hpp
#pragma once
#include <drivers/drv_hrt.h>
#include <lib/perf/perf_counter.h>
#include <lib/systemlib/mavlink_log.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/defines.h>
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>
#include <matrix/matrix/math.hpp>
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>
#include <uORB/SubscriptionCallback.hpp>
#include <uORB/topics/manual_control_switches.h>
#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/vehicle_attitude.h>
using namespace time_literals;
class MulticopterSelfCheck :
public ModuleBase<MulticopterSelfCheck>,
public ModuleParams,
public px4::WorkItem
{
public:
MulticopterSelfCheck();
~MulticopterSelfCheck() override;
bool init();
static int task_spawn(int argc, char *argv[]);
static int custom_command(int argc, char *argv[]);
static int print_usage(const char *reason = nullptr);
private:
hrt_abstime _time_stamp_last_loop{0};
void Run() override;
perf_counter_t _loop_perf;
uORB::SubscriptionCallbackWorkItem _local_pos_sub{this, ORB_ID(vehicle_local_position)};
uORB::Subscription _vehicle_attitude_sub{ORB_ID(vehicle_attitude)};
uORB::Subscription _manual_control_switches_sub{ORB_ID(manual_control_switches)};
};
MulticopterSelfCheck.cpp
#include "MulticopterSelfCheck.hpp"
#include <stdio.h>
MulticopterSelfCheck::MulticopterSelfCheck():
ModuleParams(nullptr),
WorkItem(MODULE_NAME, px4::wq_configurations::rate_ctrl),
_loop_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": cycle"))
{
}
MulticopterSelfCheck::~MulticopterSelfCheck()
{
perf_free(_loop_perf);
}
bool MulticopterSelfCheck::init()
{
if (!_local_pos_sub.registerCallback()) {
PX4_ERR("vehicle_local_position callback registration failed!");
return false;
}
return true;
}
void MulticopterSelfCheck::Run()
{
if (should_exit()){
_local_pos_sub.unregisterCallback();
exit_and_cleanup();
return;
}
perf_begin(_loop_perf);
vehicle_local_position_s local_pos;
if (_local_pos_sub.update(&local_pos)) {
const hrt_abstime time_stamp_now = local_pos.timestamp;
const float dt = math::constrain(((time_stamp_now - _time_stamp_last_loop) * 1e-6f), 0.002f, 0.04f);
_time_stamp_last_loop = time_stamp_now;
printf("dt = %f\r\n", (double)dt);
}
perf_end(_loop_perf);
}
int MulticopterSelfCheck::task_spawn(int argc, char *argv[])
{
MulticopterSelfCheck *instance = new MulticopterSelfCheck();
if (instance) {
_object.store(instance);
_task_id = task_id_is_work_queue;
if (instance->init()) {
return PX4_OK;
}
} else {
PX4_ERR("alloc failed");
}
delete instance;
_object.store(nullptr);
_task_id = -1;
return PX4_ERROR;
}
int MulticopterSelfCheck::custom_command(int argc, char *argv[])
{
return print_usage("unknown command");
}
int MulticopterSelfCheck::print_usage(const char *reason)
{
if (reason) {
PX4_WARN("%s\n", reason);
}
PRINT_MODULE_DESCRIPTION(
R"DESCR_STR(
### Description
Self check.
)DESCR_STR");
PRINT_MODULE_USAGE_NAME("mc_self_check", "check");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
return 0;
}
extern "C" __EXPORT int mc_self_check_main(int argc, char *argv[])
{
return MulticopterSelfCheck::main(argc, argv);
}
CMakeLists.txt
px4_add_module(
MODULE modules__mc_self_check
MAIN mc_self_check
COMPILE_FLAGS
${MAX_CUSTOM_OPT_LEVEL}
SRCS
MulticopterSelfCheck.cpp
MulticopterSelfCheck.hpp
DEPENDS
px4_work_queue
)
- 添加编译指令
在 Firmware/boards/px4/sitl/default.cmake 下的 px4_add_board 函数的 MODULES 后加上mc_self_check
。
一些版本的PX4需要 Kconfig 文件,并且使用指令进行配置编译项。Kconfig例子如下
menuconfig MODULES_MC_SELF_CHECK
bool "self_check"
default n
---help---
Enable support for self_check
menuconfig USER_MC_SELF_CHECK
bool "mc_self_check running as userspace module"
default y
depends on BOARD_PROTECTED && MODULES_MC_SELF_CHECK
---help---
Put self_check in userspace memory
指令为
make px4_sitl_default boardconfig
随后选择需要编译的文件。
-
添加启动命令
在 Firmware/ROMFS/px4fmu_common/init.d/rc.mc_apps 最后加上mc_self_check start
。 -
编译运行
先清除编译,否则可能会报错。依次执行以下指令
make clean
make px4_sitl_default gazebo
最终可见如下输出
该输出是在 Multicopter.cpp/MulticopterSelfCheck::Run() 中编写的。
二、定时执行任务
如果要定时执行,修改代码如下
MulticopterSelfCheck.hpp
/**
* Multicopter self-check.
*/
#pragma once
#include <drivers/drv_hrt.h>
#include <lib/perf/perf_counter.h>
#include <lib/systemlib/mavlink_log.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/defines.h>
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>
#include <px4_platform_common/posix.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include <matrix/matrix/math.hpp>
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>
#include <uORB/SubscriptionCallback.hpp>
#include <uORB/topics/manual_control_switches.h>
#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/vehicle_attitude.h>
using namespace time_literals;
class MulticopterSelfCheck :
public ModuleBase<MulticopterSelfCheck>,
public ModuleParams,
//public px4::WorkItem
public px4::ScheduledWorkItem // different
{
public:
MulticopterSelfCheck();
~MulticopterSelfCheck() override;
bool init();
static int task_spawn(int argc, char *argv[]);
static int custom_command(int argc, char *argv[]);
static int print_usage(const char *reason = nullptr);
private:
hrt_abstime _time_stamp_last_loop{0};
void Run() override;
perf_counter_t _loop_perf;
uORB::SubscriptionCallbackWorkItem _local_pos_sub{this, ORB_ID(vehicle_local_position)};
uORB::Subscription _vehicle_attitude_sub{ORB_ID(vehicle_attitude)};
uORB::Subscription _manual_control_switches_sub{ORB_ID(manual_control_switches)};
};
MulticopterSelfCheck.cpp
#include "MulticopterSelfCheck.hpp"
MulticopterSelfCheck::MulticopterSelfCheck():
ModuleParams(nullptr),
//WorkItem(MODULE_NAME, px4::wq_configurations::rate_ctrl),
ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::rate_ctrl), // different
_loop_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": cycle"))
{
}
MulticopterSelfCheck::~MulticopterSelfCheck()
{
perf_free(_loop_perf);
}
bool MulticopterSelfCheck::init()
{
// if (!_local_pos_sub.registerCallback()) {
// PX4_ERR("vehicle_local_position callback registration failed!");
// return false;
// }
ScheduleOnInterval(50000_us); // different
return true;
}
void MulticopterSelfCheck::Run()
{
if (should_exit()){
_local_pos_sub.unregisterCallback();
exit_and_cleanup();
return;
}
perf_begin(_loop_perf);
const hrt_abstime time_stamp_now = hrt_absolute_time();
const float dt = (time_stamp_now - _time_stamp_last_loop) * 1e-6f;
_time_stamp_last_loop = time_stamp_now;
printf("dt = %f\r\n", (double)dt);
perf_end(_loop_perf);
}
int MulticopterSelfCheck::task_spawn(int argc, char *argv[])
{
MulticopterSelfCheck *instance = new MulticopterSelfCheck();
if (instance) {
_object.store(instance);
_task_id = task_id_is_work_queue;
if (instance->init()) {
return PX4_OK;
}
} else {
PX4_ERR("alloc failed");
}
delete instance;
_object.store(nullptr);
_task_id = -1;
return PX4_ERROR;
}
int MulticopterSelfCheck::custom_command(int argc, char *argv[])
{
return print_usage("unknown command");
}
int MulticopterSelfCheck::print_usage(const char *reason)
{
if (reason) {
PX4_WARN("%s\n", reason);
}
PRINT_MODULE_DESCRIPTION(
R"DESCR_STR(
### Description
Self check.
)DESCR_STR");
PRINT_MODULE_USAGE_NAME("mc_self_check", "check");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
return 0;
}
extern "C" __EXPORT int mc_self_check_main(int argc, char *argv[])
{
return MulticopterSelfCheck::main(argc, argv);
}
在 init() 中决定运行频率,此时是50000us=50ms,运行结果如下
并不是精确度50ms=0.05s,这主要是由于该循环也有一定调用周期,好像是250Hz=4ms,因此很难刚好总在0.05s。