标扫地机用ROS吗?不用ROS用什么?2024第六拆来了

大家好,我是心情不好烧块板,心情好了烧块板,一共烧了两块板的小鱼。不信请看!
图片

昨天偷了个懒,继续书接上回(扫地机器人的密码居然放抽纸里?2024第五拆来了)。

登录之后,第一步看看自己在哪个目录

pwd 命令安排

Last login: Thu Jan 11 22:34:26 CST 2024 on ttyS0
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.4.39 armv7l)


 * Documentation:  https://help.ubuntu.com/
root@rockrobo:~# pwd
/root

返回 /root

看看这个目录下有什么

root@rockrobo:~# ls
root@rockrobo:~#

啥都没有,root 空荡荡,程序在哪里?

这个机器人是开机自启动的

so ?

看看当前系统有那些进程不就知道了

安排

root@rockrobo:~# ps -ax
  PID TTY      STAT   TIME COMMAND
   59 ?        S<     0:00 [lds_motor_workq]
   67 ?        S      0:00 [auto_cpu_hotplu]
   68 ?        S<     0:00 [wifi_led]
  514 ?        Ss     0:00 /bin/bash /usr/bin/logrotate.sh
  719 ?        S<Lsl   0:01 WatchDoge /opt/rockrobo/watchdog
  227 ?        S      0:00 upstart-udev-bridge --daemon
  767 ?        S      0:00 upstart-file-bridge --daemon
  770 ?        S      0:00 upstart-socket-bridge --daemon
  791 ?        S<sl   0:02 rrlogd /opt/rockrobo/rrlog/rrlog.conf
  819 ?        S<     0:00 /bin/bash /opt/rockrobo/rrlog/toprotation.sh
  830 ?        S<sl   0:02 player /opt/rockrobo/cleaner/conf/ruby_chassis.cfg
  890 ?        S<sl   0:00 RoboController
  893 ?        S<sl   0:00 AppProxy
  895 ?        S<sl   0:00 wlanmgr
  901 ?        S<sl   0:00 miio_client -d /mnt/data/miio/ -l 2
 1110 ?        S<s    0:00 /sbin/wpa_supplicant -s -B -P /var/run/wpa_supplicant
 1167 ?        S<s    0:00 /bin/bash /opt/rockrobo/miio/miio_client_helper_nomqt
...

当然上面只是一部分,小鱼删掉了很多看起来不重要的

简单分析下

这个扫地机器人可以通过米家 app 进行操控,所以肯定有和小米有关的进程

901 ?        S<sl   0:00 miio_client -d /mnt/data/miio/ -l 2
 1167 ?        S<s    0:00 /bin/bash /opt/rockrobo/miio/miio_client_helper_nomqt

miio 听起来像吃的,了解米家接入流程的小伙伴,欢迎留言介绍下这两个东西

图片

机器人日志管理很重要,这两个就是和日志有关的进程

791 ?        S<sl   0:02 rrlogd /opt/rockrobo/rrlog/rrlog.conf
  514 ?        Ss     0:00 /bin/bash /usr/bin/logrotate.sh

rrlog = rockrobo+log ? 这种命名方式 logrotate 这个一看就是循环日志了,毕竟只有 4G 的存储,又搞成三四个系统,日志必须循环利用(删掉最旧的,保留最新的,不断循环)

图片

机器人要保证进程意外退出可以重新启动,放只狗最好不过了

看门狗安排

719 ?        S<Lsl   0:01 WatchDoge /opt/rockrobo/watchdog

接着就到重点了,我们来看看这个系统有没有用 ROS

如果用了,版本应该是 Ubuntu14 对应的 indigo

怎么确认有没有用 ROS 呢?

很简单,全局搜索有没有 roscore 这个文件,ROS1 肯定有 roscore

安排

root@rockrobo:~# find / -type f -name '*roscore*'
root@rockrobo:~#

从结果可以看出来,并没有用

这里理所当然,毕竟系统空间和内存就那么大一点

紧接着第二个问题就来了,不用 ROS 用什么?

这个问题问的真的是好上加好

先找到程序文件在哪里再说

