VINS-Mono代码阅读笔记(三):vins_estimator中main函数分析

2023-05-16

在VINS-Mono代码阅读笔记(一):从Euroc数据集的运行开始 中我们已经初步知道了vins_estimator中订阅和发布的topic,那么,在研究vins_estimator模块的代码时,一个很有用的思路就是关注接收到的每一个topic是怎么进行处理的,发送的topic的message信息有哪些。把这些搞清楚了,这个模块的主要工作也就搞清楚了。

1.vins_estimator的main函数

main函数代码路径为:src/VINS-Mono/vins_estimator/src/estimator_node.cpp,该函数代码如下:

int main(int argc, char **argv)
{
    //1.相关初始化
    ros::init(argc, argv, "vins_estimator");
    ros::NodeHandle n("~");
    ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Info);
    //2.参数读取
    readParameters(n);
    //3.设置状态估计器的参数
    estimator.setParameter();
#ifdef EIGEN_DONT_PARALLELIZE
    ROS_DEBUG("EIGEN_DONT_PARALLELIZE");
#endif
    ROS_WARN("waiting for image and imu...");
    //4.注册发布器
    registerPub(n);
    /**
     * ros::TransportHints().tcpNoDelay()允许指定hints到roscpp的传输层,这里使用没延迟的TCP。其实也可以使用UPD传输,
    */
    //5.订阅topic
    ros::Subscriber sub_imu = n.subscribe(IMU_TOPIC, 2000, imu_callback, ros::TransportHints().tcpNoDelay());
    ros::Subscriber sub_image = n.subscribe("/feature_tracker/feature", 2000, feature_callback);
    ros::Subscriber sub_restart = n.subscribe("/feature_tracker/restart", 2000, restart_callback);
    ros::Subscriber sub_relo_points = n.subscribe("/pose_graph/match_points", 2000, relocalization_callback);
    //6.创建process线程,这个是主线程
    std::thread measurement_process{process};
    ros::spin();

    return 0;
}

可以看出,上边main函数的代码从逻辑功能上可以分为六部分:ROS相关初始化、参数读取、estimator中相关参数的设置、topic发布器注册、订阅topic、创建measurement_process线程。

下面看看以上代码中都具体做了什么。

2.estimator中的参数读取

main函数中readParameters函数中读取了配置文件中设置的相关参数。这个配置文件路径为:src/VINS-Mono/config/euroc/euroc_config.yaml,所以可以直接打开该文件来查看各个参数的值。

