ROS运动规划学习五---global_planner

2023-05-16

文章目录

  • 前言
  • 一、global_planner功能包结构
  • 二、planner_core
    • 1.执行过程
    • 2. calculatePotentials()
    • 3. getPlanFromPotential()
  • 总结


前言

本节将学习ROS中的全局规划期global_planner功能包,前面已经介绍了nav_core、move_base、costmap_2d功能包。全局规划大都基于静态地图进行规划,产生路径点,然后给到局部规划器进行局部规划,ROS中常见的全局规划器功能包有navfn、global_planner(Dijkstra、A*)、asr_navfn、Movelt!(常用于机械臂)等.


一、global_planner功能包结构

在这里插入图片描述
plan_node文件是全局规划的入口;planner_core是global_planner的核心,进行初始化,调用A*或者Dijkstra进行全局规划;quadratic_calculator(二次逼近方式,常用) 和potential_calculator(直接返回当前点代价最小值,累加前面的代价值)在生成搜索路径中用到;搜索到路径后使用回溯grid_path(栅格路径)、gradient_path(梯度路径)获得最终路径;之后orientation_filter进行方向滤波。
栅格路径:从终点开始找上下左右四个点中最小的栅格直到起点
梯度路径:从周围八个栅格中找到下降梯度最大的点

二、planner_core

1.执行过程

首先,注册全局路径插件,使其成为ros插件,在ros中使用

PLUGINLIB_EXPORT_CLASS(global_planner::GlobalPlanner, nav_core::BaseGlobalPlanner)

进行初始化:如果没有初始化,就执行初始化操作,获取costmap的尺寸大小,初始化参数:old_navfn_behavior_、use_quadratic(是否使用二次逼近:是:调用QuadraticCalculator-推荐,否:调用PotentialCalculator)、use_dijkstra(true:使用dijkstra,false:A*)、use_grid_path(是:栅格路径;否:梯度路径–一般平滑性较好)

void GlobalPlanner::initialize(std::string name, costmap_2d::Costmap2D* costmap, std::string frame_id){
if (!initialized_) {
        ros::NodeHandle private_nh("~/" + name);
        costmap_ = costmap;
        frame_id_ = frame_id;
        unsigned int cx = costmap->getSizeInCellsX(), cy = costmap->getSizeInCellsY();
        //参数:
        private_nh.param("old_navfn_behavior", old_navfn_behavior_, false);
        if(!old_navfn_behavior_)
            convert_offset_ = 0.5;
        else
            convert_offset_ = 0.0;
        bool use_quadratic;    //是否二次逼近获取路径
        private_nh.param("use_quadratic", use_quadratic, true);
        if (use_quadratic)
            p_calc_ = new QuadraticCalculator(cx, cy); 
        else
            p_calc_ = new PotentialCalculator(cx, cy); 
        bool use_dijkstra;  是否使用dijkstra全局规划
        private_nh.param("use_dijkstra", use_dijkstra, true);
        if (use_dijkstra)
        {
            DijkstraExpansion* de = new DijkstraExpansion(p_calc_, cx, cy);
            if(!old_navfn_behavior_)
                de->setPreciseStart(true);
            planner_ = de;
        }
        else
            planner_ = new AStarExpansion(p_calc_, cx, cy);   
        bool use_grid_path;  //是否使用栅格路径
        private_nh.param("use_grid_path", use_grid_path, false);
        if (use_grid_path)
            path_maker_ = new GridPath(p_calc_);  //new 出path_maker_实例,从可行点中提取路径
        else
            path_maker_ = new GradientPath(p_calc_);
        //方向滤波
        orientation_filter_ = new OrientationFilter();
       //路径发布
        plan_pub_ = private_nh.advertise<nav_msgs::Path>("plan", 1);
        //视场显示,一般不用
        potential_pub_ = private_nh.advertise<nav_msgs::OccupancyGrid>("potential", 1);
		//是否探索未知区域,flase--不可到达
        private_nh.param("allow_unknown", allow_unknown_, true);
        planner_->setHasUnknown(allow_unknown_);
        //窗口信息
        private_nh.param("planner_window_x", planner_window_x_, 0.0);
        private_nh.param("planner_window_y", planner_window_y_, 0.0);
        private_nh.param("default_tolerance", default_tolerance_, 0.0);
        private_nh.param("publish_scale", publish_scale_, 100);
        private_nh.param("outline_map", outline_map_, true);
        ......
}

makePlan函数—主要函数
通过输入起始位姿、目标点,返回plan路径结果,调用makePlan函数

bool GlobalPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal,std::vector<geometry_msgs::PoseStamped>& plan) 
{
    return makePlan(start, goal, default_tolerance_, plan);
} 

