movebase导航和地图数据的使用 - 3 movebase的初始化分析



MoveBase::MoveBase(tf::TransformListener& tf) :

tf_(tf),

as_(NULL),

planner_costmap_ros_(NULL), controller_costmap_ros_(NULL),

bgp_loader_("nav_core","nav_core::BaseGlobalPlanner"),

blp_loader_("nav_core","nav_core::BaseLocalPlanner"),

recovery_loader_("nav_core","nav_core::RecoveryBehavior"),

planner_plan_(NULL), latest_plan_(NULL),controller_plan_(NULL),

runPlanner_(false), setup_(false), p_freq_change_(false),c_freq_change_(false), new_global_plan_(false) {



//这个actionserver使用了actionlib中的逻辑,actionlib提供了一套框架,可以建立一个server,client可以发送可抢断的taskrequest, 可以将之前的taskrequest取消,覆盖。并且可以不断得到反馈的框架。,基于此框架,每当有新的targetgoal被设定时,会执行executeCb函数。

as_ = newMoveBaseActionServer(ros::NodeHandle(), "move_base",boost::bind(&MoveBase::executeCb, this, _1), false);



ros::NodeHandleprivate_nh("~"); 使用privatenamespace的handle,也就是使用move_base作为ns的handle.

ros::NodeHandle nh;



recovery_trigger_ = PLANNING_R;



//get some parameters that will be global to the move basenode

std::string global_planner, local_planner;

private_nh.param("base_global_planner",global_planner, std::string("navfn/NavfnROS"));

private_nh.param("base_local_planner",local_planner,std::string("base_local_planner/TrajectoryPlannerROS"));

//实际使用的global/localplanner分别是:

//tshao@tshao-OptiPlex-9020:~$rosparam get /move_base/base_global_planner

//navfn/NavfnROS

//tshao@tshao-OptiPlex-9020:~$rosparam get /move_base/base_local_planner

//dwa_local_planner/DWAPlannerROS



private_nh.param("global_costmap/robot_base_frame",robot_base_frame_, std::string("base_link"));

private_nh.param("global_costmap/global_frame",global_frame_, std::string("/map"));

private_nh.param("planner_frequency",planner_frequency_, 0.0);

private_nh.param("controller_frequency",controller_frequency_, 20.0);

private_nh.param("planner_patience",planner_patience_, 5.0);

private_nh.param("controller_patience",controller_patience_, 15.0);



private_nh.param("oscillation_timeout",oscillation_timeout_, 0.0);

private_nh.param("oscillation_distance",oscillation_distance_, 0.5);



//set up plan triple buffer

planner_plan_ = new std::vector<geometry_msgs::PoseStamped>();

latest_plan_ = new std::vector<geometry_msgs::PoseStamped>();

controller_plan_ = newstd::vector<geometry_msgs::PoseStamped>();



//set up the planner's thread

//planThread,是工作线程?这个线程会根据一个target调用plan算法生成一个plan.一个Plan其实就是一些点,而之后具体使用这些点去驱动底座行走,并不是本thread的工作内容。

planner_thread_ = newboost::thread(boost::bind(&MoveBase::planThread, this));

//for comanding the base

//向mobilebase底座发送命令的topic,这个topic会被remap。

vel_pub_ = nh.advertise<geometry_msgs::Twist>("cmd_vel",1);

current_goal_pub_ =private_nh.advertise<geometry_msgs::PoseStamped>("current_goal",0 );



ros::NodeHandle action_nh("move_base");

action_goal_pub_ =action_nh.advertise<move_base_msgs::MoveBaseActionGoal>("goal",1);



//we'll provide a mechanism for some people to send goals asPoseStamped messages over a topic

//they won't get any useful information back about its status,but this is useful for tools

//like nav_view and rviz

//这里监听一个/move_base_simple/goal的topic.使用者可以向这个topic发送消息,设定一个目的地,我们监听这个消息,调用goalCB处理,其实具体的处理方法是将这个消息,转换成对actionServer的相应service的调用。所以这里其实会简介导致MoveBase::executeCb被调用。

ros::NodeHandlesimple_nh("move_base_simple");

goal_sub_ =simple_nh.subscribe<geometry_msgs::PoseStamped>("goal",1, boost::bind(&MoveBase::goalCB, this, _1));





//we'll assume the radius of the robot to be consistent withwhat's specified for the costmaps

private_nh.param("local_costmap/inscribed_radius",inscribed_radius_, 0.325);

private_nh.param("local_costmap/circumscribed_radius",circumscribed_radius_, 0.46);

private_nh.param("clearing_radius",clearing_radius_, circumscribed_radius_);

private_nh.param("conservative_reset_dist",conservative_reset_dist_, 3.0);



private_nh.param("shutdown_costmaps",shutdown_costmaps_, false);

private_nh.param("clearing_rotation_allowed",clearing_rotation_allowed_, true);

private_nh.param("recovery_behavior_enabled",recovery_behavior_enabled_, true);



//create the ros wrapper for the planner's costmap... andinitializer a pointer we'll use with the underlying map

//为globalplanner建立costmap.

planner_costmap_ros_ = newcostmap_2d::Costmap2DROS("global_costmap", tf_);

planner_costmap_ros_->pause();



//initialize the globalplanner

try {

//check if a non fully qualified name has potentially beenpassed in

if(!bgp_loader_.isClassAvailable(global_planner)){

std::vector<std::string> classes =bgp_loader_.getDeclaredClasses();

for(unsigned int i = 0; i < classes.size(); ++i){

if(global_planner == bgp_loader_.getName(classes[i])){

//if we've found a match... we'll get the fullyqualified name and break out of the loop

ROS_WARN("Planner specifications should nowinclude the package name. You are using a deprecated API. Pleaseswitch from %s to %s in your yaml file.",

global_planner.c_str(), classes[i].c_str());

global_planner = classes[i];

break;

}

}

}

//加载并初始化globalplanner

planner_ =bgp_loader_.createInstance(global_planner);

planner_->initialize(bgp_loader_.getName(global_planner),planner_costmap_ros_);

} catch (const pluginlib::PluginlibException& ex)

{

ROS_FATAL("Failed to create the %s planner, are yousure it is properly registered and that the containing library isbuilt? Exception: %s", global_planner.c_str(), ex.what());

exit(1);

}



//create the ros wrapper for the controller's costmap... andinitializer a pointer we'll use with the underlying map

//建立localcostmap

controller_costmap_ros_ =new costmap_2d::Costmap2DROS("local_costmap", tf_);

controller_costmap_ros_->pause();



//create a local planner

try {

//check if a non fully qualified name has potentially beenpassed in

if(!blp_loader_.isClassAvailable(local_planner)){

std::vector<std::string> classes =blp_loader_.getDeclaredClasses();

for(unsigned int i = 0; i < classes.size(); ++i){

if(local_planner == blp_loader_.getName(classes[i])){

//if we've found a match... we'll get the fullyqualified name and break out of the loop

ROS_WARN("Planner specifications should nowinclude the package name. You are using a deprecated API. Pleaseswitch from %s to %s in your yaml file.",

local_planner.c_str(), classes[i].c_str());

local_planner = classes[i];

break;

}

}

}



//建立并初始化localplanner.

tc_ =blp_loader_.createInstance(local_planner);

ROS_INFO("Createdlocal_planner %s", local_planner.c_str());

tc_->initialize(blp_loader_.getName(local_planner), &tf_,controller_costmap_ros_);

} catch (const pluginlib::PluginlibException& ex)

{

ROS_FATAL("Failed to create the %s planner, are yousure it is properly registered and that the containing library isbuilt? Exception: %s", local_planner.c_str(), ex.what());

exit(1);

}



// Start actively updating costmaps based on sensor data

planner_costmap_ros_->start();

controller_costmap_ros_->start();



//advertise a service forgetting a plan

make_plan_srv_ = private_nh.advertiseService("make_plan",&MoveBase::planService, this);



//advertise a service forclearing the costmaps

clear_costmaps_srv_ =private_nh.advertiseService("clear_costmaps",&MoveBase::clearCostmapsService, this);



//if we shutdown our costmaps when we're deactivated... we'lldo that now

if(shutdown_costmaps_){

ROS_DEBUG_NAMED("move_base","Stoppingcostmaps initially");

planner_costmap_ros_->stop();

controller_costmap_ros_->stop();

}



//load any user specified recovery behaviors, and if thatfails load the defaults

if(!loadRecoveryBehaviors(private_nh)){

loadDefaultRecoveryBehaviors();

}



//initially, we'll need to make a plan

state_ = PLANNING;



//we'll start executing recovery behaviors at the beginning ofour list

recovery_index_ = 0;



//we're all set up now so we can start the action server

as_->start();



//设置reconfig的callback/

dsrv_ = newdynamic_reconfigure::Server<move_base::MoveBaseConfig>(ros::NodeHandle("~"));

dynamic_reconfigure::Server<move_base::MoveBaseConfig>::CallbackTypecb = boost::bind(&MoveBase::reconfigureCB, this, _1, _2);

dsrv_->setCallback(cb);



//http://docs.ros.org/api/costmap_2d/html/classcostmap__2d_1_1Costmap2DROS.html

//http://docs.ros.org/api/costmap_2d/html/classcostmap__2d_1_1Costmap2D.html#a43ca3645f610b4586810376c96d0d226

walk_thread_ = NULL;

private_nh.param<double>("square_size",square_size_, 5.0);

private_nh.param<double>("threshold", t_,2.0);

ROS_INFO("MoveBase::MoveBase, amc: square_size %lf,threshold %lf\n", square_size_, t_);

amcInProcess = false;

amc_service_srv_ =private_nh.advertiseService("automatic_map_construction",&MoveBase::amcCallback, this);

}