根据刚刚查看系统进程的提示,所有的文件目录好像都指向了这个文件夹 /opt/rockrobo/

比如看门狗就在 /opt/rockrobo/watchdog

进去看看

root@rockrobo:~# cd /opt/rockrobo/
root@rockrobo:/opt/rockrobo# pwd
/opt/rockrobo
root@rockrobo:/opt/rockrobo# ls
buildnumber  firmware  miio       rr-release  scripts  watchdog
cleaner      logs      resources  rrlog       sys      wlan

是这里没跑了

buildnumber 应该是构建时间等信息

打开看看

root@rockrobo:/opt/rockrobo# cat buildnumber 
2021010900REL

20210109 应该是时间

00 应该是次数之类的

REL 应该就代表 RELEASE 表示发行版本(在发行版本前,还会有 Debug 之类的测试版本)

没想到吧,这个固件是 2021 年构建的,而这个系统是 2014 的 Ubuntu

祖传系统,真滴香啊~

继续看,还有一个版本编号

root@rockrobo:/opt/rockrobo# cat rr-release 
ROCKROBO_VERSION=3.5.8_004028

小鱼差点在文件的海洋迷失自我,忘记自己来干嘛的了

对了,看看不用 ROS 做通信框架,会用什么?

可是还有很多目录没看,回头再说吧

从目录名字推断 cleaner 应该是和自动清扫相关的

进去看看

root@rockrobo:/opt/rockrobo/cleaner# ls
bin  conf  lib  misc

四个目录,要说看通信,当然要看看库(通信肯定要用通信库了)

进到 lib 目录看一看

root@rockrobo:/opt/rockrobo/cleaner/lib# ls
libNavDriver.so      libpkginfoapi.so    libplayerdrivers.so    libplayerutil.so    librrlocale.so           librubysupport.so
libblcommon.so       libplayerc++.so     libplayerinterface.so  libplayerwkb.so     librrlog.so              libuart_api.so
libcares.so.2        libplayerc.so       libplayerjpeg.so       libroboipc.so       librrslamdrv.so          libuart_api.so.3
libcares.so.2.1.0    libplayercommon.so  libplayertcp.so        librrcurl.so.4      librubycompassdriver.so  libuart_api.so.3.2.1
libchassisdriver.so  libplayercore.so    libplayerudp.so        librrcurl.so.4.3.0  librubylaserdriver.so

好多呀

看到几个关键的

比如:

导航 libNavDriver.so

雷达驱动 librubylaserdriver.so

Slam建图定位 librrslamdrv.so

串口通讯 libuart_api.so

罗盘?IMU librubycompassdriver.so

日志记录 librrlog.so

关于通信,这里的库挺多,串口,TCP, UDP,IPC

不过小鱼觉得对于机器人本体通信,肯定是用 IPC

什么是 IPC 呢?

小鱼介绍下

IPC(Inter-Process Communication)就是进程间通信

IPC 是一系列面向多线程间数据交换的技术集合。IPC 技术的方法被分为:消息发送、同步、内存共享和远程过程调用(RPC)这几方面功能。IPC 技术使得进程间可以交换信息,同步数据,共享资源。

那基本就搞清楚了,原来是用 IPC 进行代替 ROS 的功能

那这个 libroboipc.so 到底提供哪些功能呢?

反汇编下试试?试试就试试

先用 nm 试试, 结果没装

emmm

装一下,既然是 Ubuntu ,先 update 一下