调用的是下面的makePlan函数:

bool GlobalPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, double tolerance,std::vector<geometry_msgs::PoseStamped>& plan)

以下是函数内部程序:
加锁,保证线程安全

boost::mutex::scoped_lock lock(mutex_); //加锁

1.是否已经初始化;

	//初始化
	if (!initialized_) {
        ROS_ERROR("This planner has not been initialized yet, but it is being used, please call initialize() before use");
        return false;
    }

2.清空路径;

    plan.clear();

3.判断目标点和起始点的坐标系和全局坐标系一致

{
    if (goal.header.frame_id != global_frame) {
        ROS_ERROR("The goal pose passed to this planner must be in the %s frame.  It is instead in the %s frame.", global_frame.c_str(), goal.header.frame_id.c_str());
        return false;
    }
    if (start.header.frame_id != global_frame) {
        ROS_ERROR("The start pose passed to this planner must be in the %s frame.  It is instead in the %s frame.", global_frame.c_str(), start.header.frame_id.c_str());
        return false;
    }
}

4.判断起始点和目标点是否超出地图范围

    double wx = start.pose.position.x;
    double wy = start.pose.position.y;
    unsigned int start_x_i, start_y_i, goal_x_i, goal_y_i;
    double start_x, start_y, goal_x, goal_y;
    if (!costmap_->worldToMap(wx, wy, start_x_i, start_y_i)) {
    ROS_WARN("The robot's start position is off the global costmap. Planning will always fail, are you sure the robot has been properly localized?");
        return false;
    }
    if(old_navfn_behavior_){
        start_x = start_x_i;
        start_y = start_y_i;
    }else{
        worldToMap(wx, wy, start_x, start_y);
    }
    wx = goal.pose.position.x;
    wy = goal.pose.position.y;
    if (!costmap_->worldToMap(wx, wy, goal_x_i, goal_y_i)) {
        ROS_WARN_THROTTLE(1.0, "The goal sent to the global planner is off the global costmap. Planning will always fail to this goal.");
        return false;
    }
    if(old_navfn_behavior_){
        goal_x = goal_x_i;
        goal_y = goal_y_i;
    }else{
        worldToMap(wx, wy, goal_x, goal_y);
    }

5.清除起始单元格,不可能是障碍物

    clearRobotCell(start, start_x_i, start_y_i);

6.确保全局规划用的数组大小和地图大小一致

    int nx = costmap_->getSizeInCellsX(), ny = costmap_->getSizeInCellsY();
    p_calc_->setSize(nx, ny);
    planner_->setSize(nx, ny);
    path_maker_->setSize(nx, ny);
    potential_array_ = new float[nx * ny];
    if(outline_map_)
        outlineMap(costmap_->getCharMap(), nx, ny, costmap_2d::LETHAL_OBSTACLE);

7.计算势场数组:用到的是calculatePotentials函数

    bool found_legal = planner_->calculatePotentials(costmap_->getCharMap(), start_x, start_y, goal_x, goal_y,nx * ny * 2, potential_array_);
    if(!old_navfn_behavior_)
        planner_->clearEndpoint(costmap_->getCharMap(), potential_array_, goal_x_i, goal_y_i, 2);
    if(publish_potential_)
        publishPotential(potential_array_);

8.提取全局路径:使用函数getPlanFromPotential,结果保存在plan发出

     if (found_legal) {
        if (getPlanFromPotential(start_x, start_y, goal_x, goal_y, goal, plan)) {
            // 更新目标点的时间戳,和路径的其他点时间戳一致
            geometry_msgs::PoseStamped goal_copy = goal;
            goal_copy.header.stamp = ros::Time::now();
            plan.push_back(goal_copy);
        } else {
            ROS_ERROR("Failed to get a plan from potential when a legal potential was found. This shouldn't happen.");
        }
    }else{
        ROS_ERROR("Failed to get a plan.");
    }