//读取参数
void readParameters(ros::NodeHandle &n)
{
    std::string config_file;
    config_file = readParam<std::string>(n, "config_file");
    cv::FileStorage fsSettings(config_file, cv::FileStorage::READ);
    if(!fsSettings.isOpened())
    {
        std::cerr << "ERROR: Wrong path to settings" << std::endl;
    }

    fsSettings["imu_topic"] >> IMU_TOPIC;

    SOLVER_TIME = fsSettings["max_solver_time"];
    NUM_ITERATIONS = fsSettings["max_num_iterations"];
    MIN_PARALLAX = fsSettings["keyframe_parallax"];//10
    MIN_PARALLAX = MIN_PARALLAX / FOCAL_LENGTH;//最小视差=最小视差/焦距=10.0/460.0

    std::string OUTPUT_PATH;
    fsSettings["output_path"] >> OUTPUT_PATH;
    VINS_RESULT_PATH = OUTPUT_PATH + "/vins_result_no_loop.csv";
    std::cout << "result path " << VINS_RESULT_PATH << std::endl;

    // create folder if not exists
    //创建输出目录:output_path: "/home/shaozu/output/"
    FileSystemHelper::createDirectoryIfNotExists(OUTPUT_PATH.c_str());

    std::ofstream fout(VINS_RESULT_PATH, std::ios::out);
    fout.close();

    ACC_N = fsSettings["acc_n"];
    ACC_W = fsSettings["acc_w"];
    GYR_N = fsSettings["gyr_n"];
    GYR_W = fsSettings["gyr_w"];
    G.z() = fsSettings["g_norm"];
    ROW = fsSettings["image_height"];
    COL = fsSettings["image_width"];
    ROS_INFO("ROW: %f COL: %f ", ROW, COL);
    //IMU和camera之间的外参
    ESTIMATE_EXTRINSIC = fsSettings["estimate_extrinsic"];
    if (ESTIMATE_EXTRINSIC == 2)
    {
        ROS_WARN("have no prior about extrinsic param, calibrate extrinsic param");
        RIC.push_back(Eigen::Matrix3d::Identity());
        TIC.push_back(Eigen::Vector3d::Zero());
        EX_CALIB_RESULT_PATH = OUTPUT_PATH + "/extrinsic_parameter.csv";

    }
    else 
    {
        if ( ESTIMATE_EXTRINSIC == 1)
        {
            ROS_WARN(" Optimize extrinsic param around initial guess!");
            EX_CALIB_RESULT_PATH = OUTPUT_PATH + "/extrinsic_parameter.csv";
        }
        if (ESTIMATE_EXTRINSIC == 0)
            ROS_WARN(" fix extrinsic param ");

        cv::Mat cv_R, cv_T;
        fsSettings["extrinsicRotation"] >> cv_R;
        fsSettings["extrinsicTranslation"] >> cv_T;
        Eigen::Matrix3d eigen_R;
        Eigen::Vector3d eigen_T;
        cv::cv2eigen(cv_R, eigen_R);
        cv::cv2eigen(cv_T, eigen_T);
        Eigen::Quaterniond Q(eigen_R);
        eigen_R = Q.normalized();
        RIC.push_back(eigen_R);
        TIC.push_back(eigen_T);
        ROS_INFO_STREAM("Extrinsic_R : " << std::endl << RIC[0]);
        ROS_INFO_STREAM("Extrinsic_T : " << std::endl << TIC[0].transpose());
        
    } 

    INIT_DEPTH = 5.0;
    BIAS_ACC_THRESHOLD = 0.1;
    BIAS_GYR_THRESHOLD = 0.1;
    //获取TD,图像和IMU数据在时间上的偏移量,这里配置文件中为0.0
    TD = fsSettings["td"];
    ESTIMATE_TD = fsSettings["estimate_td"];
    if (ESTIMATE_TD)
        ROS_INFO_STREAM("Unsynchronized sensors, online estimate time offset, initial td: " << TD);
    else
        ROS_INFO_STREAM("Synchronized sensors, fix time offset: " << TD);

    ROLLING_SHUTTER = fsSettings["rolling_shutter"];
    if (ROLLING_SHUTTER)
    {
        TR = fsSettings["rolling_shutter_tr"];
        ROS_INFO_STREAM("rolling shutter camera, read out time per line: " << TR);
    }
    else
    {
        TR = 0;
    }
    
    fsSettings.release();
}

3.estimator中的参数设置

setParameter代码如下:

void Estimator::setParameter()
{
    //单目的情况下相机个数为1,所以NUM_OF_CAN值为1
    for (int i = 0; i < NUM_OF_CAM; i++)
    {
        tic[i] = TIC[i];
        ric[i] = RIC[i];
    }
    f_manager.setRic(ric);
    //FOCAL_LENGTH=460
    ProjectionFactor::sqrt_info = FOCAL_LENGTH / 1.5 * Matrix2d::Identity();
    ProjectionTdFactor::sqrt_info = FOCAL_LENGTH / 1.5 * Matrix2d::Identity();
    // 配置文件中td的解释:initial value of time offset. unit: s. readed image clock + td = real image clock (IMU clock)
    td = TD;
}

4.创建estimator中的topic发布器

registerPub函数代码如下,estimator中要发布多少个topic这里就创建多少个topic发布器。