root@rockrobo:~# apt update
Hit http://ppa.launchpad.net trusty InRelease                                  
Hit http://ppa.launchpad.net trusty/main armhf Packages        
Hit http://ppa.launchpad.net trusty/main Translation-en                        
Ign http://us.ports.ubuntu.com trusty InRelease                 
Hit http://us.ports.ubuntu.com trusty-updates InRelease
Hit http://us.ports.ubuntu.com trusty-security InRelease                       
Hit http://us.ports.ubuntu.com trusty Release.gpg                              
Hit http://us.ports.ubuntu.com trusty-updates/main Sources                     
Hit http://us.ports.ubuntu.com trusty-updates/restricted Sources               
Hit http://us.ports.ubuntu.com trusty-updates/main armhf Packages              
Hit http://us.ports.ubuntu.com trusty-updates/restricted armhf Packages        
Hit http://us.ports.ubuntu.com trusty-updates/main Translation-en              
Hit http://us.ports.ubuntu.com trusty-updates/restricted Translation-en        
Hit http://us.ports.ubuntu.com trusty-security/main Sources                    
Hit http://us.ports.ubuntu.com trusty-security/restricted Sources              
Hit http://us.ports.ubuntu.com trusty-security/main armhf Packages             
Hit http://us.ports.ubuntu.com trusty-security/restricted armhf Packages       
Hit http://us.ports.ubuntu.com trusty-security/main Translation-en             
Hit http://us.ports.ubuntu.com trusty-security/restricted Translation-en       
Hit http://us.ports.ubuntu.com trusty Release                                  
Hit http://us.ports.ubuntu.com trusty/main Sources                             
Hit http://us.ports.ubuntu.com trusty/restricted Sources                       
Hit http://us.ports.ubuntu.com trusty/main armhf Packages                      
Hit http://us.ports.ubuntu.com trusty/restricted armhf Packages                
Hit http://us.ports.ubuntu.com trusty/multiverse armhf Packages                
Hit http://us.ports.ubuntu.com trusty/universe armhf Packages                  
Hit http://us.ports.ubuntu.com trusty/main Translation-en                      
Hit http://us.ports.ubuntu.com trusty/multiverse Translation-en                
Hit http://us.ports.ubuntu.com trusty/restricted Translation-en                
Hit http://us.ports.ubuntu.com trusty/universe Translation-en                  
Reading package lists... Done                                                  
W: Ignoring Provides line with DepCompareOp for package gdb-minimal
W: You may want to run apt-get update to correct these problems

真的可以,接着 apt 安装试试

root@rockrobo:~# sudo apt-get install binutils
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  binutils-doc
The following NEW packages will be installed:
  binutils
0 upgraded, 1 newly installed, 0 to remove and 122 not upgraded.
Need to get 2006 kB of archives.
After this operation, 8114 kB of additional disk space will be used.
Get:1 http://us.ports.ubuntu.com/ubuntu-ports/ trusty-updates/main binutils armhf 2.24-5ubuntu14.2 [2006 kB]
Fetched 2006 kB in 12s (167 kB/s)                                              
Selecting previously unselected package binutils.
(Reading database ... 15018 files and directories currently installed.)
Preparing to unpack .../binutils_2.24-5ubuntu14.2_armhf.deb ...
Unpacking binutils (2.24-5ubuntu14.2) ...
Setting up binutils (2.24-5ubuntu14.2) ...
Processing triggers for libc-bin (2.19-0ubuntu6.6) ...

安装完成!

测试下,对了, 先介绍下 nm 命令吧

nm 是 Linux 下的一个强大的文本分析工具,主要用于列出指定文件中的符号(如常用的函数名、全局变量等)。这个命令通常用于检查和分析二进制文件、库文件和可执行文件中的符号表。

nm上 (有点长,心疼一下手指头)

nm -D libroboipc.so 
         U __aeabi_atexit@CXXABI_ARM_1.3.3
         U __aeabi_unwind_cpp_pr0@GCC_3.5
         U __aeabi_unwind_cpp_pr1@GCC_3.5
0001aba8 B __bss_end__
0001aba8 B _bss_end__
0001a6fc B __bss_start
0001a6fc B __bss_start__
         U calloc@GLIBC_2.4
         U clock_gettime@GLIBC_2.4
         U close@GLIBC_2.4
000058d9 T CloseSharedRegion
000068c9 T CompletePacket
0000577d T CreateSharedRegion
         U __cxa_begin_catch@CXXABI_1.3
         U __cxa_end_catch@CXXABI_1.3
         U __cxa_end_cleanup@CXXABI_1.3
         w __cxa_finalize@GLIBC_2.4
         U __cxa_rethrow@CXXABI_1.3
00004f55 T DecodeMessage
00005939 T DestroySharedRegion
0001a268 D dpIPCSettings
0001a6fc D _edata
0001aba8 B __end__
0001aba8 B _end
         U __errno_location@GLIBC_2.4
         U fclose@GLIBC_2.4
         U fcntl@GLIBC_2.4
