文章

QGC代码架构解析:MAVLink参数服务及QGC参数管理模块

MAVLink参数服务网页:Parameter Protocol

1. 微服务:Parameter Protocol

基本流程为请求->响应返回。请求/消息列表:

  • PARAM_REQUEST_LIST:请求所有参数。随后远端会周期性发送所有参数,直到发送完毕。请求数据结构:
    • target_system(uint8_t):System ID
    • target_component(uint8_t):Component ID
  • PARAM_REQUEST_READ:请求单个参数。请求数据结构:
    • target_system(uint8_t):System ID
    • target_component(uint8_t):Component ID
    • param_id(char[16]):参数名称,与param_index二选一
    • param_index(int16_t):参数索引(-1表示忽略)
  • PARAM_SET:设置单个参数。请求数据结构:
    • target_system(uint8_t):System ID
    • target_component(uint8_t):Component ID
    • param_id(char[16]):参数名称
    • param_value(float):参数值
    • param_type(uint8_t):参数数据类型枚举
  • PARAM_VALUE:参数值响应。响应数据结构(系统ID以及组件ID在mavlink_message_t中):
    • param_id(char[16]):参数名称
    • param_value(float):参数值
    • param_type(uint8_t):参数数据类型枚举
    • param_count(uint16_t):参数总数
    • param_index(uint16_t):当前参数索引

知识点总结

  • 获取/设置所有子系统的参数:target_component设置为 MAV_COMP_ID_ALL(QGC就是采取这种方式)。
  • 参数响应消息中,带有参数总数和当前索引,QGC可以判断是否接收完毕。
  • param_value有两种格式存储参数值:转换为float类型;或者直接按照原始数据复制到param_value域。Ardupilot直接使用memcpy的方式(小端)。MAVLink参数协议中,定义了相应的标志位,表示使用哪种方式存储。
  • QGC发送设置命令PARAM_SET之后,飞机端会返回一个PARAM_VALUE消息作为确认:Parameter Protocol – Write Parameters
  • PX4固件支持缓存机制,即通过返回名称为PARAM_HASH,值为哈希值的PARAM_VALUE消息,确认参数没有变化:Parameter Protocol – PX4
  • 设置参数非法等原因导致飞机拒绝设置时,飞机端返回STATUS_TEXT消息。

1.1. 参数存储代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 定义如下结构体,适用于原始字节流存储参数值(Bytewise)
// https://github.com/mavlink/c_library_v2/blob/master/mavlink_types.h
MAVPACKED(
typedef struct param_union {
	union {
		float param_float;
		int32_t param_int32;
		uint32_t param_uint32;
		int16_t param_int16;
		uint16_t param_uint16;
		int8_t param_int8;
		uint8_t param_uint8;
		uint8_t bytes[4];
	};
	uint8_t type;
}) mavlink_param_union_t;
1
2
3
4
5
6
7
mavlink_param_union_t param;
int32_t integer = 20000;
param.param_int32 = integer;
param.type = MAV_PARAM_TYPE_INT32;

// Then send the param by providing the float bytes to the send function
mavlink_msg_param_set_send(xxx, xxx, param.param_float, param.type, xxx);

1.2. 协议限制及缺陷

  • 没有同步保证一致性机制,即发送修改命令,飞机端的参数可能已经更新了,跟QGC不一样了。安全的方式是:设置时,QGC将修改前的值带入,让飞机端进行比较。
  • 如果有多个关联参数需要一起设置的,没有原子操作机制。

新增的服务Extended Parameter Protocol,数据类型可以支持uint64_t以及字节流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MAVPACKED(
typedef struct {
    union {
        float       param_float;
        double      param_double;
        int64_t     param_int64;
        uint64_t    param_uint64;
        int32_t     param_int32;
        uint32_t    param_uint32;
        int16_t     param_int16;
        uint16_t    param_uint16;
        int8_t      param_int8;
        uint8_t     param_uint8;
        uint8_t     bytes[MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_VALUE_LEN];
    };
    uint8_t type;
}) param_ext_union_t;

1.3. 资料

2. QGC参数管理模块

参数管理模块ParameterManager主要提供参数的请求,缓存功能,以及参数的设置功能。以及对外提供参数访问接口(参数管理模块不直接对UI层提供参数列表,由各个AutoPilotPlugin中各个部件模块提供比较合理),故参数模块应该作为一个公共模块,提供给plugin使用。另外,还提供了离线参数加载功能,离线参数文件定义在FirmwarePlugin中。

下载的参数,存储在成员变量_mapCompId2FactMap中:

1
QMap<int /* comp id */, QMap<QString /* parameter name */, Fact*>> _mapCompId2FactMap;

缓存的文件名格式为<系统ID>_<组件ID>.v2,存储目录定义在ParameterManager::parameterCacheDir()中。参数存储格式为:

1
2
3
4
5
6
typedef QPair<int /* FactMetaData::ValueType_t */, QVariant /* Fact::rawValue */> ParamTypeVal;
typedef QMap<QString /* parameter name */, ParamTypeVal> CacheMapName2ParamTypeVal;

// 展开之后为
// QMap<QString, std::pair<int, QVariant>>
// 即 QMap<参数名称, <参数类型枚举, 参数值>>

2.1. 参数请求

QGC初始化时,请求所有参数:

  • 从网站(不是飞控)下载参数文件,仅针对APM固件,入口:APMAirframeComponentController::loadParameters
  • 使用FTP从飞控下载参数文件,入口函数refreshAllParameters
  • 通过参数服务请求参数,入口函数refreshAllParameters

请求完成之后,都需要调用_checkInitialLoadComplete

ParameterManager中,跟请求相关的主要的数据结构定义:

1
2
3
QMap<int, int> _paramCountMap;                              ///< Key: Component id, Value: count of parameters in this component
QMap<int, QMap<int, int>> _waitingReadParamIndexMap;        ///< Key: Component id, Value: Map { Key: parameter index still waiting for, Value: retry count }
QMap<int, QList<int>> _failedReadParamIndexMap;             ///< Key: Component id, Value: failed parameter index

2.2. 参数设置

由于生成的参数列表,存在_mapCompId2FactMap中,及每个参数以Fact表示,使用Fact值变更的信号,设置单个参数。

本文由作者按照 CC BY 4.0 进行授权