VINS-Mono代码阅读笔记(十一):进入pose_graph节点代码分析

2023-05-16

本篇笔记紧接着上一篇VINS-Mono代码阅读笔记(十):vins_estimator中的非线性优化,来接着学习VINS-Mono系统中重定位和全局优化部部分的代码。这部分代码在pose_graph节点中,首先看一下在第一篇笔记中贴出来的下面这张系统运行时的Node graph图。

从这张图中可以看到pose_graph在系统节点中所处的位置以及它要订阅和发布的topic有哪些,rviz就是根据posegraph节点中发布的topic来进行可视化显示的。那么下面就根据这张图,结合代码和论文来学习这部分代码。

1.入口main函数

pose_graph节点的main函数在pose_graph_node.cpp中,启动pose_graph节点的启动代码在euroc.launch(vin_estimator/launch下的所有launch文件)文件当中,代码如下:

<launch>
    <arg name="config_path" default = "$(find feature_tracker)/../config/euroc/euroc_config.yaml" />
	  <arg name="vins_path" default = "$(find feature_tracker)/../config/../" />
    
    <node name="feature_tracker" pkg="feature_tracker" type="feature_tracker" output="log">
        <param name="config_file" type="string" value="$(arg config_path)" />
        <param name="vins_folder" type="string" value="$(arg vins_path)" />
    </node>

    <node name="vins_estimator" pkg="vins_estimator" type="vins_estimator" output="screen">
       <param name="config_file" type="string" value="$(arg config_path)" />
       <param name="vins_folder" type="string" value="$(arg vins_path)" />
    </node>

    <node name="pose_graph" pkg="pose_graph" type="pose_graph" output="screen">
        <param name="config_file" type="string" value="$(arg config_path)" />
        <param name="visualization_shift_x" type="int" value="0" />
        <param name="visualization_shift_y" type="int" value="0" />
        <param name="skip_cnt" type="int" value="0" />
        <param name="skip_dis" type="double" value="0" />
    </node>

</launch>

这个launch文件里配置了所有节点运行时需要的参数,这里我们需要留意一下pose_graph下的几个参数,在后边的代码流程分析中会看到它们的身影。

pose_graph中main函数代码如下:

