PX4代码学习系列博客(3)——px4固件目录结构和代码风格

2023-05-16

写在前面

px4不是普通的单片机程序,其中没有main函数。它实际上是一个操作系统,上面运行着很多应用程序(类比windows),比如姿态解算,位置解算,姿态控制,位置控制等。每个应用之间通过uORB通信。所以要想读懂px4的程序,就不能按照单片机的思维,先找main函数,再看它调用了哪些函数,然后去别的文件看这些函数是怎么实现的。我的方法是:先明确每个目录下面有什么,然后有针对性地去看,比如要看旋翼的姿态控制,可以去目录Firmware\src\modules\mc_att_control下,要看NuttX的帮助文档,可以去目录Firmware\NuttX\nuttx\Documentation下,等等。

本文所用的固件是1.6.5

目录结构:

px4的源码的根目录下内容如下:

这里写图片描述

由于我的代码用git和云端同步,用eclipse进行编译过,所以会比刚下载的固件多一些内容。

build打头的4个文件夹,是编译后的结果,刚下载的固件是没有的。其中Firmware\build_px4fmu-v2_default\src\firmware\nuttx\px4fmu-v2_default.px4是可以直接在地面站上给飞控下载的二进制文件。其他的编译选项目录结构和这个类似。

cmake文件夹下用到最多的是configs文件夹,都是.cmake文件,这些.cmake文件会调用其他文件夹下的.cmake文件,我们可以不关心其他文件夹。如果用pixhawk硬件,那么常用的是nuttx_px4fmu-v2_default.cmake。还有其他的一些配置,适用于不同的硬件和选择不同的模块(应用程序)进行编译。其中,fmu-v1和fmu-v2适用于Pixhawk,fmu-v3适用于Pixhawk 2,fmu-v4适用于Pixracer,stm32f4discovery用于stm32discovery开发板,rpi适用于树莓派。后缀_default代表默认,_lpe代码不用ekf2而用lpe进位置解算等等。

Documentation文件夹下是一些开发者文档,对理解代码结构和飞控的模式切换有帮助。
Images,integrationtests文件夹目前还不明确。

launch文件夹是仿真环境用到的文件,在gazebo中生成世界,配置ros节点等。比如gazebo_ardrone_empty_world_offboard_attitudedemo.launch这个文件,它需要Firmware\src\platforms\ros\nodes\demo_offboard_position_setpoints在ros中运行。这个demo的结果是gazebo中的飞机模型会上升的1m的高度然后悬停。我曾经在这个文件中改变代码实现在gazebo中飞特定轨迹。由于offboard模式比较危险,可以在这里进行算法的测试,稳定后再到实际飞行器上测试。

mavlink文件夹下是mavlink消息的定义,打包,发送,接收,解包的函数,全部由.h文件组成,相当于库函数。是飞行器与地面站,飞行器之间通信的协议,消息定义比较齐全,并且由于其开源特性可以自行扩展。

msg文件夹下是uORB通信用到的数据结构,它在编译的过程中会自行生成.h文件,比如position_setpoint.msg文件会在Firmware\build_px4fmu-v2_default\src\modules\uORB\topics下生成position_setpoint.h文件。

NuttX文件夹是NuttX系统需要的文件。它属于px4固件的子模块,在没有更新子模块之前,这个文件夹下面是没有任何文件的。

nuttx-打头的两个的文件夹,具体内容没有深究过,不过从字面意思上讲,一个是对于不同硬件版本的配置文件,一个是NuttX系统的补丁。

ROMFS文件夹下是启动过程中调用的文件,Firmware\ROMFS\px4fmu_common\ini.d\rcS是启动脚本,它在stm32底层初始化和NuttX系统初始化完成后执行。它根据参数设置的不同决定启用哪些模块(应用程序),如果是旋翼的话,它会调用Firmware\ROMFS\px4fmu_common\init.d\rc.mc_apps。

src文件夹是源代码,其中dirvers文件夹下是各种传感器的驱动文件,examples文件夹是一些测试用的模块(应用程序),include文件夹下是px比较基础的一些变量定义和文件包含,lib文件夹下是调用的库文件,包括向量,矩阵运算,GPS转XY距离坐标,滤波算法等,platforms文件夹下也是px4专属的一些变量和函数的定义,modules文件夹是学习px4飞控控制算法最关键的部分,因为它的下面是我本文一开始就说的在操作系统上运行的各种功能的应用程序,包括但不限于姿态解算,位置解算,姿态控制,位置控制。