ROS naviagtion analysis: costmap_2d--Costmap2DROS 在上一篇文章中moveBase就有关于costmap_2d的使用: planner_costmap_ros_是用于全局导航的地图,controller_costmap_ros_是局部导航用的地图,地图类型为经过ROS封装的costmap_2d::Costmap2DROS*。 以下是这个ROS类的UML: 看看这个类的成员变量:LayeredCostmap* layered_costmap_ 阅读详情

相关推荐

移动小车+机械臂组合机器人:ROS导航与视觉抓取实战指南

移动机器人技术中,将移动底盘与机械臂结合构成复合机器人,是解决大范围空间内自主作业的关键路径。其核心在于打通“移动到目标位置”与“执行精细操作”两大能力闭环,涉及SLAM建图、定位导航、机械臂运动规划、手眼标定与视觉抓取等关键技术栈。ROS作为主流机器人中间件,通过TF坐标变换、MoveIt!与导航栈实现了多模块协同控制。该技术广泛应用于仓储物流分拣、智能巡检、家庭服务及科研教学等场景。本文以移动小车加六轴机械臂为例,系统梳理从系统架构、环境配置、底盘导航、机械臂控制到视觉抓取的完整工程流程,并针对联调中的

weixin_34344403的博客 378

ROS探索总结(十四)——move_base(路径规划)

