PX4-固定翼的姿态控制

2023-05-16

下面分析代码的版本是v1.8.2

1 参数介绍

固定翼中有很多参数,理解这些参数的含义非常重要

FW_AIRSPD_TRIM 巡航状态下的空速 15m/s
FW_AIRSPD_MIN 最小空速  10m/s
FW_AIRSPD_MAX 最大空速  20m/s
gspd_scaling_trim 
FW_R_TC 外环控制器的比例参数,这只是一个初始值
FW_RR_P 内环控制器的比例参数
FW_RR_I 内环控制器的积分参数
FW_RR_IMAX 限制内环积分的最大值,可以抵抗风?
FW_R_RMAX 设定角速度的最大值
FW_RLL_TO_YAW_FF 横滚对偏航的前馈增益 这个参数乘于横滚后直接加载偏航的输出上
FW_RR_FF 从速率设定值直接前馈到控制表面输出。使用此方法可以在不引入噪声放大的情况下,获得更紧凑的控制器响应。
FW_RSP_OFF 期望角度的偏置值,可以用来抵消飞机的不平衡
FW_MAN_R_SC 手动模式下的缩放值,这个值乘于摇杆输出后直接作用在执行器上
FW_MAN_R_MAX 自稳模式下,期望角度的最大值,直接乘于摇杆的输入就可以得到期望角度了
FW_ACRO_X_MAX 特技模式下,期望角速度的最大值,直接乘于摇杆的输入就得到期望的角速度
FW_DTRIM_R_VMIN 最小空速时,用来计算Roll增量的参数
FW_DTRIM_R_VMAX 最大空速时,用于计算Roll增量的参数
FW_DTRIM_R_FLPS 襟翼完全展开时,用于计算Rol增量的参数

FW_ARSP_MODE 空速计模式的选择,0为启用空速计,1为禁用
FW_BAT_SCALE_EN 是否根据电池情况来缩放油门的输入量
FW_RATT_TH Rattitude模式下,手动输入的最大值

 2 源码分析

run函数 结合源代码阅读最佳,源码太多,不直接粘贴了,文件路径为Firmware/src/modules/fw_att_control/

run
前面部分和其他函数都一样,订阅大量的主题,更新参数。最后一个fds订阅的是姿态,只要有新姿态
就开始进行控制。
如果有新的消息推送,记录下控制的时间差
如果是垂直起飞的固定翼,比如TAILSITTER: 垂直起降的固定翼,需要转换横滚和偏航
将四元数转换成欧拉角,更新消息,调用vehicle_manual_poll函数
如果不允许控制偏航,或者是除于自动飞行过的模式,禁止Yaw的控制
初始化积分锁
control_flaps 对副翼控制并控制襟翼
下面进入角速度的控制(如果在手动模式或者自稳模式下):
	判断空速计是否能用,并得到空速
	计算空速的缩放值,用于姿态的控制
	gspd_scaling_trim设定为0.6倍的空速,用在起飞轮的控制上
	判断积分是否需要重置?需要的话清0
	准备好控制需要用到的数据,角度、角速度、期望角度(从vehicle_manual_poll计算得到)
	如果是从别的控制模式切换过来的,重置下最大的角速度和(姿态控制模式和自动模式分开设置)	
	trim_roll等等是干嘛用的?
	是否允许角度控制,允许的话:
		通过串级PID来控制角度,最后的计算量直接作为输出,其中油门的期望值来自于摇杆
		如果开启了电池补偿,则对油门输出进行修改
		最后把期望的角速度发布出去
	否则就是纯角速度控制
		进行内环的角度控制
	发布一些控制信息
加上横滚对于偏航的前向增益,可以用来抵消横滚是对于偏航的不利影响。
就是对偏航的输出加上一个横滚输出带来的增益这么简单?
随后整理控制器的输出发布出去

 vehicle_manual_poll 函数
判断是否为手动控制模式,接受到新的manual_control_setpoint,就进行控制
只有当符合控制条件,rattitude模式下,手动输入不超过阈值;不允许爬升控制,板外控制
手动控制模式下支持姿态控制则,摇杆输入的就是姿态期望值,支持角速度控制的话,摇杆
输入量就是角速度期望值。否则的话摇杆的输入量就直接作为输出量

