自动驾驶规划 - Apollo Lattice Planner算法【1】
文章目录
- Lattice Planner简介
- Lattice Planner 算法思路
- 1. 离散化参考线的点
- 2. 在参考线上计算匹配点
- 3. 根据匹配点,计算Frenet坐标系的S-L值
- 4. parse the decision and get the planning target
- 5. 生成横纵向采样路径
- 6. 轨迹cost值计算,进行碰撞检测
- 7. 优先选择cost最小的轨迹且不碰撞的轨迹
- 总结
Lattice Planner简介
LatticePlanner算法属于一种局部轨迹规划器,输出轨迹将直接输入到控制器,由控制器完成对局部轨迹的跟踪控制。因此,Lattice Planner输出的轨迹是一条光滑无碰撞满足车辆运动学约束和速度约束的平稳安全的局部轨迹。Lattice Planner的输入端主要由三部分组成,感知及障碍物信息、参考线信息及定位信息。局部规划模块的输出是带有速度信息的一系列轨迹点组成的轨迹,其保证了车辆控制器在车辆跟踪控制过程中的平稳性和安全性。挺复杂的越挖越多,看来得慢慢总结了(主要为了学思路,总结到自己的项目中)。
局部规划模块的输出是带有速度信息(速度信息哪里来的?)的一系列轨迹点组成的轨迹,其保证了车辆控制器在车辆跟踪控制过程中的平稳性和安全性。下面讲一下Apollo中的Lattice Planner的算法过程和代码解析。《刚学,写得可能不好,大佬们评论区指正😭😭》
Lattice Planner 算法思路
- 离散化参考线的点
- 在参考线上计算匹配点
- 根据匹配点,计算Frenet坐标系的S-L值
- 计算障碍物的s-t图
- 生成横纵向采样路径
- 计算cost值,进行碰撞检测
- 优先选择cost最小的轨迹且不碰撞的轨迹
在整体Apollo代码的结构,Lattice Planner的主要思路和实现是在Plan里面的PlanOnReferenceLine中,如下。
Status LatticePlanner::Plan(const TrajectoryPoint& planning_start_point,Frame* frame, ADCTrajectory* ptr_computed_trajectory) {... auto status =PlanOnReferenceLine(planning_start_point, frame, &reference_line_info);//主要是逻辑在这个函数里面...
}
PlanOnReferenceLine 主要是7步,按照上面的算法逻辑解析。
1. 离散化参考线的点
作为Lattice Planner的第一步,这部分的主要做的是将reference_line上的点,一个个搬到path_points中,其中增加了计算起点到当前点的累积距离s,s的主要作用是为S-L坐标系使用。
// 1. 离散化参考线的点(obtain a reference line and transform it to the PathPoint format)auto ptr_reference_line =std::make_shared<std::vector<PathPoint>>(ToDiscretizedReferenceLine(reference_line_info->reference_line().reference_points()));
详细函数逻辑:大部分的数据还是没变的,但是新增了s,主要用于S-L坐标系。
std::vector<PathPoint> ToDiscretizedReferenceLine(//离散化referenLineconst std::vector<ReferencePoint>& ref_points) {double s = 0.0;std::vector<PathPoint> path_points;for (const auto& ref_point : ref_points) {PathPoint path_point;path_point.set_x(ref_point.x());//笛卡尔坐标系下的点横坐标path_point.set_y(ref_point.y());path_point.set_theta(ref_point.heading());//航向角path_point.set_kappa(ref_point.kappa());//曲率path_point.set_dkappa(ref_point.dkappa());//曲率变化if (!path_points.empty()) {double dx = path_point.x() - path_points.back().x();double dy = path_point.y() - path_points.back().y();s += std::sqrt(dx * dx + dy * dy);//两点之间的距离}path_point.set_s(s);//Frenet坐标系会用到,ref_points的起点到当前path_point的距离path_points.push_back(std::move(path_point));//std::move的作用?????}return path_points;
}
2. 在参考线上计算匹配点
第二步是基于车当前所在的点(x,y),找到参考线上的最近匹配点,为什么要这样做? 因为参考线是车要循迹的线,车都是在不断向参考线修正的,直到此时和参考线完全重合就是最优的状态。
- 这一步的思路是,遍历参考线reference_line,找到距离车🚗当前点最近的点,没错就是穷举遍历(相信c++的计算速度😄)。
- 找到最近点后,不是直接把这个点当成匹配点,而是基于参考线上的该点往前后各找一个点,把这两个点连接成向量,方向向前。
- 然后把车当前的点(下图P)投影到这个向量上,这个投影点才是第二步要找的匹配点。
PathPoint matched_point = PathMatcher::MatchToPath(*ptr_reference_line, planning_init_point.path_point().x(),planning_init_point.path_point().y());//planning_init_point.path_point()当前定位点
- 根据距离找点
PathPoint PathMatcher::MatchToPath(const std::vector<PathPoint>& reference_line,const double x, const double y) {//x、y是当前定位点CHECK_GT(reference_line.size(), 0U);auto func_distance_square = [](const PathPoint& point, const double x,const double y) {double dx = point.x() - x;double dy = point.y() - y;return dx * dx + dy * dy;//两点距离平方};double distance_min = func_distance_square(reference_line.front(), x, y);std::size_t index_min = 0;for (std::size_t i = 1; i < reference_line.size(); ++i) {//遍历reference_line,找到距离最小的点的double distance_temp = func_distance_square(reference_line[i], x, y);//计算当前点到reference_line上i点的距离if (distance_temp < distance_min) {distance_min = distance_temp;//距离index_min = i;//点的索引}}//向后找一个点std::size_t index_start = (index_min == 0) ? index_min : index_min - 1;//向前找一个点std::size_t index_end = (index_min + 1 == reference_line.size()) ? index_min : index_min + 1;//目的主要是将当前的定位点投影到距离最短点的前后点的连线上,做预处理if (index_start == index_end) {return reference_line[index_start];}//投影操作return FindProjectionPoint(reference_line[index_start],reference_line[index_end], x, y);
}
- 找到点之后算当前定位点在参考线上的投影
PathPoint PathMatcher::FindProjectionPoint(const PathPoint& p0,const PathPoint& p1, const double x,const double y) {//P0A向量double v0x = x - p0.x();double v0y = y - p0.y();//P0P1向量double v1x = p1.x() - p0.x();double v1y = p1.y() - p0.y();double v1_norm = std::sqrt(v1x * v1x + v1y * v1y);double dot = v0x * v1x + v0y * v1y;double delta_s = dot / v1_norm;//P0B长度return InterpolateUsingLinearApproximation(p0, p1, p0.s() + delta_s);//计算投影点的具体各项数据
}
手绘图:
简单理解一下这个图就能看懂代码了。😁😁
- 计算投影点的具体各项数据
主要用线性插值(主要根据占比权重来算),公式做了合并同类项。
PathPoint InterpolateUsingLinearApproximation(const PathPoint &p0,const PathPoint &p1,const double s) {double s0 = p0.s();double s1 = p1.s();PathPoint path_point;double weight = (s - s0) / (s1 - s0);//p0.x()+weight*(p1.x()-p0.x())double x = (1 - weight) * p0.x() + weight * p1.x();double y = (1 - weight) * p0.y() + weight * p1.y();double theta = slerp(p0.theta(), p0.s(), p1.theta(), p1.s(), s);double kappa = (1 - weight) * p0.kappa() + weight * p1.kappa();double dkappa = (1 - weight) * p0.dkappa() + weight * p1.dkappa();double ddkappa = (1 - weight) * p0.ddkappa() + weight * p1.ddkappa();path_point.set_x(x);path_point.set_y(y);path_point.set_theta(theta);path_point.set_kappa(kappa);//曲率path_point.set_dkappa(dkappa);//曲率求导path_point.set_ddkappa(ddkappa);path_point.set_s(s);return path_point;
}
3. 根据匹配点,计算Frenet坐标系的S-L值
第3步的是计算车当前点P在Frenet坐标系下的坐标,这部分的原理可参考其他博客,主要就是套公式转换一下,为下面在S-T图的生成生成做准备。
在Frenet坐标系下的s就是第一步计算的s,L大小是上面手绘图的∣AB∣|AB|∣AB∣,方向和P0P1P_{0}P_{1}P0P1垂直,指向A。
std::array<double, 3> init_s;std::array<double, 3> init_d;ComputeInitFrenetState(matched_point, planning_init_point, &init_s, &init_d);auto ptr_prediction_querier = std::make_shared<PredictionQuerier>(frame->obstacles(), ptr_reference_line);
补充说明一下,Frenet坐标系就是S-L坐标系,Frenet坐标系下的参数主要还是s,l,s就是累积距离,l就是后面提到的d,类似横向距离。
4. parse the decision and get the planning target
该部分总体代码:
// 加入感知信息时,里面涉及多个函数,具体包括障碍物筛选,去掉与车辆未来轨迹不发生冲突的障碍物,设置动态障碍物。auto ptr_path_time_graph = std::make_shared<PathTimeGraph>(ptr_prediction_querier->GetObstacles(), *ptr_reference_line,reference_line_info, init_s[0]起始点,init_s[0] + FLAGS_speed_lon_decision_horizon=200, 0.0,FLAGS_trajectory_time_length=8s, init_d);double speed_limit =reference_line_info->reference_line().GetSpeedLimitFromS(init_s[0]);reference_line_info->SetLatticeCruiseSpeed(speed_limit);//限制巡航速度PlanningTarget planning_target = reference_line_info->planning_target();
这部分是计算障碍物的S-T图,这里的S是frenet下的s,t是时间。这部分接收感知那边传来的障碍物信息,计算障碍物在frenet坐标系下的最大值和最小值,代码如下:
SLBoundary PathTimeGraph::ComputeObstacleBoundary(const std::vector<common::math::Vec2d>& vertices,const std::vector<PathPoint>& discretized_ref_points) const {double start_s(std::numeric_limits<double>::max());double end_s(std::numeric_limits<double>::lowest());double start_l(std::numeric_limits<double>::max());double end_l(std::numeric_limits<double>::lowest());for (const auto& point : vertices) {//转frenet坐标auto sl_point = PathMatcher::GetPathFrenetCoordinate(discretized_ref_points,point.x(), point.y());//计算障碍物在s-l坐标系下的最大值最小值start_s = std::fmin(start_s, sl_point.first);end_s = std::fmax(end_s, sl_point.first);start_l = std::fmin(start_l, sl_point.second);end_l = std::fmax(end_l, sl_point.second);}SLBoundary sl_boundary;//下图障碍物的显示sl_boundary.set_start_s(start_s);sl_boundary.set_end_s(end_s);sl_boundary.set_start_l(start_l);sl_boundary.set_end_l(end_l);return sl_boundary;
}
像上图描述的,就是将障碍物投影到frenet坐标系下,和车的预瞄轨迹点是否有交集(apollo 的预瞄距离是200米),没有交集的就不需要考虑。
动态障碍物的思路大概一样,动态障碍物可以看作多个静态障碍物,如下图,主要都是投影到frenet坐标系下,为下一步在S-T图上表达障碍物,以及在S- T图上做撒点采样,生成轨迹做铺垫。
解析一下这个图,中间是🚗轨迹,左右分别是车道边界,t0,t1在车道线内则考虑,其他时刻不考虑,其实详细思路更加复杂😭。
到这里,我们就能够得到障碍物的距S-T图
5. 生成横纵向采样路径
这步是关键,前面的Frenet坐标系和障碍物的S-T图可以说都是为了后面生成轨迹做铺垫的。
对于上图,有些司机会按照右图中浅红色的轨迹,选择绕开蓝色的障碍车。另外有一些司机开车相对保守,会沿着右图中深红色较短的轨迹做一个减速,给蓝色障碍车让路。
既然对于同一个场景,人类司机会有多种处理方法,那么Lattice规划算法的第一步就是采样足够多的轨迹,提供尽可能多的选择。
如何进行横纵向采样呢?
- 横向采样
横向轨迹的采样需要涵盖多种横向运动状态。现在Apollo的代码中设计了三个末状态横向偏移量,-0.5,0.0和0.5,以及四个到达这些横向偏移量的纵向位移,分别为10,20,40,80。用两层循环遍历各种组合,再通过多项式拟合,即可获得一系列的横向轨迹。
-
纵向采样
纵向轨迹采样需要考虑巡航、跟车或超车、停车这三种状态。也就是说3种情况下都要生成轨迹,后面再进行评估选择cost小的。
有了S-T图的概念,观察左图中的两条规划轨迹。红色的是一条跟车轨迹,绿色的是超车轨迹。这两条轨迹反映在S-T图中,就如右图所示。红色的跟车轨迹在蓝色阴影区域下方,绿色的超车轨迹在蓝色阴影区域上方。
如果有多个障碍物,就对这些障碍物分别采样超车和跟车所对应的末状态。
总结下来就是遍历所有和车道有关联的障碍物,对他们分别采样超车和跟车的末状态,然后用多项式拟合即可获得一系列纵向轨迹。多项式拟合如何生成多项式轨迹?可以看一下下面这篇blog。
无人车-运动规划-高阶多项式曲线方程求解
上图是将所有的轨迹整合,交给下一步来评估。
Lattice Planner会根据起点和终点的状态,在位置空间和时间上同时进行撒点。撒点的起始状态和终止状态各有6个参数,包括了3个横向参数,即横向位置、横向位置的导数和导数的导数;3个纵向参数,即纵向位置、纵向位置的一阶导数也就是速度、纵向位置的二阶导数(也就是加速度)。
起点的参数是车辆当时真实的状态,终点状态则是撒点枚举的各个情况。在确定了终点和起点状态以后,再通过五阶或者四阶的多项式连接起始状态和终止状态,从而得到规划的横向和纵向轨迹。
6. 轨迹cost值计算,进行碰撞检测
有了轨迹的cost以后,就是一个循环检测的过程。在这个过程中,每次会先挑选出cost最低的轨迹,对其进行物理限制检测和碰撞检测。如果挑出来的轨迹不能同时通过这两个检测,就将其筛除,考察下一条cost最低的轨迹。
TrajectoryEvaluator trajectory_evaluator(init_s, planning_target, lon_trajectory1d_bundle, lat_trajectory1d_bundle,ptr_path_time_graph, ptr_reference_line);// Get instance of collision checker and constraint checkerCollisionChecker collision_checker(frame->obstacles(), init_s[0], init_d[0],*ptr_reference_line, reference_line_info,ptr_path_time_graph);
7. 优先选择cost最小的轨迹且不碰撞的轨迹
获得采用轨迹之后,接着需要进行目标轨迹的曲率检查和碰撞检测,目的是为了使目标采样轨迹满足车辆的运动学控制要求和无碰撞要求,这样就形成了安全可靠的轨迹簇。这些轨迹簇都可以满足车辆的控制要求,但并不是最优的,因此需要从轨迹簇中选出一组最优的运行轨迹。这时就需要引入轨迹评价函数,用来对候选轨迹进行打分。
轨迹评价函数主要为了使得目标轨迹尽量靠近静态参考线轨迹运行,同时,速度尽量不发生大突变,满足舒适性要求,且尽量远离障碍物。因此最后轨迹评价函数可以通过如下伪代码描述:
traj_cost = k_lat * cost_lat + k_lon * cost_lon + k_obs * obs_cost;
上式中:
k_lat : 表示纵向误差代价权重
cost_lat: 表示纵向误差,综合考虑纵向速度误差,时间误差及加加速度的影响。
k_lon : 表示横向误差代价权重
cost_lon: 表示横向向误差,综合考虑了横向加速度误差及横向偏移误差的影响。
k_obs : 表示障碍物代价权重
obs_cost: 表示障碍物距离损失。
最后选择出代价值最好的一条轨迹输入到控制器,用于控制器的跟踪控制。
while (trajectory_evaluator.has_more_trajectory_pairs()) {double trajectory_pair_cost =trajectory_evaluator.top_trajectory_pair_cost();auto trajectory_pair = trajectory_evaluator.next_top_trajectory_pair();// combine two 1d trajectories to one 2d trajectoryauto combined_trajectory = TrajectoryCombiner::Combine(*ptr_reference_line, *trajectory_pair.first, *trajectory_pair.second,planning_init_point.relative_time());// check longitudinal and lateral acceleration// considering trajectory curvaturesauto result = ConstraintChecker::ValidTrajectory(combined_trajectory);if (result != ConstraintChecker::Result::VALID) {++combined_constraint_failure_count;switch (result) {case ConstraintChecker::Result::LON_VELOCITY_OUT_OF_BOUND:lon_vel_failure_count += 1;break;case ConstraintChecker::Result::LON_ACCELERATION_OUT_OF_BOUND:lon_acc_failure_count += 1;break;case ConstraintChecker::Result::LON_JERK_OUT_OF_BOUND:lon_jerk_failure_count += 1;break;case ConstraintChecker::Result::CURVATURE_OUT_OF_BOUND:curvature_failure_count += 1;break;case ConstraintChecker::Result::LAT_ACCELERATION_OUT_OF_BOUND:lat_acc_failure_count += 1;break;case ConstraintChecker::Result::LAT_JERK_OUT_OF_BOUND:lat_jerk_failure_count += 1;break;case ConstraintChecker::Result::VALID:default:// Intentional emptybreak;}continue;}// check collision with other obstaclesif (collision_checker.InCollision(combined_trajectory)) {++collision_failure_count;continue;}// put combine trajectory into debug dataconst auto& combined_trajectory_points = combined_trajectory;num_lattice_traj += 1;reference_line_info->SetTrajectory(combined_trajectory);reference_line_info->SetCost(reference_line_info->PriorityCost() +trajectory_pair_cost);reference_line_info->SetDrivable(true);// Print the chosen end condition and start conditionADEBUG << "Starting Lon. State: s = " << init_s[0] << " ds = " << init_s[1]<< " dds = " << init_s[2];// castauto lattice_traj_ptr =std::dynamic_pointer_cast<LatticeTrajectory1d>(trajectory_pair.first);if (!lattice_traj_ptr) {ADEBUG << "Dynamically casting trajectory1d ptr. failed.";}}
}
总结
总体讲清楚了算法的过程,但是代码层面涉及太多,后面还得慢慢深入,特别是采样的过程的代码得再解析。
参考:
Baidu Apollo 6.2 Lattice Planner规划算法
Apollo星火计划学习笔记——第七讲自动驾驶规划技术原理1
Lattice算法之六轨迹评估
相关文章:

自动驾驶规划 - Apollo Lattice Planner算法【1】
文章目录Lattice Planner简介Lattice Planner 算法思路1. 离散化参考线的点2. 在参考线上计算匹配点3. 根据匹配点,计算Frenet坐标系的S-L值4. parse the decision and get the planning target5. 生成横纵向采样路径6. 轨迹cost值计算,进行碰撞检测7. 优…...

以太坊数据开发-Web3.py-安装连接以太坊数据
Web3.py是连接以太坊的python库,它的API从web3.js中派生而来。如果你用过web3.js,你会对它的API很熟悉。但惭愧的是,作为一个以太坊上Dapp的开发者,我几乎没有直接使用过web3.js,也没有看过它的API。 官网:…...

【触摸屏功能测试】MQTT_STD本地调试说明-测试记录
1、MQTT简介 MQTT是一种基于发布/订阅模式的“轻量级”通讯协议。它是针对受限的、低带宽的、高延迟的、网络不可靠的环境下的网络通讯设备设计的。 发布是指客户端将消息传递给服务器,订阅是指客户端接收服务器推送的消息。每个消息有一个主题,包含若干…...

六十分之十三——黎明前
目录一、目标二、计划三、完成情况四、提升改进(最少3点)五、意外之喜(最少2点)六、总结一、目标 明确可落地,对于自身执行完成需要一定的努力才可以完成的 1.8本技术管理书籍阅读(使用番茄、快速阅读、最后输出思维导图)2.吴军系列硅谷来信1听书、香帅的北大金融…...

【Call for papers】CRYPTO-2023(CCF-A/网络与信息安全/2023年2月16日截稿)
Crypto 2023 will take place in Santa Barbara, USA on August 19-24, 2023. Crypto 2023 is organized by the International Association for Cryptologic Research (IACR). The proceedings will be published by Springer in the LNCS series. 文章目录1.会议信息2.时间节…...
线程的信号量和互斥量
文章目录线程的信号量初始化信号量:sem_init减少信号量:sem_wait增加信号量:sem_post删除信号量:sem_destroy代码示例线程的互斥量初始化互斥量:pthread_mutex_init锁住互斥量:pthread_mutex_lock解锁互斥量…...
关于Linux,开源社区与国产化的本质区别
因为生产力驱动而非理想主义驱动。 开源运动的蓬勃发展来自于GNU(GNU is not unix),RichardMatthewStallman领导着一群黑客,带着对比尔盖茨的鄙视,制定了GPL协议,以后人人都能从伟大的前人身上学习到源代码的精髓,让软…...

Win11下Linux子系统迁移方法及报错解决
Win11 将Linux子系统从C盘迁移到其他盘Win11下Linux子系统迁移方法及报错解决1、下载LxRunOffline2、ERROR:directory is not empty 报错解决参考链接Win11下Linux子系统迁移方法及报错解决 C盘满了,Ubuntu子系统占了100多G怎么办?直接将子系…...
python维护的一些基础方法
1】通过命令行查看python安装库的基本信息 pip show numpy # 查看python中numpy库的安装版本信息 2】python 环境的开发与维护 python的开发与C\MATLAB等最大的不同就是,python中版本的更新不对历史版本负责,就是说你以历史版本开发的python程序&#…...
C语言 数组元素的指针
1.一个变量有地址,一个数组包含若干个元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。 2.指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放入一个指针变量中)。 3.所谓…...