9.给路径添加方向

    orientation_filter_->processPath(start, plan);    //orientation_filter.cpp

10.发布路径并可视化,删除new的对象,释放内存

    publishPlan(plan);
    delete[] potential_array_;
    return !plan.empty();

makePlan结束

2. calculatePotentials()

若全局规划器选择A* ,,就去astar.cpp中找;选择Dijkstra就去dijkstra.cpp中找。

bool AStarExpansion::calculatePotentials(unsigned char* costs, double start_x, double start_y, double end_x, double end_y,int cycles, float* potential) 
{
//参数:costs地图指针、起点坐标、终点坐标、循环次数(地图栅格的二倍)、代价数组
//下面是A*算法过程,使用队列 queue ,按照一定的优先级,将起放入队列;将potential数组全部设为最大POT_HIGH;将起点的potential设为0
	queue_.clear();//清空队列
    int start_i = toIndex(start_x, start_y);   //起点的索引
    queue_.push_back(Index(start_i, 0));  //起点加入队列
    std::fill(potential, potential + ns_, POT_HIGH);  // ns_ : 单元格总数
    potential[start_i] = 0;
    int goal_i = toIndex(end_x, end_y);   //目标点索引
    int cycle = 0;
    //进入循环,只要队列不为空,得到最小cost的索引,并删除
    while (queue_.size() > 0 && cycle < cycles){
        Index top = queue_[0];
        std::pop_heap(queue_.begin(), queue_.end(), greater1());
        queue_.pop_back();
        int i = top.i;
        //若i=目标点索引,搜索成功,返回true
        if (i == goal_i)
            return true;
        //将代价最小点i周围点加入搜索队里并更新代价值, 即对前后左右四个点执行add函数
        add(costs, potential, potential[i], i + 1, end_x, end_y);
        add(costs, potential, potential[i], i - 1, end_x, end_y);
        add(costs, potential, potential[i], i + nx_, end_x, end_y);
        add(costs, potential, potential[i], i - nx_, end_x, end_y);
        
		cycle++;
    }
    return false;
}

add函数
首先进行边界检查,超出地图范围返回,障碍物点返回,已经搜索过的点返回;
之后开始进行判断,这里用的是简单的potential_calculator计算代价,同时使用的是曼哈顿距离计算代价。

void AStarExpansion::add(unsigned char* costs, float* potential, float prev_potential, int next_i, int end_x,int end_y) {
    if (next_i < 0 || next_i >= ns_)
        return;
    if (potential[next_i] < POT_HIGH)
        return;
    if(costs[next_i]>=lethal_cost_ && !(unknown_ && costs[next_i]==costmap_2d::NO_INFORMATION))
        return;
    potential[next_i] = p_calc_->calculatePotential(potential, costs[next_i] + neutral_cost_, next_i, prev_potential);
    int x = next_i % nx_, y = next_i / nx_;
    float distance = abs(end_x - x) + abs(end_y - y);
    queue_.push_back(Index(next_i, potential[next_i] + distance * neutral_cost_));
    std::push_heap(queue_.begin(), queue_.end(), greater1());
}

3. getPlanFromPotential()

在planner_core.cpp中,同时调用 path_maker_->getPath函数得到path,但没有方向信息

bool GlobalPlanner::getPlanFromPotential(double start_x, double start_y, double goal_x, double goal_y,const geometry_msgs::PoseStamped& goal,
                                        std::vector<geometry_msgs::PoseStamped>& plan) {
    if (!initialized_) {
        ROS_ERROR("This planner has not been initialized yet, but it is being used, please call initialize() before use");
        return false;
    }
    std::string global_frame = frame_id_;
    // 清空路径
    plan.clear();
    std::vector<std::pair<float, float> > path;
    // 这个path的点只有在map中的位置信息(x,y)
    if (!path_maker_->getPath(potential_array_, start_x, start_y, goal_x, goal_y, path)) {
        ROS_ERROR("NO PATH!");
        return false;
    }
    //获取到path
    ros::Time plan_time = ros::Time::now();
    // 将path中每个点转换到world下,方向信息还没加入,这里统一设为零,然后依次存储到plan中
    for (int i = path.size() -1; i>=0; i--) {
        std::pair<float, float> point = path[i];
        // 把map的全局路径转换到world下
        double world_x, world_y;
        mapToWorld(point.first, point.second, world_x, world_y);
        geometry_msgs::PoseStamped pose;
        pose.header.stamp = plan_time;
        pose.header.frame_id = global_frame;
        pose.pose.position.x = world_x;
        pose.pose.position.y = world_y;
        pose.pose.position.z = 0.0;
        pose.pose.orientation.x = 0.0;
        pose.pose.orientation.y = 0.0;
        pose.pose.orientation.z = 0.0;
        pose.pose.orientation.w = 1.0;
        plan.push_back(pose);
    }
    if(old_navfn_behavior_){
            plan.push_back(goal);
    }
    return !plan.empty();
}