int main(int argc, char **argv)
{
    //1.ROS相关初始化
    ros::init(argc, argv, "pose_graph");
    ros::NodeHandle n("~");
    //2.注册topic的发布
    posegraph.registerPub(n);

    // read param
    //3.读取相关参数
    n.getParam("visualization_shift_x", VISUALIZATION_SHIFT_X);//在euroc.launch中为0
    n.getParam("visualization_shift_y", VISUALIZATION_SHIFT_Y);//在euroc.launch中为0
    n.getParam("skip_cnt", SKIP_CNT);//在euroc.launch中为0
    n.getParam("skip_dis", SKIP_DIS);//在euroc.launch中为0
    std::string config_file;
    n.getParam("config_file", config_file);
    cv::FileStorage fsSettings(config_file, cv::FileStorage::READ);
    if(!fsSettings.isOpened())
    {
        std::cerr << "ERROR: Wrong path to settings" << std::endl;
    }

    double camera_visual_size = fsSettings["visualize_camera_size"];
    cameraposevisual.setScale(camera_visual_size);
    cameraposevisual.setLineWidth(camera_visual_size / 10.0);

    //配置文件中该值为1
    LOOP_CLOSURE = fsSettings["loop_closure"];
    std::string IMAGE_TOPIC;
    int LOAD_PREVIOUS_POSE_GRAPH;
    //闭环检测的判断
    if (LOOP_CLOSURE)
    {
        //闭环情况下相关参数的读取
        ROW = fsSettings["image_height"];
        COL = fsSettings["image_width"];
        std::string pkg_path = ros::package::getPath("pose_graph");
        string vocabulary_file = pkg_path + "/../support_files/brief_k10L6.bin";
        cout << "vocabulary_file" << vocabulary_file << endl;
        posegraph.loadVocabulary(vocabulary_file);

        BRIEF_PATTERN_FILE = pkg_path + "/../support_files/brief_pattern.yml";
        cout << "BRIEF_PATTERN_FILE" << BRIEF_PATTERN_FILE << endl;
        m_camera = camodocal::CameraFactory::instance()->generateCameraFromYamlFile(config_file.c_str());

        fsSettings["image_topic"] >> IMAGE_TOPIC;        
        fsSettings["pose_graph_save_path"] >> POSE_GRAPH_SAVE_PATH;
        fsSettings["output_path"] >> VINS_RESULT_PATH;
        fsSettings["save_image"] >> DEBUG_IMAGE;

        // create folder if not exists
        FileSystemHelper::createDirectoryIfNotExists(POSE_GRAPH_SAVE_PATH.c_str());
        FileSystemHelper::createDirectoryIfNotExists(VINS_RESULT_PATH.c_str());

        VISUALIZE_IMU_FORWARD = fsSettings["visualize_imu_forward"];
        LOAD_PREVIOUS_POSE_GRAPH = fsSettings["load_previous_pose_graph"];
        FAST_RELOCALIZATION = fsSettings["fast_relocalization"];
        VINS_RESULT_PATH = VINS_RESULT_PATH + "/vins_result_loop.csv";
        std::ofstream fout(VINS_RESULT_PATH, std::ios::out);
        fout.close();
        fsSettings.release();
        //4.加载先前保存的位姿图
        if (LOAD_PREVIOUS_POSE_GRAPH)
        {
            printf("load pose graph\n");
            m_process.lock();
            posegraph.loadPoseGraph();
            m_process.unlock();
            printf("load pose graph finish\n");
            load_flag = 1;
        }
        else
        {
            printf("no previous pose graph\n");
            load_flag = 1;
        }
    }

    fsSettings.release();
    /**
     * 5.订阅了七个topic
    */
    //IMU前向传播
    ros::Subscriber sub_imu_forward = n.subscribe("/vins_estimator/imu_propagate", 2000, imu_forward_callback);
    //订阅里程计topic
    ros::Subscriber sub_vio = n.subscribe("/vins_estimator/odometry", 2000, vio_callback);
    //订阅图像img
    ros::Subscriber sub_image = n.subscribe(IMAGE_TOPIC, 2000, image_callback);
    //订阅keyframe pose
    ros::Subscriber sub_pose = n.subscribe("/vins_estimator/keyframe_pose", 2000, pose_callback);
    //订阅相机到IMU之间的外参
    ros::Subscriber sub_extrinsic = n.subscribe("/vins_estimator/extrinsic", 2000, extrinsic_callback);
    //订阅点云topic
    ros::Subscriber sub_point = n.subscribe("/vins_estimator/keyframe_point", 2000, point_callback);
    //订阅重定位相对位姿
    ros::Subscriber sub_relo_relative_pose = n.subscribe("/vins_estimator/relo_relative_pose", 2000, relo_relative_pose_callback);
    //6.创建pose_graph中要发布的5个topic的发布器
    pub_match_img = n.advertise<sensor_msgs::Image>("match_image", 1000);
    pub_camera_pose_visual = n.advertise<visualization_msgs::MarkerArray>("camera_pose_visual", 1000);
    pub_key_odometrys = n.advertise<visualization_msgs::Marker>("key_odometrys", 1000);
    pub_vio_path = n.advertise<nav_msgs::Path>("no_loop_path", 1000);
    pub_match_points = n.advertise<sensor_msgs::PointCloud>("match_points", 100);

    std::thread measurement_process;
    std::thread keyboard_command_process;
    //7.创建process线程,也相当于是pose_graph的主线程
    measurement_process = std::thread(process);
    //8.创建command线程,监听命令行中键盘的输入
    keyboard_command_process = std::thread(command);


    ros::spin();

    return 0;
}

总结一下,main函数中主要做了以下工作:

main函数中,订阅的topic回调函数中对msg的解析处理基本上都是将解析出来的数据存入本pose_graph节点中的buf当中,这些数据在后边的process线程中会用到。process线程当中的工作才是posegraph节点的灵魂所在,所以也是我们后边要重点分析的。

2.poseGraph构造函数

在main函数中有个posegraph对象,该对象是在pose_graph_node.cpp中创建的全局对象。PoseGraph类的构造函数在创建该对象的时候,创建了一个优化4自由度位姿的线程,全局优化就是在这个线程t_optimization当中进行的,optimize4DoF我们后边会重点关注。

