Nav2通用教程-3

目录

Overview

Requirements

Tutorial Steps

0- Setup Your Enviroment Variables

1- Launch Turtlebot 3

2- Launch Nav2

3- Launch RVIZ

4- Initialize the Location of Turtlebot 3

5- Send a Goal Pose

(SLAM) Navigating While Mapping

Overview

Requirements

Tutorial Steps

0- Launch Robot Interfaces

1- Launch Navigation2

2- Launch SLAM

 3- Working with SLAM

4- Getting Started Simplification

(STVL) Using an External Costmap Plugin

Overview

Costmap2D and STVL              

Tutorial Steps

0- Setup

1- Install STVL

 2- Modify Navigation2 Parameter

3- Launch Navigation2

4- RVIZ

Overview

Requirements

GPS Localization Overview


Overview

        这个教程展示了如何使用 ROS 2 Nav2 在物理 Turtlebot 3 机器人上控制和导航 Turtlebot 3。在完成此教程之前,强烈建议先完成入门教程,特别是如果你对 ROS 和 Nav2 不太熟悉的话。

        这个教程可能需要大约 1 小时左右的时间完成。这取决于你在 ROS、机器人方面的经验,以及你使用的计算机系统。

Requirements

        你需要安装 Nav2 和 Turtlebot3。如果你还没有安装它们,请按照入门教程进行安装。

Tutorial Steps

0- Setup Your Enviroment Variables

在本教程期间,每次打开新终端时,请先运行以下命令:

source /opt/ros/<ros2-distro>/setup.bash
export TURTLEBOT3_MODEL=waffle

将 `<ros2-distro>` 替换为你正在使用的 ROS 2 版本。

1- Launch Turtlebot 3

        你需要启动机器人的界面。

ros2 launch turtlebot3_bringup robot.launch.py  use_sim_time:=False
2- Launch Nav2

        你需要有一个目标环境的地图,可以是事先建立好的,也可以实时使用 SLAM 创建。

        如果感兴趣的话,有一个使用案例教程展示了如何在 SLAM 模式下使用 Nav2。(SLAM)同时建图和导航(SLAM) Navigating While Mapping

所需文件:

  • your-map.map

  • your-map.yaml

        <your_map>.yaml 是我们想要提供给 Nav2 的地图的配置文件。在这种情况下,它包含地图分辨率值、障碍物和自由空间的阈值,以及地图文件的位置。确保这些值是正确的。关于 map.yaml 的更多信息可以在这里找到。

        启动 Nav2。如果你设置了 autostart:=False,你需要在 RViz 中点击“启动”按钮来初始化节点。确保 use_sim time 被设置为 False,因为我们想使用系统时间而不是来自 Gazebo 的仿真时间。

ros2 launch nav2_bringup bringup_launch.py use_sim_time:=False autostart:=False map:=/path/to/your-map.yaml

         请不要忘记将 "/path/to/your-map.yaml" 更改为 your-map.yaml 文件的实际路径。

3- Launch RVIZ

        使用预定义的配置文件启动 RVIZ。

ros2 run rviz2 rviz2 -d $(ros2 pkg prefix nav2_bringup)/share/nav2_bringup/rviz/nav2_default_view.rviz

        现在,你应该能在 RViz 的绘图中心看到 Turtlebot 3 机器人模型的影子。如果你将 auto_start 参数设置为 false,请单击“Start”按钮(左下角)。接着,地图应该会在 RViz 中显示出来。

4- Initialize the Location of Turtlebot 3

        首先,找到地图上机器人的位置。查看机器人在房间中的位置。

        在 RViz 中设置机器人的姿势。点击“2D Pose Estimate”按钮,在地图上指定机器人的位置。绿色箭头的方向表示 Turtlebot 的朝向。

        现在,Turtlebot 的 3D 模型应该会移动到该位置。对于估计位置的小误差是可以容忍的。

5- Send a Goal Pose

        选择地图上 Turtlebot 的目标位置。你可以使用 Nav2 Goal 或 GoalTool 按钮向 Turtlebot 3 发送目标位置和目标方向。

        注意:Nav2 Goal 按钮使用 ROS 2 动作来发送目标,而 GoalTool 则将目标发布到一个主题中。

        一旦你定义了目标姿态,Nav2 将会找到全局路径并开始在地图上导航机器人。

        现在,你可以看到 Turtlebot 3 在房间里朝着目标位置移动。