00007520 T _fini
00005705 T FlushSharedRegion
         U fopen@GLIBC_2.4
         U __fprintf_chk@GLIBC_2.4
         U fread@GLIBC_2.4
         U free@GLIBC_2.4
         U ftruncate@GLIBC_2.4
0001a94c B g_Channels
         U getpid@GLIBC_2.4
0000566d T GetSharedRegion
0001a724 B g_FailureCount
0001a948 B g_hAnyArrived
0001a918 B g_hOneArrived
0001ab90 B g_mapCompleteEcho
         w __gmon_start__
0001a90c B g_mtxQueue
0001a908 B g_mtxSeqGen
0001a48c D g_ProcMatrix
0001a910 B g_RecvThread
0001a914 B g_RecvType
0001a234 D g_rgnProcessAbbr
0001a728 B g_rgnQueue
         U __gxx_personality_v0@CXXABI_1.3
000023fc T _init
         U _IO_putc@GLIBC_2.4
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
         w _Jv_RegisterClasses
         U malloc@GLIBC_2.4
         U memcpy@GLIBC_2.4
         U memmove@GLIBC_2.4
         U memset@GLIBC_2.4
         U mmap@GLIBC_2.4
         U msync@GLIBC_2.4
         U munmap@GLIBC_2.4
         U open@GLIBC_2.4
         U __open_2@GLIBC_2.7
00005841 T OpenSharedRegion
000051c5 T pLogPrint
         U poll@GLIBC_2.4
         U __printf_chk@GLIBC_2.4
         U pthread_cancel@GLIBC_2.4
         U pthread_cond_destroy@GLIBC_2.4
         U pthread_cond_init@GLIBC_2.4
         U pthread_cond_signal@GLIBC_2.4
         U pthread_cond_timedwait@GLIBC_2.4
         U pthread_cond_wait@GLIBC_2.4
         U pthread_create@GLIBC_2.4
         U pthread_detach@GLIBC_2.4
         U pthread_mutex_destroy@GLIBC_2.4
         U pthread_mutex_init@GLIBC_2.4
         U pthread_mutex_lock@GLIBC_2.4
         U pthread_mutex_unlock@GLIBC_2.4
         U pthread_self@GLIBC_2.4
         U puts@GLIBC_2.4
         U read@GLIBC_2.4
000044ad T RecvPacket
000046c1 T RecvPacketEx
0000571d T ReleaseSharedRegion
000059e1 T ScGetEnter
00005a95 T ScGetLeave
00005999 T ScGetState
00005a4d T ScSetEnter
00005b01 T ScSetLeave
00003ba9 T SendPacket
00006b25 T SendPacketEx
         U shm_open@GLIBC_2.4
         U shm_unlink@GLIBC_2.4
         U sigaction@GLIBC_2.4
         U __snprintf_chk@GLIBC_2.4
         U __sprintf_chk@GLIBC_2.4
         U __stack_chk_fail@GLIBC_2.4
         U __stack_chk_guard@GLIBC_2.4
         U stderr@GLIBC_2.4
         U stdout@GLIBC_2.4
         U strcpy@GLIBC_2.4
         U strlen@GLIBC_2.4
         U strncmp@GLIBC_2.4
         U strncpy@GLIBC_2.4
         U syscall@GLIBC_2.4
         U time@GLIBC_2.4
         U __vsnprintf_chk@GLIBC_2.4
         U write@GLIBC_2.4
