PX4-7-飞控参数

参数是PX4飞控中掉电保存的变量,用于存储飞控的设置、校准系数等数据。

PX4有一套完善的参数框架,对于用户而言只需要非常简单的几个语句就可以完成参数的添加、读取和写入操作。

这一篇我们简单聊一下PX4的参数机制,这部分内容不是所有同学都会用的到,不过有一个框架性的认识对于熟悉PX4的框架也有一定的帮助。

我们以1.11.3版本为例,简单的描述一下PX4的参数操作流程:

代码构建

在编译构建时PX4执行src/lib/parameters/CMakeLists.txt 中脚本文件 px_process_params.py ,这个脚本会历遍所有的源码目录,找到xxx_params.c文件,根据这个文件生成parameters.xml文件。这个文件自动创建在build/xxx/parameters.xml中。

然后执行 px_generate_params.py 脚本,根据parameters.xml文件生成参数头文件和c文件,生成的文件在build/xxx/src/lib/parameters目录下。

稍微阅读这几个文件,里面主要定义了所有参数的名称、数据类型和默认值。

载入参数文件

在PX4启动脚本(ROMFS/px4fmu_common/init.d/rcS)中执行参数载入操作从存储器中读取参数

# Set the parameter file if mtd starts successfully.
if mtd start
then
set PARAM_FILE /fs/mtd_params
fi
# Load parameters.
param select $PARAM_FILE
if ! param load
then
param reset
fi

加载参数文件后,会更新build/xxx/src/lib/parameters/px4_parameters.c文件在中px4_parameters结构体的数据,这就是PX4所有参数的参数表了,在文件尾部显示了参数总数,有近千个参数。

应用加载参数

应用中使用参数比较简单,添加几条语句就可以,我们以代码比较简单的src/drivers/heater/heater.cpp模块为例。

  • 参数变量定义

    在头文件中通过参数宏结构进行参数变量的定义

    DEFINE_PARAMETERS(
    (ParamFloat<px4::params::SENS_IMU_TEMP_I>)  _param_sens_imu_temp_i,
    (ParamFloat<px4::params::SENS_IMU_TEMP_P>)  _param_sens_imu_temp_p,
    (ParamInt<px4::params::SENS_TEMP_ID>) _param_sens_temp_id,
    (ParamFloat<px4::params::SENS_IMU_TEMP>) _param_sens_imu_temp
    )
  • 更新参数

    在源文件中添加变量更新函数,检测变量是否发生变化,更新变量

    void Heater::update_params(const bool force)
    {
       // check for parameter updates
       if (_parameter_update_sub.updated() || force) {
           // clear update
           parameter_update_s pupdate;
           _parameter_update_sub.copy(&pupdate);

           // update parameters from storage
           ModuleParams::updateParams();
    }
    }

应用加载与更新参数的机制

在应用的头文件中,通过 DEFINE_PARAMETERS 宏完成参数变量类的定义,我们可以看一下这个宏的内容:

#define _DEFINE_SINGLE_PARAMETER(x) \
 do_not_explicitly_use_this_namespace::PAIR(x);

#define _CALL_UPDATE(x) \
 STRIP(x).update();

#define _DEFINE_PARAMETER_UPDATE_METHOD(...) \
 protected: \
 void updateParamsImpl() final { \
   APPLY_ALL(_CALL_UPDATE, __VA_ARGS__) \
 } \
 private:

#define DEFINE_PARAMETERS(...) \
 APPLY_ALL(_DEFINE_SINGLE_PARAMETER, __VA_ARGS__) \
 _DEFINE_PARAMETER_UPDATE_METHOD(__VA_ARGS__)

从内容我们可以大致了解,这里使用命名空间 do_not_explicitly_use_this_namespace中参数类定义参数变量,并且定义了应用中所有参数的更新类updateParamsImpl,这个函数在上一部分的ModuleParams::updateParams()中调用,里面的实现为

class ModuleParams
{
   virtual void updateParams()
   {
       for (const auto &child : _children) {
         child->updateParams();
       }
       updateParamsImpl();
   }
}

在参数更新时,使用STRIP(x).update() 方法更新应用中每个使用到的参数,这个方法定义在do_not_explicitly_use_this_namespace中:

bool update()
{
int32_t value_int;
int ret = param_get(handle(), &value_int);

if (ret == 0) {
_val = value_int != 0;
return true;
}

return false;
}

这些宏定义中值得注意的是APPLY_ALL()方法,这个宏定义使代码中展开复杂的结构,为应用的头文件中定义的所有变量展开变量定义和update()方法,其目的是使代码更加简洁。

这样的宏定义方式大家感兴趣也可以参考一下,减少重复性代码可以使自己的代码结构更加简洁清晰。

参数更新消息

可以发现PX4使用了uORB机制向所有使用参数的应用广播参数的变化,每个使用参数的应用都会订阅 uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)}; 消息。在检测到参数更新时去更新应用使用到的参数值。

这样的设计有好处是处理方式统一,结构简洁。

当然它的代价是在一个参数发生更新时,所有的应用都会收到更新通知去检查更新自己使用的参数。

总结

以上是PX4的参数系统的大致机制,当然还有很多非常有意思的细节信息没有展开。这些信息对于使用而言没有作用不大,对于希望磨砺自己代码能力的同学却是不错的参考,里面使用到的宏定义、模板类、代码生成等等都是不错的学习参考。

源自: AcmeUavs


默认 最新
当前暂无评论,小编等你评论哦!
点赞 评论 收藏
关注