https://blog.youkuaiyun.com/hcx25909/article/details/9470297

chengde6896383的专栏 1473

四足机器人技术栈解析:从硬件到AI的工程化落地与商业思考

机器人技术作为人工智能与自动化领域的关键分支,其核心在于将感知、决策与控制算法集成于物理实体,实现自主作业。其技术原理涵盖硬件层(如高扭矩密度电机)、驱动控制、状态估计、运动规划、感知导航及智能应用等多个层级,通过系统集成解决复杂环境下的稳定运动与任务执行问题。该技术的核心价值在于替代或辅助人类完成危险、重复或高精度作业,在工业巡检、物流仓储、特种作业等场景展现出巨大潜力。本文以四足机器人为具体载体,深入探讨其完整技术栈构成,并分析从实验室原型到可靠产品的工程化挑战,其中涉及**系统集成**与**工程化量产

weixin_34050519的博客 501

45.在ROS中实现global planner(1)- 实现一个可以用的模板

本文简单实现了一个的插件,显然实际没啥用,不过可以作为一个模板,基于该模板实现自己的算法。后面我们将基于该模板实现可用的全局规划。本文代码见。

PIBOT导航机器人 3240

ROS导航【01】: move_base包(导航和路径规划)

move_base 包提供了一个动作的实现(参见 actionlib 包),给定世界坐标上的一个目标,将尝试通过移动基点到达它。 move_base 节点将全局和局部规划器链接在一起以完成其全局导航任务。它支持任何遵循 nav_core 宝中指定的 nav_core::BaseGlobalPlanner 接口的全局规划器和任何遵循 nav_core 宝中指定的 nav_core::BaseLocalPlanner 接口的本地规划器。