代码阅读方法:

说到px4的代码,我们一般指的是src\modules文件夹下的代码。这个文件夹下的代码是分模块的,每个模块除功能外,代码的风格(函数和变量定义的格式,类的使用和封装)是一样的,所以只要看懂了一个的结构,其他的就很好理解了。我这里以最简单的模块attitude_estimator_q为例来说明。

打开Firmware\src\modules\attitude_estimator_q文件夹,下面有三个文件,其中CMakeLists.txt是编译时用到的文件,attitude_estimator_q_params.c是程序默认参数的设置,都不需要更改。我们只需要关注attitude_estimator_q_main.cpp。
下面这个文件是我把类的实现中除task_main之外的全部去掉,然后在类中定义变量和函数地方加注释形成的。

/****************************************************************************
 *
 *   Copyright (c) 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

 /*
 * Modified from file attitude_estimator_q_main.cpp
 * 2017/08/19
 * author:qianrenzhan(1006325356@qq.com)
 * 为了展示px4代码结构,并不能通过编译
 */

#include <px4_config.h>
#include <px4_posix.h>
#include <px4_tasks.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <poll.h>
#include <fcntl.h>
#include <float.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <uORB/uORB.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/control_state.h>
#include <uORB/topics/vehicle_control_mode.h>
#include <uORB/topics/vehicle_global_position.h>
#include <uORB/topics/att_pos_mocap.h>
#include <uORB/topics/airspeed.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/estimator_status.h>
#include <drivers/drv_hrt.h>

#include <mathlib/mathlib.h>
#include <mathlib/math/filter/LowPassFilter2p.hpp>
#include <lib/geo/geo.h>

#include <systemlib/param/param.h>
#include <systemlib/perf_counter.h>
#include <systemlib/err.h>
#include <systemlib/mavlink_log.h>


extern "C" __EXPORT int attitude_estimator_q_main(int argc, char *argv[]);   
//这是main函数的申明,nuttx的main函数和普通单片机不一样,它的命名格式是“应用程序名称”+“_”+“main”。
//在NUTTX系统上注册的函数,在执行的时候回启动或者关闭这个模块(应用程序),还能返回模块的工作状态。


using math::Vector;
using math::Matrix;
using math::Quaternion;
//用到了math命名空间下的Vector,Matrix,Quaternion类,因为姿态估计涉及到向量,矩阵的运算,以及四元数。

class AttitudeEstimatorQ;
//这是类的前向申明,可以在类没有实现的时候定义类的指针对象。

namespace attitude_estimator_q
{
AttitudeEstimatorQ *instance;
}
//定义类的指针对象instance,它属于命名空间attitude_estimator_q,是全局变量。
//这里的命名空间很关键,因为别的模块也会定义这样的全局变量,但是不同模块可能不是一个人写的,
//变量有冲突的情况下用前缀attitude_estimator_q::就可以解决。


class AttitudeEstimatorQ
{
public:
    AttitudeEstimatorQ();
    //构造函数中得到该模块需要用到的参数的句柄,给变量赋初值。
    ~AttitudeEstimatorQ();

    int     start();                
    //函数功能:为attitude_estimator任务设置优先级,分配堆栈空间,指定服务函数。

    static void task_main_trampoline(int argc, char *argv[]);
    //attitude_estimator任务服务函数,它只调用task_main函数。

    void        task_main();
    //被attitude_estimator任务服务函数调用

private:
    static constexpr float _dt_max = 0.02;
    bool    _task_should_exit = false;      /**< if true, task should exit */
    int     _control_task = -1;             /**< task handle for task */

    //将要订阅的uORB消息
    int     _sensors_sub = -1;
    int     _params_sub = -1;
    int     _vision_sub = -1;
    int     _mocap_sub = -1;
    int     _airspeed_sub = -1;
    int     _global_pos_sub = -1;

    //将要发布的uORB消息
    orb_advert_t    _att_pub = nullptr;
    orb_advert_t    _ctrl_state_pub = nullptr;
    orb_advert_t    _est_state_pub = nullptr;