void registerPub(ros::NodeHandle &n)
{
    pub_latest_odometry = n.advertise<nav_msgs::Odometry>("imu_propagate", 1000);
    pub_path = n.advertise<nav_msgs::Path>("path", 1000);
    pub_relo_path = n.advertise<nav_msgs::Path>("relocalization_path", 1000);
    pub_odometry = n.advertise<nav_msgs::Odometry>("odometry", 1000);
    pub_point_cloud = n.advertise<sensor_msgs::PointCloud>("point_cloud", 1000);
    pub_margin_cloud = n.advertise<sensor_msgs::PointCloud>("history_cloud", 1000);
    pub_key_poses = n.advertise<visualization_msgs::Marker>("key_poses", 1000);
    pub_camera_pose = n.advertise<nav_msgs::Odometry>("camera_pose", 1000);
    pub_camera_pose_visual = n.advertise<visualization_msgs::MarkerArray>("camera_pose_visual", 1000);
    pub_keyframe_pose = n.advertise<nav_msgs::Odometry>("keyframe_pose", 1000);
    pub_keyframe_point = n.advertise<sensor_msgs::PointCloud>("keyframe_point", 1000);
    pub_extrinsic = n.advertise<nav_msgs::Odometry>("extrinsic", 1000);
    pub_relo_relative_pose=  n.advertise<nav_msgs::Odometry>("relo_relative_pose", 1000);
    //可视化的相关设置
    cameraposevisual.setScale(1);
    cameraposevisual.setLineWidth(0.05);
    keyframebasevisual.setScale(0.1);
    keyframebasevisual.setLineWidth(0.01);
}

5.订阅topic,并处理相关消息

1)订阅IMU消息

ros::Subscriber sub_imu = n.subscribe(IMU_TOPIC, 2000, imu_callback, ros::TransportHints().tcpNoDelay());

imu订阅的回调函数为imu_callback,在imu_callback函数中对接收到的imu消息进行处理。

//imu回调函数,将imu_msg存入imu_buf,递推IMU的PQV并发布"imu_propagate”
void imu_callback(const sensor_msgs::ImuConstPtr &imu_msg)
{
    //用时间戳来判断IMU message是否乱序
    if (imu_msg->header.stamp.toSec() <= last_imu_t)
    {
        ROS_WARN("imu message in disorder!");
        return;
    }
    last_imu_t = imu_msg->header.stamp.toSec();
    //在修改多个线程共享的变量的时候要进行上锁,防止多个线程同时访问该变量
    m_buf.lock();
    imu_buf.push(imu_msg);//新来的imu_msg放入imu_buf队列当中
    m_buf.unlock();

    //这里调用notify_one唤醒的是process线程
    con.notify_one();

    last_imu_t = imu_msg->header.stamp.toSec();

    {
        std::lock_guard<std::mutex> lg(m_state);
        //预测函数,这里推算的是tmp_P,tmp_Q,tmp_V
        predict(imu_msg);
        std_msgs::Header header = imu_msg->header;
        header.frame_id = "world";
        //发布imu_propagate topic
        if (estimator.solver_flag == Estimator::SolverFlag::NON_LINEAR)
            pubLatestOdometry(tmp_P, tmp_Q, tmp_V, header);
    }
}

imu_callback中调用的predict函数代码如下:

//从IMU测量值imu_msg和上一个PVQ递推得到当前PVQ
void predict(const sensor_msgs::ImuConstPtr &imu_msg)
{
    double t = imu_msg->header.stamp.toSec();
    //init_imu初始化的值为1
    if (init_imu)
    {
        latest_time = t;
        init_imu = 0;
        return;
    }
    //计算当前imu_msg距离上一个imu_msg的时间间隔
    double dt = t - latest_time;
    latest_time = t;
    //获取x,y,z三个方向上的线加速度
    double dx = imu_msg->linear_acceleration.x;
    double dy = imu_msg->linear_acceleration.y;
    double dz = imu_msg->linear_acceleration.z;
    Eigen::Vector3d linear_acceleration{dx, dy, dz};
    //获取x,y,z三个方向上的角速度
    double rx = imu_msg->angular_velocity.x;
    double ry = imu_msg->angular_velocity.y;
    double rz = imu_msg->angular_velocity.z;
    Eigen::Vector3d angular_velocity{rx, ry, rz};

    Eigen::Vector3d un_acc_0 = tmp_Q * (acc_0 - tmp_Ba) - estimator.g;

    Eigen::Vector3d un_gyr = 0.5 * (gyr_0 + angular_velocity) - tmp_Bg;
    tmp_Q = tmp_Q * Utility::deltaQ(un_gyr * dt);

    Eigen::Vector3d un_acc_1 = tmp_Q * (linear_acceleration - tmp_Ba) - estimator.g;

    Eigen::Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1);
    //利用位移公式计算位移
    tmp_P = tmp_P + dt * tmp_V + 0.5 * dt * dt * un_acc;
    //加速度情况下速度计算
    tmp_V = tmp_V + dt * un_acc;
    //线加速度
    acc_0 = linear_acceleration;
    //角速度
    gyr_0 = angular_velocity;
}