(C语言)指针进阶
问:1. ( ),[ ],->,,--,. ,*的操作符优先级是怎么样的?2. Solve the problems:只有一个常量字符串与一个字符指针,该怎么打印常量字符串所有内容…...

DS期末复习卷(三)
选择题 某数据结构的二元组形式表示为A(D,R),D{01,02,03,04,05,06,07,08,09},R{r},r{<01,02>,<01&a…...

Java链表模拟实现+LinkedList介绍
文章目录一、模拟实现单链表成员属性成员方法0,构造方法1,addFirst——头插2,addLast——尾插3,addIndex——在任意位置插入3.1,checkIndex——判断index合法性3.2,findPrevIndex——找到index-1位置的结点…...

MySQL——单表、多表查询
一、单表查询 素材: 表名:worker-- 表中字段均为中文,比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 varcha…...

关于表的操作 数据库(3)
目录 前期准备工作: 一、单表查询: 二、多表查询: 前期准备工作: 修改数据库的配置文件,,使其可以显示库名,其中//d代表当前使用的数据库名 注:vim /etc/my.cnf.d/mysql-server.c…...

C++:红黑树
红黑树的概念 红黑树是一棵二叉搜索树,但是红黑树通过增加一个存储位表示结点的颜色RED或BLACK。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出2倍,因而是接近平衡的。 红黑树的性质 ⭐…...
每天一道算法题の中缀表达式
中缀表达式(、-、*、/) :中缀表达式是指操作符位于操作数之间的数学表达式。例如,在中缀表达式"2 3"中,操作符""位于操作数"2"和"3"之间。现给定一个中缀表达式,…...
Dar语法基础-泛型
泛型 如果查看基本数组类型 List 的 API 文档,您会发现该类型实际上是 List<E>。 <…> 表示法将 List 标记为泛型(或参数化)类型——具有正式类型参数的类型。 按照惯例,大多数类型变量的名称都是单字母的࿰…...
rt-thread------串口(一)配置
系列文章目录 rt-thread 之 fal移植 rt-thread 之 生成工程模板 文章目录系列文章目录前言一、串口的配置step1:通过串口名字找到串口句柄step2:配置串口参数step3:设置串口接收回调函数step4:打开串口设备前言 UART(…...

Android - 自动系统签名
一、系统签名 以下是两类应用开发场景: 普通应用开发:使用公司自定义 keystore 进行签名,如:微信、支付宝系统应用开发:使用 AOSP 系统签名或厂商自定义 keystore 进行签名,如:设置、录音 系…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...