    struct {
        param_t w_acc;
        param_t w_mag;
        param_t w_ext_hdg;
        param_t w_gyro_bias;
        param_t mag_decl;
        param_t mag_decl_auto;
        param_t acc_comp;
        param_t bias_max;
        param_t ext_hdg_mode;
        param_t airspeed_mode;
    }       _params_handles;        /**< handles for interesting parameters */

    //可以配置的参数
    float       _w_accel = 0.0f;
    float       _w_mag = 0.0f;
    float       _w_ext_hdg = 0.0f;
    float       _w_gyro_bias = 0.0f;
    float       _mag_decl = 0.0f;
    bool        _mag_decl_auto = false;
    bool        _acc_comp = false;
    float       _bias_max = 0.0f;
    int     _ext_hdg_mode = 0;
    int     _airspeed_mode = 0;

    //从uORB获取到的传感器原始值
    Vector<3>   _gyro;
    Vector<3>   _accel;
    Vector<3>   _mag;
    vehicle_attitude_s _vision = {};
    Vector<3>   _vision_hdg;
    att_pos_mocap_s _mocap = {};
    Vector<3>   _mocap_hdg;
    airspeed_s _airspeed = {};

    //解算结果
    Quaternion  _q;
    Vector<3>   _rates;
    Vector<3>   _gyro_bias;
    vehicle_global_position_s _gpos = {};
    Vector<3>   _vel_prev;
    Vector<3>   _pos_acc;

    //低通滤波器
    math::LowPassFilter2p _lp_accel_x;
    math::LowPassFilter2p _lp_accel_y;
    math::LowPassFilter2p _lp_accel_z;
    math::LowPassFilter2p _lp_gyro_x;
    math::LowPassFilter2p _lp_gyro_y;
    math::LowPassFilter2p _lp_gyro_z;

    hrt_abstime _vel_prev_t = 0;

    bool        _inited = false;
    bool        _data_good = false;
    bool        _ext_hdg_good = false;

    orb_advert_t    _mavlink_log_pub = nullptr;

    void update_parameters(bool force);
    //是否进行参数更新

    bool init();
    //变量初始化

    bool update(float dt);
    //关键的解算算法在此处,它在task_main中的while循环中被调用

    // Update magnetic declination (in rads) immediately changing yaw rotation
    void update_mag_declination(float new_declination);
};