imu_callback中调用的pubLatestOdometry函数如下,该函数中主要是发布predict中计算出来的PVQ信息。

/**
 * 发布最新的由imu直接递推得到的PQV
*/
void pubLatestOdometry(const Eigen::Vector3d &P, const Eigen::Quaterniond &Q, const Eigen::Vector3d &V, const std_msgs::Header &header)
{
    Eigen::Quaterniond quadrotor_Q = Q ;

    nav_msgs::Odometry odometry;
    odometry.header = header;
    odometry.header.frame_id = "world";
    odometry.pose.pose.position.x = P.x();
    odometry.pose.pose.position.y = P.y();
    odometry.pose.pose.position.z = P.z();
    odometry.pose.pose.orientation.x = quadrotor_Q.x();
    odometry.pose.pose.orientation.y = quadrotor_Q.y();
    odometry.pose.pose.orientation.z = quadrotor_Q.z();
    odometry.pose.pose.orientation.w = quadrotor_Q.w();
    odometry.twist.twist.linear.x = V.x();
    odometry.twist.twist.linear.y = V.y();
    odometry.twist.twist.linear.z = V.z();
    pub_latest_odometry.publish(odometry);
}

2)订阅feature消息

ros::Subscriber sub_image = n.subscribe("/feature_tracker/feature", 2000, feature_callback);

回调函数feature_callback函数代码如下:

//feature回调函数,将feature_msg放入feature_buf
void feature_callback(const sensor_msgs::PointCloudConstPtr &feature_msg)
{
    //如果是第一个检测到的特征则直接忽略掉,这里直接return了二没有将该feature加入到feature_buf中
    if (!init_feature)
    {
        //skip the first detected feature, which doesn't contain optical flow speed
        init_feature = 1;
        return;
    }
    m_buf.lock();
    feature_buf.push(feature_msg);
    m_buf.unlock();
    //唤醒process线程,处理feature_buf中的
    con.notify_one();
}

3)订阅restart消息

ros::Subscriber sub_restart = n.subscribe("/feature_tracker/restart", 2000, restart_callback);

回调函数restart_callback函数代码如下,这里的restart消息处理中主要是将estimator中的相关参数和存储数据的buf清除掉。

//restart回调函数,收到restart消息时清空feature_buf和imu_buf,估计器重置,时间重置
void restart_callback(const std_msgs::BoolConstPtr &restart_msg)
{
    if (restart_msg->data == true)
    {
        ROS_WARN("restart the estimator!");
        //重启estimator的时候需要先上锁将feature_buf、imu_buf都清空,
        m_buf.lock();
        while(!feature_buf.empty())
            feature_buf.pop();
        while(!imu_buf.empty())
            imu_buf.pop();
        m_buf.unlock();
        m_estimator.lock();
        estimator.clearState();
        estimator.setParameter();
        m_estimator.unlock();
        current_time = -1;
        last_imu_t = 0;
    }
    return;
}

4)订阅match_points消息

ros::Subscriber sub_relo_points = n.subscribe("/pose_graph/match_points", 2000, relocalization_callback);

回调函数relocalization_callback代码如下,该函数对于接收到的匹配的地图点信息存放在relo_buf中,为后边的重定位提供数据支持。

//relocalization回调函数,将points_msg放入relo_buf
void relocalization_callback(const sensor_msgs::PointCloudConstPtr &points_msg)
{
    //printf("relocalization callback! \n");
    m_buf.lock();
    relo_buf.push(points_msg);
    m_buf.unlock();
}

6.创建measurement_process线程

std::thread measurement_process{process};

在这里创建了measurement_process线程,线程的入口函数为process,这个线程也就运行了起来。该线程为estimator中最重要的逻辑处理函数,IMU预计分和图像处理等重要的操作都是在该线程中实现的。

由于process函数中的内容太多了,对process的代码分析放到下一篇博客中进行介绍。

VINS-Mono代码阅读笔记(四):vins_estimator中process线程代码分析

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