00005f1d T _Z10RRSetEventPv
00005d05 T _Z11RRWaitEventPvi
00003935 T _Z12DoInitializePKc
000050b5 T _Z12GetProcIndexPKc
00003609 T _Z12pChannelOpen16ProcessAbbrIndexS_
000034c1 T _Z12pChannelReadPvS_ji
000051ad T _Z12ProcAbToName16ProcessAbbrIndex
00005c51 T _Z12RRCloseEventPv
00005fd1 T _Z12RRResetEventPv
000038d9 T _Z13pChannelClosePv
000032ed T _Z13pChannelWritePvS_ji
00003c75 T _Z13pDoRecvPacket10ModuleID_tP8Packet_t
00003b35 T _Z13pDoSendPacketP8Packet_tP13SendOptions_t
00005b49 T _Z13RRCreateEventbbPKc
00003a71 T _Z14DoUninitializePKc
000031f9 T _Z14pIgnoreSIGPIPE16ProcessAbbrIndex
000031b5 T _Z14pModIdToProcAb10ModuleID_t
00006511 T _Z14RRSetSemaphorePv
00007201 T _Z15pHandleEchoExit16ProcessAbbrIndex
00006215 T _Z15RRWaitSemaphorePvi
000048b9 T _Z16pContentToStringj
0000615d T _Z16RRCloseSemaphorePv
0000661d T _Z16RRResetSemaphorePv
00007071 T _Z17ASyncWaiterThreadPv
00005609 T _Z17pSharedRegionSyncPvb
0000602d T _Z17RRCreateSemaphorebbPKc
00004061 T _Z18pPostProcessPacketP8Packet_t
0000353d T _Z19GetProcessNameByPidiPc
00005289 T _Z19pSharedRegionCreatePKcjb
0000549d T _Z20pSharedRegionDestroyPvb
000032a5 T _Z21GetNextSequenceNumberP8Packet_t
000069cd T _Z21pHandleEchoCompletionP20EchoResponseInternal
00006a61 T _Z22CompletionContainerAddjPv
00006895 T _Z23CompletionContainerLockv
000068b5 T _Z23CompletionContainerSizev
000055b1 T _Z23pSharedRegionGetAddressPv
000066b1 T _Z25CompletionContainerCreatev
00007039 T _Z25CompletionContainerRemovej
000068a5 T _Z25CompletionContainerUnlockv
00006709 T _Z26CompletionContainerDestroyv
00006809 T _Z27CompletionContainerRetrievej
000071dd T _Z36CompletionContainerRemoveWithoutLockj
00002be5 T _Z7DllInitv
000029a5 T _Z9DllUninitv
         U _ZdlPv@GLIBCXX_3.4
00005001 W _ZNSt11_Deque_baseIP8Packet_tSaIS1_EE17_M_initialize_mapEj
00004fd9 W _ZNSt11_Deque_baseIP8Packet_tSaIS1_EED1Ev
00004fd9 W _ZNSt11_Deque_baseIP8Packet_tSaIS1_EED2Ev
00007435 W _ZNSt3mapIjPvSt4lessIjESaISt4pairIKjS0_EEED1Ev
00007435 W _ZNSt3mapIjPvSt4lessIjESaISt4pairIKjS0_EEED2Ev
00007369 W _ZNSt8_Rb_treeIjSt4pairIKjPvESt10_Select1stIS3_ESt4lessIjESaIS3_EE16_M_insert_uniqueERKS3_
00007445 W _ZNSt8_Rb_treeIjSt4pairIKjPvESt10_Select1stIS3_ESt4lessIjESaIS3_EE5eraseERS1_
00007411 W _ZNSt8_Rb_treeIjSt4pairIKjPvESt10_Select1stIS3_ESt4lessIjESaIS3_EE8_M_eraseEPSt13_Rb_tree_nodeIS3_E
         U _Znwj@GLIBCXX_3.4
         U _ZSt17__throw_bad_allocv@GLIBCXX_3.4
         U _ZSt18_Rb_tree_decrementPSt18_Rb_tree_node_base@GLIBCXX_3.4
         U _ZSt18_Rb_tree_incrementPKSt18_Rb_tree_node_base@GLIBCXX_3.4
         U _ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base@GLIBCXX_3.4
         U _ZSt28_Rb_tree_rebalance_for_erasePSt18_Rb_tree_node_baseRS_@GLIBCXX_3.4
         U _ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_@GLIBCXX_3.4

开始分析前先看看基本指令介绍,每一行的中间都有一个符号 T G B W U 之类的,分别代表的意思是什么?

简单理解:T 大概率是函数 U 大概率是别的文件里的函数 B 大概率是没有初始化的全局变量 D 初始化的变量

