Ardupilot速率控制器rate_controller_run解析

2023-05-16

Ardupilot速率控制器rate_controller_run解析

  • PID速率控制器源码解析
    • rate_controller_run()
    • PID运算
      • 积分限制update_i()
    • get_ff()
    • set_xxx()
  • 内容补充:函数中陀螺仪数据的获取

rate_controller_run()在APM中是作为PID控制器将输入的期望角速率转换计算得到实际的电机控制指令的。下面将以Copter为例进行讲解。


所有无人机的PID速率控制器都是在fast_loop()这个以400Hz频率运行的函数中被实时调用的。而update_flight_mode()函数通常以100Hz频率被调用,速率控制器的运行频率高于姿态角控制器也是符合常识的。

在运行rate_controller_run()这个函数之前需要实时获取到IMU数据。

// Main loop - 400hz
void Copter::fast_loop()
{
    // update INS immediately to get current gyro data populated
    ins.update();

    // run low level rate controllers that only require IMU data
	attitude_control->rate_controller_run();
	...
}

 

PID速率控制器源码解析

rate_controller_run()

void AC_AttitudeControl_Multi::rate_controller_run()
{
	// 将油门与姿态混合移至所需位置(从此处调用,因为每次迭代都方便地调用它)
	// 此处与PID控制器关系不大,就不细展开了
    update_throttle_rpy_mix();

	// 获取到最新的陀螺仪角速度参数
    Vector3f gyro_latest = _ahrs.get_gyro_latest();

	// get_rate_xxx_pid()返回该通道上的pid控制器
	// update_all():真正的PID控制器,根据输入的期望角速率和当前角速率进行PID运算
	// 运算得到电机控制指令并通过set_xxx()函数赋值给这个通道上的电机
	_motors.set_roll(get_rate_roll_pid().update_all(_rate_target_ang_vel.x, gyro_latest.x, _motors.limit.roll));
	// get_ff()根据期望角速率计算前馈量
    _motors.set_roll_ff(get_rate_roll_pid().get_ff());

    _motors.set_pitch(get_rate_pitch_pid().update_all(_rate_target_ang_vel.y, gyro_latest.y, _motors.limit.pitch));
    _motors.set_pitch_ff(get_rate_pitch_pid().get_ff());

    _motors.set_yaw(get_rate_yaw_pid().update_all(_rate_target_ang_vel.z, gyro_latest.z, _motors.limit.yaw));
    _motors.set_yaw_ff(get_rate_yaw_pid().get_ff());
    
	// 控制监视器更新
    control_monitor_update();
}

可以看到这个函数分别对Roll、Pitch和Yaw三个通道进行PID运算。以Roll通道为例,get_rate_roll_pid()返回该通道的PID控制器,然后通过update_all()接收期望和测量角速度计算得到电机控制指令,然后通过set_roll()函数实现电机控制指令的设置。set_roll_ff()中类似,只不过计算的是前馈量。

下面以Roll通道为例进行细节分解。

PID运算

get_rate_xxx_pid()函数原型如下,返回一个AC_AttitudeControl_Multi类中的AC_PID类对象,这个对象就是对应该通道的PID控制器(等多详细内容看:Ardupilot姿态控制器 PID控制流程)

    // pid accessors
    AC_PID& get_rate_roll_pid() override { return _pid_rate_roll; }
    AC_PID& get_rate_pitch_pid() override { return _pid_rate_pitch; }
    AC_PID& get_rate_yaw_pid() override { return _pid_rate_yaw; }

然后调用PID控制器的update_all()进行PID计算