VINS-Mono代码阅读笔记(三):vins_estimator中main函数分析 的相关文章

  • MotionBuilder与NOKOV度量动捕系统连接教程

    目录 一 动捕软件安装 二 数据录制 导入与导出 xff08 一 xff09 创建 Markerset xff08 二 xff09 数据采集 xff08 三 xff09 数据导入 xff08 四 xff09 数据导出 三 插件安装与 Mot
  • NOKOV动作捕捉系统使多场协同无人机自主建造成为可能

    近年来 xff0c 工业机器人的兴起使得建造的效率和安全性得以提升 xff0c 但由于机器人由于大小与活动范围的限制 xff0c 在大型建筑上难以施展拳脚 上海同济大学建筑系的无人机自主建造小组 xff0c 正在进行以无人机取代工业机器人进
  • 多智能体系统集群协同控制实验平台详解与典型案例

    目录 一 机器人实验是智能体集群研究必要手段 二 动作捕捉系统解决智能体集群实验系统多个痛点 三 多智能体集群协同控制实验平台 1 Crazyswarm多无人机集群编队实验平台 2 Robotarium机器人平台 3 中科院自动化所智能集群
  • NOKOV度量动作捕捉协助完成无人机室内定位研究

    随着工业发展 技术进步 xff0c 无人机的使用在各行各业愈发普遍 xff0c 开始出现无人机飞行送外卖 智能无人机自主巡检等多方面应用 在这一过程中 xff0c 无人机飞行定位就成为了重中之重 西北工业大学无人机特种技术国防科技重点实验室
  • 光学动作捕捉系统构成

    一套光学动作捕捉系统由红外动作捕捉镜头 动作捕捉软件 反光标识点 POE交换机 和若干配件组成 xff08 如标定框和镜头固定装置等 xff09 其本质是定位系统 xff0c 通过计算分析 xff0c 来获取与其相关的速度 加速度等多种运动
  • vscode命令行起本地服务,可发送http请求

    在我们vscode中默认打开的是file协议 xff0c 但是往往我们会有ajax等请求 xff0c 需要发送http等其他协议 xff0c 所以我们需要搭起本地服务器 xff1a 1 xff1a cd 进去到文件位置 xff0c 运行 n
  • 动作捕捉用于仿生机器人的运动规划

    随着机器人 三维动画 虚拟现实等产业的发展 xff0c 关于仿生机器人的动作研究早已成为重要的热点课题 如何让机器人或虚拟人物做出合理 流畅的姿态呢 xff1f 这就要涉及到逆运动学算法研究 人体很复杂 xff0c 传统算法需优化 由于人体
  • 智能化人机协作 遮挡情况下准确识别目标信息

    研究背景 废旧产品 xff08 end of life products xff09 的拆卸是工程全生命周期管理的一个基本步骤 在减少资源消耗和温室气体排放的同时 xff0c 回收可重复使用的部件可能创造相当的经济价值 xff0c 同时也能
  • 线下·香港 | 工业大数据与智能系统前沿会议

    由香港理工大学主办的工业大数据与智能系统前沿会议将于2023年4月28日至5月1日在香港举行 届时来自海外 内地及香港的知名科学家将聚首 xff0c 将围绕大会主题 面向人机共融的工业转型 发表演讲 xff0c 分享他们的独到见解并探讨最新
  • 人机耦合模型研究及其在下肢外骨骼机器人设计中的应用

    在外骨骼研究中 xff0c 一个合适的人机耦合模型非常重要 xff0c 它可以帮助预测外骨骼系统直接作用于人体产生的影响 xff0c 避免不必要的伤害和能量损失 xff0c 同时也有助于优化外骨骼系统的设计和控制 xff0c 提高其佩戴的舒
  • STM32】 DMA原理,步骤超细详解,一文看懂DMA

    如需转载请注明地址 xff1a https blog csdn net as480133937 article details 104927922 DMA的基本介绍 什么是DMA DMA的基本定义 DMA xff0c 全称Direct Me
  • float类型数据在报文中的传输方法

    方法1 xff1a 转化成整型传输 假如保留float类型数据为两位小数 xff0c 我们可以将float数据 100 转换成整型数据传输 xff0c 对端收到后 xff0c 再 100 xff0c 转换成float类型 方法2 xff1a
  • 101、104规约解析

    转载 xff1a 电网101 104规约解析 xff08 Java xff09 张二狗和苗翠花的博客 CSDN博客 iec101 java 1 前言 最近在研究广东电网的101与104规约 xff0c 也就是DL T634 5101 200
  • Ubuntu:Python多版本切换。

    使用 update alternatives更改系统Python版本 1 查看可选版本 sudo update alternatives list python 如果提示 xff1a update alternatives error no
  • ROS(melodic)安装问题汇总及解决方法

    终于装上了ROS xff0c 费了很大的波折 xff0c 基本上能遇到的问题都遇到了 xff0c 记在这里希望能给遇到同样问题的朋友一点参考 首先是在虚拟机上装ubuntu 18 04 xff0c 这个没什么问题 xff0c 所用的镜像文件
  • Http请求出现invalid http response问题的原因分析

    发生场景 xff1a A系统发送Http请求调用B系统提供的接口 xff1b 发生问题 xff1a A系统报错 xff0c 提示 invalid http response 错误信息 xff1b 问题分析 xff1a 根据翻译 xff0c
  • STM32利用CUBEMX建立自定义HID工程,并且完成64字节的IN,OUT传输功能。

    STM32 Customed HID开发流程 本文介绍的是STM32的cubeMX自定义HID的开发流程 cubeMX配置customed HID模式 更多详细配置壳查看代码CubeMX的配置文件 修改usbd custome hid if
  • STM32 uart 单线半双工模式(cube版本)

    STM32 uart 单线半双工模式 xff08 cube版本 xff09 1 引言 在某些场合下需要进行三线制串口通信 xff08 信号线只有一根 xff09 xff0c 这就要求进行单线半双工的模式进行通信 在这种情况进行数据协议传输的
  • AS5600磁编码器开发记录

    AS5600使用简介 xff08 程序员版 xff09 本文由 智御电子 提供 xff0c 同时提供范例教程 xff0c 以便电子爱好者交流学习 前言 xff1a 最近由于工作需要接触到AS5600这颗磁角度传感器 xff0c 以前就对相关
  • STM32 硬件UART接收超时检测设置

    STM32 硬件UART接收超时检测设置 本文作者 智御电子 xff0c 期待与电子爱好者交流学习 应用场景 在uart应用中有时候需要进行双工通信 xff0c 主机需要对从机的数据进行接收超时检测 xff0c 例如modbus协议 xff