/**
 * PoseGraph构造函数
*/
PoseGraph::PoseGraph()
{
    posegraph_visualization = new CameraPoseVisualization(1.0, 0.0, 1.0, 1.0);
    posegraph_visualization->setScale(0.1);
    posegraph_visualization->setLineWidth(0.01);
    //创建位姿优化线程
    t_optimization = std::thread(&PoseGraph::optimize4DoF, this);
    earliest_loop_index = -1;
    t_drift = Eigen::Vector3d(0, 0, 0);
    yaw_drift = 0;
    r_drift = Eigen::Matrix3d::Identity();
    w_t_vio = Eigen::Vector3d(0, 0, 0);
    w_r_vio = Eigen::Matrix3d::Identity();
    global_index = 0;
    sequence_cnt = 0;
    sequence_loop.push_back(0);
    base_sequence = 1;

}

3.process线程

process线程入口函数代码如下:

/**
 * process线程入口函数
*/
void process()
{
    //1.是否进行闭环检测的判断,不过不做闭环检测则直接返回
    if (!LOOP_CLOSURE)
        return;
    while (true)//该线程一直在循环执行
    {
        sensor_msgs::ImageConstPtr image_msg = NULL;
        sensor_msgs::PointCloudConstPtr point_msg = NULL;
        nav_msgs::Odometry::ConstPtr pose_msg = NULL;

        // find out the messages with same time stamp
        m_buf.lock();
        //2.获取“相同时间戳”内的pose_msg、image_msg、point_msg
        if(!image_buf.empty() && !point_buf.empty() && !pose_buf.empty())
        {
            //图像时间戳晚于位姿时间戳,则将该位姿pop出去
            if (image_buf.front()->header.stamp.toSec() > pose_buf.front()->header.stamp.toSec())
            {
                pose_buf.pop();
                printf("throw pose at beginning\n");
            }
            else if (image_buf.front()->header.stamp.toSec() > point_buf.front()->header.stamp.toSec())
            {
                //图像时间戳晚于点云时间戳,则将点云位姿pop出去
                point_buf.pop();
                printf("throw point at beginning\n");
            }
            else if (image_buf.back()->header.stamp.toSec() >= pose_buf.front()->header.stamp.toSec() 
                && point_buf.back()->header.stamp.toSec() >= pose_buf.front()->header.stamp.toSec())
            {
                //则pose_msg中存放的是关键帧位姿
                pose_msg = pose_buf.front();
                pose_buf.pop();
                while (!pose_buf.empty())
                    pose_buf.pop();
                while (image_buf.front()->header.stamp.toSec() < pose_msg->header.stamp.toSec())
                    image_buf.pop();
                image_msg = image_buf.front();
                image_buf.pop();

                while (point_buf.front()->header.stamp.toSec() < pose_msg->header.stamp.toSec())
                    point_buf.pop();
                point_msg = point_buf.front();
                point_buf.pop();
            }
        }
        m_buf.unlock();

        if (pose_msg != NULL)
        {
            //printf(" pose time %f \n", pose_msg->header.stamp.toSec());
            //printf(" point time %f \n", point_msg->header.stamp.toSec());
            //printf(" image time %f \n", image_msg->header.stamp.toSec());
            // skip fisrt few SKIP_FIRST_CNT值为10
            //3.剔除掉了前SKIP_FIRST_CNT(值为10)帧数据
            if (skip_first_cnt < SKIP_FIRST_CNT)
            {
                skip_first_cnt++;
                continue;
            }
            //SKIP_CNT在euroc.launch中为0
            if (skip_cnt < SKIP_CNT)
            {
                skip_cnt++;
                continue;
            }
            else
            {
                skip_cnt = 0;
            }
            //4.解析image_msg信息存入ptr变量当中
            cv_bridge::CvImageConstPtr ptr;
            if (image_msg->encoding == "8UC1")
            {
                sensor_msgs::Image img;
                img.header = image_msg->header;
                img.height = image_msg->height;
                img.width = image_msg->width;
                img.is_bigendian = image_msg->is_bigendian;
                img.step = image_msg->step;
                img.data = image_msg->data;
                img.encoding = "mono8";
                ptr = cv_bridge::toCvCopy(img, sensor_msgs::image_encodings::MONO8);
            }
            else
                ptr = cv_bridge::toCvCopy(image_msg, sensor_msgs::image_encodings::MONO8);
            
            cv::Mat image = ptr->image;
            // build keyframe
            //5.将当前图像位置和上次图像的位置之间的距离大于SKIP_DIS的图像,创建为关键帧并加入到位姿图当中
            Vector3d T = Vector3d(pose_msg->pose.pose.position.x,
                                  pose_msg->pose.pose.position.y,
                                  pose_msg->pose.pose.position.z);
            Matrix3d R = Quaterniond(pose_msg->pose.pose.orientation.w,
                                     pose_msg->pose.pose.orientation.x,
                                     pose_msg->pose.pose.orientation.y,
                                     pose_msg->pose.pose.orientation.z).toRotationMatrix();
            //计算当前帧图像的位置距离上帧图像之间的距离,并判断是否大于SKIP_DIS
            if((T - last_t).norm() > SKIP_DIS)//SKIP_DIS值为0
            {
                vector<cv::Point3f> point_3d; 
                vector<cv::Point2f> point_2d_uv; 
                vector<cv::Point2f> point_2d_normal;
                vector<double> point_id;
                //遍历点云消息中的点
                for (unsigned int i = 0; i < point_msg->points.size(); i++)
                {
                    cv::Point3f p_3d;
                    p_3d.x = point_msg->points[i].x;
                    p_3d.y = point_msg->points[i].y;
                    p_3d.z = point_msg->points[i].z;
                    point_3d.push_back(p_3d);

                    cv::Point2f p_2d_uv, p_2d_normal;
                    double p_id;
                    p_2d_normal.x = point_msg->channels[i].values[0];
                    p_2d_normal.y = point_msg->channels[i].values[1];
                    p_2d_uv.x = point_msg->channels[i].values[2];
                    p_2d_uv.y = point_msg->channels[i].values[3];
                    p_id = point_msg->channels[i].values[4];
                    point_2d_normal.push_back(p_2d_normal);
                    point_2d_uv.push_back(p_2d_uv);
                    point_id.push_back(p_id);

                    //printf("u %f, v %f \n", p_2d_uv.x, p_2d_uv.y);
                }
                //创建关键帧
                KeyFrame* keyframe = new KeyFrame(pose_msg->header.stamp.toSec(), frame_index, T, R, image,
                                   point_3d, point_2d_uv, point_2d_normal, point_id, sequence);   
                m_process.lock();
                start_flag = 1;
                //位姿图中加入关键帧,flag_detect_loop设置为1
                posegraph.addKeyFrame(keyframe, 1);
                m_process.unlock();
                frame_index++;
                last_t = T;
            }
        }
        //6.线程休眠5ms
        std::chrono::milliseconds dura(5);
        std::this_thread::sleep_for(dura);
    }
}

