PathDecider 详细解读

目录

PathDecider的主要功能

PathDecider代码分析

Process()

MakeObjectDecision()

MakeStaticObstacleDecision()

MakeStaticObstacleDecision()的流程图​编辑

MakeStaticObstacleDecision()的代码解析

GenerateObjectStopDecision()

PathDecider里用到的其他函数

path_decision->AddLongitudinalDecision()

两个unordered_map

ObjectDecisionType Obstacle::MergeLongitudinalDecision()

path_decision->MergeWithMainStop()

obstacle.MinRadiusStopDistance()


PathDecider的主要功能

PathDecider路径决策类就是对阻塞自车参考线的障碍物做决策,是否要纵向stop,或者是否可以横向ignore,或者是否要车道内横向让行(nudge),apollo路径决策时是只考虑静态障碍物,动态障碍物决策在速度规划时考虑。

PathDecider代码分析

Process()

pathdecider的主要功能由Process()这个函数实现。

Process()函数的作用:对自车参考线的障碍物调用MakeObjectDecision()函数去对这些阻碍自车参考线障碍物做决策

Status PathDecider::Process(const ReferenceLineInfo *reference_line_info,
                            const PathData &path_data,
                            PathDecision *const path_decision) {
  /// 如果复用了之前的path则可以跳过
  if (FLAGS_enable_skip_path_tasks && reference_line_info->path_reusable()) {
    return Status::OK();
  }

  std::string blocking_obstacle_id;
  if (reference_line_info->GetBlockingObstacle() != nullptr) {
    blocking_obstacle_id = reference_line_info->GetBlockingObstacle()->Id();
  }
  /// 对障碍物做路径决策
  if (!MakeObjectDecision(path_data, blocking_obstacle_id, path_decision)) {
    const std::string msg = "Failed to make decision based on tunnel";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  return Status::OK();
}

MakeObjectDecision()

MakeObjectDecision()函数的作用:调用MakeStaticObstacleDecision()函数对静态障碍物做决策,路径决策时只考虑静态障碍物
 

bool PathDecider::MakeObjectDecision(const PathData &path_data,
                                     const std::string &blocking_obstacle_id,
                                     PathDecision *const path_decision) {
  if (!MakeStaticObstacleDecision(path_data, blocking_obstacle_id,
                                  path_decision)) {
    AERROR << "Failed to make decisions for static obstacles";
    return false;
  }
  return true;
}

MakeStaticObstacleDecision()

MakeStaticObstacleDecision()函数的作用:对静态障碍物做决策,若障碍物边界距离自车未来边界最近的横向距离大于3m就横向Ignore,若<0.15m就做纵向stop决策,若[0.15,3.0]m时就做nudge决策,nudge决策也分为车道内向左绕行,车道内向右绕行。

MakeStaticObstacleDecision()的流程图

 
MakeStaticObstacleDecision()的代码解析
bool PathDecider::MakeStaticObstacleDecision(
    const PathData &path_data, const std::string &blocking_obstacle_id,
    PathDecision *const path_decision) {
  // Sanity checks and get important values.
  ACHECK(path_decision);
  /// 获取frenet坐标系下的路径坐标
  const auto &frenet_path = path_data.frenet_frame_path();
  if (frenet_path.empty()) {
    AERROR << "Path is empty.";
    return false;
  }
  /// 获取自车半车宽
  const double half_width =
      common::VehicleConfigHelper::GetConfig().vehicle_param().width() / 2.0;
  /// 设置自车横向半径,意思就是里自车边缘横向距离(FLAGS_lateral_ignore_buffer)以上的障碍物忽略
  const double lateral_radius = half_width + FLAGS_lateral_ignore_buffer;

  // Go through every obstacle and make decisions.
  for (const auto *obstacle : path_decision->obstacles().Items()) {
    const std::string &obstacle_id = obstacle->Id();
    const std::string obstacle_type_name =
        PerceptionObstacle_Type_Name(obstacle->Perception().type());
    ADEBUG << "obstacle_id[<< " << obstacle_id << "] type["
           << obstacle_type_name << "]";

    /// 如果不是静态障碍物或者是虚拟障碍物就跳过
    if (!obstacle->IsStatic() || obstacle->IsVirtual()) {
      continue;
    }
    // - skip decision making for obstacles with IGNORE/STOP decisions already.
    /// 如果横向纵向决策都已经有了ignore就跳过
    if (obstacle->HasLongitudinalDecision() &&
        obstacle->LongitudinalDecision().has_ignore() &&
        obstacle->HasLateralDecision() &&
        obstacle->LateralDecision().has_ignore()) {
      continue;
    }
    /// 如果纵向决策已经有了stop就跳过
    if (obstacle->HasLongitudinalDecision() &&
        obstacle->LongitudinalDecision().has_stop()) {
      // STOP decision
      continue;
    }
    // - add STOP decision for blocking obstacles.
    /// 如果障碍物的id是属于静态阻塞障碍物 blocking_obstacle_id,
    /// 并且当前injector里的规划状态不处于借道场景的话,就对这个阻塞的障碍物添加stop决策,
    /// 并打上PathDecider/blocking_obstacle的标签
    if (obstacle->Id() == blocking_obstacle_id &&
        !injector_->planning_context()
             ->planning_status()
             .path_decider()
             .is_in_path_lane_borrow_scenario()) {
      // Add stop decision
      ADEBUG << "Blocking obstacle = " << blocking_obstacle_id;
      ObjectDecisionType object_decision;
      *object_decision.mutable_stop() = GenerateObjectStopDecision(*obstacle);
      path_decision->AddLongitudinalDecision("PathDecider/blocking_obstacle",
                                             obstacle->Id(), object_decision);
      continue;
    }
    // - skip decision making for clear-zone obstacles.
    /// 障碍物投影到参考线的ST边界,跳过那些边界类型是禁停区KEEP_CLEAR的障碍物
    if (obstacle->reference_line_st_boundary().boundary_type() ==
        STBoundary::BoundaryType::KEEP_CLEAR) {
      continue;
    }

    // 0. IGNORE by default and if obstacle is not in path s at all.
    ObjectDecisionType object_decision;
    object_decision.mutable_ignore();
    /// 获取障碍物在在参考线上投影的SL边界sl_boundary
    /// 获取障碍物的SL边界,其实就是(start_s,end_s,start_l,end_l)
    const auto &sl_boundary = obstacle->PerceptionSLBoundary();
    /// 如果障碍物的s不在路径path的s范围内,直接对这个障碍物横纵向都添加ignore决策,
    /// 并打上tag PathDecider/not-in-s
    if (sl_boundary.end_s() < frenet_path.front().s() ||
        sl_boundary.start_s() > frenet_path.back().s()) {
      path_decision->AddLongitudinalDecision("PathDecider/not-in-s",
                                             obstacle->Id(), object_decision);
      path_decision->AddLateralDecision("PathDecider/not-in-s", obstacle->Id(),
                                        object_decision);
      continue;
    }

    /// frenet_point就是在自车path路径上找到距离障碍物SLBoundary最近的点
    const auto frenet_point = frenet_path.GetNearestPoint(sl_boundary);
    /// curr_l就是frenet_point的L坐标
    const double curr_l = frenet_point.l();
    /// min_nudge_l = 自车车宽一半 + 静态障碍物缓冲距离的一半
    double min_nudge_l =
        half_width +
        config_.path_decider_config().static_obstacle_buffer() / 2.0;
    /// l方向上,静态障碍物离path太远了,就横向决策上ignore,并打上PathDecider/not-in-l的tag
    /// 横向距离太远判定是自车和静态障碍物之间的横向距离要大于FLAGS_lateral_ignore_buffer
    if (curr_l - lateral_radius > sl_boundary.end_l() ||
        curr_l + lateral_radius < sl_boundary.start_l()) {
      // 1. IGNORE if laterally too far away.
      path_decision->AddLateralDecision("PathDecider/not-in-l", obstacle->Id(),
                                        object_decision);
    } else if (sl_boundary.end_l() >= curr_l - min_nudge_l &&
               sl_boundary.start_l() <= curr_l + min_nudge_l) {
      /// l方向上,静态障碍物离path太近了,而且此障碍物要距离自车最近
      /// 就做出纵向决策上的stop,并且打上PathDecider/nearest-stop的tag
      /// 横向距离太近判定是自车和静态障碍物之间的横向距离要小于
      /// config_.path_decider_config().static_obstacle_buffer()
      // 2. STOP if laterally too overlapping.
      *object_decision.mutable_stop() = GenerateObjectStopDecision(*obstacle);

      if (path_decision->MergeWithMainStop(
              object_decision.stop(), obstacle->Id(),
              reference_line_info_->reference_line(),
              reference_line_info_->AdcSlBoundary())) {
        path_decision->AddLongitudinalDecision("PathDecider/nearest-stop",
                                               obstacle->Id(), object_decision);
      } else {
        /// l方向上,静态障碍物离path太近了,而且此障碍物要距离自车不是最近的
        /// 就做出纵向决策上的ignore,并且打上PathDecider/not-nearest-stop的tag
        ObjectDecisionType object_decision;
        object_decision.mutable_ignore();
        path_decision->AddLongitudinalDecision("PathDecider/not-nearest-stop",
                                               obstacle->Id(), object_decision);
      }
    } else {
      // 3. NUDGE if laterally very close.
      /// l方向上,当静态障碍物离自车的距离小于FLAGS_lateral_ignore_buffer
      /// 并且大于config_.path_decider_config().static_obstacle_buffer()
      /// 那就在横向上做出nudge的决策,并且根据sl_boundary判断出nudge的方向
      if (sl_boundary.end_l() < curr_l - min_nudge_l) {  // &&
        // sl_boundary.end_l() > curr_l - min_nudge_l - 0.3) {
        // LEFT_NUDGE
        ObjectNudge *object_nudge_ptr = object_decision.mutable_nudge();
        object_nudge_ptr->set_type(ObjectNudge::LEFT_NUDGE);
        object_nudge_ptr->set_distance_l(
            config_.path_decider_config().static_obstacle_buffer());
        path_decision->AddLateralDecision("PathDecider/left-nudge",
                                          obstacle->Id(), object_decision);
      } else if (sl_boundary.start_l() > curr_l + min_nudge_l) {  // &&
        // sl_boundary.start_l() < curr_l + min_nudge_l + 0.3) {
        // RIGHT_NUDGE
        ObjectNudge *object_nudge_ptr = object_decision.mutable_nudge();
        object_nudge_ptr->set_type(ObjectNudge::RIGHT_NUDGE);
        object_nudge_ptr->set_distance_l(
            -config_.path_decider_config().static_obstacle_buffer());
        path_decision->AddLateralDecision("PathDecider/right-nudge",
                                          obstacle->Id(), object_decision);
      }
    }
  }

  return true;
}

GenerateObjectStopDecision()

GenerateObjectStopDecision()函数的作用:设置停止决策的属性,往里设置停止距离,设置停止点x,y,heading等

ObjectStop PathDecider::GenerateObjectStopDecision(
    const Obstacle &obstacle) const {
  ObjectStop object_stop;

  /// 停止距离的计算就是自车以最小转弯半径可以绕过障碍物而不装上障碍物的最小s
  double stop_distance = obstacle.MinRadiusStopDistance(
      VehicleConfigHelper::GetConfig().vehicle_param());
  object_stop.set_reason_code(StopReasonCode::STOP_REASON_OBSTACLE);
  object_stop.set_distance_s(-stop_distance);

  const double stop_ref_s =
      obstacle.PerceptionSLBoundary().start_s() - stop_distance;
  const auto stop_ref_point =
      reference_line_info_->reference_line().GetReferencePoint(stop_ref_s);
  object_stop.mutable_stop_point()->set_x(stop_ref_point.x());
  object_stop.mutable_stop_point()->set_y(stop_ref_point.y());
  object_stop.set_stop_heading(stop_ref_point.heading());
  return object_stop;
}    

PathDecider里用到的其他函数

path_decision->AddLongitudinalDecision()

path_decision->AddLongitudinalDecision()函数的主要作用:对障碍物加上对应的纵向decision,但是障碍物原本已有decision时进行逻辑上的merge,主要由ObjectDecisionType Obstacle::MergeLongitudinalDecision()实现,对于所有decision,merge的结果永远是安全价值大的decision覆盖掉安全价值小的decision,横纵向的decision安全价值定义在两个unordered_map里面:const std::unordered_map<ObjectDecisionType::ObjectTagCase, int, Obstacle::ObjectTagCaseHash> Obstacle::s_longitudinal_decision_safety_sorter_、const std::unordered_map<ObjectDecisionType::ObjectTagCase, int, Obstacle::ObjectTagCaseHash> Obstacle::s_lateral_decision_safety_sorter_ 。

两个unordered_map
const std::unordered_map<ObjectDecisionType::ObjectTagCase, int,
                         Obstacle::ObjectTagCaseHash>
    Obstacle::s_longitudinal_decision_safety_sorter_ = {
        {ObjectDecisionType::kIgnore, 0},
        {ObjectDecisionType::kOvertake, 100},
        {ObjectDecisionType::kFollow, 300},
        {ObjectDecisionType::kYield, 400},
        {ObjectDecisionType::kStop, 500}};

const std::unordered_map<ObjectDecisionType::ObjectTagCase, int,
                         Obstacle::ObjectTagCaseHash>
    Obstacle::s_lateral_decision_safety_sorter_ = {
        {ObjectDecisionType::kIgnore, 0}, {ObjectDecisionType::kNudge, 100}};
ObjectDecisionType Obstacle::MergeLongitudinalDecision()

ObjectDecisionType Obstacle::MergeLongitudinalDecision(
    const ObjectDecisionType& lhs, const ObjectDecisionType& rhs) {
  if (lhs.object_tag_case() == ObjectDecisionType::OBJECT_TAG_NOT_SET) {
    return rhs;
  }
  if (rhs.object_tag_case() == ObjectDecisionType::OBJECT_TAG_NOT_SET) {
    return lhs;
  }
  const auto lhs_val =
      FindOrDie(s_longitudinal_decision_safety_sorter_, lhs.object_tag_case());
  const auto rhs_val =
      FindOrDie(s_longitudinal_decision_safety_sorter_, rhs.object_tag_case());
  /// 如果decision的value不同就按value就行decision merge,否者相同的的话就比较决策中的distance_s()
  if (lhs_val < rhs_val) {
    return rhs;
  } else if (lhs_val > rhs_val) {
    return lhs;
  } else {
    if (lhs.has_ignore()) {
      return rhs;
    } else if (lhs.has_stop()) {
      return lhs.stop().distance_s() < rhs.stop().distance_s() ? lhs : rhs;
    } else if (lhs.has_yield()) {
      return lhs.yield().distance_s() < rhs.yield().distance_s() ? lhs : rhs;
    } else if (lhs.has_follow()) {
      return lhs.follow().distance_s() < rhs.follow().distance_s() ? lhs : rhs;
    } else if (lhs.has_overtake()) {
      return lhs.overtake().distance_s() > rhs.overtake().distance_s() ? lhs
                                                                       : rhs;
    } else {
      DCHECK(false) << "Unknown decision";
    }
  }
  return lhs;  // stop compiler complaining
}
path_decision->MergeWithMainStop()

path_decision->MergeWithMainStop()函数的主要作用:对于多个stop的decision,根据stop decision里的stop距离来进行merge,永远选择离我们最近的stop decision。

bool PathDecision::MergeWithMainStop(const ObjectStop &obj_stop,
                                     const std::string &obj_id,
                                     const ReferenceLine &reference_line,
                                     const SLBoundary &adc_sl_boundary) {
  common::PointENU stop_point = obj_stop.stop_point();
  common::SLPoint stop_line_sl;
  reference_line.XYToSL(stop_point, &stop_line_sl);

  double stop_line_s = stop_line_sl.s();
  /// stop decision必须在reference_line范围内
  if (stop_line_s < 0.0 || stop_line_s > reference_line.Length()) {
    AERROR << "Ignore object:" << obj_id << " fence route_s[" << stop_line_s
           << "] not in range[0, " << reference_line.Length() << "]";
    return false;
  }

  // check stop_line_s vs adc_s, ignore if it is further way than main stop
  /// 计算停止距离s
  const auto &vehicle_config = common::VehicleConfigHelper::GetConfig();
  stop_line_s = std::fmax(
      stop_line_s, adc_sl_boundary.end_s() -
                       vehicle_config.vehicle_param().front_edge_to_center());

  if (stop_line_s >= stop_reference_line_s_) {
    ADEBUG << "stop point is farther than current main stop point.";
    return false;
  }

  main_stop_.Clear();
  main_stop_.set_reason_code(obj_stop.reason_code());
  main_stop_.set_reason("stop by " + obj_id);
  main_stop_.mutable_stop_point()->set_x(obj_stop.stop_point().x());
  main_stop_.mutable_stop_point()->set_y(obj_stop.stop_point().y());
  main_stop_.set_stop_heading(obj_stop.stop_heading());
  stop_reference_line_s_ = stop_line_s;

  ADEBUG << " main stop obstacle id:" << obj_id
         << " stop_line_s:" << stop_line_s << " stop_point: ("
         << obj_stop.stop_point().x() << obj_stop.stop_point().y()
         << " ) stop_heading: " << obj_stop.stop_heading();
  return true;
}
obstacle.MinRadiusStopDistance()

obstacle.MinRadiusStopDistance()函数的作用:计算自车以当前最小的转弯半径,绕靠这个障碍物所需要的最小的S距离(函数内的计算将reference_line当作直线近似处理),外加一个安全的stop_distance_buffer ,要想直观的解释计算过程需要画图(不会用电脑画图,图之后奉上)。

double Obstacle::MinRadiusStopDistance(
    const common::VehicleParam& vehicle_param) const {
  if (min_radius_stop_distance_ > 0) {
    return min_radius_stop_distance_;
  }
  static constexpr double stop_distance_buffer = 0.5;
  const double min_turn_radius = VehicleConfigHelper::MinSafeTurnRadius();
  double lateral_diff =
      vehicle_param.width() / 2.0 + std::max(std::fabs(sl_boundary_.start_l()),
                                             std::fabs(sl_boundary_.end_l()));
  const double kEpison = 1e-5;
  lateral_diff = std::min(lateral_diff, min_turn_radius - kEpison);
  double stop_distance =
      std::sqrt(std::fabs(min_turn_radius * min_turn_radius -
                          (min_turn_radius - lateral_diff) *
                              (min_turn_radius - lateral_diff))) +
      stop_distance_buffer;
  stop_distance -= vehicle_param.front_edge_to_center();
  /// 将stop_distance限制在最大值和最小值之间
  stop_distance = std::min(stop_distance, FLAGS_max_stop_distance_obstacle);
  stop_distance = std::max(stop_distance, FLAGS_min_stop_distance_obstacle);
  return stop_distance;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/735636.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言入门4-函数和程序结构

函数举例 读取字符串&#xff0c;如果字符串中含有ould则输出该字符串&#xff0c;否则不输出。 #include <stdio.h>// 函数声明 int getLine(char s[], int lim); int strindex(char s[], char t[]);int main() {char t[] "ould"; // 要查找的目标子字符串…

自然语言处理学习路线(1)——NLP的基本流程

NLP基本流程 【NLP基本流程】 0. 获取语料 ——> 1. 语料预处理 ——> 2. 特征工程&选择 ——> 3. 模型训练 ——> 4. 模型输出&上线 【NLP基本流程图】 Reference 1. 自然语言处理(NLP)的一般处理流程&#xff01;-腾讯云开发者社区-腾讯云 2. …

Vatee万腾平台:智能科技的领航者

随着科技的飞速发展&#xff0c;数字化转型已成为企业、行业乃至整个社会不可逆转的趋势。在这个变革的浪潮中&#xff0c;Vatee万腾平台凭借其卓越的技术实力、前瞻的战略眼光和卓越的服务品质&#xff0c;成为了智能科技的领航者。 Vatee万腾平台致力于为企业提供全方位的数字…

【Python机器学习】利用t-SNE进行流形学习

虽然PCA通常是用于变换数据的首选方法&#xff0c;使你能够用散点图将其可视化&#xff0c;但这一方法的性质限制了其有效性。 有一类用于可视化的算法叫做流形学习算法&#xff0c;它允许进行更复杂的映射&#xff0c;通常也可以给出更好的可视化。其中特别有用的一个就是t-S…

google gemini1.5 flash视频图文理解能力初探(一)

市面能够对视频直接进行分析的大模型着实不多&#xff0c;而且很多支持多模态的大模型那效果着实也不好。 从这篇公众号不只是100万上下文&#xff0c;谷歌Gemini 1.5超强功能展示得知&#xff0c;Gemini 1.5可以一次性处理1小时的视频、11小时的音频或100,000行代码&#xff0…

c++设计模式之一创建型模式

1、创建型模式&#xff08;常见的设计模式&#xff09; Factory 模式&#xff08;工厂模式&#xff0c;被实例化的子类&#xff09; 在面向对象系统设计中经常可以遇到以下的两类问题&#xff1a; 下面是第一类问题和代码示例&#xff1a;我们经常会抽象出一些类的公共接口以…

stm32学习笔记---新建工程步骤和点灯演示

目录 STM32的三种开发方式 基于寄存器的方式 基于库函数的方式 基于Hal库的方式 固件库介绍 新建基于标准库的工程步骤 配置寄存器来完成点灯操作 添加库函数来完成点灯操作 添加库函数 开始点灯操作 第一步&#xff1a;使能时钟 第二步&#xff1a;配置端口模式 …

ic基础|功耗篇03:ic设计人员如何在代码中降低功耗?一文带你了解行为级以及RTL级低功耗技术

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

鞠婧祎多个商标被丝芭传媒申请注册!

近日鞠婧祎与丝芭传媒合约引发网络关注&#xff0c;普推商标老杨经检索发现&#xff0c;丝芭传媒早在2016起就申请注册了“鞠婧祎”24个商标&#xff0c;涉及多个商标分类&#xff0c;这些基本都下商标注册证。 不管对经纪公司还是网红公司&#xff0c;有实力的基本都会对旗下的…

# Kafka_深入探秘者(2):kafka 生产者

Kafka_深入探秘者&#xff08;2&#xff09;&#xff1a;kafka 生产者 一、kafka 消息发送流程解析 1、kafka &#xff1a;java 客户端 数据生产流程解析 二、kafka 发送类型 1、kafka 发送类型–发送即忘记&#xff1a;producer.send(record) 同步发送 //通过 send() 发送完…

【Vue3组件】分享一下自己写的简约风格评论区组件

代码比较简单&#xff0c;方便大家二次开发&#xff0c;旨在快速提供基础的样式模板&#xff0c;自行迭代定制 预览 简介 通用评论组件 组件功能 此组件旨在创建一个具备嵌套回复能力的通用评论区域&#xff0c;适用于构建动态、互动性强的用户讨论场景。 接收数据结构 组件通…

Paimon Trino Presto的关系 分布式查询引擎

Paimon支持的引擎兼容性矩阵&#xff1a; Trino 是 Presto 同项目的不同版本&#xff0c;是原Faceboo Presto创始人团队核心开发和维护人员分离出来后开发和维护的分支&#xff0c;Trino基于Presto&#xff0c;目前 Trino 和 Presto 都仍在继续开发和维护。 Trino 生态系统-客…

虚拟机IP地址频繁变化的解决方法

勾八动态分配IP&#xff0c;让我在学习redis集群的时候&#xff0c;配置很多的IP地址&#xff0c;但是由于以下原因导致我IP频繁变动&#xff0c;报错让我烦恼&#xff01;&#xff01;&#xff01;&#xff01; 为什么虚拟机的IP地址会频繁变化&#xff1f; 虚拟机IP地址频繁…

webpack处理js资源10--webpack入门学习

处理 js 资源 有人可能会问&#xff0c;js 资源 Webpack 不能已经处理了吗&#xff0c;为什么我们还要处理呢&#xff1f; 原因是 Webpack 对 js 处理是有限的&#xff0c;只能编译 js 中 ES 模块化语法&#xff0c;不能编译其他语法&#xff0c;导致 js 不能在 IE 等浏览器运…

Zabbix+Garafana监控部署

ZabbixGarafana监控部署 一、IP规划 服务器IP备注zabbix-server192.168.100.128zabbix服务端zabbix-mysql192.168.100.130数据库zabbix-client192.168.100.132zabbix客户端garafana-server192.168.100.134Garafana 二、zabbix-server安装zabbix ​ 配置IP地址为&#xff1a…

俄语打招呼和问候的12种表达方式,柯桥俄语培训

- Как дела ? 近况如何&#xff1f; -Нормально, а ты как? 还行吧&#xff0c;你呢&#xff1f; Vol.2 -Как себя чувствуете? 你感觉如何&#xff1f; -Все замечательно! 一切都非常棒。 Vol.3 -Ка…

基于matlab的图像灰度化与图像反白

1原理 2.1 图像灰度化原理 图像灰度化是将彩色图像转换为灰度图像的过程&#xff0c;使得每个像素点仅包含一个灰度值&#xff0c;从而简化了图像的复杂度。灰度化原理主要可以分为以下几种方法&#xff1a; 亮度平均法 原理&#xff1a;将图像中每个像素的RGB值的平均值作为…

Vue40 修改默认配置

修改默认配置 在官网查看各个属性的作用 ### 在vue.config.js文件中&#xff0c;修改属性的值

计算机网络 静态路由及动态路由RIP

一、理论知识 1.静态路由 静态路由是由网络管理员手动配置在路由器上的固定路由路径。其优点是简单和对网络拓扑变化不敏感&#xff0c;缺点是维护复杂、易出错&#xff0c;且无法自动适应网络变化。 2.动态路由协议RIP RIP是一种基于距离向量的动态路由协议。它使用跳数作…

接口自动化拓展:Flask框架安装、介绍及工作中的应用!

Flask是一个轻量级的Python Web框架&#xff0c;用于构建Web应用程序和API。它简洁而灵活&#xff0c;容易上手&#xff0c;并且非常适合用于开发小型到中型规模的应用程序。在接口自动化测试中&#xff0c;Flask可以作为服务器框架&#xff0c;用于搭建测试接口。 本文将从零…