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解析 的相关文章

  • 自定义 RepositoryRestController 映射 url 在 spring-data-rest 中抛出 404

    我写了一个自定义RepositoryRestController使用其相应的实体存储库 对此 url 执行请求时 查询正在我的控制台中运行 但 url 返回 404 我还可以在日志中看到此 url 的 requestHandlerMappi
  • AngularJS 指令从控制器访问属性

    我正在尝试访问控制器函数中指令的属性 然而 当我访问它时 它是未定义的 我注意到如果我做一个简单的计时器它就可以工作 有没有办法仅在指令及其范围准备好并设置为使用之后才执行代码 我摆弄了它 确保您的控制台已打开 http jsfiddle
  • 如何在 ASP.net 控制器操作中访问整个查询字符串

    我知道如果我有一个像 XController Action id 1 这样的 url 和一个操作方法 void Action int id id 参数将自动从查询字符串中读取 但是 当我事先不知道所有参数的名称时 如何访问整个查询字符串 例
  • ASP.NET MVC - 如果您不想将 .js 文件存储在 /Scripts 中,您将它们放在哪里?

    我有许多 js 文件 我希望将它们存储在与其视图相同的目录中 它们特定于视图 它只是为了将 javascript 与视图的 HTML 分开 但是 将它们添加到 Views ControllerName 目录不起作用 因为当向网络服务器发出
  • 错误:调用非对象上的成员函数 get()

    我正在尝试使用 Swift Message 发送邮件 但是当我发送数据时 它不会发送 并且出现以下错误 FatalErrorException 错误 调用成员函数 get 非对象在 vagrant vendor symfony symfon
  • 如何在 ASP.NET MVC 中将参数传递给局部视图?

    假设我有这个部分视图 Your name is strong firstName lastName strong 可以通过仅限儿童的操作来访问 例如 ChildActionOnly public ActionResult FullName
  • 如何在 Grails 集成测试中制作两个内容不同的帖子

    我正在测试一个控制器 我无法发表两个内容不同的帖子 下面是一个示例 其中我使用一些数据 post1 使用 json1 执行到 cardController 的发布 然后 我使用不同的数据执行另一篇文章 post2 和 json2 但我无法成
  • 我该如何解决这个问题?单元类型存在于两个dll文件中

    我目前正在学习使用 Visual Studio 11 beta 的教程 当尝试在我的一个类中设置字段值的最大长度时 MaxLength 50 public string LastName get set 它出错并且不会让我编译 因为MaxL
  • Spring 3 MVC Controller集成测试-将Principal注入到方法中

    作为 Spring 3 MVC 的一部分 可以将当前登录的用户 原理 对象注入到控制器方法中 E g Controller public class MyController RequestMapping value update meth
  • yii2 在 gridview 中更改控制器操作

    我有 ItemController 并在 actionView 中放置了 Itempicture 的 gridview 我希望当我单击图标视图时 更新和删除 然后转到 ItempictureController 那么如何使用不同的控制器更改
  • CodeIgniter 仅允许在登录时访问某些控制器

    我有一些 CodeIgniter 控制器 只能由已登录的用户访问 即 this gt session gt userdata username 不为空 如果未经身份验证的人尝试访问所述控制器 他们应该收到 header location a
  • 如何确定 rspec 控制器测试的主题?

    所以除了好奇之外 我没有什么充分的理由需要知道这一点 最好的理由 但我不确定这里发生了什么 背景 我正在研究 RSpec 书并更新示例 第 24 章 Rails 控制器有一个消息控制器的测试 spec controllers message
  • 反转博客条目和评论的显示顺序,Ruby on Rails

    我是 Rails 新手 所以可以在这里使用一些帮助 我已经按照几个教程创建了一个博客 其中包含评论 甚至还有一些 AJAX 花哨的内容 但我仍然坚持一些我希望很简单的事情 博客和评论的默认显示是首先列出最旧的 我如何反转它以在顶部显示最新条
  • JavaScript 中的简单金融利率函数

    我正在寻找一个简单的 javascript 金融 RATE 函数 我找到了这个 但似乎太难理解了 我想简化这个功能 需要你的帮助 如果有人有最简单的功能 请回答 这是一个等效的 Excel RATE 函数 var rate function
  • 使用 Joda Time 进行 Grails 控制器单元测试

    当我有一个带有 Joda LocalDateTime 字段的域对象时 一些生成所有创建的控制器测试失败 grails create app bugdemo cd bugdemo grails create domain class Item
  • 如何在Spring-MVC方法中绑定抽象类的子类?

    给定 Spring MVC 控制器中的 保存 方法 RequestMapping value save public void save ModelAttribute MY KEY final MyModel myModel 拥有位于myM
  • Rails - 重定向回来,除非上一页是艺术家页面

    我想重定向回上一页 除非上一页是我的 艺术家 控制器的 显示 操作 所以我想它看起来会是这样的 if previous page was artist show redirect to track artist track else red
  • 如何从控制器运行 symfony 2 run 命令

    我想知道我怎样才能跑交响乐2来自浏览器查询或控制器的命令 这是因为我没有任何可能托管来运行它 并且每个 cron 作业都是由管理员设置的 我什至没有启用exec 因此 当我想测试它时 我必须将命令中的所有内容复制到某个测试控制器 这不是最佳
  • 提醒用户对应用程序进行评分的警报

    正如您可能在某些应用程序中看到的那样 会弹出一个警报 要求用户在 iTunes 中对应用程序进行评分 通常您可以选择的选项如下 当然 这将打开应用程序的评分页面 第二个选项是 不 谢谢 它会关闭警报 第三个选项通常是稍后 它会稍后显示警报
  • ASP.NET MVC OutputCache 不适用于根 URI

    我正在学习 ASP NET MVC 并被一个问题困扰 在HomeController中 Index操作具有OutputCache属性 但它似乎不起作用 HandleError public class HomeController Cont

随机推荐

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

    关于卡尔曼滤波 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 函数中陀螺仪数据