process中的核心操作,就是根据estimator节点当中发送的关键帧位姿来创建“符合条件”的新关键帧添加到位姿图当中。所有的闭环检测和重定位等操作都在posegraph.addKeyFrame当中进行,后边重点分析这块。

4.command线程

command线程中要处理的工作相对要少的多,主要是检测用户键盘输入是否为's'和'n'。如果接收到了键盘输入的's',则保存位姿图到指定的路径中;如果接收到的键盘输入为'n',则创建新的位姿图序列,这里最多支持5个位姿图序列。每一个关键帧都有其所在的序列(对应KeyFrame类当中的int sequence)。这里保存位姿图的操作,在后边将闭环检测和重定位分析清楚后对其再做解释。

void command()
{
    if (!LOOP_CLOSURE)
        return;
    while(1)
    {
        //检查用户键盘输入是否为s
        char c = getchar();
        if (c == 's')
        {
            m_process.lock();
            //用户键盘输入s后,保存当前的位姿图(地图)
            posegraph.savePoseGraph();
            m_process.unlock();
            printf("save pose graph finish\nyou can set 'load_previous_pose_graph' to 1 in the config file to reuse it next time\n");
            // printf("program shutting down...\n");
            // ros::shutdown();
        }
        //检查用户键盘输入是否为n,为n则开始一个新的图像序列
        if (c == 'n')
            new_sequence();

        std::chrono::milliseconds dura(5);
        std::this_thread::sleep_for(dura);
    }
}

VINS-Mono代码阅读笔记(十二):将关键帧加入位姿图当中

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

