ArduPilot提供了丰富的数据记录功能,通过AP_Logger来管理数据记录
1. AP_Logger::WriteBlock
程序的数据记录主要通过AP_Logger::WriteBlock()函数来进行,函数原型:
class AP_Logger {
...
void WriteBlock(const void *pBuffer, uint16_t size);
...
};
表示写入一个大小为size的区块。这个区块为包含数据结构的区块,常用的用法如下
void Plane::Log_Write_AETR()
{
struct log_AETR pkt = {
LOG_PACKET_HEADER_INIT(LOG_AETR_MSG)
,time_us : AP_HAL::micros64()
,aileron : SRV_Channels::get_output_scaled(SRV_Channel::k_aileron)
,elevator : SRV_Channels::get_output_scaled(SRV_Channel::k_elevator)
,throttle : SRV_Channels::get_output_scaled(SRV_Channel::k_throttle)
,rudder : SRV_Channels::get_output_scaled(SRV_Channel::k_rudder)
,flap : SRV_Channels::get_slew_limited_output_scaled(SRV_Channel::k_flap_auto)
,steering : SRV_Channels::get_output_scaled(SRV_Channel::k_steering)
,speed_scaler : get_speed_scaler(),
};
logger.WriteBlock(&pkt, sizeof(pkt));
}
如上为写入一个log_AETR数据结构的例子,表示飞行器的控制信号,结构体log_AETR的数据定义如下
struct PACKED log_AETR {
LOG_PACKET_HEADER; //数据块的包头,
uint64_t time_us; //时间(微秒)
float aileron; //滚转控制
float elevator; //俯仰控制
float throttle; //油门
float rudder; //偏航控制
float flap; //襟翼输出
float steering; //转向控制
float speed_scaler; //速度缩放因子
};
其中,LOG_PACKET_HEADER为数据包头,定义为两个字符的起头和一个msgid,如下
#define LOG_PACKET_HEADER uint8_t head1, head2, msgid;
对于不同类型的数据记录,msgid不同,对于log_AETR结构,包头数据为
LOG_PACKET_HEADER_INIT(LOG_AETR_MSG)
其中
#define LOG_PACKET_HEADER_INIT(id) head1 : HEAD_BYTE1, head2 : HEAD_BYTE2, msgid : id
表示两个起头字符HEAD_BYTE1和HEAD_BYTE2,它们的定义如下
#define HEAD_BYTE1 0xA3 // Decimal 163
#define HEAD_BYTE2 0x95 // Decimal 149
msgid为LOG_AETR_MSG,定义在一个枚举类型(enum)中
enum log_messages {
...
LOG_AETR_MSG,
...
};
这样就完成了一个数据块的写入,数据块的含义由msgid确认,每一个msgid对应了数据块的内容。
2. LogStructure
所有数据块的内容在Plane::log_structure[]中定义,Plane::log_structure是一个数组,记录了所有数据记录类型的含义,通常定义如下
const struct LogStructure Plane::log_structure[] = {
log_structure item1,
log_structure item2,
...
{ LOG_AETR_MSG, sizeof(log_AETR),
"AETR", "Qfffffff", "TimeUS,Ail,Elev,Thr,Rudd,Flap,Steer,SS", "s-------", "F-------" , true },
...
}
每一行为一个数据记录类型的定义,分别对应不同类型的数据记录内容,LOG_AETR_MSG也为其中的一行,LogStructure的定义如下
struct LogStructure {
uint8_t msg_type; //数据记录类型
uint8_t msg_len; //数据记录长度
const char *name; //数据记录名称
const char *format; //数据记录格式
const char *labels; //数据项标签
const char *units; //数据项单位
const char *multipliers; //数据项比例因子
bool streaming; //是否可限制写入速度
};
对应LOG_AETR_MSG数据,含义如下
msg_type: LOG_AETR_MSG //数据记录id
msg_len: sizeof(log_AETR) //数据块大小
name: "AETR" //数据类型名称
format: "Qfffffff" //数据项类型,Q表示uint64_t,f表示float
labels: "TimeUS,Ail,Elev,Thr,Rudd,Flap,Steer,SS" //数据项标签
units: "s-------" //数据项单位
multipliers: "F-------" //数据项乘数因子
streaming: true //是否可以限制写入速度(允许WriteStreaming)
其中数据项格式类型定义如下
| 格式字符 | 数据类型 | 说明 |
|---|---|---|
| b | int8_t | 有符号8位整数 |
| B | uint8_t | 无符号8位整数 |
| h | int16_t | 有符号16位整数 |
| H | uint16_t | 无符号16位整数 |
| i | int32_t | 有符号32位整数 |
| I | uint32_t | 无符号32位整数 |
| q | int64_t | 有符号64位整数 |
| Q | uint64_t | 无符号64位整数 |
| f | float | 单精度浮点数 |
| d | double | 双精度浮点数 |
| n | char[4] | 4字节字符数组(通常用于存储短标识符) |
| N | char[16] | 16字节字符数组 |
| Z | char[64] | 64字节字符数组 |
| L | int32_t | 专用于经纬度,单位为1e-7度,(如-35.1332423°存储为-351332423) |
| M | uint8_t | 无符号8位整数,专用于存储飞行模式 |
数据项单位定义如下
| 单位字符 | 对应的物理单位 | 说明 |
|---|---|---|
| - | 无 | 无单位(如字符串或Pi等纯数值) |
| s | 秒 | 时间戳 (TimeUS)、控制周期 (Dt) |
| m | 米 | 高度 (Alt)、距离、GPS位置精度 |
| d | 度(deg) | 姿态角 (Roll, Pitch)、角度误差 |
| % | 百分比 | 油门输出 (Thr)、电机出力 |
| v | 伏特 | 电池电压、传感器供电电压 |
| A | 安培 | 电流、电池放电电流 |
| P | 帕斯卡 | 气压计 (Press)、空速计 (DiffPress) |
| O | 摄氏度 | 温度 (Temp)、温控状态 |
| n | 米/秒 | 空速、地速 (Airspeed, GSpd) |
| k | 度/秒 | 角速度 (Rate)、陀螺仪数据 |
| o | 米/秒² 加速度计数据 (AccX, AccY, AccZ) | |
| D | 纬度(度) | GPS纬度 (Lat) |
| U | 经度(度) | GPS经度 (Lng) |
| h | 航向(度) | GPS航向、罗盘航向 (Heading) |
| G | 高斯 | 磁力计数据 (MagX, MagY, MagZ) |
| S | 卫星数量 | GPS定位状态 (Sats) |
| Y | 微秒 | PWM脉宽、RC输入值 |
| q | 转/分钟 | 电机转速 (RPM) |
| r | 弧度 | 角度(SI单位) |
| N | 牛顿 | 推力、力(Force) |
| z | 赫兹 | 控制频率(Freq) |
| ? | 未知 | 未知物理单位 |
乘数因子的字符定义如下
| 字符 | 乘数 (Multiplier) | 说明与典型用途 |
|---|---|---|
| - | 0 | 无乘数,用于字符串或无需缩放的数值 |
| ? | 1 | 乘数尚未确定时的占位符 |
| 0 | 1e0 | 缩放倍数为1,即原始值即为标准单位值 |
| A | 1e-1 | 乘以 0.1 |
| B | 1e-2 | 乘以 0.01,常用于将厘米转换为米(除以100) |
| C | 1e-3 | 乘以 0.001,常用于将毫单位转换为标准单位 |
| F | 1e-6 | 乘以 0.000001,用于将微秒转换为秒 |
3. 数据记录的查看
ArduPilot的数据记录功能会在飞机飞行结束后产生.bin数据日志文件,通常通过MissionPlanner地面站程序来查看数据日志文件
如上,在MissionPlanner窗口的左侧选项卡中选择DataFlash Logs,然后选择Review a Log,就可以选择对应的数据日志文件(.bin)打开,出现数据日志窗口如下