void
FixedwingAttitudeControl::vehicle_manual_poll()
{
	// only update manual if in a manual mode
	if (_vcontrol_mode.flag_control_manual_enabled) {

		// Always copy the new manual setpoint, even if it wasn't updated, to fill the _actuators with valid values
		if (orb_copy(ORB_ID(manual_control_setpoint), _manual_sub, &_manual) == PX4_OK) {

			// Check if we are in rattitude mode and the pilot is above the threshold on pitch
			if (_vcontrol_mode.flag_control_rattitude_enabled) {
				if (fabsf(_manual.y) > _parameters.rattitude_thres || fabsf(_manual.x) > _parameters.rattitude_thres) {
					_vcontrol_mode.flag_control_attitude_enabled = false;
				}
			}

			if (!_vcontrol_mode.flag_control_climb_rate_enabled &&
			    !_vcontrol_mode.flag_control_offboard_enabled) {

				if (_vcontrol_mode.flag_control_attitude_enabled) {
					// STABILIZED mode generate the attitude setpoint from manual user inputs
					_att_sp.timestamp = hrt_absolute_time();
					_att_sp.roll_body = _manual.y * _parameters.man_roll_max + _parameters.rollsp_offset_rad;
					_att_sp.roll_body = math::constrain(_att_sp.roll_body, -_parameters.man_roll_max, _parameters.man_roll_max);
					_att_sp.pitch_body = -_manual.x * _parameters.man_pitch_max + _parameters.pitchsp_offset_rad;
					_att_sp.pitch_body = math::constrain(_att_sp.pitch_body, -_parameters.man_pitch_max, _parameters.man_pitch_max);
					_att_sp.yaw_body = 0.0f;
					_att_sp.thrust = _manual.z;

					Quatf q(Eulerf(_att_sp.roll_body, _att_sp.pitch_body, _att_sp.yaw_body));
					q.copyTo(_att_sp.q_d);
					_att_sp.q_d_valid = true;

					if (_attitude_sp_pub != nullptr) {
						/* publish the attitude rates setpoint */
						orb_publish(_attitude_setpoint_id, _attitude_sp_pub, &_att_sp);

					} else if (_attitude_setpoint_id) {
						/* advertise the attitude rates setpoint */
						_attitude_sp_pub = orb_advertise(_attitude_setpoint_id, &_att_sp);
					}

				} else if (_vcontrol_mode.flag_control_rates_enabled &&
					   !_vcontrol_mode.flag_control_attitude_enabled) {

					// RATE mode we need to generate the rate setpoint from manual user inputs
					_rates_sp.timestamp = hrt_absolute_time();
					_rates_sp.roll = _manual.y * _parameters.acro_max_x_rate_rad;
					_rates_sp.pitch = -_manual.x * _parameters.acro_max_y_rate_rad;
					_rates_sp.yaw = _manual.r * _parameters.acro_max_z_rate_rad;
					_rates_sp.thrust = _manual.z;

					if (_rate_sp_pub != nullptr) {
						/* publish the attitude rates setpoint */
						orb_publish(_rates_sp_id, _rate_sp_pub, &_rates_sp);

					} else if (_rates_sp_id) {
						/* advertise the attitude rates setpoint */
						_rate_sp_pub = orb_advertise(_rates_sp_id, &_rates_sp);
					}

				} else {
					/* manual/direct control */
					_actuators.control[actuator_controls_s::INDEX_ROLL] = _manual.y * _parameters.man_roll_scale + _parameters.trim_roll;
					_actuators.control[actuator_controls_s::INDEX_PITCH] = -_manual.x * _parameters.man_pitch_scale +
							_parameters.trim_pitch;
					_actuators.control[actuator_controls_s::INDEX_YAW] = _manual.r * _parameters.man_yaw_scale + _parameters.trim_yaw;
					_actuators.control[actuator_controls_s::INDEX_THROTTLE] = _manual.z;
				}
			}
		}
	}
}

 3 串级PID内外环的控制

control_attitude外环控制,外环就是一个纯比例,比例的增益为控制时间间隔

