Apollo Planning——换道:LANE_CHANGE_DECIDER
LaneChangeDecider 是lanefollow 场景下,所调用的第一个task,它的作用主要有两点:判断当前是否进行变道,以及变道的状态,并将结果存在变量lane_change_status中;变道过程中将目标车道的reference line放置到首位,变道结束后将当前新车道的reference line放置到首位
LaneChangeDecider的具体逻辑如下:
1、PublicRoadPlanner 的 LaneFollowStage 配置了以下几个task 来实现具体的规划逻辑,LaneChangeDecider是第一个task:
scenario_type: LANE_FOLLOW
stage_type: LANE_FOLLOW_DEFAULT_STAGE
stage_config: {stage_type: LANE_FOLLOW_DEFAULT_STAGEenabled: truetask_type: LANE_CHANGE_DECIDERtask_type: PATH_REUSE_DECIDERtask_type: PATH_LANE_BORROW_DECIDERtask_type: PATH_BOUNDS_DECIDERtask_type: PIECEWISE_JERK_PATH_OPTIMIZERtask_type: PATH_ASSESSMENT_DECIDERtask_type: PATH_DECIDERtask_type: RULE_BASED_STOP_DECIDERtask_type: ST_BOUNDS_DECIDERtask_type: SPEED_BOUNDS_PRIORI_DECIDERtask_type: SPEED_HEURISTIC_OPTIMIZERtask_type: SPEED_DECIDERtask_type: SPEED_BOUNDS_FINAL_DECIDER# task_type: PIECEWISE_JERK_SPEED_OPTIMIZERtask_type: PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZERtask_type: RSS_DECIDER
}
2、在stage阶段会依次调用每个 task 的 Execute() 函数,LaneChangeDecider继承自 Decider 类,Decider继承自基类 task 类,并且override了Execute() 方法;
modules/planning/tasks/task.h
class Task {public:explicit Task(const TaskConfig& config);Task(const TaskConfig& config,const std::shared_ptr<DependencyInjector>& injector);virtual ~Task() = default;const std::string& Name() const;const TaskConfig& Config() const { return config_; }virtual common::Status Execute(Frame* frame,ReferenceLineInfo* reference_line_info);virtual common::Status Execute(Frame* frame);protected:Frame* frame_ = nullptr;ReferenceLineInfo* reference_line_info_ = nullptr;TaskConfig config_;std::string name_;std::shared_ptr<DependencyInjector> injector_;
};
modules/planning/tasks/deciders/decider.h
class Decider : public Task {public:explicit Decider(const TaskConfig& config);Decider(const TaskConfig& config,const std::shared_ptr<DependencyInjector>& injector);virtual ~Decider() = default;apollo::common::Status Execute(Frame* frame, ReferenceLineInfo* reference_line_info) override;apollo::common::Status Execute(Frame* frame) override;protected:virtual apollo::common::Status Process(Frame* frame, ReferenceLineInfo* reference_line_info) {return apollo::common::Status::OK();}virtual apollo::common::Status Process(Frame* frame) {return apollo::common::Status::OK();}
};
重写Execute() 的代码在 modules/planning/tasks/deciders/decider.cc
apollo::common::Status Decider::Execute(Frame* frame, ReferenceLineInfo* reference_line_info) {Task::Execute(frame, reference_line_info);// 调用 子类 modules/planning/tasks/deciders/lane_change_decider/lane_change_decider.cc 类LaneChangeDecider中的 Process 方法return Process(frame, reference_line_info);
}
由以上分析可知,LaneChangeDecider 的主要决策逻辑在Process() 方法中,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);/*** modules/planning/conf/planning_config.pb.txt* default_task_config: {task_type: LANE_CHANGE_DECIDERlane_change_decider_config {enable_lane_change_urgency_check: falseenable_prioritize_change_lane: falseenable_remove_change_lane: falsereckless_change_lane: falsechange_lane_success_freeze_time: 1.5change_lane_fail_freeze_time: 1.0}}* **/const auto& lane_change_decider_config = config_.lane_change_decider_config();// 通过frame拿到车辆此时所在的区域参考线个数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);}//判断是否是强制换道功能,如果是,调用优先换道功能if (lane_change_decider_config.reckless_change_lane()) {// 将换道参考线放到参考线的首位PrioritizeChangeLane(true, reference_line_info);return Status::OK();}/*** modules/planning/proto/planning_status.proto* * message ChangeLaneStatus {* enum Status {* IN_CHANGE_LANE = 1; // during change lane state* CHANGE_LANE_FAILED = 2; // change lane failed* CHANGE_LANE_FINISHED = 3; // change lane finished* }* optional Status status = 1;* // the id of the route segment that the vehicle is driving on* optional string path_id = 2;* // the time stamp when the state started.* optional double timestamp = 3;* // the starting position only after which lane-change can happen.* optional bool exist_lane_change_start_position = 4 [default = false];* optional apollo.common.Point3D lane_change_start_position = 5;* // the last time stamp when the lane-change planning succeed.* optional double last_succeed_timestamp = 6;* // if the current path and speed planning on the lane-change* // reference-line succeed.* optional bool is_current_opt_succeed = 7 [default = false];* // denotes if the surrounding area is clear for ego vehicle to* // change lane at this moment.* optional bool is_clear_to_change_lane = 8 [default = false];* }** **/// 获取换道信息,记录当前时间戳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);// /判断传进来的referenceLineinfo是否是变道参考线,如果是则通过if (current_reference_line_info->IsChangeLanePath()) {// IsClearToChangeLane()检查该参考线是否满足变道条件// IsClearToChangeLane 只考虑传入的参考线上的动态障碍物,不考虑虚的和静态的障碍物prev_status->set_is_clear_to_change_lane(IsClearToChangeLane(current_reference_line_info));}// 头次进入task,车道换道状态应该为空,默认设置为换道结束状态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();}// 判断参考线数量bool has_change_lane = reference_line_info->size() > 1;ADEBUG << "has_change_lane: " << has_change_lane;// 如果只有一条参考线(比如往某个方向只有一条车道),那就通过updatestatus将车辆状态设置为CHANGE_LANE_FINISHED,// 这也符合我们认知,单向只有一条车道,还换什么道,所以车辆就该一直处于换到结束的状态if (!has_change_lane) {// 没有换道参考线(参考线数量小于1条):如果上个周期状态是已经换道完成或者换道失败,则返回进入下个task或者下个周期const auto& path_id = reference_line_info->front().Lanes().Id();if (prev_status->status() == ChangeLaneStatus::CHANGE_LANE_FINISHED) {} // 如果上个周期状态是正在换道,更新换道状态else if (prev_status->status() == ChangeLaneStatus::IN_CHANGE_LANE) {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);}return Status::OK();// 下面的else处理不止一条参考线的情况,正常道路都不止一条参考线,// 主要逻辑为状态切换,实际操作还是通过 updatestatus 来实时更新车辆的换道状态。} else { // has change lane in reference lines.// 得到当前参考线的idauto current_path_id = GetCurrentPathId(*reference_line_info);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);}// 上一次换道中if (prev_status->status() == ChangeLaneStatus::IN_CHANGE_LANE) {// 换道开始的参考线是否和当前参考线未同一条线if (prev_status->path_id() == current_path_id) {// 如果是,表示没有换道完成PrioritizeChangeLane(true, reference_line_info);} else {// RemoveChangeLane(reference_line_info);PrioritizeChangeLane(false, reference_line_info);ADEBUG << "removed change lane.";// 更新换道状态为CHANGE_LANE_FINISHEDUpdateStatus(now, ChangeLaneStatus::CHANGE_LANE_FINISHED, current_path_id);}return Status::OK();} // 上一次换道失败else if (prev_status->status() == ChangeLaneStatus::CHANGE_LANE_FAILED) {if (now - prev_status->timestamp() < lane_change_decider_config.change_lane_fail_freeze_time()) {// 当前时间减去上次换道的时间间隔小于1s // RemoveChangeLane(reference_line_info);PrioritizeChangeLane(false, reference_line_info);ADEBUG << "freezed after failed";} else {// 当前时间减去上次换道的时间间隔大于1s 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) {// 当前时间减去上次换道的时间间隔小于1.5s 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 {// 当前时间减去上次换道的时间间隔大于等于1.5s PrioritizeChangeLane(true, reference_line_info);// 更改换道状态为 IN_CHANGE_LANEUpdateStatus(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();
}
3、其中lane_change_decider_config 配置文件很关键,决定了整个函数的流程走向,它定义在以下两个文件中:
modules/planning/conf/planning_config.pb.txt
lane_change_decider_config {enable_lane_change_urgency_check: falseenable_prioritize_change_lane: falseenable_remove_change_lane: falsereckless_change_lane: falsechange_lane_success_freeze_time: 1.5change_lane_fail_freeze_time: 1.0}
modules/planning/conf/scenario/lane_follow_config.pb.txt
lane_change_decider_config {enable_lane_change_urgency_check: true}
4、判断是否为可变车道时调用了 IsChangeLanePath(),它的逻辑也很简单, 如果自车在当前ReferenceLine 的车道segment上,则为FALSE;如果自车不在当前ReferenceLine 的车道segment上,则为TRUE。
bool ReferenceLineInfo::IsChangeLanePath() const {// 如果自车在当前ReferenceLine 的车道segment上,则为FALSE// 如果自车不在当前ReferenceLine 的车道segment上,则为TRUE。return !Lanes().IsOnSegment();
}
5、更新变道状态时用到了 UpdateStatus() 函数,它的定义如下:
void LaneChangeDecider::UpdateStatus(ChangeLaneStatus::Status status_code,const std::string& path_id) {UpdateStatus(Clock::NowInSeconds(), status_code, path_id);
}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);
}
6、在调整参考线的顺序时,使用了PrioritizeChangeLane() 函数,它的调整参考线顺序的功能,需要配置enable_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();// 如果没有配置变道优先,则退出该函数if (!lane_change_decider_config.enable_prioritize_change_lane()) {return;}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_lineis_prioritize_change_lane == false: prioritizenon_change_lane_reference_line */// 0、is_prioritize_change_lane 根据参考线数量置位True 或 False// 1、如果 is_prioritize_change_lane 为True// 首先获取第一条参考线的迭代器,然后遍历所有的参考线,如果当前的参考线为允许变道参考线,则将第一条参考线更换为当前迭代器所指向的参考线.// 注意,可变车道为按迭代器的顺序求取,一旦发现可变车道,即推出循环。// 2、如果 is_prioritize_change_lane 为False,// 找到第一条不可变道的参考线,将第一条参考线更新为当前不可变道的参考线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;}reference_line_info->splice(reference_line_info->begin(),*reference_line_info, iter);ADEBUG << "reference_line_info->IsChangeLanePath(): " << reference_line_info->begin()->IsChangeLanePath();
}
7、 IsClearToChangeLane() 判断当前的参考线是否变道安全,并将结果写入lane_change_status 这个变量中
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()) {// a) 只对动态障碍物进行处理,忽略虚拟障碍物和静态障碍物; if (obstacle->IsVirtual() || obstacle->IsStatic()) {ADEBUG << "skip one virtual or static obstacle";continue;}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();// 遍历当前目标的预测轨迹点集,或得预测轨迹的边界点for (const auto& p : obstacle->PerceptionPolygon().points()) {// 对于动态障碍物,先进行投影,获取S和L值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());}// c) 忽略换道目标参考线上2.5米之外的障碍物;if (reference_line_info->IsChangeLanePath()) {static constexpr double kLateralShift = 2.5;if (end_l < -kLateralShift || start_l > kLateralShift) {continue;}}// Raw estimation on whether same direction with ADC or not based on// prediction trajectory// 根据航向角判断是否为相同方向bool same_direction = true;// d) 对于需要考虑的障碍物进行方向粗略计算,评估是否和自车同向;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);}// 设置安全距离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;// e) 根据方向,计算纵向上的安全距离,考虑了速度差,比较直观。分为前方和后方两个维度。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;}/*** f) 根据前面计算的阈值,判断障碍物是否安全,采用的是滞回区间的方法,* 如果障碍物小于安全距离,laneChangeBlocking 为true。* 如果障碍物大于安全距离,laneChangeBlocking 为false。* 通过滞回区间进行滤波。一旦发现有block的障碍物,函数就返回,* 就认为该Reference 非clear(安全)。* static bool HysteresisFilter(const double obstacle_distance,const double safe_distance,const double distance_buffer,const bool is_obstacle_blocking);* * **/// 判断障碍物是否满足安全距离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;
}bool LaneChangeDecider::HysteresisFilter(const double obstacle_distance,const double safe_distance,const double distance_buffer,const bool is_obstacle_blocking) {if (is_obstacle_blocking) {return obstacle_distance < safe_distance + distance_buffer;} else {return obstacle_distance < safe_distance - distance_buffer;}
}
相关文章:
Apollo Planning——换道:LANE_CHANGE_DECIDER
LaneChangeDecider 是lanefollow 场景下,所调用的第一个task,它的作用主要有两点:判断当前是否进行变道,以及变道的状态,并将结果存在变量lane_change_status中;变道过程中将目标车道的reference line放置到…...
Python 爬虫之简单的爬虫(三)
爬取动态网页(上) 文章目录 爬取动态网页(上)前言一、大致内容二、基本思路三、代码编写1.引入库2.加载网页数据3.获取指定数据 总结 前言 之前的两篇写的是爬取静态网页的内容,比较简单。接下来呢给大家讲一下如何去…...
为突发事件提供高现势性数据支撑!大势智慧助力中山市2023应急测绘保障演练举行
12月14日,2023年度中山市应急测绘保障演练在中山树木园举行,市自然资源局总工程师邓宇文出席本次演练活动。来自全市自然资源、应急管理部门和部分测绘单位的近70人现场观摩了演练。本次演练由中山市自然资源局主办、中山市自然资源信息中心承办…...
图片速览 OOD用于零样本 OOD 检测的 CLIPN:教 CLIP 说不
PAPERCODEhttps://arxiv.org/pdf/2308.12213v2.pdfhttps://github.com/xmed-lab/clipn 文章创新 以往由CLIP驱动的零样本OOD检测方法,只需要ID的类名,受到的关注较少。 本文提出了一种新的方法,即CLIP说“不”(CLIPN)…...
a16z:加密行业2024趋势“无缝用户体验”
近日,知名加密投资机构a16z发布了“Big ideas 2024”,列出了加密行业在 2024 年几个具备趋势的“大想法”,其中 Seamless UX(无缝用户体验)赫然在列。 从最为直观的理解上,Seamless UX 是在强调用户在使用产…...
C# WPF上位机开发(属性页面的设计)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 在软件开发中,属性或者参数设置是很重要的一个部分。这个时候如果不想通过动态添加控件的方法来处理的话,那么可以通过tab控…...
macOS 安装 oh-my-zsh 后 node 报错 command not found : node
最近为了让终端中显示 git 分支的名称,安装了 oh-my-zsh ,安装之后呢,我原先安装的 Volta、 node 都没法用了,报错如下: 这时候粗略判断应该是系统变量出了问题,oh-my-zsh 的变量文件是 ~/.zshrc࿰…...
AI 绘画 | Stable Diffusion 视频数字人
前言 本篇文章教会你如何利用Stable Diffusion WEB UI,使用一个人物图片转换成为一个口播视频。本篇内容的教程以WINDOWS系统为例,教你如何安装使用。 先看视频效果 彭于晏图片生成口播视频 安装 首先需要在windows电脑上安装ffmpeg,按照本教程《在 Windows PC 上轻松下载并…...
《代码随想录》--二叉树(一)
《代码随想录》--二叉树 第一部分 1、二叉树的递归遍历2、二叉树的迭代遍历3、统一风格的迭代遍历代码4、二叉树的层序遍历226.翻转二叉树 1、二叉树的递归遍历 前序遍历 中序遍历 后序遍历 代码 前序遍历 class Solution {public List<Integer> preorderTraversal(T…...
shell编程-数组与运算符详解(超详细)
文章目录 前言一、 Shell数组1. 声明和初始化数组2. 访问数组元素3. 数组长度4. 遍历数组5. 修改数组元素6. 删除数组元素7. 示例 二、Shell运算符1. 算术运算符1.1 加法运算符 ()1.2 减法运算符 (-)1.3 乘法运算符 (*)1.4 除法运算符 (/)1.5 取余运算符 (%) 2. 关系运算符2.1 …...
Vim入门
Vim使用入门 1.Vim编辑器的三种常用模式 一般模式:刚打开文件是它,从编辑模式按“ESC”退回的模式也是它。可以执行各种编辑操作,如移动光标、复制、粘贴、删除、查找替换等 ; 编辑模式:在一般模式下按下 i、I、a、A、o、O 等键…...
动态加载库
no_mangle 不要改标识符 首先是认识这个标注:mangle,英文的含义“撕裂、碾压”。我第一次把这个单次误以为是manage,说实话两个单词还挺像的。 RUS中函数或静态变量使用#[no_mangle]这个标注属性后,编译器就不会修改它们的名字了…...
React中渲染html结构---dangerouslySetInnerHTML
dangerouslySetInnerHTML胡子{}语法绑定的内容全部作为普通文本渲染,渲染html结构基于---dangerouslySetInnerHTMLdangerouslySetInnerHTML是React标签的一个属性,类似于vue的v-html有2个{{}},第一个{}代表jsx语法开始,第二个是代表dangerous…...
计网02-计算机网络参考模型
一、OSI七层参考模型 1、分层的思想 分层模型用于网络协议的设计方法,本质是将网络节点间复杂的通信问题分成若干简单的问题逐一解决,通过网络的层次去找问题,将复杂问题简单化。 2、OSI参考模型 由于早期计算机厂商使用的是私有的网络模…...
模块测试:确保软件质量的关键步骤
引言: 在软件开发过程中,模块测试是确保软件质量的关键环节。通过模块化的设计和测试方法,可以提高开发效率、降低错误率,并最终提供稳定可靠的软件产品。本文将介绍模块测试的概念、重要性以及实施步骤,帮助读者了解如…...
Postman接口测试之Postman常用的快捷键
作为一名IT程序猿,不懂一些工具的快捷方式,应该会被鄙视的吧。收集了一些Postman的快捷方式,大家一起动手操作~ 简单操作 xc 请求 操作MAC系统windows系统请求网址 ⌘L Ctrl L 保存请求 ⌘S Ctrl S 保存请求为 ⇧⌘S Ctrl Shift S发送…...
keil自动分配SDRAM空间设置使用
1.修改.sct文件 添加 RW_RAM1 0xC0400000 UNINIT 0x00400000 { ; RW data .ANY (SD_RAM1) 使用 #define LOCATION_ATTRIBUTE(name) __attribute__ ((section(name))) __attribute__ ((aligned(4)))uint8_t sdram_buf[0x100000] __attribute__ ((section("SD_RAM1")…...
TikTok获客怎么做?可以定制一个获客工具!
随着社交媒体的兴起,越来越多的企业开始将目光投向了短视频平台,TikTok作为其中的佼佼者,凭借其独特的算法和内容推荐机制,吸引了大量用户的关注。 那么,如何在TikTok上获取更多的客户呢?本文将为您揭秘TikTok获客的…...
数据结构(Chapter Two -02)—顺序表基本操作实现
在前一部分我们了解线性表和顺序表概念,如果有不清楚可以参考下面的博客: 数据结构(Chapter Two -01)—线性表及顺序表-CSDN博客 首先列出线性表的数据结构: #define MaxSize 50 //定义顺序表最大长度 typedef struct{ElemType data…...
SQL语句整理二--Mysql
文章目录 知识点梳理:1. mysql 中 in 和 exists 区别2. varchar 与 char 的区别 查看表结构:获取当前时间:查看建表语句:修改用户密码:查看所有用户:grant命令:判断当前数据库有多少连接数&…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