Overview

        这篇文档介绍了如何在 SLAM 中使用 Nav2。以下步骤向 ROS 2 用户展示了如何生成占用格地图并使用 Nav2 控制其机器人移动。本教程适用于仿真和物理机器人,但此处将在物理机器人上完成。

        在完成本教程之前,强烈建议先完成入门指南 Getting Started ,特别是如果您对 ROS 和 Navigation2 不太熟悉的话。

        在本教程中,我们将使用 SLAM Toolbox。更多信息可以在  ROSCon talk for SLAM Toolbox中找到。

Requirements

您需要安装 Navigation2、Turtlebot3 和 SLAM Toolbox。如果尚未安装,请按照入门指南进行操作。

可以通过以下命令安装 SLAM Toolbox:

sudo apt install ros-<ros2-distro>-slam-toolbox

或者在您的工作区从源代码构建:

git clone -b <ros2-distro>-devel
git@github.com:stevemacenski/slam_toolbox.git

Tutorial Steps

0- Launch Robot Interfaces

        在本教程中,我们将使用 turtlebot3。如果您有其他机器人,请根据您机器人的特定接口进行替换。通常包括 URDF 的机器人状态发布器、模拟或物理机器人接口、控制器、安全节点等。

        在本教程中,每当您打开新的终端时,请首先运行以下命令。

source /opt/ros/<ros2-distro>/setup.bash
export TURTLEBOT3_MODEL=waffle

        启动您的机器人接口和机器人状态发布器。

