- 前言
- 一、 解锁检查参数
- 1电源检查CBRK_SUPPLY_CHK
- 2.USB连接检查CBRK_USB_CHK
- 3.安全开关检查CBRK_IO_SAFETY
- 4.传感器检查
- 5.CPU利用率检查
- 6.SD卡检查
- 二、安全设置
- 1.低电量保护
- 2.遥控信号丢失保护
- 3.地理围栏保护
- 4.数据链路丢失保护
- 5.返航模式设置
- 6.着陆模式设置
- 三、任务航点参数
- 航点半径
- 从原点到第一个航路点的最大水平距离
- 航路点之间的最大水平距离
- 最小悬停高度
- 启用偏航控制
- 起飞高度
- 是否需要起飞点
- 航路点航向接受所需的最大偏航误差(度)
- 偏航模式
- 置信半径
- 固定翼着陆前高度置信半径
- 固定翼高度置信半径
- 盘旋半径(仅固定翼)
- 四、无人机室内视觉定位参数
- 五、其他参数
- 无人机长时间无法进入定点模式
- 关闭蜂鸣器
- 设置无人机自稳或定高模式下最大的倾斜角度
- 状态估计算法选择参数
- 空速计开关
- 发动机故障检测开关
- 固定翼模式解锁检查
- 电调检查
- DShot电调配置
- DShot 电机最小输出
- 主GPS的串口配置
- 主GPS协议
- MAVLink的串口配置
- 最大MAVLink发送速率
- 成功起飞后的动作
- 修改定高数据来源
- 设置日志记录条件
- 设置自动加锁时间
- 六、控制参数
- 参数的导出和导入
- 自定义参数
- 常用函数解析
- 1.参数查找函数param_find
- 2.参数获取函数param_get
前言
PX4 1.11以上版本
PX4所有参数都在firmware-build/src/lib/parameters/px4_parameters.h文件里
注意,修改某些参数可能使飞机不稳定,本文仅供交流学习,不负相关责任。具体修改时请自行权衡。
4、PX4主要参数讲解
一、 解锁检查参数
解锁检查参数的主要作用是设置飞控解锁的条件。常用的有以下几个。
1电源检查CBRK_SUPPLY_CHK
这个参数是检查解锁时是否有电池供电,默认是需要插电流计供电才可以解锁。如果想通过其他方式(如ESC供电)给飞控供电进行解锁,则需要设置该参数为894281。
2.USB连接检查CBRK_USB_CHK
这个参数是检查起飞时是否有USB连接,默认情况下有USB连接时是无法解锁的,如果需要插USB解锁,需要设置为197848
3.安全开关检查CBRK_IO_SAFETY
默认情况下安全开关是慢闪状态,设置该参数蔚22027时,上电后安全开关自动切换为双闪。
4.传感器检查
飞控在解锁前会对传感器的状态进行检查,如果检查不通过,则不能解锁。
(1)如果报错加速度偏移过大,high Accelerometer bios
可以把com_arm_ekf_ab
这个参数调大一些,在1.13以后版本的固件中,把EKF2_ABL_LIM
调大。
(2)同理可以通过改下面这个参数把陀螺仪的起飞检查阈值该大一些,com_arm_ekf_gb
(3)如果报罗盘某个度数没包含的错误,COM_ARM_MAG_ANG
设为-1
(4)如果GPS搜星少,长时间没有进入GPS定位,可以把下面EKF2_GPS_CHECK
改成0
(5)如果报下面的错
把下面这个COM_ARM_IMU_ACC
改大一些,图中以加速度计为例,如果陀螺仪出现类似报错也是修改相应的参数
(6)如果偏航角一直漂移
解决办法是校准陀螺仪
(7)如果报传感器未包含的错
PREFLIGHT FAIL: ACCEL SENSORS INCONSISTENT - CHECK CALIBRATION
当来自不同 IMU 单元的加速度测量值不一致时,会产生此错误消息。
此检查仅适用于具有多个 IMU 的板。
解决办法
将COM_ARM_IMU_ACC
参数改大(可能要超限强制保存)。
同理
PREFLIGHT FAIL: GYRO SENSORS INCONSISTENT - CHECK CALIBRATION
检查COM_ARM_IMU_GYR参数
(8)PREFLIGHT FAIL: EKF INTERNAL CHECKS
如果水平 GPS 速度、偏航角、垂直 GPS 速度或者垂直位置传感器(气压计默认情况下可以使测距仪或 GPS ,如果使用非标准参数)其中之一新息过多,会产生此错误消息。 新息指的是惯性导航计算预测值与传感器测量值之间的差异。
用户应检查日志文件中新息级别以确定原因。 这些可以在ekf2_innovations消息下找到。 常见问题 / 解决方案包括:
IMU 启动时漂移。 可以通过重启自驾仪来解决。 可能需要 IMU 加速度计和陀螺仪校准。
相邻磁干扰在飞行器运动中。 通过等待或者重新上电解决。
磁力计校准不良在飞行器运动中。。 通过重新校准解决。
启动时的初始冲击或快速移动导致惯性导航失败。 通过重新启动飞行器并在前 5 秒内最大限度地减少移动来解决此问题。
(9)PREFLIGHT FAIL: EKF YAW ERROR
当使用陀螺仪数据估计的偏航角和来自磁力计或外部视觉系统的偏航角不一致时,产生该误差。
检查 IMU 数据是否存在较大的偏航率漂移,并检查磁力计的对准和校准。
可以修改COM_ARM_EKF_YAW
关闭此检查
(10)PREFLIGHT FAIL: EKF HORIZ POS ERROR
当 IMU 和位置测量数据(GPS 或外部视觉)不一致时会产生此问题。
检查位置传感器数据是否存在不真实的数据跳转。 如果数据质量看起来不错,请执行加速度计和陀螺仪校准并重新启动飞行器。
可以通过COM_ARM_EKF_POS
参数禁用
(11)PREFLIGHT FAIL: EKF VEL ERROR
当 IMU 和 GPS 速度测量数据不一致时会产生此错误。
检查 GPS 速度数据是否存在不真实的数据跳转。 如果 GPS 质量看起来没有问题,请执行加速度计和陀螺仪校准并重新启动飞行器。
可以通过COM_ARM_EKF_VEL
参数禁用
(12)PREFLIGHT FAIL: EKF HGT ERROR
当 IMU 和高度测量数据不一致时会产生此错误。
执行加速度计和陀螺仪校准并重新启动飞行器。 如果错误仍然存在,请检查高度传感器数据是否存在问题。
可以通过COM_ARM_EKF_HGT
参数禁用
(13) 如果报错 yaw estimate error ,则把下面参数改大
COM_ARM_EKF_YAW
5.CPU利用率检查
COM_CPU_MAX
该参数设置为-1将禁用CPU利用率检查,如果改参数大于0,当飞控CPU利用率大于该值或者检测不到CPU信息时,将不能解锁,报下面的错:
Fail: No CPU load information
或者
Fail: CPU load too high:
6.SD卡检查
如果报错:
Crash dumps present on SD,vehicle needs service
将COM_ARM_HFLT_CHECK
改为Disabled
二、安全设置
1.低电量保护
在地面站的安全设置中,低电量保护有如下三种动作,警告(只发出警告,不执行任何动作),降落(在电量低于故障保护水平时,直接降落),在临界水平时返航,在紧急水平时降落(在电量低于故障保护水平时返航,在电量低于紧急水平时降落)
2.遥控信号丢失保护
在遥控信号丢失超过超时时间后,会出发遥控器丢失保护,可以设置为不使能,返航,降落等模式
3.地理围栏保护
地理围栏是指以无人机设置围栏时的位置为圆心,设置的最大半径和最大高度为半径和高度的一个圆柱体范围,如果无人机飞行过程超出了这个范围,就会出发相应的故障保护动作,有不使能,警告,保持,返航,停止等动作。如果设置了相应的动作,那么无人机必须需要在有GPS信号的时候才能解锁
4.数据链路丢失保护
与地面站或者板卡的mavlink数据丢失时间超过设置的超时时间,会触发该保护,保护动作有:保持、返航、降落等
5.返航模式设置
下图可以设置返航后爬升的高度,无人机在返航时,先原地爬升到设置的返航高度,再飞回起飞点,返回起飞点上空后根据设置,可以选择立即着陆、留待但不着陆,留待一定的时间后着陆
6.着陆模式设置
设置着陆时的下降速率,以及着陆后几秒加锁电机
三、任务航点参数
航点半径
NAV_ACC_RAD
此参数设置判断到达航点的置信半径
从原点到第一个航路点的最大水平距离
故障保护检查,以防止在新的起飞位置执行先前飞行中存储的飞行任务。将值设置为零或更小以禁用。如果当前航路点距离起始位置的距离大于MIS_DIS_1WP,则不会启动任务。
MIS_DIST_1WP
航路点之间的最大水平距离
故障保护检查,以防止运行路径太远的任务。将值设置为零或更小以禁用。如果两个后续航路点之间的任何距离大于MIS_DIST_WPS,任务将不会开始
MIS_DIST_WPS
最小悬停高度
这是系统将始终遵守的最小高度值。其目的是避开地面效应。如果不应该有最小悬停高度,则将其设为-1
MIS_LTRMIN_ALT
启用偏航控制
如果启用,偏航命令将发送到机体,载具将沿着其飞行方向前进。如果禁用,载具机头将转向感兴趣区域(ROI),(仅影响多翼机和感兴趣区域(ROI)任务项)
MIS_MNT_YAW_CTL
起飞高度
这是起飞模式下系统将起飞到的最小高度。
MIS_TAKEOFF_ALT
是否需要起飞点
如果设置,任务可行性检查器将检查任务中是否有起飞点。
MIS_TAKEOFF_REQ
航路点航向接受所需的最大偏航误差(度)
MIS_YAW_ERR
偏航模式
指定自动模式下的偏航航向,有指向航点、指向home点、远离home点、沿轨迹、指向航点(偏航优先)五种
MPC_YAW_MODE
置信半径
默认航点的置信半径,如果设置,如果航点中也设置了置信半径,则将被航路中的置信半径覆盖。对于固定翼,L1转弯距离被用于水平置信半径。
NAV_ACC_RAD
固定翼着陆前高度置信半径
固定翼着陆前最后一个航路点的高度置信半径。这通常小于标准垂直置信半径,因为靠近地面需要更高的精度。
NAV_FW_ALTL_RAD
固定翼高度置信半径
固定飞行高度的置信半径。
NAV_FW_ALT_RAD
盘旋半径(仅固定翼)
任务、保持模式、返航模式等的盘旋半径默认值(仅限固定翼)。
NAV_LOITER_RAD
四、无人机室内视觉定位参数
如果想让无人机在室内通过视觉进行定位,需要修改两个参数,
一个是EKF2_AID_MASK,改成24,位置和航向用视觉的数据。如下:
另一个是EKF2_HGT_MODE
,改成Vison
,如下:
五、其他参数
无人机长时间无法进入定点模式
无人机在室外,位置数据来源为GPS,且GPS正常,但长时间无法进定点
确认EKF2_AID_MASK为1,
修改EKF2_GPS_CHECK为0,然后重启飞控
关闭蜂鸣器
CBRK_BUZZER
改为782097
设置无人机自稳或定高模式下最大的倾斜角度
状态估计算法选择参数
SYS_MC_EST_GROUP
,该参数可以指定飞控状态估计的算法,有单四元数互补滤波,四元数互补滤波加LPE,EKF2,默认采用EKF2,使用ekf2所需的最低传感器配置为加速度计、陀螺仪、磁力计、气压计。如果缺少任意一个,则EKF2无法运行,如果缺少磁力计和气压计,可以使用四元数互补滤波进行姿态解算,如果有位置传感器(如GPS),可以采用四元数互补滤波加LPE进行位姿估计。
如果报Disarmed by auto preflight disarming
将COM_DISARM_PRFLT
禁用或改大一点
空速计开关
将此参数设置为162128将禁用空速传感器检查。
CBRK_AIRSPD_CHK
发动机故障检测开关
将此参数设置为284953将禁用发动机故障检测
CBRK_ENGINEFAIL
固定翼模式解锁检查
将此参数设置为159753将允许VTOL在固定翼模式下解锁
CBRK_VTOLARMING
电调检查
需要检测到所有电调才能解锁,此参数只正对可以返回状态的电调。正常电调配置不受此参数更改的影响。
COM_ARM_CHK_ESCS
DShot电调配置
启用/禁用DShot电调。不同的模式定义不同的速度,例如DShot150=150kb/s。并非所有ESC都支持所有模式。注:这将启用FMU输出上的DShot。对于带有IO的飞控板,需要禁用IO,将DShot电调接到FMU通道
DSHOT_CONFIG
DShot 电机最小输出
DShot的最小输出值(以百分比为单位)。该值取决于电调。确保将其设置得足够高,以便电机在怠速时始终旋转
DSHOT_MIN
主GPS的串口配置
配置要在哪个串行端口上运行主GPS。
GPS_1_CONFIG
主GPS协议
选择GPS协议(基于串口的数据协议)。选择自动检测将探测所有协议,因此速度较慢。
GPS_1_PROTOCOL
MAVLink的串口配置
配置要在哪个串口上运行MAVLink
MAV_0_CONFIG
最大MAVLink发送速率
配置MAVLink流的最大发送速率(字节/秒)。如果配置的数据流超过最大速率,则会自动降低每个数据流的发送速率。如果该值设置为0,则为理论值最大速率的一半。这对应于波特率/20(字节/秒)(波特率/10=8N1配置链路上的最大数据速率)
MAV_0_RATE
成功起飞后的动作
成功起飞后的模式转换。
COM_TAKEOFF_ACT
修改定高数据来源
ekf2_hgt_mode
设置日志记录条件
SDLOG_MODE
如果要上电后就开始记录日志,需要设置成从boot到shutdown
设置自动加锁时间
COM_DISARM_LAND
这个参数设置在地面解锁无人机后不打油门自动加锁的时间
-1表示不自动加锁
六、控制参数
多旋翼位置控制模式
参数的导出和导入
先找一架正常能飞的无人机连接地面站
在参数页面右上角点击工具->保存到文件
保存的时候文件名注明参数的相关信息然后将需要加载参数的无人机连接至地面站,注意需要加载参数的无人机必须和保存的参数脚本的固件版本、机架类型,飞控硬件等信息一致,否则可能炸机。
如果固件版本不一致,就先刷一下相应的固件,再加载参数,固件一致后,点击重置参数为固件的默认值
然后点击从文件载入
选择需要导入的参数文件
导入正常的话地面站上面所有的参数都是正常的,没有红色的提示
这个时候可以不用校准传感器,但是需要校准电调,如果用的遥控器和导入参数脚本所用的无人机的不一致,则需要校准遥控器。
自定义参数
首先自定义一个模块,在Firmware/src/modules文件夹下创建03param_test文件夹,然后在03param_test文件夹下面创建下面四个文件:
(1) 定义参数文件,我这里创建了param_test_params.c文件,在该文件中添加如下两行定义:
PARAM_DEFINE_FLOAT(PARAM_TEST1, 0.2f);
PARAM_DEFINE_INT32(PARAM_TEST2, 0);
(2) 编辑param_test.h
#pragma once
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>
#include <uORB/Subscription.hpp>
#include <uORB/Publication.hpp>
#include <uORB/topics/parameter_update.h>
extern "C" __EXPORT int param_test_main(int argc, char *argv[]);
class param_test : public ModuleBase<param_test>, public ModuleParams
{
public:
param_test(int example_param, bool example_flag);
virtual ~param_test() = default;
/** @see ModuleBase */
static int task_spawn(int argc, char *argv[]);
/** @see ModuleBase */
static param_test *instantiate(int argc, char *argv[]);
/** @see ModuleBase */
static int custom_command(int argc, char *argv[]);
/** @see ModuleBase */
static int print_usage(const char *reason = nullptr);
/** @see ModuleBase::run() */
void run() override;
/** @see ModuleBase::print_status() */
int print_status() override;
private:
/**
* Check for parameter changes and update them if needed.
* @param parameter_update_sub uorb subscription to parameter_update
* @param force for a parameter update
*/
void parameters_update(bool force = false);
DEFINE_PARAMETERS(
(ParamFloat<px4::params::PARAM_TEST1>) _param_test1, /**< example parameter */
(ParamInt<px4::params::PARAM_TEST2>) _param_test2 /**< another parameter */
)
// Subscriptions
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
};
主要是在DEFINE_PARAMETERS里添加下面这条语句定义
DEFINE_PARAMETERS(
(ParamFloat<px4::params::PARAM_TEST1>) _param_test1, /**< example parameter */
(ParamInt<px4::params::PARAM_TEST2>) _param_test2 /**< another parameter */
)
编辑param_test.cpp
#include "param_test.h"
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/log.h>
#include <px4_platform_common/posix.h>
#include <uORB/topics/parameter_update.h>
int param_test::print_status()
{
PX4_INFO("Running");
// TODO: print additional runtime information about the state of the module
return 0;
}
int param_test::custom_command(int argc, char *argv[])
{
/*
if (!is_running()) {
print_usage("not running");
return 1;
}
// additional custom commands can be handled like this:
if (!strcmp(argv[0], "do-something")) {
get_instance()->do_something();
return 0;
}
*/
return print_usage("unknown command");
}
int param_test::task_spawn(int argc, char *argv[])
{
_task_id = px4_task_spawn_cmd("module",
SCHED_DEFAULT,
SCHED_PRIORITY_DEFAULT,
1024,
(px4_main_t)&run_trampoline,
(char *const *)argv);
if (_task_id < 0)
{
_task_id = -1;
return -errno;
}
return 0;
}
param_test *param_test::instantiate(int argc, char *argv[])
{
int example_param = 0;
bool example_flag = false;
bool error_flag = false;
int myoptind = 1;
int ch;
const char *myoptarg = nullptr;
// parse CLI arguments
while ((ch = px4_getopt(argc, argv, "p:f", &myoptind, &myoptarg)) != EOF)
{
switch (ch)
{
case 'p':
example_param = (int)strtol(myoptarg, nullptr, 10);
break;
case 'f':
example_flag = true;
break;
case '?':
error_flag = true;
break;
default:
PX4_WARN("unrecognized flag");
error_flag = true;
break;
}
}
if (error_flag)
{
return nullptr;
}
param_test *instance = new param_test(example_param, example_flag);
if (instance == nullptr)
{
PX4_ERR("alloc failed");
}
return instance;
}
param_test::param_test(int example_param, bool example_flag)
: ModuleParams(nullptr)
{
}
void param_test::run()
{
while (!should_exit())
{
double param_test1=_param_test1.get();
int param_test2=_param_test2.get();
PX4_INFO("param_test1=%lf param_test2=%d\n",param_test1,param_test2);
usleep(100000);
}
}
void param_test::parameters_update(bool force)
{
// check for parameter updates
if (_parameter_update_sub.updated() || force)
{
// clear update
parameter_update_s update;
_parameter_update_sub.copy(&update);
// update parameters from storage
updateParams();
}
}
int param_test::print_usage(const char *reason)
{
if (reason)
{
PX4_WARN("%s\n", reason);
}
PRINT_MODULE_DESCRIPTION(
R"DESCR_STR(
### Description
Section that describes the provided module functionality.
This is a template for a module running as a task in the background with start/stop/status functionality.
### Implementation
Section describing the high-level implementation of this module.
### Examples
CLI usage example:
$ module start -f -p 42
)DESCR_STR");
PRINT_MODULE_USAGE_NAME("module", "template");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAM_FLAG('f', "Optional example flag", true);
PRINT_MODULE_USAGE_PARAM_INT('p', 0, 0, 1000, "Optional example parameter", true);
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
return 0;
}
int param_test_main(int argc, char *argv[])
{
return param_test::main(argc, argv);
}
通过上面的代码设置的参数只有在重启后才会生效,如果想使参数立即生效,可以用parameters_update()函数。下面的param_test.cpp
会使参数立即生效。
#include "param_test.h"
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/log.h>
#include <px4_platform_common/posix.h>
#include <uORB/topics/parameter_update.h>
int param_test::print_status()
{
PX4_INFO("Running");
// TODO: print additional runtime information about the state of the module
return 0;
}
int param_test::custom_command(int argc, char *argv[])
{
/*
if (!is_running()) {
print_usage("not running");
return 1;
}
// additional custom commands can be handled like this:
if (!strcmp(argv[0], "do-something")) {
get_instance()->do_something();
return 0;
}
*/
return print_usage("unknown command");
}
int param_test::task_spawn(int argc, char *argv[])
{
_task_id = px4_task_spawn_cmd("module",
SCHED_DEFAULT,
SCHED_PRIORITY_DEFAULT,
1024,
(px4_main_t)&run_trampoline,
(char *const *)argv);
if (_task_id < 0)
{
_task_id = -1;
return -errno;
}
return 0;
}
param_test *param_test::instantiate(int argc, char *argv[])
{
int example_param = 0;
bool example_flag = false;
bool error_flag = false;
int myoptind = 1;
int ch;
const char *myoptarg = nullptr;
// parse CLI arguments
while ((ch = px4_getopt(argc, argv, "p:f", &myoptind, &myoptarg)) != EOF)
{
switch (ch)
{
case 'p':
example_param = (int)strtol(myoptarg, nullptr, 10);
break;
case 'f':
example_flag = true;
break;
case '?':
error_flag = true;
break;
default:
PX4_WARN("unrecognized flag");
error_flag = true;
break;
}
}
if (error_flag)
{
return nullptr;
}
param_test *instance = new param_test(example_param, example_flag);
if (instance == nullptr)
{
PX4_ERR("alloc failed");
}
return instance;
}
param_test::param_test(int example_param, bool example_flag)
: ModuleParams(nullptr)
{
parameters_update(true);
}
void param_test::run()
{
while (!should_exit())
{
parameters_update();
double param_test1=_param_test1.get();
int param_test2=_param_test2.get();
PX4_INFO("param_test1=%lf param_test2=%d\n",param_test1,param_test2);
usleep(100000);
}
}
void param_test::parameters_update(bool force)
{
// check for parameter updates
if (_parameter_update_sub.updated() || force)
{
// clear update
parameter_update_s update;
_parameter_update_sub.copy(&update);
// update parameters from storage
updateParams();
}
}
int param_test::print_usage(const char *reason)
{
if (reason)
{
PX4_WARN("%s\n", reason);
}
PRINT_MODULE_DESCRIPTION(
R"DESCR_STR(
### Description
Section that describes the provided module functionality.
This is a template for a module running as a task in the background with start/stop/status functionality.
### Implementation
Section describing the high-level implementation of this module.
### Examples
CLI usage example:
$ module start -f -p 42
)DESCR_STR");
PRINT_MODULE_USAGE_NAME("module", "template");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAM_FLAG('f', "Optional example flag", true);
PRINT_MODULE_USAGE_PARAM_INT('p', 0, 0, 1000, "Optional example parameter", true);
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
return 0;
}
int param_test_main(int argc, char *argv[])
{
return param_test::main(argc, argv);
}
编辑CMakeLists.txt
px4_add_module(
MODULE modules__03param_test
MAIN param_test
SRCS
param_test.cpp
)
然后将03param_test添加到编译脚本
我这里添加到fmu-v5的脚本
(3) 先在Firmware路径执行make parameters_metadata
(4 )然后编译固件下载到飞控
make px4_fmu-v5_default upload
连接地面站,刷新参数
就可以找到添加的参数
需要注意的是,用到这个参数的线程在被执行的时候,地面站才会显示这个参数,也就是param_test start
要执行。
如果进程是手动启动的,在手动启动后要刷新参数,地面站才会显示自定义的参数
可以在启动脚本或者程序里使用自定义的参数
可以仿造SYS_MC_EST_GROUP来写
仿写如下:
if param compare PARAM_TEST2 0
then
a start
else
b start
fi
常用函数解析
1.参数查找函数param_find
PX4通过param_find()函数对参数进行查找,该函数的使用方法如下:
param_t handle = param_find("GPS_YAW_OFFSET");
参数为函数名,如果能够找到参数,则返回该参数的索引值(PX4中的所有参数存放在一个结构体数组中,数组中每个结构体代表一个参数,里面存放着参数名和参数的值,按照参数名的字母顺寻排列,返回的索引值即为该参数在结构体数组中的索引),如果找不到该参数,返回最大值0xffff。该函数定义如下:
param_t param_find(const char *name)
{
return param_find_internal(name, true);
}
调用了函数param_find_internal(),继续看该函数的定义如下,由于参数是按照字母顺序排列的,这里通过二分查找来查找参数:
static param_t param_find_internal(const char *name, bool notification)
{
perf_count(param_find_perf);
二分查找的中间值
param_t middle;
二分查找的头
param_t front = 0;
二分查找的尾
param_t last = param_info_count;
当头小于等于尾时,继续执行
while (front <= last) {
middle就是头和尾的中间数
middle = front + (last - front) / 2;
通过strcmp进行比较
int ret = strcmp(name, param_name(middle));
name就是需要查找的参数名,param_name(middle)就是根据索引值middle返回参数名称,定义如下:
const char *param_name(param_t param)
{
return handle_in_range(param) ? px4::parameters[param].name : nullptr;
}
handle_in_range就是判断参数是否在最大索引值param_info_count范围内,定义如下:
static constexpr bool handle_in_range(param_t param) { return (param < param_info_count); }
param_info_count就是将结构体数组parameters总的大小除以单个结构体param_info_s的大小。
static constexpr uint16_t param_info_count = sizeof(px4::parameters) / sizeof(param_info_s);
如果参数的索引在最大索引值param_info_count范围内,则返回参数名px4::parameters[param].name
参数结构体数组parameters的定义如下:
static constexpr param_info_s parameters[] = {
{
"ASPD_BETA_GATE",
.val = { .i = 1},
},
{
"ASPD_BETA_NOISE",
.val = { .f = 0.3 },
},
......(一共一千多个参数,每个参数的结构都一样,后面不列举)
}
该数组由结构体param_info_s
组成,该结构提定义如下:包含参数名name和参数值val。
struct param_info_s {
const char *name;
union param_value_u val;
};
参数值val是一个共用体,包含指针、int32和float三种类型,一般都用int32或者float
union param_value_u {
void *p;
int32_t i;
float f;
};
通过strcmp进行比较时,name=param_name(middle)两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止。若name=param_name(middle),则返回零,说明找到了参数,这时二分查找的中间值middle即为函数的索引值,返回参数的索引值middle。
if (ret == 0) {
if (notification) {
param_set_used(middle);
}
perf_end(param_find_perf);
return middle;
}
如果没有找到参数并且中间值middle和front相等,说明已经到了最和一个位置也没有找到参数,跳出循环返回未找到
else if (middle == front) {
/* An end point has been hit, but there has been no match */
break;
}
若name<param_name(middle),则返回负数;由于结构体数组parameters是安照参数名的字母顺序从小到大排列的,因此需要差查找的参数名name对应的索引值应该在front和middle之间,因此front不动,将last置为middle,从而在front和middle之间继续二分查找
else if (ret < 0) {
last = middle;
}
若name>param_name(middle),则返回正数,此时需要差查找的参数名name对应的索引值应该在middle和last之间,因此last不动,将front置为middle,从而在middle和last之间继续二分查找
else {
front = middle;
}
}
未找到则返回PARAM_INVALID(0xffff)
/* not found */
return PARAM_INVALID;
}
2.参数获取函数param_get
param_get主要用于获取参数的值,函数定义如下:
宏定义
#define param_get(param, val) param_get_cplusplus(param, val)
参数有float和int32_t两种类型,因此进行了函数的重载,根据不同的类型进行类型检查,然后调用param_get(param, (void *)val)获取参数值
static inline int param_get_cplusplus(param_t param, float *val)
{
CHECK_PARAM_TYPE(param, PARAM_TYPE_FLOAT);
return param_get(param, (void *)val);
}
static inline int param_get_cplusplus(param_t param, int32_t *val)
{
CHECK_PARAM_TYPE(param, PARAM_TYPE_INT32);
return param_get(param, (void *)val);
}
param_get(param_t param, void *val)的定义如下:
int
param_get(param_t param, void *val)
{
perf_count(param_get_perf);
如果参数的索引超出范围,返回错误
if (!handle_in_range(param)) {
PX4_ERR("get: param %" PRId16 " invalid", param);
return PX4_ERROR;
}
if (!params_active[param]) {
PX4_DEBUG("get: param %" PRId16 " (%s) not active", param, param_name(param));
}
int result = PX4_ERROR;
if (val) {
param_lock_reader();
调用param_get_value_ptr(param)返回参数值的指针
const void *v = param_get_value_ptr(param);
通过memcpy将参数值赋值到指针val指向的地址。
if (v) {
memcpy(val, v, param_size(param));
result = PX4_OK;
}
param_unlock_reader();
}
return result;
}
函数param_get_value_ptr(param)的定义如下:
static const void *
param_get_value_ptr(param_t param)
{
param_assert_locked();
如果参数索引在最大范围内
if (handle_in_range(param)) {
/* work out whether we’re fetching the default or a written value */
struct param_wbuf_s *s = param_find_changed(param);
if (s != nullptr) {
return &s->val;
} else {
if (params_custom_default[param] && param_custom_default_values) {
// get default from custom default storage
param_wbuf_s key{};
key.param = param;
param_wbuf_s *pbuf = (param_wbuf_s *)utarray_find(param_custom_default_values, &key, param_compare_values);
if (pbuf != nullptr) {
return &pbuf->val;
}
}
// otherwise return static default value
switch (param_type(param)) {
case PARAM_TYPE_INT32:
return &px4::parameters[param].val.i;
case PARAM_TYPE_FLOAT:
return &px4::parameters[param].val.f;
}
}
}
return nullptr;
}