随机推荐

  • 发送GET请求 示例

    发送GET请求 64 param url 请求地址 64 param param 请求参数 64 param headers 64 return private String requestByGet String url Map lt S
  • STL不同容器的优缺点

    一 容器的分类 1 序列容器 xff08 1 xff09 vector 典型的序列容器 xff0c 任意元素的读取 修改具有O 1 xff0c 在序列尾部进行插入 删除是O 1 xff0c 但在序列的头部插入 删除的时间复杂度是O n xf
  • c语言(数组)

    交换算法 xff08 将最小值换到第一位 xff0c 最大值换到最后一位 xff09 include lt stdio h gt void main int o 61 0 int buf 10 接收用户输入的数组 for o lt 10 o
  • STM32外设串口资源用完了怎么办--------串口模拟解决问题(再也不用多个STM32或其它MCU)

    之前做项目的时候遇到了一个问题 xff0c 当把MCU本身的串口资源用完的时候 xff0c 却还需要使用多几个串口 xff0c 又不想使用几个MCU解决这个问题 那么模拟串口是解决这个问题的一种方法 下图是我对串口通信时序图的个人理解 xf
  • scanf函数中的格式字符串及注意事项

    scanf函数称为格式输入函数 xff0c 即按用户指定的格式从键盘上把数据输入到指定的变量之中 scanf函数的一般形式为 xff1a scanf 格式控制字符串 地址表列 xff1b 格式字符串的一般形式为 xff1a 输入数据宽度 长
  • 【C/C++】标准库, STL, Boost等的联系

    Backto C C 43 43 Index 标准库 最最开始 只有 C 语言 使用着使用着 一些常用的功能被写成了库 各种组织都是自己私有的库 后来为了方便统一使用和交流 就制定了标准 标准里的库 就是 C 标准库 后来 C 43 43
  • 数组与链表的优缺点和区别

    1 数组 xff1a 数组是将元素在内存中连续存放 xff0c 由于每个元素占用内存相同 xff0c 可以通过下标迅速访问数组中任何元素 但是如果要 在数组中增加一个元素 xff0c 需要移动大量元素 xff0c 在内存中空出一 个元素的空
  • 堆空间与栈空间的区别

    1 栈区 xff08 stack xff09 xff1a 又编译器自动分配释放 xff0c 存放函数的参数值 xff0c 局部变量的值等 xff0c 其操作方式类似于数据结构的 栈 2 堆区 xff08 heap xff09 xff1a 一
  • strtok函数及其实现

    头文件 xff1a include lt string h gt 定义函数 xff1a char strtok char s const char delim 函数说明 xff1a strtok 用来将字符串分割成一个个片段 参数s 指向欲
  • 服务器和客户机的信息函数以及读写函数

    1 服务器和客户机的信息函数 xff08 1 xff09 字节转换函数 在网络上面有着许多类型的机器 xff0c 这些机器在表示数据的字节顺序是不同的 xff0c 比如i386芯片是低字节在内存地址的低 端 xff0c 高字节在高端 xff
  • TCP协议的拥塞控制机制

    最初的TCP协议只有基于窗口的流控制 xff08 flow control xff09 机制而没有拥塞控制机制 流控制作为接受方管理发送方发送 数据的方式 xff0c 用来防止接受方可用的数据缓存空间的溢出 流控制是一种局部控制机制 xff
  • 构造函数为什么不能是虚函数

    1 从存储空间角度 xff0c 虚函数对应一个指向vtable虚函数表的指针 xff0c 这大家都知道 xff0c 可是这个指向vtable的指针其实是存储在对象的内存空间的 问题出来了 xff0c 如果构造函数是虚的 xff0c 就需要通
  • openmv学习五:OLED

    首先需要将SSD1306x py这个文件放到OPENMV中 代码 from machine import I2C Pin 从 machine 模块导入 I2C Pin 子模块 from ssd1306x import SSD1306 I2C
  • 自旋锁的实现及优化

    自旋锁也是一种互斥锁 xff0c 和mutex锁相比 xff0c 它的特点是不会阻塞 xff0c 如果申请不到锁 xff0c 就会不断地循环检测锁变量的状态 xff0c 也就是自旋 自旋锁的实现算法大多使用TAS算法或者CAS算法 TAS算
  • C语言----详解字符串相关的库函数(建议收藏)

    文章目录 系列文章目录前言一 C语言相关字符串库函数一览表 二 strlen函数 三 strcpy函数四 strcat函数 五 strcmp函数 六 strncpy函数 七 strncat函数 八 strncmp函数 九 strstr函数
  • C/C++头文件与变量的声明和定义

    C C 43 43 头文件与变量的声明和定义 最近遇到了变量重复包含的问题 xff0c 才发现自己有好多知识已经模糊了 xff0c 真惭愧 首先说下头文件 xff0c 其实头文件对计算机而言没什么作用 xff0c 她只是在预编译时在 inc
  • C语言寄存器变量register

    用register声明的变量是寄存器变量 xff0c 是存放在CPU的寄存器里的 而我们平时声明的变量是存放在内存中的 虽说内存的速度已经很快了 xff0c 不过跟寄存器比起来还是差得远 寄存器变量和普通变量比起来速度上的差异很大 xff0
  • Curl(C++)使用教程

    1 Curl简介 2 Easy interface 3 Multi interface 1 Curl简介 libcurl作为是一个多协议的便于客户端使用的URL传输库 xff0c 基于C语言 xff0c 提供C语言的API接口 xff0c
  • GPS原始RMC数据解析之DDMM.MMMM

    环境 GPS BD 定位模块 1 模块输出数据如下 GNRMC 100756 000 V 4000 0005 N 11559 9745 E 6 21 223 00 050313 N 68 2 了解换算规则 ddmm mmmm规则和dd dd
  • VINS-Mono代码阅读笔记(三):vins_estimator中main函数分析

    在VINS Mono代码阅读笔记 xff08 一 xff09 xff1a 从Euroc数据集的运行开始 中我们已经初步知道了vins estimator中订阅和发布的topic xff0c 那么 xff0c 在研究vins estimato