ros2 launch turtlebot3_bringup robot.launch.py
1- Launch Navigation2

        启动导航时不包括 `nav2_amcl` 和 `nav2_map_server`。这里假设 SLAM 节点会发布到 `/map` 主题并提供 `map->odom` 的转换。(在启动导航时,不会包含 nav2_amclnav2_map_server 这两个节点。这假设的情况是,SLAM 节点将会发布地图到 /map 主题,并提供 map->odom 的转换关系

ros2 launch nav2_bringup navigation_launch.py
2- Launch SLAM

        启动你选择的 SLAM 实现。确保它提供了 `map->odom` 的变换关系和 `/map` 主题。运行 Rviz,并添加你想要可视化的主题,比如 `/map`、`/tf`、`/laserscan` 等。在本教程中,我们将使用 SLAM Toolbox。

ros2 launch slam_toolbox online_async_launch.py
 3- Working with SLAM

        通过RViz或ROS 2命令行请求一个目标来移动你的机器人,例如:

ros2 topic pub /goal_pose geometry_msgs/PoseStamped "{header: {stamp: {sec: 0}, frame_id: 'map'}, pose: {position: {x: 0.2, y: 0.0, z: 0.0}, orientation: {w: 1.0}}}"

        你应该能够实时看到地图更新!要将此地图保存到文件中:

ros2 run nav2_map_server map_saver_cli -f ~/map

4- Getting Started Simplification

        如果你只想在 Turtlebot3 的起步沙盒环境中运行 SLAM,我们也提供了一种简单的方法将 SLAM 作为一个启动配置来启用。你可以继续使用 `tb3_simulation_launch.py`,并将 `slam` 配置设置为 `true`,而不是单独启动接口、导航和 SLAM。我们提供了以上的说明,假设你想在自己的机器人上运行 SLAM,该机器人会有独立的模拟/机器人接口和导航启动文件,而这些文件在 `tb3_simulation_launch.py` 中合并,方便进行简单测试。

       这段描述在解释使用启动配置来启用 SLAM 的方法。它提到如果你只想在 Turtlebot3 起步沙盒环境中进行 SLAM,可以使用 `tb3_simulation_launch.py` 这个启动文件,并将其中的 `slam` 配置设置为 `true`,这样就能直接启动 SLAM,而不必单独启动机器人接口、导航和 SLAM。这个方法是为了方便在特定的模拟环境中进行简单的 SLAM 测试。 

ros2 launch nav2_bringup tb3_simulation_launch.py slam:=True
  1. 准备工作 

    • 设置环境:在新终端中运行source /opt/ros/<ros2-distro>/setup.bashexport TURTLEBOT3_MODEL=waffle

    • 启动机器人接口:使用ros2 launch turtlebot3_bringup robot.launch.py启动机器人的接口和状态发布器。通过 turtlebot3_bringup 包提供的 robot.launch.py 文件,启动机器人的接口和状态发布器。这会启动与 Turtlebot3 通信所需的节点和硬件接口。

  2. 启动 Navigation2

    • 使用ros2 launch nav2_bringup navigation_launch.py启动导航,但不包含 nav2_amclnav2_map_server,假设 SLAM 节点会发布地图到 /map 主题并提供 map->odom 的转换关系。Nav2 是 ROS 2 的导航库,通过 navigation_launch.py 启动,这个库包含了一系列导航相关的节点和算法,它们能够使机器人根据地图实现导航功能。
  3. 启动 SLAM

    • 启动选择的 SLAM 实现,例如使用 SLAM Toolbox,确保它提供 map->odom 的变换关系和 /map 主题。在 Rviz 中添加要可视化的主题,如 /map/tf/laserscan 等。SLAM 是在机器人移动时构建地图并同时定位机器人自身位置的技术。在这里,启动 SLAM 的目的是让机器人能够构建环境地图,并通过生成的地图进行定位。
  4. 使用 SLAM

    • 通过 RViz 或 ROS 2 命令行发送目标位置给机器人,例如:ros2 topic pub /goal_pose geometry_msgs/PoseStamped "{header: {stamp: {sec: 0}, frame_id: 'map'}, pose: {position: {x: 0.2, y: 0.0, z: 0.0}, orientation: {w: 1.0}}}"。这将移动机器人并实时更新地图。
  5. 保存地图

    • 使用 ros2 run nav2_map_server map_saver_cli -f ~/map 将地图保存到文件中。
  6. 简化起步

    • 如果只想在 Turtlebot3 起步沙盒环境中运行 SLAM,可以使用 tb3_simulation_launch.py 启用 SLAM。在该配置中,tb3_simulation_launch.py 合并了模拟/机器人接口和导航启动文件,方便进行简单的 SLAM 测试。使用命令 ros2 launch nav2_bringup tb3_simulation_launch.py slam:=True 启动这个配置。

Overview

        这个教程演示了如何加载和使用外部插件。本示例以时空体素图层( Spatio Temporal Voxel Layer ,STVL)成本地图插件库( pluginlib )插件作为示例。STVL是一个示范性的pluginlib插件,同样的过程也适用于其他成本地图插件以及插件规划器、控制器和行为。

        在完成本教程之前,请查看前两个有关仿真和物理硬件中导航的教程(如果有)。本教程假定您具有导航知识和对成本地图的基本理解。

        对于在2021年12月之前使用Ubuntu 20.04的用户,存在一个与OpenVDB及其二进制文件libjmalloc相关的已知问题。如果你看到类似于“Could not load library LoadLibrary error: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2: cannot allocate memory in static TLS block”的错误,可以通过以下方式解决:export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2,直到OpenVDB发布新的二进制文件。

Costmap2D and STVL              

        Costmap 2D(它是一种二维数据对象,用于将传感器信息(例如激光雷达或深度摄像头)和静态/动态障碍物信息融合成一个栅格化的视图。这个视图代表了机器人周围环境的状态,其中障碍物和可行驶区域被表示为不同的值或层次)是我们用来将传感器信息缓冲成全局视图的数据对象,机器人将使用这个视图来创建路径规划和控制力度。  用于在运行时创建自定义行为。Costmap2D包含的示例pluginlib插件包括障碍物图层、体素图层、静态图层和膨胀图层。

        然而,这些只是基本实现提供的示例插件。Navigation2中Costmap2D的另一个可用的pluginlib插件是STVL。

        STVL的主要作用是处理来自3D传感器(如深度摄像头、声纳、激光雷达等)的数据,并将这些数据转换成稀疏的体积世界模型。这种模型是一种更高维度、更详细地描述机器人周围环境的数据表示方式。它能够在时间上逐渐移除过期的数据,从而使机器人能够在高度动态的环境中更有效地感知和规划路径。

        Navigation2是一个ROS(机器人操作系统)中的导航堆栈,旨在提供机器人导航和路径规划的模块化和可扩展解决方案。Costmap2D是Navigation2中的一个重要组件,用于将传感器信息整合成机器人周围环境的栅格化视图。而pluginlib是ROS中的一个库,允许开发者创建可插拔的模块,以便在运行时灵活地加载和使用这些模块。

        在Navigation2中,Costmap2D使用pluginlib来实现各种功能,其中包括不同类型的图层(如障碍物图层、体素图层、静态图层和膨胀图层)。这些图层插件允许用户根据实际需求定制Costmap2D的行为,例如,某些插件可能负责障碍物检测,另一些可能负责地图的膨胀或者其他特定功能。

        STVL(Semantic Traffic Violation Layer)是Navigation2中提供的另一个Costmap2D的插件,它是为特定目的而设计的,用于检测和处理语义交通违规情况。它可以帮助机器人理解并遵守交通规则,这对于在复杂的环境中安全导航是很重要的。

        因此,Navigation2是一个完整的导航框架,Costmap2D是其中的一个重要组件,而pluginlib则为Costmap2D提供了灵活性,使其可以通过插件来扩展和定制功能。STVL则是Costmap2D的一个特定插件,用于处理语义交通违规情况。这些组件和插件共同构成了ROS中机器人导航中的一部分。

        STVL是另一个类似于体素图层的3D感知插件。有关它如何工作的更详细概述可以在这个存储库中 in this repo找到,但它可以将来自深度摄像头、声纳、激光雷达等的3D数据缓冲到稀疏体积世界模型中,并按比例和基于时间的过期模型逐渐移除体素。这在高度动态的环境中对机器人尤其有用,并且可将3D传感器处理的资源利用率降低最多2倍。STVL也将3D激光雷达和雷达视为一流支持对象。你可以在这个视频中 in this video 找到STVL的ROSCon讲座。

Tutorial Steps

0- Setup

按照“入门指南” Getting Started 中的步骤来安装和设置机器人,用于硬件测试或仿真,根据需要而定。确保安装了ROS 2、Navigation2和Gazebo。

1- Install STVL

STVL可以通过ROS 2的ROS Build Farm进行安装:

sudo apt install ros-<ros2-distro>-spatio-temporal-voxel-layer

你也可以通过将存储库克隆到Navigation2的工作空间并进行源代码构建的方式来安装:

git clone -b <ros2-distro>-devel git@github.com:stevemacenski/spatio_temporal_voxel_layer
 2- Modify Navigation2 Parameter

        STVL是Costmap2D中的一个可选插件,与其他所有插件一样。在Navigation2中,Costmap Plugins会在其各自的costmap内的plugin_names和plugin_types变量中加载。例如,以下代码将分别加载静态图层和障碍物图层插件,分别命名为static_layer和obstacle_layer:

global_costmap:
  global_costmap:
    ros__parameters:
      use_sim_time: True
      plugins: ["static_layer", "obstacle_layer"]
        对于Galactic版本或更新版本,plugin_names和plugin_types已被替换为一个名为plugins的字符串向量,用于存储插件名称。现在,类型被定义在插件中的plugin_name命名空间中(例如,plugin: MyPlugin::Plugin)。代码块中的内联注释将帮助您进行操作指引。

        要加载STVL插件,需要添加一个新的插件名称和类型。例如,如果应用程序需要一个STVL图层而不需要障碍物图层,我们的文件将是这样的:

global_costmap:
  global_costmap:
    ros__parameters:
      use_sim_time: True
      plugins: ["static_layer", "stvl_layer"]

        类似于体素图层,注册完插件后,我们可以在stvl_layer命名空间下添加STVL图层的配置。一个完整描述的STVL配置参数示例如下:

stvl_layer:
  plugin: "spatio_temporal_voxel_layer/SpatioTemporalVoxelLayer"
  enabled: true
  voxel_decay: 15.
  decay_model: 0
  voxel_size: 0.05
  track_unknown_space: true
  unknown_threshold: 15
  mark_threshold: 0
  update_footprint_enabled: true
  combination_method: 1
  origin_z: 0.0
  publish_voxel_map: true
  transform_tolerance: 0.2
  mapping_mode: false
  map_save_duration: 60.0
  observation_sources: pointcloud
  pointcloud:
    data_type: PointCloud2
    topic: /intel_realsense_r200_depth/points
    marking: true
    clearing: true
    obstacle_range: 3.0
    min_obstacle_height: 0.0
    max_obstacle_height: 2.0
    expected_update_rate: 0.0
    observation_persistence: 0.0
    inf_is_valid: false
    filter: "voxel"
    voxel_min_points: 0
    clear_after_reading: true
    max_z: 7.0
    min_z: 0.1
    vertical_fov_angle: 0.8745
    horizontal_fov_angle: 1.048
    decay_acceleration: 15.0
    model_type: 0

        请将上述文本(包括plugin_names和plugin_types的注册)复制粘贴到你的nav2_params.yaml文件中,以在你的应用程序中启用STVL。确保更改本地和全局costmaps的配置。

        注意:其他Navigation2服务器(如规划、行为和控制)的Pluginlib插件可以以相同的方式进行设置。

        这句话的意思是,要在你的应用程序中启用STVL,需要将前面提到的包含plugin_names和plugin_types注册的文本添加到你的nav2_params.yaml文件中。这样做将允许你修改本地和全局costmaps的配置,使得STVL成为导航系统的一部分。

        另外,这段话还指出类似的方法可以用于设置其他Navigation2服务器(如规划、行为和控制)所使用的Pluginlib插件,只需在相应的配置文件中进行类似的更改和注册。这意味着你可以使用相同的方法来配置和激活其他Navigation2模块所需的插件。

3- Launch Navigation2

        按照“入门指南 Getting Started ”中的相同流程,在Gazebo中使用Navigation2启动一个模拟机器人。Navigation2现在使用STVL作为其3D感知成本地图层。

4- RVIZ

        在RViz中打开并设置publish_voxel_map为true后,你可以通过{local, global}_costmap/voxel_grid话题来可视化底层数据结构的3D网格。注意:建议在RViz中将 PointCloud2 的大小设置为你的体素尺寸,将样式设置为盒子 Boxes ,并选择中性颜色以获得最佳可视化效果。

Overview

        这个教程展示了如何使用GPS传感器作为全局定位的数据源,利用robot_localization(RL)进行传感器融合,并使用Nav2来跟随GPS航点。本教程由 Kiwibot 的Pedro Gonzalez编写。

Requirements

        假设已经安装或本地构建了ROS2和Nav2相关的软件包。另外,你还需要安装robot_localization和mapviz:

sudo apt install ros-<ros2-distro>-robot-localization
sudo apt install ros-<ros2-distro>-mapviz
sudo apt install ros-<ros2-distro>-mapviz-plugins
sudo apt install ros-<ros2-distro>-tile-map

        robot_localization是一个ROS包,用于多传感器数据融合和机器人定位。它能够将来自多个传感器(如IMU、GPS、里程计等)的数据进行融合,提供更准确和鲁棒的机器人定位。

        这个软件包使用扩展卡尔曼滤波器(EKF)或累积器进行传感器数据的融合。通过结合来自不同传感器的信息,它能够解决单个传感器可能存在的误差、不确定性或漂移问题,从而提高机器人的定位精度和稳定性。

        robot_localization对于需要高精度定位的机器人应用非常有用,特别是在需要在复杂环境中进行导航或需要对机器人位置进行精确控制的情况下。

        这个教程的代码托管在`nav2_gps_waypoint_follower_demo`上。尽管我们将介绍设置的最重要步骤,但强烈建议在设置开发环境时克隆并构建这个软件包。

GPS Localization Overview

        GPS(全球定位系统)或更广义地说是GNSS(全球导航卫星系统),是一种依赖卫星提供接收器所处地球位置估计的技术。这些卫星在大约20,000公里的轨道上运行,并使用射频不断广播时间信号,当卫星在视线范围内时,接收器接收到这些信号,并使用三边测量法来估计它们的纬度、经度和海拔高度。

        通常,GPS设备使用WGS84标准来计算它们的位置,这个标准定义了一个笛卡尔坐标系,其原点位于地球质心,z轴指向北方,x轴指向第一个子午线,如下图所示。

        然而,这个参考系统对描述运动和表示地球表面上或接近地球表面的物体周围的环境来说并不实用:想象一下,你的机器人位于一个足球场上,你希望它从一端移动到另一端,你的导航任务可能是这样的:

“go from X=4789.413km, Y=177.511km z=4194.292km to X=4789.475km, Y=177.553km z=4194.22km”

        另外,如果你的机器人例如装备有二维激光雷达,你也需要将其数据转换到这个参考系统中。创建一个局部参考系统会更有意义,这样你可以告诉你的机器人“向前移动100米”,然后你的传感器数据可以相应地填充你的环境表示,对吗?

        为了解决这个问题,大地测量学提出了几种针对地球表面定位的平面投影系统。其中之一是UTM坐标系统UTM coordinate system,它假设地球是一个椭球体,并将其划分为60个区域,每个区域跨越6经度度。一个区域表示椭球体表面在与其中央子午线平行的割线圆柱上的投影;然后每个区域分成20个纬度带,跨越8纬度度,这些带创建了局部网格区域,其中位置使用来自该区域原点的平面坐标表示。下图显示了横跨南美洲的网格区域。

        robot_localization使用这个投影系统将WGS84参考系统中的GPS测量值转换为笛卡尔坐标系,该坐标系以GPS所在网格区域的原点为中心。这是通过navsat_transform节点实现的。该节点符合REP 103中的ENU约定,即UTM坐标系统的+x轴朝东,+y轴朝北,+z轴向上。

        在现实世界中,GPS传感器可能存在噪声:使用独立GPS设备时,在良好条件下预期精度为1-2米,最多可达10米,在GPS传感器捕获到更少或更多卫星时,位置可能会频繁跳跃,这会显著降低导航质量。存在多种定位增强技术来减少GPS测量误差,其中最常见的之一称为RTK(实时差分定位),它可以将接收器的精度提高到1厘米。如果在你的应用程序中精度很重要,强烈推荐使用这项技术;但这需要部署第二个称为基站的固定GPS,大部分美国和欧洲已经覆盖有免费公共基站,你可以连接使用。你可以在这里了解更多关于RTK的信息和入门指南。在本教程中,我们假设机器人的GPS能够准确、平稳地估计机器人的位置。

此外,要完整描述机器人的定位,我们还需要知道其方向,但独立的GPS传感器不提供方向测量,只提供位置测量。在本教程中,我们将“绝对方向”指代相对于基准方向(例如,东方)给出的偏航测量,与相对方向相对,后者是相对于机器人转向或任何无法直接映射到基准方向的参考而给出的。

        当使用robot_localization和GPS时,测量绝对方向是强制性的。有几种获取绝对方向数据的策略,比如带有磁力计的IMU、双GPS系统或在已知地图上进行匹配技术;在本教程中,我们假设机器人配备了一个可以按照ENU约定准确测量绝对方向的IMU,这意味着当机器人朝东时,其输出为零偏航角,朝北时为+90度。

尽管有以上假设,在实际机器人中使用的商业级IMU通常不会产生准确的绝对方向测量,因为:

- 它们可能没有磁力计。
- 它们很难校准:户外机器人通常体积大且重量重:想象一下用自动拖拉机在空中绕8字形运动。
- 机器人可能是磁力计的巨大干扰源:电动机充满永久磁铁并且可能吸引数安培电流,对传感器产生明显干扰。

因此,对于特定的应用,你应该考虑在决定如何估计绝对方向时所需的行为和定位质量。当使用没有相对于基准方向的IMU时,机器人可能需要进行一段时间的移动以收敛到正确的方向使用滤波器。使用双GPS或3D地图系统叠加,初始方向是相当好的。

对于本教程的目的,我们模拟了一个拥有绝对方向的IMU的良好建模系统,但在实际系统中可能会使用上述技术之一(或其他技术)进行增强或替代。

这一部分以后继续!对目前的项目没有帮助

这一部分以后继续!对目前的项目没有帮助

这一部分以后继续!对目前的项目没有帮助

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值