float ECL_RollController::control_attitude(const struct ECL_ControlData &ctl_data)
{
	/* Do not calculate control signal with bad inputs */
	if (!(ISFINITE(ctl_data.roll_setpoint) && ISFINITE(ctl_data.roll))) {
		return _rate_setpoint;
	}

	/* Calculate error */
	float roll_error = ctl_data.roll_setpoint - ctl_data.roll;

	/* Apply P controller */
	_rate_setpoint = roll_error / _tc;

	return _rate_setpoint;
}

内环控制,内环是控制角速度,在Roll的内环控制之前最期望的角速度做了一个变换,为什么要这样还不懂

float ECL_RollController::control_euler_rate(const struct ECL_ControlData &ctl_data)
{
	/* Transform setpoint to body angular rates (jacobian) */
	_bodyrate_setpoint = ctl_data.roll_rate_setpoint - sinf(ctl_data.pitch) * ctl_data.yaw_rate_setpoint;

	set_bodyrate_setpoint(_bodyrate_setpoint);

	return control_bodyrate(ctl_data);

}

角速度控制,

判断控制量是否有效,无效的话输出上次的控制量
获得控制周期,如果控制周期太长,积分上锁,不允许积分
计算这次控制的积分增量,如果上次输出已经打到最大了,积分增量的符号只能与之相反
内环的计算
前向增益直接乘于期望速度,为什么不是乘于角速度的误差?
内环比例为什么要乘于缩放值的平方?缩放值是空速的缩放值

这里内环的计算公式不太懂,值得再研究