VINS-Mono代码阅读笔记(十一):进入pose_graph节点代码分析 的相关文章

  • 如何创建行列总和为 1 和 0 的对称矩阵

    我试图找到一种优雅的算法来创建 1 和 0 的 N x N 矩阵 但有以下限制 每行每列之和必须为Q 可自由选择 对角线必须是 0 矩阵必须是对称的 矩阵不一定是随机的 然而 随机和非随机解都很有趣 因此对于 Q 偶数 只需使每一行成为向量
  • 平台调用 F# 回调函数

    我在 Raspberry Pi 2 ARM 7 和单声道 上使用 F 我目前正在尝试使用用 C 编写的 WiringPi 库 我已经成功地使用 P Invoke 来使用一些函数 现在我尝试使用中断 参见http wiringpi com r
  • 导出图像格式的访问图表?

    我在 Access 表单中创建了一个图表 并将其以图像格式导出 这很容易完成 但是当我关闭表单时 问题就出现了 它显示了一条弹出消息 对图表对象的操作失败 OLE 服务器可能未注册 要注册 OLE 服务器 请重新安装它 然后我做了一些改变
  • Mono - XDocument.Load 因 LoadOptions.PreserveWhitespace 失败

    使用 Mono 版本 2 10 5 以下代码在任何 XML 文档上都会失败 using System using System Collections Generic using System Linq using System IO us
  • ggplot2:将面/条文本分割成两行

    考虑以下带有长面 条带文本的 ggplot2 图 断成两行 该文本超出了专门用于分面标题的区域 library ggplot2 x lt c 1 3 1 3 y lt c 3 1 1 3 grp lt c 0 0 0 1 1 1 p lt
  • 为什么A*的复杂度在内存中是指数级的?

    维基百科关于 A 复杂度的说法如下 链接在这里 http en wikipedia org wiki A search algorithm 比当时更成问题 复杂度是A 的内存使用量 在 最坏的情况 也必须记住 指数数量的节点 我不认为这是正
  • R/Javascript:崩溃和扩展的网络

    我正在使用 R 编程语言 我有以下图形网络数据 library igraph library visNetwork from lt c Boss TeamA TeamA TeamA SubteamA1 SubteamA1 SubteamA1
  • NetworkX:翻转图

    有没有办法以相反的顺序生成图形 即我想生成垂直翻转的图形 或者如果我可以在绘制之前用一些 matplotlib 子例程翻转它 F e 我希望 357 和 358 位于顶部 1 6 位于底部 只需交换您的位置坐标即可 import netwo
  • 通过 DFS 查找图中的强连通分量

    我正在阅读有关 BFS 和 DFS 的图算法 当我分析通过DFS在图中查找强连通分量的算法时 我想到了一个疑问 为了找到强连通分量 书 Coremen 做了什么 首先它在图上运行 DFS 以获得顶点的完成时间 然后再次以完成时间的降序在图的
  • 如何避免动态图中的“堆指针意大利面条”?

    一般问题 假设您正在编写一个由图组成的系统 以及可以根据相邻节点的配置激活的图重写规则 也就是说 您有一个在运行时不可预测地增长 收缩的动态图 如果你天真地使用malloc 新节点将被分配在内存中的随机位置 经过足够的时间 你的堆将变成一个
  • 什么是好的、免费的 PHP 图表套件?

    我要做的只是基本的折线图 任何人分享的经验将不胜感激 不是真正的 PHP 但我发现 amchart 非常容易实现 而且看起来很棒 http www amcharts com http www amcharts com 还可以查看 Googl
  • 在 Kali (Debian) 中安装 mono-devel 时,软件包具有未满足的依赖关系

    我尝试安装 mono devel 并输入sudo apt get mono devel在终端中 但失败了 得到以下结果 apt get install mono devel Reading package lists Done Buildi
  • 使用 d3 在两个节点之间绘制多条边

    我一直在关注 Mike Bostock 的代码这个例子 http bl ocks org 1153292学习如何在 d3 中绘制有向图 并且想知道如何构建代码 以便可以在图中的两个节点之间添加多个边 例如 如果上例中的数据集定义为 var
  • Microsoft 开源 .NET 后 CoreCLR 与 Mono 项目的关系

    有人可以向我解释一下 Mono 和 Microsoft 最近提供的开源 Linux 可移植 NET 堆栈 CoreCLR CoreFX Roslyn ASP NET 之间当前的关系吗 很明显这些项目是重叠的 所以我很好奇它们两个的路线图是什
  • Bellman-Ford 算法检测什么?负重还是负循环?

    如果给定一个图 现在我们要从源头计算最短路径 现在 如果一条边具有负权重 但在到达目的地时有边到后边返回到该边 我的意思是如果没有循环 那么我们就没有负循环 但是here http en wikipedia org wiki Bellman
  • Floyd-Warshall 算法:获取最短路径

    假设一个图由一个表示n x n维数邻接矩阵 我知道如何获得所有对的最短路径矩阵 但我想知道有没有办法追踪所有最短路径 Blow是python代码实现 v len graph for k in range 0 v for i in range
  • Gremlin 中的广度优先枚举

    我正在尝试使用 Gremlin 进行广度优先枚举 但是我无法找到一种方法来输出枚举期间观察到的所有步骤 我只能打印出最后一次迭代的结果 我的问题是 给定这样的起始节点 我如何使用 Gremlin 跟踪所有路径 不知道整体深度 并打印出我沿途
  • umbraco 适用于单声道吗?

    我想跑Umbraco http umbraco org 在单声道上 这可能吗 目前 Umbraco 无法在 Mono 上正常运行 但人们已经在努力实现这一目标 This http kevinfitzgerald net articles u
  • 参数映射不能用于 MERGE 模式

    我收到错误参数映射不能在合并模式中使用 我如何解决此错误 我正在使用下面的代码 我非常感谢任何帮助 提前致谢 MERGE u Person names RETURN u and data2 names name Keanu Reeves1
  • R中一张图中的多个条形图

    我是 R 初学者 我需要创建一个像这样的图表 https i stack imgur com az56z jpg https i stack imgur com az56z jpg 我不知道如何生成整个数据集 基本思想是某个外显子 ID 会

