1.gpld是源码什么意思中文?
2.Navigation包 Global_planner全局路径规划源码详细解析
3.Unlua源码解析(一) 通过 UE 命名空间访问C++类型
gpld是什么意思中文?
GPLD是“Global Public License Disclosure”的缩写,翻译成汉语即为“全球公共许可证披露”。源码这是源码一种针对开源软件的许可证,它要求开源软件的源码源代码必须公开,并且必须允许其他人任意复制、源码修改、源码tacotron 2源码发布和分发这个软件的源码副本。
GPLD对于开源社区起到了非常重要的源码作用。首先,源码它保证了软件的源码源代码公开,使得其他人可以查看和修改代码,源码这样可以帮助其他开发者更好地了解软件的源码工作原理,而且也可以使得软件更加稳定和安全。源码其次,源码网页源码dataGPLD允许任何人复制、源码修改、分发软件的副本,这样可以为开源软件提供更多的贡献者和用户,并且也可以使得开源软件更加普及。
目前,GPLD已经被广泛应用于开源软件中。例如,Linux操作系统、Apache web服务器、MySQL数据库等等都采用了GPLD许可证。这些开源软件的成功证明了GPLD模式是一种非常可行的开源模式,在保证软件质量的layui登记源码同时,也能够使得软件得到更广泛地应用。随着开源软件的普及,GPLD的影响力也在不断扩大,它将会继续促进开源软件的创新和发展。
Navigation包 Global_planner全局路径规划源码详细解析
学习总结,如有错误欢迎指正!一丶plan_node.cpp从程序入口开始,首先在plan_node.cpp的main函数中,初始化了全局路径规划器。
costmap_2d::Costmap2DROS?lcr("costmap",?buffer);global_planner::PlannerWithCostmap?pppp("planner",?&lcr);在函数PlannerWithCostmap中设置了两种调用makePlan的路径:
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}1.通过make_plan服务
req.start.header.frame_id?=?"map";req.goal.header.frame_id?=?"map";bool?success?=?makePlan(req.start,?req.goal,?path);2.通过goal回调函数
//得到当前机器人在MAP中的位置cmap_->getRobotPose(global_pose);makePlan(global_pose,?*goal,?path);在getRobotPose函数中,通过tf_.transform(robot_pose, global_pose, global_frame_);函数,默认将机器人pose从base_link转换到map坐标系下,可通过参数设置。ping api源码得到起始点和目标点传入到makePlan中。
二丶 planner_core.cpp//register?this?planner?as?a?BaseGlobalPlanner?pluginPLUGINLIB_EXPORT_CLASS(global_planner::GlobalPlanner,?nav_core::BaseGlobalPlanner)global_planner 是基类nav_core :: BaseGlobalPlanner的一个插件子类
首先在构造函数中需要初始化GlobalPlanner,在initialize中对一些参数进行赋值。
GlobalPlanner::GlobalPlanner(std::string?name,?costmap_2d::Costmap2D*?costmap,?std::string?frame_id)?:GlobalPlanner()?{ //initialize?the?plannerinitialize(name,?costmap,?frame_id);}当调用makePlan时,首先就是判断是否已经被初始化:
//?code?line?~?makePlan()if?(!initialized_)?{ ROS_ERROR("This?planner?has?not?been?initialized?yet,?but?it?is?being?used,?please?call?initialize()?before?use");return?false;}m初始化完成之后,清除之前规划的Plan,以防万一。然后检查起点和终点是否在我们所需要的坐标系下,一般在map系下。
//clear?the?plan,?just?in?case?,?code?line??makePlan()plan.clear();if?(goal.header.frame_id?!=?global_frame)?{ ...}if?(start.header.frame_id?!=?global_frame){ ...}将世界坐标系的点(map 坐标系)转换成图像坐标系(图像左下角)下的点(以像素表示)
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;}在Costmap2D和GlobalPlanner中都有实现worldToMap,其实都是一样的,在GlobalPlanner中则需要通过调用Costmap2D来获取局部地图的WordPress文库源码起始点和分辨率,而在Costmap2D则可以直接使用全局变量。
bool?Costmap2D::worldToMap(double?wx,?double?wy,?unsigned?int&?mx,?unsigned?int&?my)?const{ ?if?(wx?<?origin_x_?||?wy?<?origin_y_)return?false;?mx?=?(int)((wx?-?origin_x_)?/?resolution_);?my?=?(int)((wy?-?origin_y_)?/?resolution_);?if?(mx?<?size_x_?&&?my?<?size_y_)return?true;?return?false;}old_navfnbehavior ?作为一种旧式规划行为:
The start of the path does not match the actual start location.
The very end of the path moves along grid lines.
All of the coordinates are slightly shifted by half a grid cell
现在在worldToMap所使用的convert_offset_ = 0
接下来将机器人Robot所在的位置,在costmap中设置成free,当前位置不可能是一个障碍物。 即在clearRobotCell()函数中:mx,my即当前机器人位置。
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}0设置规划地图边框:outlineMap,此函数由参数outline_map_决定。 根据costmap跟起始终止点计算网格的potential,计算的算法有两种:Dijkstra和A*,具体算法便不再讨论,资料很多。 当提取到plan之后,调用getPlanFromPotential,把path转换变成geometry_msgs::PoseStamped数据类型。
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}1此时便得到所需要的路径plan,最终调用OrientationFilter平滑之后发布出去。
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}2Unlua源码解析(一) 通过 UE 命名空间访问C++类型
通过UE4的命名空间访问C++类型的机制,让我们从一个具体的例子出发,即UE4.UKismetSystemLibrary.PrintString(“hello”),来深入解析这一过程。在Unlua提供的例子中,HelloWorld的实现展现了Lua与C++的交互方式。要理解为什么Lua的代码能最终调用C++的方法,并且成功执行,我们需要从底层逻辑出发,解析这一过程中的关键步骤。
首先,我们从Unlua.lua中的声明开始,UE4实际上被表示为全局表_G,其元表为global_mt,Index元方法为global_index。当我们在Lua代码中尝试访问UE4的成员,如UKismetSystemLibrary,实际上是在查找全局表_G中的“UKismetSystemLibrary”。为了实现这一查找,我们引入了元方法,即global_index方法,其在Lua代码中扮演了关键角色。
在访问过程中,当Lua尝试获取表中不存在的“UKismetSystemLibrary”时,会触发元方法global_index。这个过程实际上涉及到一系列的函数调用,包括RegisterClass等。注册类的逻辑在于,将C函数注册为Lua端可以通过全局名称访问的函数。在这一过程中,UE4.UKismetSystemLibrary最终会成为一个Lua端的表,其元表指向自身,并且通过特定的元方法(如Class_Index)来处理访问与调用。
在UE4.UKismetSystemLibrary.PrintString(“Hello”)的调用中,我们可以看到一系列的执行逻辑。首先,通过一系列函数调用,UE4.UKismetSystemLibrary表中实现了PrintString方法的描述信息与调用机制。这个过程涉及到类的注册、属性与方法的描述、以及在Lua端的表中存储这些描述信息。
最终,当执行PrintString方法时,Lua端的调用实际转化为C++端的函数调用。这一过程涉及到参数的转换、方法的调用机制(如PreCall、ProcessEvent、PostCall等),以及最终的返回值转换与处理。这一系列的步骤确保了Lua端的代码能够与C++端的方法进行交互,实现功能的调用与执行。
通过这一解析,我们可以清晰地看到,UE4与Unlua的结合是如何通过元方法、表操作以及函数注册机制,实现了Lua与C++之间的高效通信与调用,使得跨语言编程成为可能。这一机制不仅展示了语言间的交互灵活性,也体现了底层设计在实现复杂功能中的重要性。