float ECL_RollController::control_bodyrate(const struct ECL_ControlData &ctl_data)
{
	/* Do not calculate control signal with bad inputs */
	if (!(ISFINITE(ctl_data.pitch) &&
	      ISFINITE(ctl_data.body_x_rate) &&
	      ISFINITE(ctl_data.body_z_rate) &&
	      ISFINITE(ctl_data.yaw_rate_setpoint) &&
	      ISFINITE(ctl_data.airspeed_min) &&
	      ISFINITE(ctl_data.airspeed_max) &&
	      ISFINITE(ctl_data.scaler))) {
		return math::constrain(_last_output, -1.0f, 1.0f);
	}

	/* get the usual dt estimate */
	uint64_t dt_micros = ecl_elapsed_time(&_last_run);
	_last_run = ecl_absolute_time();
	float dt = (float)dt_micros * 1e-6f;

	/* lock integral for long intervals */
	bool lock_integrator = ctl_data.lock_integrator;

	if (dt_micros > 500000) {
		lock_integrator = true;
	}

	/* Calculate body angular rate error */
	_rate_error = _bodyrate_setpoint - ctl_data.body_x_rate; //body angular rate error

	if (!lock_integrator && _k_i > 0.0f) {

		float id = _rate_error * dt * ctl_data.scaler;

		/*
		* anti-windup: do not allow integrator to increase if actuator is at limit
		*/
		if (_last_output < -1.0f) {
			/* only allow motion to center: increase value */
			id = math::max(id, 0.0f);

		} else if (_last_output > 1.0f) {
			/* only allow motion to center: decrease value */
			id = math::min(id, 0.0f);
		}

		/* add and constrain */
		_integrator = math::constrain(_integrator + id * _k_i, -_integrator_max, _integrator_max);
	}

	/* Apply PI rate controller and store non-limited output */
	_last_output = _bodyrate_setpoint * _k_ff * ctl_data.scaler +
		       _rate_error * _k_p * ctl_data.scaler * ctl_data.scaler
		       + _integrator;  //scaler is proportional to 1/airspeed

	return math::constrain(_last_output, -1.0f, 1.0f);
}

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PX4-固定翼的姿态控制 的相关文章

  • 第十九篇:USB Audio/Video Class设备协议

    转发请注明出处 随着项目的不断进行 我想在网上查找了一下USB Audio Video的最新资料 看看有没有业内人士的更新 由于我们的项目一直在技术的最前延 而且这个USB IF官方发布的协议 也非常非常新 结果找了半天 都是我这篇文章的转
  • 《网络架构系列2-Http详解》

    不诗意的女程序媛不是好厨师 转载请注明出处 xff0c From李诗雨 https blog csdn net cjm2484836553 article details 104136511 网络架构系列2 Http详解 1 Http的协议
  • 第三十二篇:Windbg中USB2.0调试环境的搭建

    2011年的时候 xff0c 为了开发USB Mass storage UASP USB attached SCSI Protocol 的设备驱动程序 xff0c 从米国买了两个USB2 0的调试小设备 xff08 如下图 xff0c 每个
  • 理解SerDes 之一

    理解SerDes FPGA发展到今天 xff0c SerDes Serializer Deserializer 基本上是标配了 从PCI到PCI Express 从ATA到SATA xff0c 从并行ADC接口到JESD204 从RIO到S
  • 理解SerDes 之二

    理解SerDes 之二 2012 11 11 21 17 12 转载 标签 xff1a dfe serdes it 2 3 接收端均衡器 Rx Equalizer 2 3 1 线形均衡器 Linear Equalizer 接收端均衡器的目标
  • USB3.0的物理层测试探讨

    USB简介 USB Universal Serial Bus 即通用串行总线 xff0c 用于把键盘 鼠标 打印机 扫描仪 数码相机 MP3 U盘等外围设备连接到计算机 xff0c 它使计算机与周边设备的接口标准化 在USB1 1版本中支持
  • ARM SoC漫谈

    作者 xff1a 重走此间路 链接 xff1a https zhuanlan zhihu com p 24878742 来源 xff1a 知乎 著作权归作者所有 商业转载请联系作者获得授权 xff0c 非商业转载请注明出处 芯片厂商向客户介
  • μC/OS III - 任务调度 Ⅰ:调度过程和调度点

    这是 C OS III任务调度的第一篇文章 xff1a 调度过程和调度点 基于Cortex M系列的处理器 xff0c 从最简单的创建任务开始 xff0c 分析 C OS III的任务调度过程 包括上下文切换的详细过程 任务的栈分配详情 引
  • 使用CANAPE脚本script周期性发送报文

    1 新建一个drive 选择devices选项卡中的device configuration 选择device菜单 xff0c new一个新驱动CAN 名称可自定义 Next 配置通道 xff0c 导入DBC Next 选择CANAPE对应
  • 【图像处理】MATLAB:基本原理

    前言 兜兜转转 xff0c 越发意识到夯实基础的重要性 不积跬步无以至千里 xff0c 想要深入学习图像处理 xff0c 就得安下心来踏实学习 xff0c 掌握基本理论知识 xff0c 切不可再得过且过 吊儿郎当 谨记两个词 刻苦 创新 x
  • 【Kalman】卡尔曼滤波Matlab简单实现

    本节卡尔曼滤波Matlab实现是针对线性系统估计的 xff0c 仅为简单仿真 1 离散时间线性动态系统的状态方程 线性系统采用状态方程 观测方程及其初始条件来描述 线性离散时间系统的一般状态方程可描述为 其中 xff0c X k 是 k 时
  • 安装Airsim并在Airsim仿真环境下进行DDPG DQN强化学习算法无人机训练

    微软开源了基于虚幻4引擎的一款用于模拟无人机飞行的工具AirSim 用户可以用在虚幻引擎下模拟无人机的飞行并进行数据采集 非常适合做视觉算法的测试以及仿真环境的训练等等 xff0c 下面介绍如何快速使用次仿真环境完成project的运行和使
  • Android面试专题 (十一):显式Intent & 隐式Intent

    面试官 xff1a 来 xff0c 说一下Android中的显式Intent 和 隐式Intent吧 xff01 嗯 xff0c 乍一听觉得这么简单你让我说什么呢 xff1f 但是 xff0c 没办法 xff0c 面试往往面的就是基础不是嘛
  • Java设计模式 | 观察者模式解析与实战

    概述 观察者模式是一个使用率非常高的模式 xff0c 它最常用的地方是 GUI 系统 订阅 发布系统 这个模式的一个重要作用就是解耦 xff0c 将被观察者和观察者解耦 xff0c 使得它们之间的依赖性更小 xff0c 甚至做到毫无依赖 以
  • ISO 26262中的ASIL等级确定与分解

    ISO 26262中的ASIL等级确定与分解 1 引言 汽车上电子 电气系统 xff08 E E xff09 数量不断的增加 xff0c 一些高端豪华轿车上有多达70多个ECU xff08 Electronic Control Unit电子
  • 数字电路符号整理

    0 常见的数字电路符号 1 D触发器 这个就是D触发器的示意图 其中 xff0c clk为时钟 xff0c rst n为复位 xff0c d为输入 xff0c q为输出 这个功能非常简单 xff0c 复位有效的时候 xff0c 这个q的值你
  • 进程优先级详解(prio、static_prio、normal_prio、rt_priority)

    Linux 中采用了两种不同的优先级范围 xff0c 一种是 nice 值 xff0c 一种是实时优先级 在上一篇粗略的说了一下 nice 值和实时优先级 xff0c 仍有不少疑问 xff0c 本文来详细说明一下进程优先级 linux 内核
  • C++中struct和class

    在C 43 43 中我们可以看到struct和class的区别并不是很大 xff0c 两者之间有很大的相似性 那么为什么还要保留struct 这是因为C 43 43 是向下兼容的 xff0c 因此C 43 43 中保留了很多C的东西 一 首
  • Linux中的进程栈和线程栈

    转载自 xff1a Linux中的进程栈和线程栈 知乎 1 进程栈 进程栈是属于用户态栈 xff0c 和进程虚拟地址空间 Virtual Address Space 密切相关 那我们先了解下什么是虚拟地址空间 xff1a 在 32 位机器下
  • Linux内存管理(二):PTMalloc

    1 ptmalloc简介 2 内存管理数据结构 3 内存分配 4 内存回收 5 配置选项 6 注意事项 1 ptmalloc简介 Linux 中 malloc 的早期版本是由 Doug Lea 实现的 xff0c 它有一个重要问题就是在并行