随机推荐

  • C++版本发展史

    1 C 43 43 98 2 C 43 43 03 3 C 43 43 11 3 1 nullptr 3 2 auto 3 3 decltype 3 4 初始化列表 3 5 范围for循环 3 6 右值引用 3 7 字符串字面量 3 8 n
  • 分布式数据库难题(三):数据一致性

    1 什么是数据一致性 一直以来 xff0c 在 分布式系统 和 数据库 这两个学科中 xff0c 一致性 xff08 Consistency xff09 都是重要概念 xff0c 但它表达的内容却并不相同 对于分布式系统而言 xff0c 一
  • 分布式数据库难题(四):单机事务

    1 ACID的含义 在数据库中 xff0c 事务 是由多个操作构成的序列 1970 年詹姆斯 格雷 xff08 Jim Gray xff09 提出了事务的 ACID 四大特性 xff0c 将广义上的事务一致性具化到了原子性 一致性 隔离性和
  • 对一个整数进行因式分解,求出所有质因数

    1 题目描述 给定一个正整数N xff0c 对N进行质因数分解 xff0c 求解N的所有质因数 2 解题思路 xff08 1 xff09 2 是很特殊的 xff0c 必须单独列出 xff08 2 xff09 必须先判断是否质数 因为如果是质
  • Windows10下安装Ubuntu18.04LTS详细教程

    这篇文章分享自己在Windows10系统下安装VMware虚拟机 xff0c 然后在VMware中安装Ubuntu 18 04 LTS的详细过程 之所以选择在虚拟机中安装Ubuntu xff0c 主要是可以不影响自己电脑的正常使用 xff0
  • 我的2011 写给小白

    许久前就想写这篇日志了 xff0c 但是一直以各种理由搪塞着 xff0c 没空闲 xff0c 再加上该死的期末考试 xff0c 唉 xff0c 真是愁煞人也 xff0c 现在好了 xff0c 什么都完事了 xff0c 也淡定了 xff0c
  • Pixhawk的历史

    发展历程 xff1a APM gt PX4FMU IO gt Pixhawk xff1a 1 Arduino简介 Arduino就是主要以以AVR单片机为核心控制器的单片机应用开发板 xff08 当然也有其他核心的例如STM32版本的但是不
  • 姿态解算基础:欧拉角、方向余弦、四元数

    什么是姿态解算 xff1a 飞行器的姿态解算过程涉及到两个坐标系 xff0c 一个是运载体的机体坐标系 xff0c 该坐标系与运载体固连 xff0c 当运载体转动的时候 xff0c 这个坐标系也跟着转动 xff0c 我们假设运载体的坐标系为
  • 姿态解算进阶:互补滤波(陀螺仪、加速度计、地磁计数据融合)

    互补滤波原理 xff1a 在四轴入门理论知识那节我们说 xff0c 加速度计和磁传感器都是极易受外部干扰的传感器 xff0c 都只能得到2维的角度关系 xff0c 但是测量值随时间的变化相对较小 xff0c 结合加速度计和磁传感器可以得到3
  • C++实现线程池

    本文转载自 xff1a https blog csdn net caoshangpa article details 80374651 1 为什么需要线程池技术 目前的大多数网络服务器 xff0c 包括Web服务器 Email服务器以及数据
  • 详解coredump

    1 什么是coredump xff1a 2 开启或关闭core文件的生成 xff1a 3 core文件的存储位置和文件名 xff1a 4 造成程序core的原因 xff08 参考 xff09 xff1a 5 用GDB调试coredump x
  • C++中二进制、字符串、十六进制、十进制之间的转换

    1 十进制和二进制相互转换 2 字符串和二进制相互转换 3 字符串和十进制相互转换 4 十进制和十六进制相互转换 5 二进制和十六进制 1 十进制和二进制相互转换 xff08 1 xff09 十进制转二进制 int a 61 10 bits
  • 解决 docker: Invalid containerPort: 5000 .

    复制粘贴的命令报这个错误 xff0c 结果手敲了一下就好了 可能就是 v 那里字符有点问题 xff0c 或者多个空格之类的 看了下其他人说的解决办法 xff0c 说也有可能是大写字母的问题 学习不要图省事 xff0c 真的 xff01
  • linux输入yum后提示: -bash: /usr/bin/yum: No such file or directory的解决方法

    一 首先了解Linux系统下这两个命令的区别 yum xff1a 属于 xff1a RedHat系列 常见系统有 xff1a Redhat Centos Fedora等 apt get xff1a 属于 xff1a Debian系列 常见系
  • OpenCV矩形检测

    点击我爱计算机视觉标星 xff0c 更快获取CVML新技术 今天在52CV交流群里有朋友问到矩形检测的问题 xff0c 恰好前几天做了一个与此相关的项目 xff0c 调研了一下相关的算法 xff08 期间被某带bug的开源代码坑了很久 xf
  • 修改树莓派系统的虚拟内存大小(SWAP)

    树莓派默认的虚拟内存大小才100M xff0c 有时候我们需要扩大它 xff0c 树莓派的虚拟内存配置文件和debian默认的位置不一样 xff0c 所以这里我们修改的是 etc dphys swapfile sudo nano etc d
  • Python爬虫—request模块与验证码识别

    相关文章链接 xff1a Python爬虫 爬虫基础简介 Python爬虫 数据解析及案例 xff08 4K图片爬取 xff09 一 request模块 1 1 概念 python中原生的一种基于网络请求的模块 xff0c 功能非常强大 x
  • 学习 ROS 机器人没有前途?!

    点击蓝字 关注我们 本文转载自蓝桥云课合作作者 xff1a 机器马 xff0c 文末有小惊喜哦 01 ROS 是什么 机器人操作系统 xff08 ROS xff09 是一种用于编写机器人软件的灵活框架 它是工具 xff0c 库和协议的集合
  • 运维必学的监控系统——Prometheus,大牛免费直播带你入门~

    关注 实验楼 xff0c 每天分享一个项目教程 实验1小时 明晚开启 xff0c 腾讯大牛天火老师带你入门Promentheus xff08 普罗米修斯 xff09 这一当下超火的监控系统 提到监控系统 xff0c 人们往往会想到Zabbi
  • VINS-Mono代码阅读笔记(十一):进入pose_graph节点代码分析

    本篇笔记紧接着上一篇VINS Mono代码阅读笔记 xff08 十 xff09 xff1a vins estimator中的非线性优化 xff0c 来接着学习VINS Mono系统中重定位和全局优化部部分的代码 这部分代码在pose gra