1. 参数
ArduPilot有数百个参数,允许用户配置车辆飞行/驾驶的许多方面,包括姿态控制器增益等。
地面站或机载计算机如何利用mavlink实现修改飞控固件中的参数??
2. 在飞控代码中是通过参数的名字进行定位查找别设值的
其中 param_id 是 https://ardupilot.org/copter/docs/parameters.html 中的参数名,类型是 char.
3. 进入正题
F12进线程 SCHED_TASK_CLASS(GCS, (GCS*)&copter._gcs, update_receive, 400, 180, 102),
update_receive ~> packetReceived ~> packetReceived ~> handleMessage ~> handle_common_message ~> handle_common_param_message ~> handle_param_set(以此为例)
不难发现
接收MavLink消息后会经过以下几个过程:
- 解码 mavlink_msg_param_set_decode(&msg, &packet);
- 根据参数名(msg_id)找到该参数 vp = AP_Param::find(key, &var_type, ¶meter_flags);
- 赋值 vp->set_float(packet.param_value, var_type);
是如何完成赋值的?最终要将MavLink传进来的值赋给哪个具体名字的变量(或对象)??
容我慢慢道来
针对具体编译的机型,所有被使用的参数登记在Copter::var_info[]中;(以copter机型为例)
它的幅值在ArduCopter\Parameters.cpp中;
struct Info {
const char *name;
const void *ptr; // pointer to the variable in memory
union {
const struct GroupInfo *group_info;
const struct GroupInfo **group_info_ptr; // when AP_PARAM_FLAG_INFO_POINTER is set in flags
const float def_value;
ptrdiff_t def_value_offset; // Default value offset from param object, when AP_PARAM_FLAG_DEFAULT_POINTER is set in flags
};
uint16_t flags;
uint16_t key; // k_param_*
uint8_t type; // AP_PARAM_*
};
参数现在数组Copter::var_info[]中等级,然后为每个参数构造一个AP_Param类型:
// constructor with var_info
AP_Param(const struct Info *info)
{
_var_info = info;
uint16_t i;
for (i=0; info[i].type != AP_PARAM_NONE; i++) ;
_num_vars = i;
#if AP_PARAM_DYNAMIC_ENABLED
_num_vars_base = _num_vars;
#endif
if (_singleton != nullptr) {
AP_HAL::panic("AP_Param must be singleton");
}
_singleton = this;
}
那具体的参数在底层是如何获取、赋值、和使用的呢??
PID使用的地方:
// Compute the yaw angular velocity demand from the yaw angle error
const float angleP_yaw = _p_angle_yaw.kP() * _angle_P_scale.z;
看看_p_angle_yaw.kP() 是啥:
// angle controller P objects
AC_P _p_angle_roll;
AC_P _p_angle_pitch;
AC_P _p_angle_yaw;
再看看AC_P是个类:
/// @class AC_P
/// @brief Object managing one P controller
class AC_P {
public:
/// Constructor for P that saves its settings to EEPROM
///
/// @note PIs must be named to avoid either multiple parameters with the
/// same name, or an overly complex constructor.
///
/// @param initial_p Initial value for the P term.
///
AC_P(const float &initial_p = 0.0f) :
default_kp(initial_p)
{
AP_Param::setup_object_defaults(this, var_info);
}
CLASS_NO_COPY(AC_P);
/// Iterate the P controller, return the new control value
///
/// Positive error produces positive output.
///
/// @param error The measured error value
/// @param dt The time delta in milliseconds (note
/// that update interval cannot be more
/// than 65.535 seconds due to limited range
/// of the data type).
///
/// @returns The updated control output.
///
float get_p(float error) const;
/// Load gain properties
///
void load_gains();
/// Save gain properties
///
void save_gains();
/// @name parameter accessors
//@{
/// Overload the function call operator to permit relatively easy initialisation
void operator() (const float p) { _kp.set(p); }
// accessors
AP_Float &kP() { return _kp; }
const AP_Float &kP() const { return _kp; }
void kP(const float v) { _kp.set(v); }
static const struct AP_Param::GroupInfo var_info[];
private:
AP_Float _kp;
const float default_kp;
};
AC_P的构造函数:
AC_P(const float &initial_p = 0.0f) :
default_kp(initial_p)
{
AP_Param::setup_object_defaults(this, var_info);
}
哦!!原来最终参数的值是从var_info来的!!!这不就串起来了嘛!!
其他配置参数的使用流程应该同理!!