void AttitudeEstimatorQ::task_main()
{

#ifdef __PX4_POSIX
    perf_counter_t _perf_accel(perf_alloc_once(PC_ELAPSED, "sim_accel_delay"));
    perf_counter_t _perf_mpu(perf_alloc_once(PC_ELAPSED, "sim_mpu_delay"));
    perf_counter_t _perf_mag(perf_alloc_once(PC_ELAPSED, "sim_mag_delay"));
#endif

    //订阅需要的消息
    _sensors_sub = orb_subscribe(ORB_ID(sensor_combined));
    _vision_sub = orb_subscribe(ORB_ID(vehicle_vision_attitude));
    _mocap_sub = orb_subscribe(ORB_ID(att_pos_mocap));
    _airspeed_sub = orb_subscribe(ORB_ID(airspeed));
    _params_sub = orb_subscribe(ORB_ID(parameter_update));
    _global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position));

    //更新参数
    update_parameters(true);

    hrt_abstime last_time = 0;


    px4_pollfd_struct_t fds[1] = {};
    fds[0].fd = _sensors_sub;
    fds[0].events = POLLIN;

    while (!_task_should_exit) {
        int ret = px4_poll(fds, 1, 1000);
        if (ret < 0) {
            // Poll error, sleep and try again
            usleep(10000);
            PX4_WARN("Q POLL ERROR");
            continue;
            //等待有sensor_combined消息传来,否则继续等待。
        } else if (ret == 0) {
            // Poll timeout, do nothing
            PX4_WARN("Q POLL TIMEOUT");
            continue;
            //等待有sensor_combined消息传来,否则继续等待。
        }

        update_parameters(false);

        // Update sensors
        sensor_combined_s sensors;

        if (!orb_copy(ORB_ID(sensor_combined), _sensors_sub, &sensors)) {
            // 获取订阅到的主题

            if (sensors.timestamp > 0) {
                //原始数据经过低通滤波器
                _gyro(0) = _lp_gyro_x.apply(sensors.gyro_rad[0]);
                _gyro(1) = _lp_gyro_y.apply(sensors.gyro_rad[1]);
                _gyro(2) = _lp_gyro_z.apply(sensors.gyro_rad[2]);
            }
            if (sensors.accelerometer_timestamp_relative != sensor_combined_s::RELATIVE_TIMESTAMP_INVALID) {
                //原始数据经过低通滤波器
                _accel(0) = _lp_accel_x.apply(sensors.accelerometer_m_s2[0]);
                _accel(1) = _lp_accel_y.apply(sensors.accelerometer_m_s2[1]);
                _accel(2) = _lp_accel_z.apply(sensors.accelerometer_m_s2[2]);
                if (_accel.length() < 0.01f) {
                    PX4_DEBUG("WARNING: degenerate accel!");
                    continue;
                }
            }
            if (sensors.magnetometer_timestamp_relative != sensor_combined_s::RELATIVE_TIMESTAMP_INVALID) {
                _mag(0) = sensors.magnetometer_ga[0];
                _mag(1) = sensors.magnetometer_ga[1];
                _mag(2) = sensors.magnetometer_ga[2];
                if (_mag.length() < 0.01f) {
                    PX4_DEBUG("WARNING: degenerate mag!");
                    continue;
                }
            }
            _data_good = true;
        }

        //更新视觉和动作捕捉的消息
        bool vision_updated = false;

        //检查是否有新一帧的消息被发布
        orb_check(_vision_sub, &vision_updated);

        bool mocap_updated = false;
        orb_check(_mocap_sub, &mocap_updated);

        if (vision_updated) {
            orb_copy(ORB_ID(vehicle_vision_attitude), _vision_sub, &_vision);
            math::Quaternion q(_vision.q);

            math::Matrix<3, 3> Rvis = q.to_dcm();
            math::Vector<3> v(1.0f, 0.0f, 0.4f);

            // Rvis is Rwr (robot respect to world) while v is respect to world.
            // Hence Rvis must be transposed having (Rwr)' * Vw
            // Rrw * Vw = vn. This way we have consistency
            _vision_hdg = Rvis.transposed() * v;
        }

        if (mocap_updated) {
            orb_copy(ORB_ID(att_pos_mocap), _mocap_sub, &_mocap);
            math::Quaternion q(_mocap.q);
            math::Matrix<3, 3> Rmoc = q.to_dcm();

            math::Vector<3> v(1.0f, 0.0f, 0.4f);

            // Rmoc is Rwr (robot respect to world) while v is respect to world.
            // Hence Rmoc must be transposed having (Rwr)' * Vw
            // Rrw * Vw = vn. This way we have consistency
            _mocap_hdg = Rmoc.transposed() * v;
        }

        //省略airspeed和gpos部分
        /*
        bool airspeed_updated = false;
        bool gpos_updated;
        */

        //计算时间间隔,hrt_absolute_time这个函数即使任务在执行过程中被中断打断,也能返回正确的时间。
        hrt_abstime now = hrt_absolute_time();
        float dt = (last_time > 0) ? ((now  - last_time) / 1000000.0f) : 0.00001f;
        last_time = now;

        if (dt > _dt_max) {
            dt = _dt_max;
        }

        if (!update(dt)) {
        //关键的解算算法在这个函数中
            continue;
        }

        //打包将要发布的消息vehicle_attitude
        {
            vehicle_attitude_s att = {
                .timestamp = sensors.timestamp,
                .rollspeed = _rates(0),
                .pitchspeed = _rates(1),
                .yawspeed = _rates(2),
                .q = {_q(0), _q(1), _q(2), _q(3)}
            };

            /* the instance count is not used here */
            int att_inst;
            orb_publish_auto(ORB_ID(vehicle_attitude), &_att_pub, &att, &att_inst, ORB_PRIO_HIGH);
        }
        //打包将要发布的消息ctrl_state
        {
            //此处省略
        }
    }

    //任务结束后取消订阅这些消息
    orb_unsubscribe(_sensors_sub);
    orb_unsubscribe(_vision_sub);
    orb_unsubscribe(_mocap_sub);
    orb_unsubscribe(_airspeed_sub);
    orb_unsubscribe(_params_sub);
    orb_unsubscribe(_global_pos_sub);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PX4代码学习系列博客(3)——px4固件目录结构和代码风格 的相关文章

  • 主流PCB画图软件的对比区别(AD、Pads、Allegro)

    国内的EDA软件市场几乎被三家瓜分 xff0c 分别是Altium Mentor Pads Cadence xff0c 也是我们这次主要分析和比较的软件 本人用的多的是 Alitum 也用过allegro xff0c pads目前还没用过
  • 新书推荐 |《Prometheus监控实战》

    新书推荐 Prometheus监控实战 点击上图了解及购买 Docker公司前服务与支持副总裁 Kickstarter前首席技术官 Empatico首席技术官撰写 xff0c 全方位介绍继Kubernetes之后的第二个CNCF毕业项目 P
  • 腾讯大数据总体架构图,对外公开!

    导读 xff1a 腾讯作为国内体量最大的互联网公司之一 xff0c 业务涵盖用户日常生活的方方面面 xff0c 面对如此巨大业务数据量 xff0c 如果不能对数据进行专业化处理并高效有序地存 管 用 xff0c 如果不能使数据产生应有的价值
  • API安全实战

    一提起 信息安全 xff0c 不管是业内专家还是所谓的 吃瓜群众 xff0c 多半都会在脑海中浮现 网络安全 Web安全 软件安全 数据安全 等常见的词汇 市面上绝大多数安全类书籍也多集中在这几个领域 xff0c 而从API视角阐释信息安全
  • 【第115期】世界一流大学计算机专业,都在用哪些书当教材?

    导读 xff1a 转眼间离新学期开学又不远了 清华 北大 MIT CMU 斯坦福的学霸们在新学期里要学什么 xff1f 本文就带你盘点一下那些世界名校计算机专业采用的教材 不用多说 xff0c 每本都是经典的烧脑技术书 xff0c 建议配合
  • 什么是AB实验?能解决什么问题?终于有人讲明白了

    导读 xff1a 走向身边的AB实验 作者 xff1a 木羊同学 来源 xff1a 大数据DT xff08 ID xff1a hzdashuju xff09 AB实验 是一个从统计学中借来的工具 我和大家一样 xff0c 每次只要看到 统计
  • 树莓派3b引脚图

    如上图所示 xff0c 我们可以很清楚的看到各个引脚的功能 例如我们想使用pwm引脚来控制舵机 xff0c 则我们可以考虑使用其中的 BCM18 PWM0 和 BCM13 PWM1 在使用wiringPi库时 xff0c 我们定义的引脚即B
  • 跟踪slab分配堆栈流程的方法(perf、systemtap)

    跟踪slab分配堆栈流程的方法 xff08 perf systemtap xff09 内存泄露是在解决内核故障会遇到的棘手情况 xff0c 根据具体的内存使用情况 xff0c 追踪相应slab cache的分配堆栈流程 xff0c 是追踪泄
  • prometheus+grafana监控mysql、canal服务器

    一 prometheus配置 1 prometheus安装 1 1官网下载安装包 xff1a https prometheus io download 1 2解压安装包 xff1a tar zxvf prometheus 2 6 1 lin
  • mac配置jmeter

    一 步骤 1 安装jdk1 8版本 xff0c 因为jmeter是基于java环境运行的 2 安装jmeter5 x版本 二 安装jdk 1 下载jdk Java Downloads Oracle 2 下载好之后安装 xff0c 全部下一步
  • 操作系统(四):动态链接与静态链接的区别

    在回答这个问题之前希望大家大概了解一个文件编译的过程 xff0c 比如一个C文件在编译成功后文件夹里的文件会有什么变化 xff0c 大家可以先去创建一个helloworld c的文件 xff0c 观察其编译后的变化 那么问题来了 面试官经常
  • 【OpenVINS】(一)ZUPT

    参考 xff1a Measurement Update Derivations Zero Velocity Update 在典型的自主汽车场景中 xff0c 传感器系统将在停止灯处变得静止 xff0c 其中动态物体 xff08 例如交叉路口
  • OpenVINS与MSCKF_VIO RK4积分对比

    VIO系统在使用IMU测量值进行状态预测时 xff0c 需要将连续时间的微分方程离散化为差分方程 xff0c 离散化的本质是积分 xff0c 根据数值积分近似程度不同 xff0c 常用的有欧拉法 中点法和四阶龙格库塔法等 xff0c Ope
  • 全盘拷贝linux系统,转移至另一硬盘

    首先制作ubuntu启动盘 xff0c 选择try ubuntu进入live ubuntu系统 查看需拷贝硬盘盘符 span class token function sudo span span class token function
  • EKF SLAM

    EKF 方法是解决 SLAM 问题的一种经典方法 xff0c 其应用依赖于运动模型和观测模型的高斯噪声假设 在 SLAM 问题首次提出不久后 xff0c Smith 和 Cheesman 及 Durrant Whyte对机器人和路标间的几何
  • 如何将立创EDA中的元器件的原理图/封装和3D模型导入AD的库中

    如何将立创EDA中的元器件的原理图 封装和3D模型导入AD的库中 工具 xff1a AD 立创EDA专业版 fusion360 或其他3D软件 导入原理图 封装 在立创商城复制所需元器件的编号 打开立创EDA标准版或专业版 xff0c 这里
  • Xshell 提示 “要继续使用此程序,您必须应用最新的更新或使用新版本“的解决方案

    要想解决Xshell提示更新最新版问题 有两种方案 方案一 手动修改系统时间 步骤如下 右键右下角时间 弹出如下窗口 2 选中 调整日期 时间 A 并点击 弹出如下页面 更改时间 更改成之前的年份 如下图 更改成功后 再打开相应的应用 Xs
  • 2020.2.22 排位赛 G - Bucket Brigade(BFS)

    Bucket Brigade 题面 题目分析 BFS模板题 代码 span class token macro property span class token directive keyword include span span cl
  • Canal入门(二)

    Canal入门 xff08 二 xff09 canal kafka quickStart 1 基本说明 canal 1 1 1版本之后 默认支持将canal server接收到的binlog数据直接投递到MQ 目前默认支持的MQ系统有 ka
  • PID调节三个参数的作用

    1 比例调节作用 xff1a 按比例反应系统的偏差 系统一旦出现了偏差 比例调节立即产生调节作用用以减少偏差 比例作用大 可 以加快调节 能迅速反应误差 xff0c 从而减小稳态误差 但是 xff0c 比例控制不能消除稳态误差 过大的比例

