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


登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP

1