随机推荐

  • P问题、NP问题、NP完全问题和NP难问题

    在讲P类问题之前先介绍两个个概念 xff1a 多项式 xff0c 时间复杂度 知道这两概念的可以自动跳过这部分 1 多项式 xff1a axn bxn 1 43 c 恩 就是长这个样子的 xff0c 叫x最高次为n的多项式 咳咳 xff0c
  • 电容基本知识

    旁路电容 xff0c 耦合电容 xff0c 电容不同类型的使用范围 在模拟和数字PCB设计中 xff0c 旁路或去耦电容 0 1uF 应尽量靠近器件 放置 供电电源去耦电容 10uF 应放置在电路板的电源线入口处 所有情 况下 xff0c
  • 最长递增子序列的三种算法

    转载自 xff1a http qiemengdao iteye com blog 1660229 最长递增子序列 问题 给定一个长度为N的数组 xff0c 找出一个最长的单调自增子序列 xff08 不一定连续 xff0c 但是顺序不能乱 x
  • 树莓派手动指定静态IP和DNS 终极解决大法

    在把玩树莓派的过程中 xff0c 往往需要手动给它设定一个静态的IP地址 xff0c 一来可以防范DHCP自动分配的IP来回变动 xff0c 导致远程SSH时常无法连接 xff1b 二来还可以提高树莓派的网络连接速度 对此菲菲君在网上查了很
  • Anroid面试专题(十二):图片大小的优化 及 三级缓存

    面试官 xff1a 你在项目中处理过图片吗 xff0c 说一下你是如何对它做优化的 xff0c 及三级缓存是什么 xff1f 我们可以这样一步一步来回答 xff1a 1 一张图的大小是怎么计算的 要回答这个问题 xff0c 我们要先从图片说
  • UART和RS232/RS485的关系是什么?

    串口通讯是电子工程师和嵌入式开发工程师面对的最基本问题 xff0c RS232则是其中最简单最常用的通讯方式 但是初学者往往搞不清有关的名词如UART和RS232或RS485之间是什么关系 xff0c 因为它们经常被放到语句中同等的位置使用
  • TensorBoard的使用

    介绍 使用 Tensorboard 是TF 的可视化工具 xff0c 它通过对Tensoflow程序运行过程中输出的日志文件进行可视化Tensorflow程序的运行状态 xff0c 如下所示 SCALARS 对标量数据进行汇总和记录 使用方
  • Tensorflow 多 GPU 训练

    介绍 TensorFlow中的并行主要分为模型并行和数据并行 模型并行需要根据不同模型设计不同的并行方式 xff0c 其主要原理是将模型中不同计算节点放在不同硬件资源上运算 比较通用的且能简便地实现大规模并行的方式是数据并行 xff0c 其
  • Hadoop 各组件介绍

    转自 https www cnblogs com klb561 p 9085615 html Hadoop是一个由Apache基金会所开发的分布式系统基础架构 用户可以在不了解分布式底层细节的情况下 xff0c 开发分布式程序 充分利用集群
  • 8、解决Linux无法上网的各种问题

    最近发现Linux重新开机后无法上网 xff0c 不仅不能ping通windows主机也不能上外网 ifconfig后eth0也没有分配IP地址 xff0c 总之各种问题都被我碰到了 现在来一一解决 xff01 1 没有分配到IP地址 开机
  • 解决开发板ping不通主机和虚拟机的问题

    使用TFTP和NFS从虚拟机下载文件或者制作根文件系统的前提是开发板能够ping同虚拟机 xff01 相信很多人都像我一样有过ping不通的经历 xff0c 经过2 3天的研究和实验后终于把问题解决了 xff0c 而且屡试不爽 最后得出结论
  • USB摄像头驱动配置及V4L2编程

    1 摄像头驱动开发 1 1 摄像头软件系统架构 摄像头系统架构分为四层 xff1a 摄像头 支持V4L2的摄像头驱动 V4L2核心 应用程序 V4L2核心是Linux系统自带的组件 xff0c 它可以屏蔽摄像头驱动层的差异 xff0c 不管
  • 机器学习中的五种回归模型及其优缺点

    转自https blog csdn net Katherine hsr article details 79942260 好像有部分公式不能显示 xff0c 请查看原博客 本文将会介绍五种常见的回归模型的概念及其优缺点 xff0c 包括线性
  • VGGNet介绍

    VGGNet介绍 1 简要概括 VGGNet由牛津大学计算机视觉组合和Google DeepMind公司研究员一起研发的深度卷积神经网络 它探索了卷积神经网络的深度和其性能之间的关系 xff0c 通过反复的堆叠3 3的小型卷积核和2 2的最
  • PX4编译问题总结

    PX4在变编译的时候总会碰到很多问题 有些问题根据提示就可以解决 xff0c 有些问题却有点麻烦 1 找不到python jinja2模块 CMake Error at usr share cmake 3 2 Modules FindPac
  • 面试专题(十三):Service 与 IntentService

    1 Service 与 IntentService区别 Service不是运行在独立的线程 xff0c 所以不建议在Service中编写耗时的逻辑和操作 xff0c 否则会引起ANR IntentService 1 可用于执行后台耗时的任务
  • ResNet介绍

    ResNet介绍 1 简要概括 ResNet xff08 Residual Neural Network xff09 由微软研究院的Kaiming He等四名华人提出 xff0c 通过使用ResNet Unit成功训练出了152层的神经网络
  • PX4日志生成及查看

    Pixhawk的飞行日志由固件中的sd2log模块记录在SD卡的log文件中 xff0c 目前版本的格式为 px4log xff08 曾经是 bin xff09 xff0c 根据sd2log的设置不同 xff0c 包含飞行日志的文件夹的名字
  • PX4中混控器Mixer的分析

    PX4架构保证了核心控制器中不需要针对机身布局做特别处理 混控指的是把输入指令 xff08 例如 xff1a 遥控器打右转 xff09 分配到电机以及舵机的执行器 xff08 如电调或舵机PWM xff09 指令 对于固定翼的副翼控制而言
  • PX4-固定翼的姿态控制

    下面分析代码的版本是v1 8 2 1 参数介绍 固定翼中有很多参数 xff0c 理解这些参数的含义非常重要 FW AIRSPD TRIM 巡航状态下的空速 15m s FW AIRSPD MIN 最小空速 10m s FW AIRSPD M