随机推荐

  • (centos7)docker+jenkins运行python自动化

    目录 一 实现思路 二 环境准备 1 在liunx上安装docker 2 docker安装jenkins 三 访问前设置 四 配置jenkins容器 五 jenkins插件安装 1 安装git 2 安装docker 3 html Publi
  • OJ在线编程常见输入输出练习

    OJ在线编程常见输入输出练习 4 a 43 b 4 输入描述 xff1a 输入数据包括多组 每组数据一行 每行的第一个整数为整数的个数n 1 lt 61 n lt 61 100 n为0的时候结束输入 接下来n个正整数 即需要求和的每个正整数
  • js中数组与集合的相互转化

    数组 gt 集合 var a 61 1 2 3 4 5 5 var set 61 new Set a console log set 1 2 3 4 5 集合 gt 数组 var set 61 new Set set add 1 set a
  • Linux make/Makefile详解

    会不会写makefile xff0c 从侧面说明了一个人是否具备完成大型工程的能力 一个工程中的源文件不计数 xff0c 其按类型 功能 模块分别放在若干个目录中 xff0c makefile定义了一系列的 规则来指定 xff0c 哪些文件
  • 大疆H20系列吊舱,录制的视频含义

  • 写算法的方法

    写算法步骤 xff1a xff08 以下方法 xff0c 都是老生常谈 但是非常简单有用 xff09 数据结构 xff08 所有的算法都是基于数据结构的操作 所有算法都是针对数据结构的属性进行操作 列出所有的属性 xff0c 写算法逐项修改
  • Windows系统下QT+OpenCasCAD仿真开发

    背景 最近开发了一个六自由度机械臂调姿平台的控制软件 xff0c 集成了API激光跟踪仪和KUKA机器人 xff0c 实现了根据产品的测量位姿驱动仿真环境中模型并且实现模型间的碰撞检测 其中KUKA机器人的控制可以参考笔者以前的博客 xff
  • 飞控IMU姿态估计流程

    飞控中使用加速度计 xff0c 陀螺仪 xff0c 磁罗盘进行姿态估计算法流程 step1 xff1a 获取陀螺仪 xff0c 加速度计 xff0c 磁罗盘的原始数值 step2 xff1a 陀螺仪 xff0c 加速度计减去固定的偏移后得到
  • 图拓扑关系可视化的qt实现

    前言 最近在做数据可视化的相关工作 xff0c 包括曲线图 xff0c 航迹图 xff0c 图结构 xff0c 树结构等 其中树结构相关的工作笔者以前曾经做过 xff0c 可以参考笔者以前的博客 qt自定义树形控件之一和qt自定义树形控件之
  • 基于qwt3D 的3D航迹图的实现

    前言 使用qt实现三维空间直角坐标系中的航迹实时绘制网上很难查到资料 在qt下实现3D绘图通常实现方式有OpenGL VTK qwt3d QtDataVisualization等 Qcharts QCustomPlot只支持2D绘图 这里给
  • 树莓派4b连接RealSense T265

    使用的是树莓派4 8G版本 准备连接RealSense T265的双目相机 T265目前官方编译好的的只有Ubuntu16和18 其他的系统版本需要自己编译realsense驱动 安装ubuntu20 10 https ubuntu com
  • Dockerfile文件解释

    一 先来看一个简单的 Dockerfile 这个Dockerfile作用是打一个python3项目环境 FROM python 3 alpine WORKDIR app ADD app RUN pip3 install r requirem
  • 一文读懂BLOB算法

    算法执行效果 相关参考资料 看着玩的 BLOB算法简述 https blog csdn net icyrat article details 6594574 话说这老哥写的也太 简 了吧 完全口水话 把blob算法说的很神秘 说什么把blo
  • Sobel算法优化 AVX2与GPU

    国庆假期 一口气肝了10篇博客 基本上把最近的成果都做了遍总结 假期最后一天 以一个比较轻松的博客主题结束吧 这次是Sobel算法的AVX2优化 执行效果 sobel算法的原理 使用如下的卷积核 c 硬写 span class token
  • 随机Hough直线算法的改进

    背景介绍 随机Hough直线算法相比Hough直线算法 xff0c 算法效率会有提高 xff0c 但仍不能满足工程需求 因此提出使用生长的随机Hough直线算法 该算法对随机Hough直线算法进行改造 xff0c 在随机选点转到Hough空
  • MATLAB编写的读取.mat文件数据并画曲线图的gui程序

    matlab编写的读取sd卡数据的gui程序 界面截图 xff1a 打开文件界面 xff1a 导入数据后截图 xff1a 是不是高端大气上档次 xff0c 不要急 xff0c 慢慢往下看 xff0c 后面更精彩 xff0c 代码会贴出来的
  • px4飞控位置估计lpe移植到vs

    本文主要内容 px4飞控的位置估计有两种方式 xff0c 一是inav xff0c 二是lpe xff0c 用到的传感器用加速度计 xff0c 磁场传感器 xff0c gps xff0c 超声 xff0c 激光 xff0c 气压 xff0c
  • 常见的信号平滑处理方法

    本文介绍了常见的信号平滑处理方法 xff1a xff08 一阶滤波 xff0c 互补滤波 xff0c 卡尔曼滤波 xff09
  • PX4代码学习系列博客(1)——开发环境配置

    写在前面 虽然有很多关于px4博客 xff0c 但还是想自己亲手写 xff0c 一来记录自己的学习过程 xff0c 以备将来复习 xff0c 二来方便后来者参考学习 xff0c 好多西当然要大家分享 关于px4飞控程序的博客 xff0c 我
  • PX4代码学习系列博客(3)——px4固件目录结构和代码风格

    写在前面 px4不是普通的单片机程序 xff0c 其中没有main函数 它实际上是一个操作系统 xff0c 上面运行着很多应用程序 xff08 类比windows xff09 xff0c 比如姿态解算 xff0c 位置解算 xff0c 姿态