【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER

news2024/11/26 13:42:19

文章目录

  • 前言
  • LANE_CHANGE_DECIDER功能简介
  • LANE_CHANGE_DECIDER相关配置
  • LANE_CHANGE_DECIDER总体流程
  • LANE_CHANGE_DECIDER相关子函数
    • PrioritizeChangeLane
    • UpdateStatus
    • IsClearToChangeLane
    • HysteresisFilter
  • 参考

前言

在Apollo星火计划学习笔记——Apollo路径规划算法原理与实践与【Apollo学习笔记】——Planning模块讲到……Stage::Process的PlanOnReferenceLine函数会依次调用task_list中的TASK,本文将会继续以LaneFollow为例依次介绍其中的TASK部分究竟做了哪些工作。由于个人能力所限,文章可能有纰漏的地方,还请批评斧正。

modules/planning/conf/scenario/lane_follow_config.pb.txt配置文件中,我们可以看到LaneFollow所需要执行的所有task。

stage_config: {
  stage_type: LANE_FOLLOW_DEFAULT_STAGE
  enabled: true
  task_type: LANE_CHANGE_DECIDER
  task_type: PATH_REUSE_DECIDER
  task_type: PATH_LANE_BORROW_DECIDER
  task_type: PATH_BOUNDS_DECIDER
  task_type: PIECEWISE_JERK_PATH_OPTIMIZER
  task_type: PATH_ASSESSMENT_DECIDER
  task_type: PATH_DECIDER
  task_type: RULE_BASED_STOP_DECIDER
  task_type: SPEED_BOUNDS_PRIORI_DECIDER
  task_type: SPEED_HEURISTIC_OPTIMIZER
  task_type: SPEED_DECIDER
  task_type: SPEED_BOUNDS_FINAL_DECIDER
  task_type: PIECEWISE_JERK_SPEED_OPTIMIZER
  # task_type: PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER
  task_type: RSS_DECIDER

本文将从第一个task——LANE_CHANGE_DECIDER开始介绍。

LANE_CHANGE_DECIDER功能简介

在这里插入图片描述
LANE_CHANGE_DECIDER主要功能是:产生是否换道的决策,更新换道状态
主要逻辑是:首先判断是否产生多条参考线,若只有一条参考线,则保持直行。若有多条参考线,则根据一些条件(主车的前方和后方一定距离内是否有障碍物,旁边车道在一定距离内是否有障碍物)进行判断是否换道,当所有条件都满足时,则进行换道决策。

LANE_CHANGE_DECIDER相关配置

LANE_CHANGE_DECIDER的相关配置集中在以下两个文件:modules/planning/conf/planning_config.pb.txtmodules/planning/conf/scenario/lane_follow_config.pb.txt

// modules/planning/conf/planning_config.pb.txt
default_task_config: {
  task_type: LANE_CHANGE_DECIDER
  lane_change_decider_config {
    enable_lane_change_urgency_check: false
    enable_prioritize_change_lane: false
    enable_remove_change_lane: false
    reckless_change_lane: false
    change_lane_success_freeze_time: 1.5
    change_lane_fail_freeze_time: 1.0
  }
}
// modules/planning/conf/scenario/lane_follow_config.pb.txt
  task_config: {
    task_type: LANE_CHANGE_DECIDER
    lane_change_decider_config {
      enable_lane_change_urgency_check: true
    }
  }

LANE_CHANGE_DECIDER总体流程

总体流程图如下所示:
在这里插入图片描述

接着来看一看LANE_CHANGE_DECIDER的整体代码,文件路径:modules/planning/tasks/deciders/lane_change_decider/lane_change_decider.cc
LANE_CHANGE_DECIDER实现逻辑在Process函数中:

// added a dummy parameter to enable this task in ExecuteTaskOnReferenceLine
Status LaneChangeDecider::Process(
    Frame* frame, ReferenceLineInfo* const current_reference_line_info) {
  // Sanity checks.
  CHECK_NOTNULL(frame);
  // 读取配置文件
  const auto& lane_change_decider_config = config_.lane_change_decider_config();
  // 读取ReferenceLineInfo,并检查是否为空
  std::list<ReferenceLineInfo>* reference_line_info =
      frame->mutable_reference_line_info();
  if (reference_line_info->empty()) {
    const std::string msg = "Reference lines empty.";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  // 始终允许车辆变道。车辆可能持续变道 config_path:modules/planning/proto/task_config.proto
  if (lane_change_decider_config.reckless_change_lane()) {
    PrioritizeChangeLane(true, reference_line_info);
    return Status::OK();
  }
  // 获取上一时刻变道状态信息并记录时间戳
  auto* prev_status = injector_->planning_context()
                          ->mutable_planning_status()
                          ->mutable_change_lane();
  double now = Clock::NowInSeconds();
  // 判断当前参考线是否安全可用
  prev_status->set_is_clear_to_change_lane(false);
  if (current_reference_line_info->IsChangeLanePath()) {
    prev_status->set_is_clear_to_change_lane(
        IsClearToChangeLane(current_reference_line_info));
  }
  // 是否获取到状态信息
  if (!prev_status->has_status()) {
    UpdateStatus(now, ChangeLaneStatus::CHANGE_LANE_FINISHED,
                 GetCurrentPathId(*reference_line_info));
    prev_status->set_last_succeed_timestamp(now);
    return Status::OK();
  }
  // 参考线的数目是否大于1
  // 根据reference line的数量判断是否处于变道场景中,size() > 1则处于变道过程中,需要判断变道的状态
  bool has_change_lane = reference_line_info->size() > 1;
  ADEBUG << "has_change_lane: " << has_change_lane;
  // 只有一条reference line,没有进行变道
  if (!has_change_lane) {
    // 根据当前唯一的reference line,获得当前道路lane的ID
    const auto& path_id = reference_line_info->front().Lanes().Id();
    // 上一时刻是否变道完成
    if (prev_status->status() == ChangeLaneStatus::CHANGE_LANE_FINISHED) {
    // 上一时刻是否在变道中。若有,这一时刻只有一条reference line,说明变道成功
    } else if (prev_status->status() == ChangeLaneStatus::IN_CHANGE_LANE) {
    // 更新当前时刻,变道完成状态,以及当前道路的ID
      UpdateStatus(now, ChangeLaneStatus::CHANGE_LANE_FINISHED, path_id);
    // 上一时刻是否变道失败
    } else if (prev_status->status() == ChangeLaneStatus::CHANGE_LANE_FAILED) {
    } else {
      const std::string msg =
          absl::StrCat("Unknown state: ", prev_status->ShortDebugString());
      AERROR << msg;
      return Status(ErrorCode::PLANNING_ERROR, msg);
    }
    // 返回LaneChangeDecider::Process 的状态为OK
    return Status::OK();
  } else {  // has change lane in reference lines.
    // 获取自车当前所在车道的ID
    auto current_path_id = GetCurrentPathId(*reference_line_info);
    // 如果当前所在车道为空,则返回error状态
    if (current_path_id.empty()) {
      const std::string msg = "The vehicle is not on any reference line";
      AERROR << msg;
      return Status(ErrorCode::PLANNING_ERROR, msg);
    }
    // 如果上一时刻处在变道中,根据上一时刻自车所处道路ID与当前时刻所处道路ID对比,来确认变道状态
    if (prev_status->status() == ChangeLaneStatus::IN_CHANGE_LANE) {
      // ID相同则说明变道还在进行中,
      if (prev_status->path_id() == current_path_id) {
        // 同时调用PrioritizeChangeLane(),将目标车道的reference line放在首位
        PrioritizeChangeLane(true, reference_line_info);
      } else {
        // RemoveChangeLane(reference_line_info);
        // ID不同则说明变道已经完成,
        PrioritizeChangeLane(false, reference_line_info);
        ADEBUG << "removed change lane.";
        // 更新状态
        UpdateStatus(now, ChangeLaneStatus::CHANGE_LANE_FINISHED,
                     current_path_id);
      }
      return Status::OK();
    // 上一时刻变道失败
    } else if (prev_status->status() == ChangeLaneStatus::CHANGE_LANE_FAILED) {
      // TODO(SHU): add an optimization_failure counter to enter
      // change_lane_failed status
      // 判断当前时刻减上一时刻的时间差是否小于换道失败冻结时间
      // not allowed to change lane this amount of time if just failed
      if (now - prev_status->timestamp() <
          lane_change_decider_config.change_lane_fail_freeze_time()) {
        // RemoveChangeLane(reference_line_info);
        PrioritizeChangeLane(false, reference_line_info);
        ADEBUG << "freezed after failed";
      } else {
        UpdateStatus(now, ChangeLaneStatus::IN_CHANGE_LANE, current_path_id);
        ADEBUG << "change lane again after failed";
      }
      return Status::OK();
    // 若上一时刻换道完成
    } else if (prev_status->status() ==
               ChangeLaneStatus::CHANGE_LANE_FINISHED) {
      // 判断当前时刻减上一时刻的时间差是否小于换道完成冻结时间
      if (now - prev_status->timestamp() <
          lane_change_decider_config.change_lane_success_freeze_time()) {
        // RemoveChangeLane(reference_line_info);
        PrioritizeChangeLane(false, reference_line_info);
        ADEBUG << "freezed after completed lane change";
      } else {
        PrioritizeChangeLane(true, reference_line_info);
        UpdateStatus(now, ChangeLaneStatus::IN_CHANGE_LANE, current_path_id);
        ADEBUG << "change lane again after success";
      }
    } else {
      const std::string msg =
          absl::StrCat("Unknown state: ", prev_status->ShortDebugString());
      AERROR << msg;
      return Status(ErrorCode::PLANNING_ERROR, msg);
    }
  }
  return Status::OK();
}

LANE_CHANGE_DECIDER相关子函数

PrioritizeChangeLane

// 提升变道的优先级,找到变道的参考线,并将其置于首位(is_prioritize_change_lane == true)
void LaneChangeDecider::PrioritizeChangeLane(
    const bool is_prioritize_change_lane,
    std::list<ReferenceLineInfo>* reference_line_info) const {
  if (reference_line_info->empty()) {
    AERROR << "Reference line info empty";
    return;
  }

  const auto& lane_change_decider_config = config_.lane_change_decider_config();

  // TODO(SHU): disable the reference line order change for now
  if (!lane_change_decider_config.enable_prioritize_change_lane()) {
    return;
  }
  // 遍历reference_line_info列表中的元素,并检查当前元素是否为变道路径(IsChangeLanePath)
  // 找到第一个需要优先排序的元素后,循环会被中断
  // 0、is_prioritize_change_lane 根据参考线数量置位True 或 False
  // 1、如果is_prioritize_change_lane为True
  // 首先获取第一条参考线的迭代器,然后遍历所有的参考线,
  // 如果当前的参考线为允许变道参考线,则将第一条参考线更换为当前迭代器所指向的参考线,
  // 注意,可变车道为按迭代器的顺序求取,一旦发现可变车道,即推出循环。
  // 
  // 2、如果is_prioritize_change_lane 为False,
  // 找到第一条不可变道的参考线,将第一条参考线更新为当前不可变道的参考线
  auto iter = reference_line_info->begin();
  while (iter != reference_line_info->end()) {
    ADEBUG << "iter->IsChangeLanePath(): " << iter->IsChangeLanePath();
    /* is_prioritize_change_lane == true: prioritize change_lane_reference_line
       is_prioritize_change_lane == false: prioritize
       non_change_lane_reference_line */
    if ((is_prioritize_change_lane && iter->IsChangeLanePath()) ||
        (!is_prioritize_change_lane && !iter->IsChangeLanePath())) {
      ADEBUG << "is_prioritize_change_lane: " << is_prioritize_change_lane;
      ADEBUG << "iter->IsChangeLanePath(): " << iter->IsChangeLanePath();
      break;
    }
    ++iter;
  }
  // 将变道的参考线置于列表首位(is_prioritize_change_lane == true)
  reference_line_info->splice(reference_line_info->begin(),
                              *reference_line_info, iter);
  ADEBUG << "reference_line_info->IsChangeLanePath(): "
         << reference_line_info->begin()->IsChangeLanePath();
}

UpdateStatus

void LaneChangeDecider::UpdateStatus(double timestamp,
                                     ChangeLaneStatus::Status status_code,
                                     const std::string& path_id) {
  auto* lane_change_status = injector_->planning_context()
                                 ->mutable_planning_status()
                                 ->mutable_change_lane();
  lane_change_status->set_timestamp(timestamp);
  lane_change_status->set_path_id(path_id);
  lane_change_status->set_status(status_code);
}

IsClearToChangeLane

// 用于检查当前参考线是否安全,或者当前参考线是否可以偏离后返回
bool LaneChangeDecider::IsClearToChangeLane(
    ReferenceLineInfo* reference_line_info) {
  // 获得当前参考线自车的s坐标的起点与终点,以及自车线速度
  double ego_start_s = reference_line_info->AdcSlBoundary().start_s();
  double ego_end_s = reference_line_info->AdcSlBoundary().end_s();
  double ego_v =
      std::abs(reference_line_info->vehicle_state().linear_velocity());
  // 遍历障碍物,跳过虚拟的和静止的
  for (const auto* obstacle :
       reference_line_info->path_decision()->obstacles().Items()) {
    if (obstacle->IsVirtual() || obstacle->IsStatic()) {
      ADEBUG << "skip one virtual or static obstacle";
      continue;
    }
    // 初始化SL
    double start_s = std::numeric_limits<double>::max();
    double end_s = -std::numeric_limits<double>::max();
    double start_l = std::numeric_limits<double>::max();
    double end_l = -std::numeric_limits<double>::max();
    // 获取动态障碍物的边界点并转化为SL坐标
    for (const auto& p : obstacle->PerceptionPolygon().points()) {
      SLPoint sl_point;
      reference_line_info->reference_line().XYToSL(p, &sl_point);
      start_s = std::fmin(start_s, sl_point.s());
      end_s = std::fmax(end_s, sl_point.s());

      start_l = std::fmin(start_l, sl_point.l());
      end_l = std::fmax(end_l, sl_point.l());
    }
    // 以障碍物在S方向上的起始点与终点之和的二分之一作为障碍物中心点si,获取si点的道路宽度
    // 若障碍物在车道线之外,则不考虑
    if (reference_line_info->IsChangeLanePath()) {
      double left_width(0), right_width(0);
      reference_line_info->mutable_reference_line()->GetLaneWidth(
          (start_s + end_s) * 0.5, &left_width, &right_width);
      if (end_l < -right_width || start_l > left_width) {
        continue;
      }
    }

    // Raw estimation on whether same direction with ADC or not based on
    // prediction trajectory
    // 根据预测轨迹粗略判断障碍物的方向是否和自车相同
    bool same_direction = true;
    if (obstacle->HasTrajectory()) {
      double obstacle_moving_direction =
          obstacle->Trajectory().trajectory_point(0).path_point().theta();
      const auto& vehicle_state = reference_line_info->vehicle_state();
      // 获取车辆航向角
      double vehicle_moving_direction = vehicle_state.heading();
      if (vehicle_state.gear() == canbus::Chassis::GEAR_REVERSE) {
        vehicle_moving_direction =
            common::math::NormalizeAngle(vehicle_moving_direction + M_PI);
      }
      double heading_difference = std::abs(common::math::NormalizeAngle(
          obstacle_moving_direction - vehicle_moving_direction));
      same_direction = heading_difference < (M_PI / 2.0);
    }

    // TODO(All) move to confs
    static constexpr double kSafeTimeOnSameDirection = 3.0;
    static constexpr double kSafeTimeOnOppositeDirection = 5.0;
    static constexpr double kForwardMinSafeDistanceOnSameDirection = 10.0;
    static constexpr double kBackwardMinSafeDistanceOnSameDirection = 10.0;
    static constexpr double kForwardMinSafeDistanceOnOppositeDirection = 50.0;
    static constexpr double kBackwardMinSafeDistanceOnOppositeDirection = 1.0;
    static constexpr double kDistanceBuffer = 0.5;

    double kForwardSafeDistance = 0.0;
    double kBackwardSafeDistance = 0.0;
    // 根据方向、自车与运动障碍物之间速度关系设置安全距离
    if (same_direction) {
      kForwardSafeDistance =
          std::fmax(kForwardMinSafeDistanceOnSameDirection,
                    (ego_v - obstacle->speed()) * kSafeTimeOnSameDirection);
      kBackwardSafeDistance =
          std::fmax(kBackwardMinSafeDistanceOnSameDirection,
                    (obstacle->speed() - ego_v) * kSafeTimeOnSameDirection);
    } else {
      kForwardSafeDistance =
          std::fmax(kForwardMinSafeDistanceOnOppositeDirection,
                    (ego_v + obstacle->speed()) * kSafeTimeOnOppositeDirection);
      kBackwardSafeDistance = kBackwardMinSafeDistanceOnOppositeDirection;
    }
    // 通过滞后滤波器判断障碍物是否满足安全距离
    if (HysteresisFilter(ego_start_s - end_s, kBackwardSafeDistance,
                         kDistanceBuffer, obstacle->IsLaneChangeBlocking()) &&
        HysteresisFilter(start_s - ego_end_s, kForwardSafeDistance,
                         kDistanceBuffer, obstacle->IsLaneChangeBlocking())) {
      reference_line_info->path_decision()
          ->Find(obstacle->Id())
          ->SetLaneChangeBlocking(true);
      ADEBUG << "Lane Change is blocked by obstacle" << obstacle->Id();
      return false;
    } else {
      reference_line_info->path_decision()
          ->Find(obstacle->Id())
          ->SetLaneChangeBlocking(false);
    }
  }
  return true;
}

HysteresisFilter

// 滞后滤波器
// 在安全距离附近的情况下,通过引入距离缓冲区来调整安全距离的大小,从而避免频繁进行车道变换。
bool LaneChangeDecider::HysteresisFilter(const double obstacle_distance,
                                         const double safe_distance,
                                         const double distance_buffer,
                                         const bool is_obstacle_blocking) {
  if (is_obstacle_blocking) {
    // obstacle_distance是否小于safe_distance + distance_buffer,如果是则返回true,否则返回false。
    return obstacle_distance < safe_distance + distance_buffer;
  } else {
    // obstacle_distance是否小于safe_distance - distance_buffer,如果是则返回true,否则返回false。
    return obstacle_distance < safe_distance - distance_buffer;
  }
}

参考

[1] Apollo规划模块详解(五):算法实现-lane change decider
[2] Apollo Planning决策规划代码详细解析 (6):LaneChangeDecider
[3] 百度Apollo5.0规划模块代码学习(四)换道决策分析
[4] Apollo planning lane_change_decider解析

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线性代数的学习和整理8: 方阵和行列式相关(草稿-----未完成)

1.4.1 方阵 矩阵里&#xff0c;行数列数的矩阵叫做方阵方阵有很多很好的特殊属性 1.4.2 行列式 行列式是方阵的一种特殊运算如果矩阵行数列数相等&#xff0c;那么这个矩阵是方阵。行列数的计算方式和矩阵的不同只有方阵才有行列式行列式其实是&#xff0c;矩阵变化的一个面…

SLAM-VIO视觉惯性里程计

SLAM 文章目录 SLAM前言IMU与视觉比较单目视觉缺陷&#xff1a;融合IMU优势&#xff1a;相机-IMU标定松耦合紧耦合基于滤波的融合方案&#xff1a;基于优化的融合方案&#xff1a; 前言 VIO&#xff08;visual-inertial odometry&#xff09;即视觉惯性里程计&#xff0c;有时…

第十三章MyBatis高级映射

多对一映射 创建数据表 student是主表class_id关联class表的id class表 student表 创建pojo Class类 Data AllArgsConstructor NoArgsConstructor public class Class {private Long id;private String name;private List<Student> students; }Student类 Data A…

【算法系列篇】滑动窗口

文章目录 前言什么是滑动窗口1.长度最小的子数组1.1 题目要求1.2 做题思路 1.3 Java代码实现2.无重复字符的最长子串2.1 题目要求2.2 做题思路2.3 Java代码实现 3.最大连续1的个数 III3.1 题目要求3.2 做题思路3.3 Java代码实现 4.将x减到0的最小操作数4.1 题目要求4.2 做题思路…

ubuntu上使用osg3.2+osgearth2.9

一、介绍 在ubuntu上使用osgearth加载三维数字地球&#xff0c;首先要有osg和osgearth的库&#xff0c;这些可以直接使用apt-get下载安装&#xff0c;但是版本有些老&#xff0c;如果需要新版本的就需要自己编译。 #查看现有版本 sudo apt-cache madison openscenegraph #安装…

windows上ffmpeg如何录制双屏幕中的一个屏幕上的视频

首先&#xff0c;如何在window上安装ffmpeg自己查找scoop安装ffmpeg. 如题&#xff1a; 如果你有两个屏幕&#xff0c;如何让ffmpeg来录制其中的一个屏幕的视频呢。 很简单&#xff0c;首先你要查看另外一个屏幕的分辨率&#xff1a; 第一步&#xff1a;进入系统中 第二步&am…

VsCode报错:No such file or directory:‘文件名‘

1.问题&#xff1a; 昨天用VsCode直接打开py文件&#xff0c;运行后显示No such file or directory:‘directory’。但directory文件和该py文件在同一目录 2.原因&#xff1a; 直接打开py文件&#xff0c;Vscode看不到同一目录下的其他文件 3.解决方法&#xff1a; 打开文件夹…

漏洞指北-VulFocus靶场专栏-中级03

漏洞指北-VulFocus靶场专栏-初级03 中级009 &#x1f338;gxlcms-cve_2018_14685&#x1f338;step1&#xff1a;安装系统 密码rootstep2 进入后台页面 账号密码&#xff1a;admin amdin888step3 查看详细 有phpinfo() 中级010 &#x1f338;dedecms-cnvd_2018_01221&#x1f3…

EventBus3.0源码详解

详解之前要说明一下&#xff0c;LivedataBus 比EventBus更适合目前jetpack化的app&#xff0c;因为考虑到组件的生命周期处理&#xff0c;性能方面&#xff0c;EventBus还是要反射invoke的调用的&#xff0c;网上找不到有实测过的博文&#xff0c;我想来个性能对比实测&#xf…

【旅游度假】Axure酒店在线预订APP原型图 旅游度假子模块原型模板

作品概况 页面数量&#xff1a;共 10 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;旅游度假&#xff0c;生活服务 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为「酒店在线预订」的移动端…

【淘宝】商品详情页+商品列表数据采集

作为国内最大的电商平台之一&#xff0c;淘宝数据采集具有多个维度。 有人需要采集商品信息&#xff0c;包括品类、品牌、产品名、价格、销量等字段&#xff0c;以了解商品销售状况、热门商品属性&#xff0c;进行市场扩大和重要决策&#xff1b; 有人需要采集产品评论&…

EndNote(二)【文献导入、全文检索】

在开始之前我们可以先分个组以管理自己的文件&#xff0c;如果不分组的话&#xff0c;它所有的文件都会放在unfiled这个目录下&#xff1a; 如何分组也很简单&#xff1a; 然后给个名字即可&#xff1a; 文献导入&#xff08;五种方法&#xff09; 第一种&#xff1a;pdf直接导…

STM32F4X USART串口使用

STM32F4X USART串口使用 串口概念起始位波特率数据位停止位校验位串口间接线 STM32F4串口使用步骤GPIO引脚复用函数串口初始化函数串口例程 串口概念 串口是MCU与外部通信的重要通信接口&#xff0c;也是MCU在开发过程中的调试利器。串口通信有几个重要的参数&#xff0c;分别…

基于蚁狮算法优化的BP神经网络(预测应用) - 附代码

基于蚁狮算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于蚁狮算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.蚁狮优化BP神经网络2.1 BP神经网络参数设置2.2 蚁狮算法应用 4.测试结果&#xff1a;5.Matlab代码 摘要…

Chrome如何安装插件(文件夹)

1.下载的插件 说明&#xff1a;插件文件夹 2.打开扩展程序位置 3.点击已加载的扩展程序 说明&#xff1a;找到插件的位置 4.报错 说明&#xff1a;那还要进入文件里面。 5.插件的位置 说明&#xff1a;如果已经安装了插件&#xff0c;那么需要查看插件的位置。chrome输入 …

todesk远程连接出现闪退如何解决

官方提供方案&#xff1a;ToDesk远程桌面软件-免费安全流畅的远程连接电脑手机https://www.todesk.com/faq/88.html 图1 打开上述网址&#xff0c;输入“闪退”进行搜索 图2 超级实用解决方法 &#xff08;本机软件设置一下即可&#xff09; 图3 其实图2就已经解决问题了&…

【汇编语言】CS、IP与代码段

文章目录 两个关键的寄存器在CS和IP指示下代码的运行问答 两个关键的寄存器 CS: 代码段寄存器&#xff1b;IP: 指令指针寄存器&#xff1b;CS:IP : CPU将内存中CS&#xff1a;IP只想的内容当作指令执行&#xff1b; 在CS和IP指示下代码的运行 具体步骤描述&#xff1a; 1、第…

【rust/egui】(四)看看template的app.rs:update以及组件TopBottomPanelButton

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 update update实际上还是eframe::App的…

利用快慢指针,求链表的中间结点,判断链表是否是环形链表

前言 &#xff08;1&#xff09;在学习数据结构链表部分的时候&#xff0c;老师给出了几个题目。其中两个题目采用了快慢指针的技术&#xff0c;感觉有意思&#xff0c;于是写一篇博客记录一下。 快慢指针 &#xff08;1&#xff09;我们先来介绍一下快慢指针技术。这个说起来其…

Java性能分析中常用命令和工具

当涉及到 Java 性能分析时&#xff0c;有一系列强大的命令和工具可以帮助开发人员分析应用程序的性能瓶颈、内存使用情况和线程问题。以下是一些常用的 Java 性能分析命令和工具&#xff0c;以及它们的详细说明和示例。 以下是一些常用的性能分析命令和工具汇总&#xff1a; …