gongdiwudu的专栏 2万+

导航包Navigation最全完整解析(二): 对核心节点move_base进行分析

开始直接进行代码分析阶段, 首先对核心节点move_base进行分析 一、 MoveBase( &tf) 节点重要接口函数功能解析: 1. 初始化全局规划和局部规划器句柄; 2. 初始化恢复行为句柄; 3. 初始化代价地图函数句柄; 4. 其他参数、变量等初始化; 初始化1个服务: MoveBaseActionServer(, , boost::bind(&MoveBase::executeCb, this, _1), ); 初始化另开1个线程: boost::thread(bo.

Ian的博客 1891

常用ros包整理及使用心得--导航篇

包名 地址 中文使用说明 使用心得

qq_23076153的博客 496

WIFI中CSI的读取

学习目标: 目前正在做基于WIFI的无设备定位,准备使用信道状态信息(CSI),学习一下。 目前采集数据环境已经搭建好,准备研究信号的预处理。 学习内容: 1、 信号的读取——read_bf_file函数的研究 2、 3、 4、 1. read_bf_file详解: %READ_BF_FILE Reads in a file of beamforming feedback logs. % This version uses the *C* version of read_bfee, ...

sz3076799的博客 8894

ROS move_base 源码解析

ROS move_base学笔记,网上收集整理,方便理解和查看

baosheng123的博客 2263

RealSense D455的标定并运行VINS-FUSION

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

qq_40186909的博客 2万+

深入解析STM32定时器中央对齐模式3的双中断机制

本文深入解析了STM32定时器中央对齐模式3的双中断机制。该模式在一个PWM周期内,会在计数器到达ARR(上溢)和0(下溢)时各触发一次更新中断,实现更精细的实时控制。文章详细阐述了其工作原理、配置方法,并指导如何在中断服务函数中通过DIR位区分中断来源,同时探讨了其在电机控制、数字电源等场景下的应用优势与CPU负载挑战。

weixin_29164185的博客 493

【ROS-Navigation】Movebase主体源码解读

记录学习阅读ROS Navigation源码的理解,本文为Movebase主体源码学习记录,以文字总结、绘制结构图说明、代码注释为主。仍在学习过程中,有错误欢迎指正,共同进步。 Movebase的主干部分是一个Action服务器,接收用户发送的目标位置,并调用全局规划器和局部规划器,基于各层代价地图的信息进行路径规划,得到最优路径,向用户反馈机器人速度指令,驱动机器人按照指令运动,最终到达目标...

NEO's NOTEBOOK 7179

缺陷检测-金属表面缺陷检测

1介绍 缺陷检测是工业视觉技术中最重要的组成部分。业务广泛,场景丰富,技术难点高、工作量大。针对不同的场景,选择不同的相机和

huneng1991的专栏 5251

ROS源代码阅读(7)——导航(Navigation)

2021SC@SDUSC ROS源代码阅读(7) 后面主要看导航,看完需要时间,一起整理

qzyj99的博客 2328

【红绿灯识别】基于计算机视觉实现道路信号灯检测识别系统附Matlab代码

随着自动驾驶技术的快速发展,对道路交通信号灯的检测识别技术也提出了更高的要求。本文提出了一种基于计算机视觉的道路信号灯检测识别系统,该系统能够准确地检测和识别道路交通信号灯,并输出信号灯的颜色信息。该系统采用深度学习方法,利用卷积神经网络(CNN)对道路交通信号灯进行检测和识别。实验结果表明,该系统能够在复杂的环境中准确地检测和识别道路交通信号灯,具有较高的实用价值。道路交通信号灯是道路交通管理的重要组成部分,它能够有效地组织交通,提高道路通行效率,保障交通安全。

qq_59747472的博客 341

姿态传感器/陀螺仪之BMI270应用原理图设计

BMI270是一款由博世(Bosch)推出的高性能、超低功耗惯性测量单元(IMU),专为可穿戴设备、智能设备及物联网应用设计。

corlin6688的博客 2866

移动机器人导航navigation中的move_base功能包深度剖析(1)

针对移动机器人导航navigation中的move_base部分,详细剖析其实现过程。 旁边专栏还在更新ROS-Navigation 包其他源码分析,便于继续深入了解 目录前言1. 相关源码文件1.1 主要头文件(move_base/include)1.2 主要源代码文件(move_base/src)2. 源码剖析2.1 move_base包给定导航目标2.2 obstacle_layer.cpp(1)初始化ObstacleLayer::onInitialize() 前言 move_base 是一个开

abicco_ds的博客 4366

【72】【OpenCV C++ & C#】 将cv::Mat 图像转换成imgINFO 传给c#在winform上显示,OpenCV C++如何将处理后的图像传给C#呢? 如何获取图像信息呢?

本文介绍了通过OpenCV C++处理图像后传递给C#的方法。首先定义了一个结构体imgINFO存储图像信息(数据指针、宽高、通道数等),然后通过getImgInfo函数将cv::Mat转换为该结构体。文章特别指出当图像宽度不能被4整除时可能出现失真问题,并给出了两种解决方案:调整输入图像或创建新的对齐图像。此外还解释了img.step和img.cols*img.elemSize()的关系,说明它们在大多数情况下是相等的。最后提到需要通过DLL将结构体传递给C#(具体方法参见其他文章)。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 697

【ROS-Navigation】Costmap2D代价地图源码解读-1

记录学习阅读ROS Navigation源码的理解,本文为Costmap2D代价地图源码学习记录,以文字总结、绘制结构图说明、代码注释为主。仍在学习过程中,有错误欢迎指正,共同进步。 Costmap通过各层地图订阅话题、接收传感器数据,维护各层地图数据,并最终整合出一张用于路径规划的主地图。 【结构示意图】 【相关文件】 costmap_2d/src/costmap_2d_r...

NEO's NOTEBOOK 5990

【无人机项目实战】第三章:fast_planner工程解读(附C++代码)

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录系列文章目录前言一、规划系统运行逻辑【业务部分】1.Fast_planner_node.cpp【程序入口】功能代码实现2.kino_replan_fsm.cpp【状态机转移】功能代码实现KinoReplanFSM::init()函数订阅目标点回调函数订阅里程计回调函数检查路径规划是否成功【重要】执行状态机FSM定时器回调函数【重要】判断目标点是否有障碍物或者是轨迹执行过程中是否有障碍物的回调函数3

qq_35635374的博客 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Costmap_2d ROS源码解析

mapUpdateLoop这个成员函数是用于不停刷新代价地图的,它在每个循环通过updateMap函数实现,而Costmap2DROS::updateMap函数是利用LayeredCostmap的updateMap函数进行更新。大家都知道,代价地图是由不同层级的plugins逐层累加的,包括静态地图层、障碍层、膨胀层等等,那么通过LayeredCostmap的对象,创造了一个由指向plugin的共享指针组成的容器,通过配置文件,向里一一添加插件层。最后,将回调函数设置为动态重新配置服务器的回调函数。

m0_47719724的博客 1341

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

扩散模型实时预测3D占据:机器人自主导航的工程实践

在机器人自主导航领域,实时感知与建图是核心基础技术。其原理在于通过激光雷达或深度相机等传感器获取环境点云数据,并构建概率占据栅格地图,为路径规划提供空间认知。传统方法在未知区域面临“视野盲区”问题,制约了探索效率与安全性。生成式AI,特别是扩散模型,为解决这一问题提供了新的技术路径。扩散模型通过学习数据分布,能够从局部观测中生成符合物理规律的全局结构预测,其概率生成特性为不确定性建模提供了天然基础。在工程实践中,通过轻量化网络设计和概率地图融合方法,可以在保持精度的同时满足实时性要求,使机器人具备“合理推测

440

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Turtlebot+Cartographer 2D建图实战指南:从硬件选型到高质量地图生成

SLAM(同步定位与建图)是机器人自主导航的基础技术,其中2D激光SLAM因计算轻量、部署成熟,成为入门首选。Cartographer作为ROS生态中鲁棒性强、多传感器融合完善的一体化建图框架,特别适配Turtlebot等差速轮式平台。其核心价值在于将激光雷达、IMU与里程计数据深度融合,显著抑制位姿漂移与地图撕裂,提升建图可复现性。在真实硬件上,需根据传感器类型(Kinect深度相机或URG/FlashGO等2D激光雷达)选择对应数据链路与配置策略,并关注TF坐标系对齐、IMU预处理、scan话题映射等工

weixin_33842304的博客 438

【ROS-Navigation】NavFn全局规划源码解读-1

记录学习阅读ROS Navigation源码的理解,本文为NavFn全局规划源码学习记录,以文字总结、绘制结构图说明、代码注释为主。仍在学习过程中,有错误欢迎指正,共同进步。 Movebase使用的全局规划器默认为NavFn,默认使用Dijkstra算法,在地图上的起始点和目标点间规划出一条最优路径,供局部规划器具体导航使用。在理解这部分的过程中也参考了很多博客,NavFn的源码中实际上是有A...

NEO's NOTEBOOK 5793

具身智能导航实战:从语义理解到真机避障

具身智能导航是机器人实现自主移动的核心能力,其本质是融合环境感知、动态路径规划与语义推理的闭环决策系统。不同于传统ROS导航仅关注‘跑通demo’,现代工业场景要求机器人理解‘维修区禁止通行’‘去茶水间需左转’等语义指令,并在连续变化的环境中实时响应。关键技术包括多层导航框架设计、风险加权路径规划、激光点云时空连续建图,以及可推理的语义地图构建。本文聚焦真实产线部署经验,覆盖move_base深度改造、TEB规划器调优、Cartographer连续建图参数实测,以及语义层与ROS生态的工程级集成,为AGV开

weixin_27427619的博客 280

现代汽车公寓泊车机器人:ROS与V2X技术如何破解停车难题

机器人操作系统(ROS)作为机器人开发的核心框架,通过提供硬件抽象、设备控制和通信中间件,为复杂环境下的机器人自主导航与决策奠定了软件基础。其原理在于模块化设计,允许开发者集成多传感器融合、SLAM(同步定位与地图构建)和路径规划等关键算法。这一技术价值在于,它使得机器人能够从结构化工厂走向非结构化的真实世界场景,例如地下停车场。结合V2X(车用无线通信)技术,机器人能与车辆、云端进行实时数据交换,实现车场协同,从而解决传统自动泊车方案成本高、改造难的问题。这种“场端智能辅助”模式,正推动ROS和V2X技术

weixin_30723433的博客 414
上一篇: movebase导航和地图数据的使用 - 2 turtlebot中Move base的launch文件分析
下一篇: movebase导航和地图数据的使用 - 4 movebase 如何处理target请求
csshell2002
博客等级 码龄11年 30粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值