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节点代码分析 的相关文章

  • 用于计算有向图上非循环路径数量的快速算法

    简而言之 我需要一个fast计算简单有向图中有多少条非循环路径的算法 By simple我的意思是没有自环或多重边的图 Apath可以从任何节点开始 并且必须在没有传出边的节点上结束 一条路径是acyclic如果没有边出现两次 我的图 经验
  • 如何向 Mono.ZeroConf 注册服务?

    我正在尝试测试 ZeroConf 示例http www mono project com Mono Zeroconf http www mono project com Mono Zeroconf 我正在运行 OpenSuse 11 和 M
  • .NET 和 Mono 之间的开发差异

    我正在研究 Mono 和 NET C 将来当项目开发时我们需要在 Linux 服务器上运行代码 此时我一直在研究 ASP NET MVC 和 Mono 我运行 Ubuntu 发行版 想要开发 Web 应用程序 其他一些开发人员使用 Wind
  • iOS 上有像 JUNG 这样的可视化框架吗?

    有没有类似的可视化框架JUNG http jung sourceforge net applet index html对于iOS 我想实现类似的东西this http prefuse org gallery graphview iOS 上最
  • 如何在matplotlib中部分填充之间,如不同值的不同颜色

    I m trying to color the space between the graph line and the x axis The color should be based on the value of the corres
  • 如何用线条在一个Excel散点图中绘制多个分组数据

    我在 Excel 中的一张图表 带线的散点图 中绘制分组数据 按索引 时遇到一些困难 我将非常感谢您的帮助 我的数据分为三列 第一列是数据或组的索引 即每组数据的唯一编号 第二列是时间 第三列是数据 Group Time Data 1 1
  • Visual Studio 2010 中的 GTK#

    我一整天都在尝试让 GTK 在 Windows Server 2008 R2 x64 上的 Visual Studio 2010 中工作 以便我可以开始编写漂亮的跨平台 GUI 应用程序 但我对 C 有点陌生 我有一个世界的麻烦 我安装了最
  • Python igraph:从图中删除顶点

    我正在使用安然电子邮件数据集 并尝试删除没有 enron com 的电子邮件地址 即我只想拥有安然电子邮件 当我尝试删除那些没有 enron com 的地址时 一些电子邮件由于某些原因被跳过 下面显示了一个小图 其中顶点是电子邮件地址 这是
  • 在 Mono 上使用 Mono for android

    将 MonoDevelop 的编译器切换为 Mono 工具而不是 NET 看起来非常容易 您只需在 IDE 的设置下选择不同的框架即可 然而 在切换到 Mono 并使用 Mono 工具编译项目后 Mono for android 似乎不再是
  • 用xCode制作图表[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 您好 我需要绘制一些数组来分析信号 我有一个可可项目正在进行 谁能告诉我在哪里可以找到简化这项任务的工具 基本上我想像在图形计算器上一样显
  • 如何确定命名空间位于哪个程序集中?

    The MSDN documentation doesn t generally specify the assembly a namespace is in so there s no easy way to add the necess
  • 是否可以通知 Mac OS X 上的 DTrace 动态生成的代码?

    我们想扩展 Mono 的 VM 来生成可以被使用的信息DTrace http en wikipedia org wiki DTrace和仪器 我正在考虑对 Mono 运行时进行更改 以使其注册或通知它已动态生成的代码 以便 DTrace 可
  • Mono C# 获取应用程序路径

    我正在寻找我的应用程序的目录 它似乎与常规 c 不同 As in Path GetDirectoryName Application ExecutablePath 不管用 一种正确的跨平台解决方案是 Path GetDirectoryNam
  • 基于 Unix ASCII 的命令行图表/绘图工具

    有没有好的命令行 UNIX 图表 绘图 绘图工具 我正在寻找能够在 ASCII 图表上绘制 xy 点的东西 澄清一下 我正在寻找能够以 ASCII 格式输出图形 如 ascii art 风格 的东西 这样我就可以在交互式 shell 会话中
  • 如何在 Mac 上使用 Process.Start() 或等效的 Mono 并传入参数

    我正在尝试编写一些 C 代码来启动浏览器Process Start app args 其中 apps 是浏览器的路径 例如 Applications Google Chrome app Contents MacOS Google Chrom
  • 绘制点之间的所有线

    我有以下 R 代码 x lt c 0 01848598 0 08052353 0 06741172 0 11652034 y lt c 0 4177541 0 4042247 0 3964025 0 4074685 d lt data fr
  • 如何在 MATLAB 中绘制 3D 曲面图?

    我有一个像这样的数据集 0 1 0 2 0 3 0 4 1 10 11 12 13 2 11 12 13 14 3 12 13 14 15 4 13 14 15 16 我想在 matlab 中绘制 3D 曲面图 使列标题位于 y 轴 行标题
  • Python 和图形数据库。使用 java lib 包装器还是 REST api?

    我想问你在Python中使用图数据库 Neo4j 的最佳方法 你觉得我应该使用 neo4j python embedded neo4j python 嵌入式 http docs neo4j org chunked milestone pyt
  • 如何生成类似github的影响图?

    是否有一些程序 或者我错过的一些神奇的 git 插件 可以从 git 存储库获取影响图或类似的东西 而无需通过 github 就数据收集而言 我可以生成图表 我不确定从哪里开始编写自己的代码 我假设有一些标志我可以传递给 git log 来
  • 如何从网页中嵌入的 Tableau 图表中抓取工具提示值

    我试图弄清楚是否有一种方法以及如何使用 python 从网页中的 Tableau 嵌入图形中抓取工具提示值 以下是当用户将鼠标悬停在条形上时带有工具提示的图表示例 我从要从中抓取的原始网页中获取了此网址 https covid19 colo

随机推荐

  • 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