//  update_all - set target and measured inputs to PID controller and calculate outputs
//  target and error are filtered
//  the derivative is then calculated and filtered
//  the integral is then updated based on the setting of the limit flag
float AC_PID::update_all(float target, float measurement, bool limit)
{
    // don't process inf or NaN
    if (!isfinite(target) || !isfinite(measurement)) {
        return 0.0f;
    }

    // 根据是否重启滤波器采用不同的计算方法
	if (_flags._reset_filter) {
		// 如果reset标志位置1
		// 首先将reset标志位置0
		// 期望和误差按照正常方式计算,但不进行滤波
		// 本次微分量置0
        _flags._reset_filter = false;
        _target = target;
        _error = _target - measurement;
        _derivative = 0.0f;
	} else {
		// 如果不需要重置滤波器
		// 首先保存上一次计算的误差量
        float error_last = _error;
		// 计算本次输入期望与上一次保存的期望之间的偏差
		// 经过T滤波器滤波之后叠加到上一次保存的期望以获取到本次期望
        _target += get_filt_T_alpha() * (target - _target);
		// 计算本次期望与测量值之间的误差,并与上一次保存的误差作差求出偏差量
		// 经过E滤波器滤波之后叠加到上一次保存的误差上获得本次误差
        _error += get_filt_E_alpha() * ((_target - measurement) - _error);

        // 计算并且滤波微分项,操作与上面相同
        if (_dt > 0.0f) {
            float derivative = (_error - error_last) / _dt;
            _derivative += get_filt_D_alpha() * (derivative - _derivative);
        }
    }
    
	// 运算得到I项
	// 根据limit是否为true选择是否仅允许积分量向变小的方向运算
    update_i(limit);

    float P_out = (_error * _kp);	// 计算P项
    float D_out = (_derivative * _kd);	// 计算D项
	
	// 参数保存到日志的PID信息中
    _pid_info.target = _target;
    _pid_info.actual = measurement;
    _pid_info.error = _error;
    _pid_info.P = P_out;
    _pid_info.D = D_out;

	// 返回PID运算量
    return P_out + _integrator + D_out;
}

细节部分以注释,需要注意在对期望值_target,误差量_error以及微分项_derivative 计算时会经过一个滤波器,其内部只调用了get_filt_alpha()这个函数,只不过是输入的频率不同。

// get_filt_alpha - calculate a filter alpha
float AC_PID::get_filt_alpha(float filt_hz) const
{
    if (is_zero(filt_hz)) {
        return 1.0f;
    }

    // calculate alpha
    float rc = 1 / (M_2PI * filt_hz);
    return _dt / (_dt + rc);
}

函数的数学原型表示为
r c = 1 2 π f rc=\frac{1}{2πf} rc=2πf1 f i l t e r = d t d t + r c filter=\frac{dt}{dt+rc} filter=dt+rcdt

根据不同的对象输入的频率也会有所差异

积分限制update_i()

update_all()中可以看到对于积分项I单独调用了一个函数进行计算。函数源码解析如下

// 积分量运算
// 如果limit=1则仅允许积分量朝变小的方向运算,根据积分量和误差的正负确定进入if还是else中
// 如果limit=0则表明允许积分量运算上下浮动,只能进入if语句不断进行积分量累加
void AC_PID::update_i(bool limit)
{
    if (!is_zero(_ki) && is_positive(_dt)) {
        // 确保仅在输出饱和时才能减小积分器
		// 仅当(limit=0)或者(积分累积量为正但是当前误差为负)或者(积分累加量为负但是当前误差为正)的时候进行积分项的累加
		// 积分累加量和当前误差的正负相反表明积分量是朝着减小的方向计算的
		// 即仅允许积分量朝着减小的方向进行累加运算
        if (!limit || ((is_positive(_integrator) && is_negative(_error)) || (is_negative(_integrator) && is_positive(_error)))) {
            _integrator += ((float)_error * _ki) * _dt;
			// 并对计算得到的积分量进行限幅
            _integrator = constrain_float(_integrator, -_kimax, _kimax);
        }
	} else {
		// 如果积分量和误差方向相同,为了防止PID的输出由此不断累积扩大,本次积分作用取消
        _integrator = 0.0f;
    }
    _pid_info.I = _integrator;
}

在阅读这个积分量计算函数时博主是对其是一个抗积分饱和操作还是积分分离操作有一定的疑问的。然而最后还是觉得这是一个经过修改的抗积分饱和计算。

虽然一般的抗积分饱和操作都是根据设定的最大最小值来判断本次积分量进不进行累加,然而在APM中则是判断积分量 _integrator 和 _error 的正负,仅当两者相反,也就是积分量朝着变小的方向才进行积分量累加(一般limit=1),之后输出进行PID控制。但是当两者正负号相同时则是直接将积分量 _integrator 置0,也就是取消了P项,最后进行的是PD控制。

因此个人觉得这是一个不完全标准的抗积分饱和PID控制器(如有错误欢迎指出)。


get_ff()

这个函数的作用就是根据期望角速率计算出前馈控制量并且返回

float AC_PID::get_ff()
{
    _pid_info.FF = _target * _kff;	// 计算前馈控制量并保存到日志参数表中
    return _target * _kff;		// 返回前馈量
}

set_xxx()