去掉一些乱七八糟的,提取重要的内容

函数,主要这些

000058d9 T CloseSharedRegion
000068c9 T CompletePacket
0000577d T CreateSharedRegion
00004f55 T DecodeMessage
00005939 T DestroySharedRegion
00005705 T FlushSharedRegion
0000566d T GetSharedRegion
00005841 T OpenSharedRegion
000051c5 T pLogPrint
000044ad T RecvPacket
000046c1 T RecvPacketEx
0000571d T ReleaseSharedRegion
000059e1 T ScGetEnter
00005a95 T ScGetLeave
00005999 T ScGetState
00005a4d T ScSetEnter
00005b01 T ScSetLeave
00003ba9 T SendPacket
00006b25 T SendPacketEx

初始化的变量

0001a268 D dpIPCSettings
0001a6fc D _edata
0001a48c D g_ProcMatrix
0001a234 D g_rgnProcessAbbr

按照一般的逻辑,数据收发一般都有打包和拆包的过程,这个 IPC 应该也差不多

用 GPT 帮忙简单分析下每个函数和变量的的作用,供大家参考一下(往右滑可以看到完整内容)

打开共享区域(OpenSharedRegion):该函数用于打开一个已存在的共享内存区域。它可能涉及到一些权限检查和初始化操作,以确保共享内存的安全使用。
创建共享区域(CreateSharedRegion):此函数用于创建一个新的共享内存区域。它需要指定共享内存的大小和其他相关参数,如权限标志等。
关闭共享区域(CloseSharedRegion):当使用完共享内存后,应该调用此函数来关闭共享区域并释放相关资源。
获取共享区域(GetSharedRegion):此函数用于获取一个指向共享内存区域的指针,以便进行读写操作。
释放共享区域(ReleaseSharedRegion):在完成对共享内存的使用后,应该调用此函数来释放资源并确保共享内存的安全关闭。
清除共享区域(FlushSharedRegion):此函数可能用于清除或重置共享内存区域的内容,以便重新使用或进行其他操作。
发送和接收数据包(SendPacket, RecvPacket, SendPacketEx, RecvPacketEx):这些函数用于在进程之间通过共享内存传递数据。发送函数将数据写入共享内存,而接收函数从共享内存读取数据。
状态和控制操作(ScGetEnter, ScGetLeave, ScGetState, ScSetEnter, ScSetLeave):这些函数可能用于获取和控制共享内存区域的访问状态,如同步、互斥等,以确保多个进程之间的正确通信和同步。
日志输出(pLogPrint):此函数可能用于输出日志信息,以便在调试或跟踪程序时记录相关信息。
解码消息(DecodeMessage):此函数可能用于解析从共享内存接收到的数据包,将其转换为可读的格式或执行相关操作。
完成数据包(CompletePacket):此函数可能用于标记数据包的完成或处理,以便在发送或接收过程中进行状态管理。初始化变量 dpIPCSettings 可能是一个配置或设置结构体,用于配置共享内存库的行为和参数。_edata 和 g_ProcMatrix 可能与进程间通信的逻辑或状态有关。g_rgnProcessAbbr 可能是一个用于标识或命名共享内存区域的字符串数组或映射。

这里的 Region 可以理解为一个内存块~

需要传输数据就把数据放到这个内存块上,接收者就从这里读就好,这样就不存在数据拷贝

两个字 搞笑!不对,是高效!

ROS2 里也有 SHM(共享内存)对应的实现方法,速度是很快滴,前几天在群里看到小伙伴问传输大量点云用 ROS 2 很慢

当然慢,毕竟默认是走 Socket

那怎么使用 SHM,小鱼的新书里有写哦,等发布了买一本就知道了

继续拆机

用串口来看文件太慢,小鱼准备开启 SSH 将机器人的文件都拷贝出来,在电脑上慢慢欣赏

BUT,SSH 居然连不通

fishros@fishros-KLVC-WXX9:~$ ssh root@192.168.31.103
ssh: connect to host 192.168.31.103 port 22: Connection timed out

明明已经安装和开启了

root@rockrobo:~# service ssh status
ssh start/running, process 1289

怎么肥事?下期揭晓!

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值