VINS初始化

2023-05-16

VINS初始化

VINS初始化之外参在线标定

前面主要分析了外参标定出来旋转矩阵,接下来接着分析初始化。

 if (solver_flag == INITIAL)
    {
        if (frame_count == WINDOW_SIZE) //WINDOW_SIZE=20
        {
            bool result = false;
            if (ESTIMATE_EXTRINSIC != 2 && (header - initial_timestamp) > 0.1)
            {
                // cout << "1 initialStructure" << endl;
                result = initialStructure();
                initial_timestamp = header;
            }
            if (result)
            {
                solver_flag = NON_LINEAR;
                solveOdometry();
                slideWindow();
                f_manager.removeFailures();
                cout << "Initialization finish!" << endl;
                last_R = Rs[WINDOW_SIZE];
                last_P = Ps[WINDOW_SIZE];
                last_R0 = Rs[0];
                last_P0 = Ps[0];
            }
            else
                slideWindow();
        }
        else
            frame_count++;
    }
    else
    {
        TicToc t_solve;
        solveOdometry();
        //ROS_DEBUG("solver costs: %fms", t_solve.toc());

        if (failureDetection())
        {
            // ROS_WARN("failure detection!");
            failure_occur = 1;
            clearState();
            setParameter();
            // ROS_WARN("system reboot!");
            return;
        }

        TicToc t_margin;
        slideWindow();
        f_manager.removeFailures();
        //ROS_DEBUG("marginalization costs: %fms", t_margin.toc());
        // prepare output of VINS
        key_poses.clear();
        for (int i = 0; i <= WINDOW_SIZE; i++)
            key_poses.push_back(Ps[i]);

        last_R = Rs[WINDOW_SIZE];
        last_P = Ps[WINDOW_SIZE];
        last_R0 = Rs[0];
        last_P0 = Ps[0];

然后分析一下initialStructure()函数

bool Estimator::initialStructure()
{
    TicToc t_sfm;
    //check imu observibility
    {
        map<double, ImageFrame>::iterator frame_it;
        Vector3d sum_g;
        for (frame_it = all_image_frame.begin(), frame_it++; frame_it != all_image_frame.end(); frame_it++)
        {
            double dt = frame_it->second.pre_integration->sum_dt;
            Vector3d tmp_g = frame_it->second.pre_integration->delta_v / dt;
            sum_g += tmp_g;
        }
        Vector3d aver_g;
        aver_g = sum_g * 1.0 / ((int)all_image_frame.size() - 1);
        //第一次循环,求滑窗的平均线加速度
        double var = 0;
        for (frame_it = all_image_frame.begin(), frame_it++; frame_it != all_image_frame.end(); frame_it++)
        {
            double dt = frame_it->second.pre_integration->sum_dt;
            Vector3d tmp_g = frame_it->second.pre_integration->delta_v / dt;
            var += (tmp_g - aver_g).transpose() * (tmp_g - aver_g);
            //求加速度的方差
            //cout << "frame g " << tmp_g.transpose() << endl;
        }
        var = sqrt(var / ((int)all_image_frame.size() - 1));
        //第二次循环,求线加速度的标准差
        //ROS_WARN("IMU variation %f!", var);
        if (var < 0.25)
        {
            // ROS_INFO("IMU excitation not enouth!");
            //return false;
        }
    }
    // global sfm
    //frame_count+1:滑动窗口存储的是10帧值,加上最新帧,即11帧
    Quaterniond Q[frame_count + 1];
    Vector3d T[frame_count + 1];
    map<int, Vector3d> sfm_tracked_points;
    vector<SFMFeature> sfm_f;
    /**********************************************/
    struct SFMFeature
{
    bool state;
    int id;
    vector<pair<int,Vector2d>> observation;
    double position[3];
    double depth;
};
    /**********************************************/
    for (auto &it_per_id : f_manager.feature)
    {
        int imu_j = it_per_id.start_frame - 1;//编号
        SFMFeature tmp_feature;
        tmp_feature.state = false;//状态:是否被三角化
        tmp_feature.id = it_per_id.feature_id;//特征点id
        for (auto &it_per_frame : it_per_id.feature_per_frame)//当前特征点在每一帧图像的坐标
        {
            imu_j++;
            Vector3d pts_j = it_per_frame.point;//当前特征在编号imuj++帧的归一化坐标
            tmp_feature.observation.push_back(make_pair(imu_j, Eigen::Vector2d{pts_j.x(), pts_j.y()}));//tmp_feature.observation存放的是同一个特征
        }
        sfm_f.push_back(tmp_feature);//所有的特征点
    }
    Matrix3d relative_R;//???有个疑问,它的初始值是什么,没找到,但是可以cout输出????
    Vector3d relative_T;
    int l;
    if (!relativePose(relative_R, relative_T, l))
    {
        cout << "Not enough features or parallax; Move device around" << endl;
        return false;
    }
    /*************************************************************/
    bool Estimator::relativePose(Matrix3d &relative_R, Vector3d &relative_T, int &l)
{
    // find previous frame which contians enough correspondance and parallex with newest frame
    //找到前一帧与最新帧有足够的对应性和平行性
    for (int i = 0; i < WINDOW_SIZE; i++)
    {
        vector<pair<Vector3d, Vector3d>> corres;
        corres = f_manager.getCorresponding(i, WINDOW_SIZE);//第i帧和窗口最后一阵的对应特征点的归一化坐标(像素坐标)
        if (corres.size() > 20)
        {
            double sum_parallax = 0;
            double average_parallax;//平均视差
            for (int j = 0; j < int(corres.size()); j++)
            {
                Vector2d pts_0(corres[j].first(0), corres[j].first(1));
                Vector2d pts_1(corres[j].second(0), corres[j].second(1));
                double parallax = (pts_0 - pts_1).norm();
                sum_parallax = sum_parallax + parallax;
            }
            average_parallax = 1.0 * sum_parallax / int(corres.size());
            if (average_parallax * 460 > 30 && m_estimator.solveRelativeRT(corres, relative_R, relative_T))//判断视差是否大于30而且判断内点数目是否大于12
            /**************************************************************/
                bool MotionEstimator::solveRelativeRT(const vector<pair<Vector3d, Vector3d>> &corres, Matrix3d &Rotation, Vector3d &Translation)
{
    if (corres.size() >= 15)
    {
        vector<cv::Point2f> ll, rr;
        for (int i = 0; i < int(corres.size()); i++)
        {
            ll.push_back(cv::Point2f(corres[i].first(0), corres[i].first(1)));
            rr.push_back(cv::Point2f(corres[i].second(0), corres[i].second(1)));
        }
        cv::Mat mask;
        cv::Mat E = cv::findFundamentalMat(ll, rr, cv::FM_RANSAC, 0.3 / 460, 0.99, mask);
        cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
        cv::Mat rot, trans;
        int inlier_cnt = cv::recoverPose(E, ll, rr, cameraMatrix, rot, trans, mask);
        //cout << "inlier_cnt " << inlier_cnt << endl;

        Eigen::Matrix3d R;
        Eigen::Vector3d T;
        for (int i = 0; i < 3; i++)
        {   
            T(i) = trans.at<double>(i, 0);
            for (int j = 0; j < 3; j++)
                R(i, j) = rot.at<double>(i, j);
        }

        Rotation = R.transpose();
        Translation = -R.transpose() * T;
        if(inlier_cnt > 12)
            return true;
        else
            return false;
    }
    return false;
}
            /**************************************************************/
            {
                l = i;
                //ROS_DEBUG("average_parallax %f choose l %d and newest frame to triangulate the whole structure", average_parallax * 460, l);
                return true;
            }
        }
    }
    return false;
}
    /*************************************************************/

















    
    GlobalSFM sfm;
    if (!sfm.construct(frame_count + 1, Q, T, l,
                       relative_R, relative_T,
                       sfm_f, sfm_tracked_points))
    {
        cout << "global SFM failed!" << endl;
        marginalization_flag = MARGIN_OLD;
        return false;
    }

    //solve pnp for all frame
    map<double, ImageFrame>::iterator frame_it;
    map<int, Vector3d>::iterator it;
    frame_it = all_image_frame.begin();
    for (int i = 0; frame_it != all_image_frame.end(); frame_it++)
    {
        // provide initial guess
        cv::Mat r, rvec, t, D, tmp_r;
        if ((frame_it->first) == Headers[i])
        {
            frame_it->second.is_key_frame = true;
            frame_it->second.R = Q[i].toRotationMatrix() * RIC[0].transpose();
            frame_it->second.T = T[i];
            i++;
            continue;
        }
        if ((frame_it->first) > Headers[i])
        {
            i++;
        }
        Matrix3d R_inital = (Q[i].inverse()).toRotationMatrix();
        Vector3d P_inital = -R_inital * T[i];
        cv::eigen2cv(R_inital, tmp_r);
        cv::Rodrigues(tmp_r, rvec);
        cv::eigen2cv(P_inital, t);

        frame_it->second.is_key_frame = false;
        vector<cv::Point3f> pts_3_vector;
        vector<cv::Point2f> pts_2_vector;
        for (auto &id_pts : frame_it->second.points)
        {
            int feature_id = id_pts.first;
            for (auto &i_p : id_pts.second)
            {
                it = sfm_tracked_points.find(feature_id);
                if (it != sfm_tracked_points.end())
                {
                    Vector3d world_pts = it->second;
                    cv::Point3f pts_3(world_pts(0), world_pts(1), world_pts(2));
                    pts_3_vector.push_back(pts_3);
                    Vector2d img_pts = i_p.second.head<2>();
                    cv::Point2f pts_2(img_pts(0), img_pts(1));
                    pts_2_vector.push_back(pts_2);
                }
            }
        }
        cv::Mat K = (cv::Mat_<double>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
        if (pts_3_vector.size() < 6)
        {
            cout << "Not enough points for solve pnp pts_3_vector size " << pts_3_vector.size() << endl;
            return false;
        }
        if (!cv::solvePnP(pts_3_vector, pts_2_vector, K, D, rvec, t, 1))
        {
            cout << " solve pnp fail!" << endl;
            return false;
        }
        cv::Rodrigues(rvec, r);
        MatrixXd R_pnp, tmp_R_pnp;
        cv::cv2eigen(r, tmp_R_pnp);
        R_pnp = tmp_R_pnp.transpose();
        MatrixXd T_pnp;
        cv::cv2eigen(t, T_pnp);
        T_pnp = R_pnp * (-T_pnp);
        frame_it->second.R = R_pnp * RIC[0].transpose();
        frame_it->second.T = T_pnp;
    }
    if (visualInitialAlign())
        return true;
    else
    {
        cout << "misalign visual structure with IMU" << endl;
        return false;
    }
}

两帧之间三角化,把匹配点加进去

		triangulateTwoFrames(i, Pose[i], frame_num - 1, Pose[frame_num - 1], sfm_f);

内部函数实现具体理论知识可以参考三角化
VINS-MONO解析——初始化(代码部分)

void GlobalSFM::triangulatePoint(Eigen::Matrix<double, 3, 4> &Pose0, Eigen::Matrix<double, 3, 4> &Pose1,
						Vector2d &point0, Vector2d &point1, Vector3d &point_3d)
{
	Matrix4d design_matrix = Matrix4d::Zero();
	design_matrix.row(0) = point0[0] * Pose0.row(2) - Pose0.row(0);//u*r3-r1=0
	design_matrix.row(1) = point0[1] * Pose0.row(2) - Pose0.row(1);//v*r3-r2=0
	design_matrix.row(2) = point1[0] * Pose1.row(2) - Pose1.row(0);
	design_matrix.row(3) = point1[1] * Pose1.row(2) - Pose1.row(1);
	Vector4d triangulated_point;
	triangulated_point =
		      design_matrix.jacobiSvd(Eigen::ComputeFullV).matrixV().rightCols<1>();
	point_3d(0) = triangulated_point(0) / triangulated_point(3);
	point_3d(1) = triangulated_point(1) / triangulated_point(3);
	point_3d(2) = triangulated_point(2) / triangulated_point(3);
}

一般来讲,求位姿,2D-2D对极几何只是在第一次使用,也就是没有3D特征点坐标的时候使用,一旦有了特征点,之后都会用3D-2D的方式求位姿。然后会进入PnP求新位姿,然后三角化求新3D坐标的循环中。

pnp:3d->2d
PnP是求解3D到2D点对的运动方法,主要是为了估计相机的位姿。
3D->2D方法不需要使用对极约束,可以在很少的匹配点中获得较好的运动估计,是最重要的姿态估计方法。
解决PnP问题的主要方法:

  • P3P:三对点估计位姿
  • 直接线性变换(DLT)
  • EPnP
  • UPnP
  • 非线性优化(Bundle Adjustment)
bool GlobalSFM::solveFrameByPnP(Matrix3d &R_initial, Vector3d &P_initial, int i,
								vector<SFMFeature> &sfm_f)
{
	vector<cv::Point2f> pts_2_vector;
	vector<cv::Point3f> pts_3_vector;
	for (int j = 0; j < feature_num; j++)
	{
		if (sfm_f[j].state != true)
			continue;
		Vector2d point2d;
		for (int k = 0; k < (int)sfm_f[j].observation.size(); k++)
		{
			if (sfm_f[j].observation[k].first == i)
			{
				Vector2d img_pts = sfm_f[j].observation[k].second;
				cv::Point2f pts_2(img_pts(0), img_pts(1));
				pts_2_vector.push_back(pts_2);
				cv::Point3f pts_3(sfm_f[j].position[0], sfm_f[j].position[1], sfm_f[j].position[2]);
				pts_3_vector.push_back(pts_3);
				break;
			}
		}
	}
	if (int(pts_2_vector.size()) < 15)
	{
		printf("unstable features tracking, please slowly move you device!\n");
		if (int(pts_2_vector.size()) < 10)
			return false;
	}
	cv::Mat r, rvec, t, D, tmp_r;
	cv::eigen2cv(R_initial, tmp_r);//eigen形式转换成cv形式
	cv::Rodrigues(tmp_r, rvec);//旋转矩阵转换成旋转向量
	cv::eigen2cv(P_initial, t);
	cv::Mat K = (cv::Mat_<double>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
	bool pnp_succ;
	pnp_succ = cv::solvePnP(pts_3_vector, pts_2_vector, K, D, rvec, t, 1);
	if(!pnp_succ)
	{
		return false;
	}
	cv::Rodrigues(rvec, r);//
	//cout << "r " << endl << r << endl;
	MatrixXd R_pnp;
	cv::cv2eigen(r, R_pnp);
	MatrixXd T_pnp;
	cv::cv2eigen(t, T_pnp);
	R_initial = R_pnp;
	P_initial = T_pnp;
	return true;

}

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

VINS初始化 的相关文章

  • exe应用程序无法启动,因为应用程序的并行配置不正确

    问题 xff1a exe应用程序无法启动 xff0c 因为应用程序的并行配置不正确 有关详细信息 xff0c 请参阅应用程序事件日志 xff0c 或使用命令行 sxstrace exe 工具 原因查找 xff1a 1 xff09 开始 所有
  • TortoiseSVN is locked in another working copy

    TortoiseSVN提交报错 TortoiseSVN is locked in another working copy 原因 xff1a 可能是因为打开了多个commit会话 xff0c 然后又去修改了提交文件的内容 xff0c 导致文
  • Java对接企业微信

    最近需要对接企业微信 xff0c 例如将风险测评结果推送给企业微信中对应的用户 xff0c 然后用户对结果进行查看与确认操作 xff0c 所以这里就涉及到两方面 xff1a 1 xff09 将外部系统内容推送到企业微信 xff1b 2 xf
  • 微众银行面试

    机缘巧合 xff0c 其实并没有换工作的想法 xff0c 却收到了微众的面试邀请 xff0c 就想着去看看当是增长见识吧 xff0c 因为已经好久没准备面试的事情了 xff0c 而且微众毕竟作为腾讯系的看起来好像也不错 说实话那边离地铁站是
  • #TP4056#--3.7V锂电池充放电电路(实践日志篇)

    成就更好的自己 本篇为小型电源的实践日志 xff0c 内附各种充电应用电路 xff0c 并开源TP4056应用电路AD的原理图和PCB xff1b 先放一点锂电池常识性的知识 xff1a 锂电池是一类由锂金属或锂合金为负极材料 使用非水电解
  • ROS四旋翼无人机快速上手指南(1):无人机系统硬件概述与指南简介

    成就更好的自己 ROS无人机快速上手指南旨在于让使用此无人机开发平台的比赛参赛人员 xff0c 算法设计人员 xff0c 无人机爱好者更加快速的了解底层控制运作原理 xff0c 从而缩短开发周期 xff0c 减少掉坑次数 xff0c 快速验
  • ROS四旋翼无人机快速上手指南(2):Ubuntu18.04与ROS系统

    成就更好的自己 目录 Jetson版Ubuntu以及ROS的安装 xff1a ROS特性及Nano开发问题 PX4与Gazebo仿真环境 ROS与MATMAB仿真 Jetson版Ubuntu以及ROS的安装 xff1a ROS机器人系统运行
  • ROS四旋翼无人机快速上手指南(4):阿木实验室PX4功能包飞行控制分析与讲解(重点章节)

    成就更好的自己 这一章详细讲解一下阿木实验室 AMOV 的开源项目px4 command功能包 xff0c 此功能包通过mavlink协议直接控制烧录px4固件的自驾仪 xff0c 还融合了来自各个传感器的位姿 xff0c 距离等信息 xf
  • ROS四旋翼无人机快速上手指南(5):快速部署上层算法的操作与思路

    成就更好的自己 经过本系列上一篇文章关于PX4 command飞行控制功能包的分析 xff0c 相信大家对于飞整个流程有个大概的了解 xff0c 本章将在此基础上详细讲解一下应用级算法构建的思路与操作方法 关于PX4 command飞行控制
  • USB系列-LibUSB使用指南(1)-Windows下的报错与踩坑

    成就更好的自己 时隔一年再次开始撰写博客 xff0c 这一年的时间经历了很多 xff0c 现在终于稳定下来 以后很长一段时间都能够稳定的学习和更新 时间将会聚焦于USB和PCIe的开发进行 xff0c 能和大家共同进步真的很高兴 本篇为US
  • rosdep init和rosdep update出现问题解决,以及ros编程问题

    如果你在执行 rosdep init 过程中出现以下错误 ERROR cannot download default sources list from https raw githubusercontent com ros rosdist
  • linux内核体系结构

    本节介绍了linux内核的编制模式和体制结构 xff0c 然后详细描述linux内核代码目录中组织形式以及子目录各个代码文件的主要功能以及基本调用的层次关系 一个完整可用的操作系统主要由4部分组成 xff1a 硬件 操作系统内核 操作系统服
  • 基于OpenLTE的4G移动通信网络实验指导书

    基于本人本科毕业设计的成果 xff0c 设计了一套基于开源SDR项目 OpenLTE的实验指导书 xff0c 可以指引读者通过平台源码 平台提供的实验和结合实验对3GPP规范的解读分析来更直观 更多元立体的学习无线通信技术 xff0c 而不
  • 一行代码实现数组中数据频次值

    问题 xff1a 一行代码实现统计数组中每个name出现的次数 数组示例如下 xff1a 期望结果 xff1a 39 哈哈 39 2 39 哈哈1 39 1 39 哈哈2 39 2 span class token keyword var
  • mac bash_profile报错导致所有命令失效解决办法

    项目场景 xff1a 搭建flutter环境时 xff0c 在mac下需要配置环境变量 问题描述 xff1a 配置环境变量 xff0c 需要修改 bash profile文件 xff0c 修改文件保存退出后 发现文件有报错 xff0c 导致
  • 我理解的“大前端”

    前言 随着业务场景越来越复杂 xff0c 前端技术也越来越丰富 xff0c 这几年也迎来爆发期 xff0c 大前端 的概念逐渐涌现 本图根据本人理解整理 xff0c 如有不足 xff0c 欢迎指正 xff0c 感谢 一 终端 PC端 PC端
  • 前端获取用户地理定位的几种方式(Geolocation API,微信,腾讯地图)

    文章目录 前言一 Geolocation API二 微信 SDK1 引入jssdk2 获取签名 xff0c 注入配置3 调用JS SDK api 获取位置 三 第三方服务 xff08 腾讯地图服务 xff09 1 引入js文件2 获取定位
  • H5 软键盘自动搜索功能

    业务场景 xff1a 通常APP中的顶部搜索栏 xff0c 都配一个搜索按钮 同时输入文字软键盘弹起 xff0c 回车键自动变成搜索键 xff0c 点击软键盘中的搜索能进行搜索功能 xff0c 如下图taobao所示 xff1a 思考 软键
  • 基于vue-cli3构建自己的UI库

    文章目录 前言一 创建项目二 编写组件1 button组件2 引入字体图标icon文件3 引入Button组件看效果 三 修改目录结构1 packages文件夹2 打包修改2 demo展示 四 将UI库部署到npm上五 项目使用自己的UI库
  • vue3源码分析(三)—— 响应式系统(reactivity)

    系列文章目录 目录分析初始化流程响应式系统shared工具函数 文章目录 系列文章目录前言一 定义响应式数据1 reactive target 2 createReactiveObject2 1 入参2 2 响应式创建过程2 3 proxy

随机推荐

  • vue3源码分析(四)—— shared工具函数

    系列文章目录 目录分析初始化流程响应式系统shared工具函数 文章目录 系列文章目录前言1 数组中移除某元素2 字符串转数字3 转为字符串4 判定值是否发生改变5 判定数据类型5 1 数组5 2 Map5 3 Set5 4 Date5 5
  • 如何将两个rosbag包合并或者提取rosbag包中某些话题到一个rosbag里

    代码叫做merge bag py 运行的时候 python merge bag py v 1028msf bag msf bag vinReNoOutlier bag 就把msf bag和vinReNoOutlier bag完全合并在一起了
  • 解决 vscode中js变量 文件不能自动跳转问题~

    项目场景 xff1a 在项目开发中 xff0c 为了便于理解js代码逻辑和调试 xff0c 通常会使用快捷键自动定位到变量原始定义的文件位置 mac中快捷键 xff1a command 43 鼠标点击 但在vue项目开发中 xff0c 发现
  • vue3源码分析(二)—— 初始化流程

    系列文章目录 目录分析初始化流程响应式系统shared工具函数 文章目录 系列文章目录前言一 createApp在项目中的使用二 createApp源码追溯1 创建app实例1 1 ensureRenderer1 2 ensureRende
  • JS基础 ——解释执行

    文章目录 前言一 词法分析二 预编译创建全局作用域GO对象创建局部作用域AO对象 三 代码执行总结 前言 大家都知道 xff0c JS是一种不需要编译的解释型语言 但其实在浏览器执行JS代码前 xff0c 也有一个词法分析和预编译过程 xf
  • vue 项目中引入字体文件的正确方式~

    文章目录 前言一 开发中需要什么样的字体1 字体图标2 特殊字体 二 项目中引入字体文件1 字体文件2 css文件3 项目使用该字体 总结 前言 在UI设计稿中 xff0c 可能会有一些特殊字体 xff0c 或者是一些字体图标 对于特殊字体
  • vue3 使用 swiper轮播库

    文章目录 前言一 Swiper引入方式1 HTML标签引入方式2 CommonJs引入方式3 ES引入方式 xff08 采用 xff09 二 使用Swiper总结 前言 轮播图在前端开发中 xff0c 是常见需求 而Swiper库是最受前端
  • vue-cli2 老项目webpack3升级webpack5过程总结

    文章目录 背景一 webpack5环境要求二 升级步骤1 脚手架webpack cli2 升级webpack包3 更新webpack相关插件3 1 不推荐或被移除的插件3 2 升级babel到7版本3 3 更新插件 4 修改配置4 1 新增
  • 前端下载文件

    文章目录 前言二进制流前端核心实现下载功能有 xff1a 一 a标签 43 download属性二 window open url 34 blank 34 三 form表单四 接口请求 43 blob 43 a标签 43 download属
  • 前端JS 云打印 LODOP实践

    文章目录 前言一 Lodop是什么 xff1f 二 如何使用Lodop1 下载打印插件2 配置打印机3 html中植入打印控件4 调用Lodop对应的JS相关方法接口实现打印功能 三 Lodop主要方法接口三 注意点总结 前言 一般B S系
  • axios源码——工具函数utils.js

    文章目录 前言一 工具函数所在目录二 判定数据类型的函数1 isArray 判定数组 2 isString 判定字符串 3 isNumber 判定数值 4 isObject 判定对象 5 isPlainObject 判定纯对象 6 isUn
  • 源码阅读——validate-npm-package-name

    文章目录 前言一 源码阅读工具二 阅读源码1 目录结构2 package json3 index js 三 使用该包1 vue cli中使用2 create react app 中使用 总结 前言 validate npm package
  • 学习rtklib

    数据下载 日期转换和一些常用数据下载 http www gnsscalendar com index html year 61 2019 多系统精密星历和精密钟差下载 2021年10月25日更新 xff1a 单GPS精密星历文件要在这里下载
  • echarts 绘制多条折线图(横坐标,折线图条数不确定)

    项目场景 xff1a 使用echarts做业务图表统计 xff0c 记录一下在项目中图表接口返回的数据处理问题 需求描述 1 一个统计图中实现多条折现图的显示 xff0c 如下图所示 2 后台返回的数据结构 span class token
  • 线性二次型调节器(LQR)原理详解

    文章目录 前言算法解释代价函数的意义 推导过程可控性LQR控制实例参考资料 前言 LQR Linaer Quadratic Regulator xff0c 即线性二次型调节器 xff0c 是一种现代控制理论中设计状态反馈控制器 State
  • 嵌入式软件工程师常见面试问题

    嵌入式软件工程师面试题 1 stm32启动方式 xff1f 有三种 xff1a 从Flash启动 xff0c 将Flash地址0x0800 0000映射到0x00000000 这样启动以后就相当于从0x0800 0000开始的 xff0c
  • 使用python爬虫把自己的CSDN文章爬取下来并保存到MD文件

    导言 爬虫作为一个敏感技术 xff0c 千万要把握好 xff0c 如果人家不让爬那就不要头铁去试了 如何确定某个网站是否允许爬虫 在域名后面加上 robots txt查看即可 xff0c 例如 xff1a https blog csdn n
  • 寻找矩阵中的指定路径

    给定一个矩阵和一个要找的字符串 xff0c 如果有的话找出矩阵中的字符串路径 测试用例 功能测试 xff1a 在多行多列的矩阵中存在或者不存在路径 边界值测试 xff1a 矩阵只有一行或一列 xff1b 矩阵和路径中的所有字母都是相同的 特
  • Kalibr标定Intel D435i相机

    Kalibr标定Intel D435i相机 文章目录 Kalibr标定Intel D435i相机1 相机标定2 IMU标定3 相机 43 IMU联合标定4 标定结果评价 系统环境 xff1a ubuntu16 04 43 roskineti
  • VINS初始化

    VINS初始化 VINS初始化之外参在线标定 前面主要分析了外参标定出来旋转矩阵 xff0c 接下来接着分析初始化 if solver flag 61 61 INITIAL if frame count 61 61 WINDOW SIZE