如图,右侧包含所有的数据记录,其中就包括AETR数据记录,展开AETR,会列出AETR包含的所有数据项,勾选对应的数据项,就会在左侧数据窗口显示数据曲线。其中横坐标为时间,纵坐标为对应数据变量的数值。
4. 新增数据记录
在ArduPilot中新增一项数据记录,可以按照如下
1)新增数据结构定义
新增需要记录的数据结构定义,比如新增一个debug类型的数据结构记录,在LogStructure.h中增加如下数据结构定义
struct PACKED log_debug {
LOG_PACKET_HEADER;
uint64_t time_us;
float data1;
float data2;
float data3;
float data4;
float data5;
float data6;
};
表示新增的数据记录结构,其中包含时间(微秒)和6个数据记录项
2)新增数据结构描述
新增对应的数据结构描述
#define LOG_STRUCTURE_DEBUG \
{ LOG_DEBUG_MSG, sizeof(log_debug), \
"DBG", "Qffffff", "TimeUS, Data1, Data2, Data3, Data4, Data5, Data6", "s------", "F------" , true },
其中LOG_DEBUG_MSG为数据记录的ID,可以把它放到enum LogMessages中,如下
enum LogMessages: uint8_t {
...
LOG_DEBUG_MSG,
...
_LOG_LAST_MSG_
};
其中_LOG_LAST_MSG_表示最后一个消息项。数据结构描述可以放在LOG_COMMON_STRUCTURES的末尾,表示为常用的数据记录结构,如下
#define LOG_COMMON_STRUCTURES \
...
LOG_STRUCTURE_DEBUG
LOG_COMMON_STRUCTURES是定义在Plane::log_structure列表中的,如下
const struct LogStructure Plane::log_structure[] = {
LOG_COMMON_STRUCTURES,
...
这样就可以进行数据记录了。
3)数据记录
在进行上述数据记录定义后,可在程序中进行数据记录的操作了,大致如下
float data1, data2, data3, data4, data5, data6;
... //fill content of data1-data6
log_debug pkt {
LOG_PACKET_HEADER_INIT(LOG_DEBUG_MSG),
time_us : AP_HAL::micros64(),
data1 : data1,
data2 : data2,
data3 : data3,
data4 : data4,
data5 : data5,
data6 : data6
};
AP::logger().WriteBlock(&pkt, sizeof(log_debug));
申明一个log_debug的数据变量pkg,把需要记录数据内容填进去,再调用AP_Logger::WriteBlock()函数就可以记录对应数据了。新增的数据记录可以在产生的飞行日志文件(.bin)中通过MissionPlanner等工具来查看。
5万+

被折叠的 条评论
为什么被折叠?