电机指令获取函数。

    // set_roll, set_pitch, set_yaw, set_throttle
    void                set_roll(float roll_in) { _roll_in = roll_in; };        // range -1 ~ +1
    void                set_roll_ff(float roll_in) { _roll_in_ff = roll_in; };    // range -1 ~ +1
    void                set_pitch(float pitch_in) { _pitch_in = pitch_in; };    // range -1 ~ +1
    void                set_pitch_ff(float pitch_in) { _pitch_in_ff = pitch_in; };  // range -1 ~ +1
    void                set_yaw(float yaw_in) { _yaw_in = yaw_in; };            // range -1 ~ +1
    void                set_yaw_ff(float yaw_in) { _yaw_in_ff = yaw_in; };      // range -1 ~ +1

内容补充:函数中陀螺仪数据的获取

以下为补充内容,如无需求可直接跳过。

Vector3f gyro_latest = _ahrs.get_gyro_latest();

首先来看一下相关类的关系及初始化。姿态控制器类的实现及初始化看这篇博文的第二章:Ardupilot姿态控制器 PID控制流程,这边就不再多说了。

在姿态控制器AC_AttitudeControl中声明了一个protected类对象const AP_AHRS_View& _ahrs;
AP_AHRS_View类的主要作用就是创建一个获取机体姿态的窗口。什么意思呢?

我们首先还是来看一下AP_AHRS,这个类作为接口直接与硬件上的姿态传感器作用,用于获取最原始的数据,如磁力计、陀螺仪、加速度计等。同时在这个类中声明了AP_AHRS_View作为其友元类,这已经是很高的权限了,基本上可以访问到AP_AHRS类中绝大部分数据。

那么由此可以得知,AP_AHRS_View这个类的作用就是提供一个接口用以访问获取获取IMU上的传感器数据,并且提供一些数据二次处理的功能,因此其内部的大部分函数都是以get_xxx打头的。

回到类中,在AP_AHRS_View.h中定义了AP_AHRS_View类的构造函数:

// Constructor
AP_AHRS_View(AP_AHRS &ahrs, enum Rotation rotation, float pitch_trim_deg=0);

在AP_AHRS_View.cpp文件中对构造函数进行了具体实现。第一个参数表示监视的传感器,第二个参数表示传感器的旋转角度,如果是正常水平安装则为ROTATION_NONE,否则之后的计算都会将传感器数据进行角度变换,第三个参数应该是俯仰角的修整度(老实说我也还没弄懂,不过在此处也不是我们的重点)

AP_AHRS_View::AP_AHRS_View(AP_AHRS &_ahrs, enum Rotation _rotation, float pitch_trim_deg) :
    rotation(_rotation),	// 传感器旋转角度
    ahrs(_ahrs)				// 保存到AP_AHRS类对象ahrs中,后续访问都是通过这个对象实现
{
    switch (rotation) {
    case ROTATION_NONE:
        y_angle = 0;
        break;
    case ROTATION_PITCH_90:
        y_angle = 90;
        break;
    case ROTATION_PITCH_270:
        y_angle =  270;
        break;
    default:
        AP_HAL::panic("Unsupported AHRS view %u\n", (unsigned)rotation);
    }

    _pitch_trim_deg = pitch_trim_deg;
    // Add pitch trim
    rot_view.from_euler(0, radians(wrap_360(y_angle + pitch_trim_deg)), 0);
    rot_view_T = rot_view;
    rot_view_T.transpose();

    // setup initial state
    update();
}

回到函数中

// 使用最新的ins数据返回平滑和校正的陀螺仪矢量(EKF可能尚未使用过)
Vector3f AP_AHRS_View::get_gyro_latest(void) const {
    Vector3f gyro_latest = ahrs.get_gyro_latest();		// 调用ahrs对象的单数获取最新陀螺仪数据
    gyro_latest.rotate(rotation);	// 陀螺仪数据进行角度旋转
    return gyro_latest;				// 返回处理后的陀螺仪数据
}

可以看到内部调用了AP_AHRS类对象ahrs的方法

// return a smoothed and corrected gyro vector using the latest ins data (which may not have been consumed by the EKF yet)
Vector3f AP_AHRS::get_gyro_latest(void) const
{
	// 获取当前主陀螺仪传感器的索引,及当前健康且处于使用状态的传感器编号_primary_gyro
	const uint8_t primary_gyro = get_primary_gyro_index();
	// 根据索引获取到陀螺仪数据
	// 并且叠加陀螺仪漂移的当前估计
    return AP::ins().get_gyro(primary_gyro) + get_gyro_drift();
}