加入方向信息:orientation_filter.cpp

path_maker_->getPath函数:grid_path.cpp

bool GridPath::getPath(float* potential, double start_x, double start_y, double end_x, double end_y, std::vector<std::pair<float, float> >& path) {

path_maker_->getPath函数:gradient_path.cpp

bool GradientPath::getPath(float* potential, double start_x, double start_y, double goal_x, double goal_y, std::vector<std::pair<float, float> >& path) {
 

总结

本文大概梳理了global_planner的主要工作流程,具体的函数实现没有特别解释,只用作大致梳理,用到再仔细研究。

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

ROS运动规划学习五---global_planner 的相关文章

  • 将 Android 中的全局声音静音

    是否有一种方法可用于使应用程序按钮的全局声音静音 他们让事情变得比本来应该的更加复杂 你可以只使用AudioManager setStreamMute http developer android com reference android
  • catkin_make 编译报错 Unable to find either executable ‘empy‘ or Python module ‘em‘...

    文章目录 写在前面 一 问题描述 二 解决方法 参考链接 写在前面 自己的测试环境 Ubuntu20 04 一 问题描述 自己安装完 anaconda 后 再次执行 catkin make 遇到如下问题 CMake Error at opt
  • node.js - 配置节点将函数加载到全局范围内?

    在现实生活中 我在某个地方看到我们可以配置 Node js 在全局范围内执行加载的模块 但我现在找不到如何做到这一点 我为什么要问 我有一些遗留文件定义了我想在服务器和客户端上使用的语言实用程序 但是其中许多实用程序被定义为全局范围函数 例
  • 在Python中将对象添加到另一个模块的全局变量中

    我知道这是非常邪恶的 但是是否可以将对象添加到另一个模块的全局变量中 例如 module dog py import cat cat globals addVar name mittens and module cat py print n
  • Firebird 全局临时表(GTT),触摸其他表吗?

    我有一个 Firebird 数据库 v 2 5 由于失去支持 我不允许在数据库中创建过程 视图或表 我的观点太长了 Too many Contexts of Relation Procedure Views Maximum allowed
  • 全局变量默认是extern还是相当于在global中用extern声明变量?

    我已经解决了以下两个问题 C 和 C 中的 static 和 extern 全局变量 https stackoverflow com questions 11055802 static and extern global variables
  • 如何使用 PyQT5 连接和分离外部应用程序或对接外部应用程序?

    我正在使用 ROS 为多机器人系统开发 GUI 但我对界面中最不想做的事情感到困惑 在我的应用程序中嵌入 RVIZ GMAPPING 或其他屏幕 我已经在界面中放置了一个终端 但我无法解决如何向我的应用程序添加外部应用程序窗口的问题 我知道
  • 如何避免全局状态?

    所以 我正在阅读谷歌测试博客 它说全局状态很糟糕并且使得编写测试变得困难 我相信 我的代码现在很难测试 那么如何避免全局状态呢 我使用全局状态 据我所知 最重要的用途是管理我们的开发 验收和生产环境之间的关键信息 例如 我有一个名为 Glo
  • 在Java中捕获全局按键

    因此 每当用户在 Swing 应用程序中的任意位置按下空格键时 我想触发一个事件 暂停 取消暂停某些媒体 由于有如此多的控件和面板可以具有焦点 因此实际上不可能向所有控件和面板添加关键事件 更不用说总的 所以我发现 KeyboardFocu
  • 如何从里程计/tf数据获取投影矩阵?

    我想将视觉里程计的结果与 KITTI 数据集提供的事实进行比较 对于地面中的每一帧 我都有一个投影矩阵 例如 1 000000e 00 9 043683e 12 2 326809e 11 1 110223e 16 9 043683e 12
  • 模块之间共享资源的良好做法? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在非调试模式下获取 Adob​​e AIR 全局运行时错误的堆栈跟踪?

    新版本的AIR使我们能够全局捕获运行时错误并处理它们 问题是 除了错误 ID 错误消息和名称之外 它没有堆栈跟踪或任何有关错误的有用信息 例如 它可能告诉我发生了空指针异常 但它不会告诉我在哪里 哪个方法或任何事情 运行时的调试版本为我们提
  • Java - 全局、可重用的加载对话框

    我正在尝试实现一个全局加载对话框 我想调用一些静态函数来显示对话框和一些静态函数来关闭它 与此同时 我正在主线程或子线程中做一些工作 我尝试以下操作 但对话框没有更新 最后一次 在再次隐藏之前 它会更新 private static Run
  • 我应该担心“窗口未定义”JSLint 严格模式错误吗?

    这不会在严格模式下通过 JSLint use strict function w w alert w window 来自 jslint com 的错误如下所示 第 4 行第 3 行字符出现问题 window 未定义 window 隐含全局
  • 可以在 .h 文件中声明静态全局变量吗?

    static 关键字将全局变量的范围限制为该翻译单元 如果我使用static int x在 h 文件中并包含该 h 文件每隔一个文件 它们不会都属于同一个翻译单元吗 那么 x不是到处可见吗 那么现在static有什么作用呢 另外 有没有什么
  • 如何创建可以从任何控制器和刀片文件访问的全局函数

    我有两个控制器文件 homecontroller 和 backendcontroller 创建全局函数并从两个文件访问它的最佳方法是什么 I found here https stackoverflow com questions 3241
  • WPF - 全局样式?

    有没有办法为我的 WPF 应用程序设置全局样式 我希望做的是将样式应用于所有也有图像子项的按钮 嗯 有点 这是您可以做的一种包罗万象的方法 将以下元素放入您的 App xaml 中 所有按钮都会发生变化 除了您手动应用样式的按钮 但是 如果
  • Python 递归搜索带有嵌套键的字典

    我最近必须使用嵌套的字典 列表组合来解决实际数据系统中的问题 我为此工作了很长一段时间并提出了解决方案 但我非常不满意 我不得不求助于使用globals 和一个命名的临时全局参数 我不喜欢使用全局变量 这只是要求注入漏洞 我觉得必须有一种更
  • 在 ROS 中运行tensorRT时出现“LogicError:explicit_context_dependent失败:无效的设备上下文 - 没有当前活动的上下文?”

    我在 TensorRT 使用 python 中有一个推理代码 我想在 ROS 中运行此代码 但在尝试分配缓冲区时出现以下错误 LogicError explicit context dependent failed invalid devi
  • 动态链接共享库中的全局变量和静态变量会发生什么情况?

    我试图了解当具有全局变量和静态变量的模块动态链接到应用程序时会发生什么 我所说的模块是指解决方案中的每个项目 我经常使用 Visual Studio 这些模块内置于 lib 或 dll 或 exe 本身中 据我所知 应用程序的二进制文件包含

随机推荐

  • OpenStack部署(五)

    部署版本 xff1a pike 部署环境 xff1a CentOS7 6 配置文件中所有controller可修改为控制节点ip地址 配置过程中使用 echo 验证命令执行情况 Networking service 安装与配置neutron
  • 爬虫要违法了吗?小编告诉大家:守住规则,大胆去爬

    最近我学习和实践网络爬虫 xff0c 总想着在这儿抓点数据在那儿抓点数据 但不知为什么 xff0c 抓取别人网站数据时 xff0c 总会产生莫名恐慌生怕自己一不小心就侵权了 xff0c 然后被关在监狱摩擦 所以我想现在这个时候 xff0c
  • CXF开发总结

    CXF开发总结 xff08 3种模式 xff09 基于SOAP Server端开发 导包 xff0c 下载cxf包 xff0c 地址http cxf apache org xff0c 导入eclipse为web service服务提供类定义
  • 年度最受欢迎的Python的书籍,还不来看看!

    Python是一种通用的解释型编程 xff0c 主要用于Web开发 机器学习和复杂数据分析 Python对初学者来说是一种完美的语言 xff0c 因为它易于学习和理解 xff0c 随着这种语言的普及 xff0c Python程序员的机会也越
  • Html5下载功能实现

    downloader模块管理网络文件下载任务 xff0c 用于从服务器下载各种文件 xff0c 并支持跨域访问操作 通过plus downloader获取下载管理对象 Downloader下载使用HTTP的GET POST方式请求下载文件
  • 卡尔曼滤波总结(KF、EKF、UKF)

    1 马尔科夫 参考 xff1a https zhuanlan zhihu com p 489239366 2 协方差矩阵 1 xff09 对于一个样本集合S xff0c 如果每个样本是一个n维空间中的一个列向量 xff0c 则使用协方差矩阵
  • Centos7搭建Squid代理服务器

    Centos7搭建Squid代理服务器 sumu s home 1 无需验证版 http 1 1 安装 yum install squid 1 2 修改配置文件 打开文件 vim etc squid squid conf修改 http ac
  • Python 3.6解决报错:'NoneType' object has no attribute 'decode'的办法

    for repo dict in repo dicts names append repo dict 39 name 39 plot dict 61 39 value 39 repo dict 39 stargazers count 39
  • 手把手教你实现ROS依赖任意第三方库+lpsolve求解整数线性规划问题为例

    How to link dynamic libraries use third party libraries in ROS lpsolve solver as examples 喜欢的话请关注 xff0c 欢迎github 给个小星星 g
  • UCOS-III

    一 UCOSIII 简介 UCOSIII 是一个可裁剪 可固化 可剥夺 的多任务系统 xff0c 没有任务数目的限制 xff0c 是 UCOS 的第三代内核 xff0c UCOSIII 有以下几个重要的特性 xff1a 可剥夺多任务管理 x
  • 【Python】词频统计(written in python and Mapreduce)

    一 利用Python进行词频统计 xff08 一 xff09 计算机等级考试中常用的方法 首先是一个比较标准的考试中使用的方法 xff0c 针对英文文本 xff1a span class token keyword def span spa
  • 数据处理技巧(5):MATLAB 读取txt中的数据

    全是数字的类型 txt 的数据是有数字的 xff0c 如下图 xff1a 读取结点坐标 xff0c 保存在 NodeCoor 数组当中 xff0c 共1331行3列 filename span class token operator 61
  • 基于51单片机的模拟自动感应门 系统protues仿真

    硬件设计 xff08 末尾附文件 xff09 代码设计 include lt reg51 h gt 调用头文件 define uchar unsigned char 宏定义 define uint unsigned int 宏定义 端口定义
  • linux测试程序

    stresslinux super pi prime mprime nbench cpuburn gamut mersenne prime stress cpu burn in memtester memtest86 memtest86 4
  • mysql 删除多余0的问题

    0 43 CAST 字段 AS CHAR 别名 可加可不加
  • 三维点沿指定向量方向到平面的距离计算方法及C++代码实现

    设平面外一点为P p1 p2 p3 xff0c 指定的方向向量为d 61 d1 d2 d3 xff0c 平面Q方程为Ax 43 By 43 Cz 61 D xff0c 设系数ABC已经归一化 xff0c 则其法向量为n 61 A B C 则
  • ubuntu使用proxychains给终端设置代理

    有时 xff0c 我们需要下载一些国外网站上的东西 xff0c 如果用国内网络直接下载的话 xff0c 往往是连接不上的 或者有时下载一个东西速度很慢 xff0c 这都是因为国内网络限制的问题 xff0c 大大影响了我们的工作效率 解决方法
  • int为什么占4个字节?一个字节为什么是8位?

    不知道大家有没有思考过这样的问题 xff0c 一个字节为什么是8位呀 xff0c 也许还有小伙伴不知道我说的这些是什么 xff0c 没关系往下看 第一个解释 xff08 历史 xff09 是IBM为System 360设计了一套8位EBCD
  • K8S之kubectl命令详解及示例

    目录 1 查看类命令 2 操作类命令 3 进阶命令操作 4 kubectl replace 重启pod的四种方法 5 kubectl语法 1 查看类命令 获取节点和服务版本信息 kubectl get nodes 获取节点和服务版本信息 x
  • ROS运动规划学习五---global_planner

    文章目录 前言一 global planner功能包结构二 planner core1 执行过程2 calculatePotentials 3 getPlanFromPotential 总结 前言 本节将学习ROS中的全局规划期global