rotate()函数内部会对输入的rotation进行判断,并且将获取到的角速度向量旋转对应角度。

// rotate a vector by a standard rotation, attempting
// to use the minimum number of floating point operations
template <typename T>
void Vector3<T>::rotate(enum Rotation rotation)
{
    T tmp;
    switch (rotation) {
    case ROTATION_NONE:
    case ROTATION_MAX:
        return;
    case ROTATION_YAW_45: {
        tmp = HALF_SQRT_2*(float)(x - y);
        y   = HALF_SQRT_2*(float)(x + y);
        x = tmp;
        return;
	}
	...
}

关于这个rotation枚举类型变量,通常是在具体的车辆类中定义的。

如在Copter中,首先是在Copter这个类中声明了一个private类型的对象

AP_AHRS_View *ahrs_view;

然后在system.cpp中实现了对rotation的赋值,默认为不旋转

ahrs_view = ahrs.create_view(ROTATION_NONE);

再比如说在ArduSub中,直接在Sub类的构造函数中实现了类对象初始化

ahrs_view(ahrs, ROTATION_NONE),

 

如有错误请及时指出

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

Ardupilot速率控制器rate_controller_run解析 的相关文章

  • 我可以获取视图中当前控制器的名称吗?

    有没有办法从视图中找出当前控制器是什么 举个例子说明为什么我想知道这一点 如果多个控制器共享相同的布局 我可能在布局 ERB 文件中包含一部分 我想在其中突出显示基于控制器的当前页面的菜单项 也许这是一个糟糕的方法 如果是这样 更优选的方法
  • 我应该从 MVC 框架中的控制器或模型中调用 redirect() 吗?

    我正在使用 MVC PHP 框架 Codeigniter 并且我有一个直接的问题 即从哪里调用redirect 控制器还是模型 设想 用户导航到 www example com item 555 在我的模型中 我在项目数据库中搜索 ID 为
  • JavaFX 嵌套控制器 (FXML )

    In this http docs oracle com javafx 2 api javafx fxml doc files introduction to fxml html nested controllers教程中 有一个示例说明如
  • 将 .js 控制器请求渲染为 html

    我有一个before filter在我的 Rails 应用程序中 将用户发送到login url如果他们在提交请求 以 html 或 js 格式 时注销 我想要我的format js产生相同的结果format html 在以下情况下使用 通
  • 如何获取 Symfony2 中控制器的所有路由列表?

    我有一个控制器 它实现了所有路线 URL 我的想法是为所有帮助页面提供通用索引 有没有办法获取控制器 从控制器内 定义的所有路由Symfony2 您可以做的是将 cmd 与 最高 SF2 6 一起使用 php app console rou
  • asp.net mvc 按名称和区域查找控制器

    我的目标是从控制器的名称和区域中找到控制器 如果我当前的httpContext与待找到的控制器位于同一区域内 但是 我无法拨打电话ControllerFactory考虑面积 这是我的代码 public static ControllerBa
  • 我的应用程序中采用 MVVM 设计模式的控制器是什么

    我开发了一个 WPF 应用程序 我有一个继承自 Window 的主窗口 一个选项卡控件以及该选项卡控件中的许多选项卡项 这些选项卡控件继承自 UserControl 每个 tabitem 都有自己的 cs 文件 我在其中使用 C 编写所有业
  • 从另一个控制器调用 WebApi 控制器

    所以我的解决方案中有两个项目 两者都是WebApi 我在两者中都有控制器 我可以从客户端调用它们 javascript 问题是我需要从第一个项目的控制器中的方法调用第二个项目的控制器中的方法 我还认为我应该声明我需要调用的方法是 Post
  • 如何从控制器运行 symfony 2 run 命令

    我想知道我怎样才能跑交响乐2来自浏览器查询或控制器的命令 这是因为我没有任何可能托管来运行它 并且每个 cron 作业都是由管理员设置的 我什至没有启用exec 因此 当我想测试它时 我必须将命令中的所有内容复制到某个测试控制器 这不是最佳
  • 如何删除供应商代码插入的回调?

    我正在使用的 gem 插入了一个我想删除的 after save 回调 在我看来 从数组中删除符号比用猴子补丁解决问题更干净 如何访问回调数组 class UserSession lt Authlogic Session Base Don
  • AppDelegate 或 AppController

    在阅读可可教程时 我注意到一些教程使用AppDelegate还有一些AppController用于定义IBActions打开使用子类的各种窗口NSWindowController 这有某种经验法则吗 我创建一个仅是我的应用程序委托的类 并实
  • GEF + EMF:为什么当调用refreshChildren() 时,我的编辑器不删除已删除对象的图形?

    我已经为类似图形的 EMF 模型实现了 GEF 编辑器 并为图形中的某种类型的节点提供了删除命令 我想我已经完成了所有必要的步骤以使此设置正常工作 vainolo https stackoverflow com users 817399 v
  • Laravel 将数据传递给路由

    我是 Laravel 5 的新手 我需要一些帮助 因为我无法解决我的简单问题 我有一个数据列表http sample com partners http sample com partners如果我单击数据链接 我希望将其重定向到 http
  • MVC 模型在 OnExecuted 操作过滤器中为 null ...或者设置模型的更优雅的方式?

    我有一个 ActionFilter 它覆盖了 OnActionExecuted 方法 在 POST 操作中 filterContext Controller ViewData Model 始终为 null 我确实发现下面的文章似乎在说它不应
  • 如何为 ApplicationController 中 after_action 过滤器中的所有操作渲染 json?

    是否可以在 Rails ApplicationController 中创建一个 after filter 方法 该方法在每个操作上运行并呈现为 JSON 我正在构建一个 API 并且希望将控制器中的每个操作的输出呈现为 JSON 客户控制器
  • Twitter 搜索 API 速率限制如何运作?

    我不清楚 Twitter 速率限制 每个访问令牌 用户每小时 350 个请求 的含义 他们如何限制请求 在 1 个请求中我可以获得多少数据 速率限制基于请求 而不是您收到的数据量 例如字节 考虑到这一点 您可以通过使用您正在调用的特定端点的
  • Magento 路由器 URL - 需要连字符的路径名称

    假设我使用自定义控制器 其 url 路径 前端名称为 customcategory 好吧 显然如果我有一个名为 TestController php 和indexAction的控制器文件 url 路径将是 customcategory te
  • Grails 域 obj 操作参数和关联数据绑定

    我知道 Grails v2 3引入了一些变化 https github com grails grails core wiki Data Binding数据绑定的工作方式 但是当我有一个域 obj 作为操作参数时 我正在努力弄清楚如何让自动
  • 什么时候应该使用视图控制器的 addSubview 方法?

    我正在为 iPhone 编程 我想知道何时使用视图的 addSubview 方法以及何时使用模态视图控制器 presentModalViewController 更复杂的是 如果您使用导航控制器 我没有 并且可以使用 PushViewCon
  • Laravel 4 路由 404 错误

    当我路由到某个页面时 我无法让 Laravel 找到该页面 我的路线已设置并被识别 当我使用 URL route account create 创建链接时 laravel 会成功地将其解析为 account create 以了解我希望链接转

随机推荐

  • 卡尔曼滤波通俗易懂的解释

    关于卡尔曼滤波 xff0c 网上的资料很多 xff0c 但是有很大一部分都是不断堆叠公式 xff0c 然后用各种晦涩难懂的专业术语进行解释 xff0c 说实话我刚开始看的时候也是云里雾里 xff0c 因此写下这篇博客是为了照顾和我一样的萌新
  • STM32通过PWM控制ESC30C电调

    最近在搞一个水下推进器 xff0c 这东西的控制其实跟四旋翼的螺旋桨控制差不多 但我也是第一次用STM32板子来控制电调驱动桨叶旋转 xff0c 因此踩了很多坑 网上找了很多资料 xff0c 但是很多都写的不是很清楚 xff0c 这边稍微记
  • STM32F7同一定时器多路输出PWM波通道之间相互影响问题

    2020 8 12更新 这次用Cube直接生成PWM控制代码 xff0c 然后再RT Thread Studio上编写程序 xff0c 发现可实现TIM1和TIM8的8路PWM波调控 xff0c 因此上面论述的问题可能是自己在写底层时有某些
  • Ardusub源码解析学习(一)——Ardusub主程序

    APM Sub源码解析学习 xff08 一 xff09 Ardusub主程序 前言一 准备工作二 Ardusub cpp解析2 1 scheduler table2 2 schedulerget scheduler tasks setup
  • Ardusub源码解析学习(二)——电机库

    Ardusub源码解析学习 xff08 二 xff09 电机库学习 一 RC输入与输出1 1 RC Input1 2 RC Output 二 电机库学习2 1 setup motors 2 2 add motor raw 6dof 2 3
  • Ardusub源码解析学习(三)——车辆类型

    APM Sub源码解析学习 xff08 三 xff09 车辆类型 一 前言二 class AP HAL HAL三 class AP Vehicle3 1 h3 2 cpp 四 class Sub4 1 h4 2 cpp 五 总结 一 前言
  • 年度回忆录(2012.10----2013.01)

    寒假结束了 xff0c 年也过完了 xff0c 提前回来一天就开始着手补上这迟到的年终总结 xff0c 写了一个多星期还觉得有些东西没有写出来 xff0c 无奈 xff0c 点到为止吧 2012 年的后半年经历了很多 xff0c 收获了很多
  • Ardusub学习——飞行模式

    参考资料 xff1a Ardusb官方手册 Sub Rework joystick input and pilot input in general Flight Modes Ardusub支持多种飞行模式 xff0c 但是其中一部分需要有
  • Ardusub源码解析学习(五)——从manual model开始

    Ardusub源码解析学习 xff08 五 xff09 从manual model开始 manual init manual run 从本篇开始 xff0c 将会陆续对Ardusub中各种模式进行介绍 xff0c stabilize mod
  • 重读Ardupilot中stabilize model+MAVLINK解包过程

    APM源码和MAVLINK解析学习 重读stabilize stabilize modelinit run handle attitude MAVLINK消息包姿态信息传输过程 之前写的模式都是基于master版本的 xff0c 这次重读s
  • QGC添加自定义组件和发送自定义MAVLINK消息

    QGC添加自定义组件和发送自定义MAVLINK消息 一 添加自定义组件1 1 在飞行界面添加组件1 2 实现组件事件1 3 在MOCK模拟链接中实现验证1 4 验证 二 自定义MAVLINK消息的一些预备知识三 QGC自定义MAVLINK消
  • MAVLINK消息在Ardupilot中的接收和发送过程

    MAVLINK消息在Ardupilot中的接收和发送过程 SCHED TASKupdate receive update send 由于现在网上很多的都是APM旧版本的解释 xff0c 因此把自己的一些学习所得记录下来 截至写博客日期 xf
  • Ardupilot姿态控制器 PID控制流程

    Ardupilot姿态控制器 PID控制流程 一 PID姿态控制器1 1 Copter姿态控制官方原图1 2 ArduCopter V4 X STABILIZE 二 姿态控制器类实现2 1 类成员解析2 1 1 类成员变量2 1 2 类成员
  • APM姿态旋转理论基础

    APM姿态旋转理论基础 一 坐标系1 1 NED坐标系1 2 机体坐标系 二 欧拉角姿态变化率与机体角速度的关系 三 旋转矩阵3 1 基本公式3 2 矩阵作差3 3 旋转矩阵与变换矩阵的区别 四 DCM五 轴角法5 1 基本概念5 2 与旋
  • 详解APM的开方控制器sqrt_controller

    前言 前面说过 xff0c sqrt controller是对P项进行整定用途的 xff0c 目的就是让P项的控制响应 软 下来 xff0c 实际上就是一个经过改进的P控制器 读懂了sqrt controller xff0c 那么你对APM
  • Ardupilot前馈及平滑函数input_euler_angle_roll_pitch_yaw解析

    Ardupilot前馈及平滑函数input euler angle roll pitch yaw解析 源码解析这个函数做了什么部分细节euler accel limit input shaping angle 姿态变化率与机体角速度之间的关
  • Ardupilot倾转分离函数thrust_heading_rotation_angles

    Ardupilot倾转分离函数thrust heading rotation angles 什么是轴角分离源码分析一些细节补充效果显示及进一步修改 本文主要写一下自己对于APM倾转分离 xff08 轴角分离 xff09 函数的一些学习笔记及
  • Spring IOC原理解析

    首先恭喜守宏同学找到了自己心仪的工作 xff0c 入职的事情终于尘埃落定 xff0c 也算是一个新的开始吧 和守宏聊天的时候也说了很多有关工作的事情 xff0c 畅想了以后美好的未来 xff0c 也想到了今后的种种困难 不说别的就是单单在北
  • Ardupilot四元数姿态控制函数attitude_controller_run_quat解析

    Ardupilot四元数姿态控制函数attitude controller run quat解析 源码解析细节讲解thrust heading rotation angles update ang vel target from att e
  • Ardupilot速率控制器rate_controller_run解析

    Ardupilot速率控制器rate controller run解析 PID速率控制器源码解析rate controller run PID运算积分限制update i get ff set xxx 内容补充 xff1a 函数中陀螺仪数据