当前位置: 首页 > news >正文

桂平市住房和城乡建设局门户网站深圳保障房

桂平市住房和城乡建设局门户网站,深圳保障房,楼盘建设信息网站,网站可以随便创建么我们知道在ROS中#xff0c;由很多互不相干的节点组成了一个复杂的系统#xff0c;单个的节点看起来是没起什么作用#xff0c;但是节点之间进行了通信之后#xff0c;相互之间能够交互信息和数据的时候#xff0c;就变得很有意思了。 节点之间进行通信的一个常用方法就是…我们知道在ROS中由很多互不相干的节点组成了一个复杂的系统单个的节点看起来是没起什么作用但是节点之间进行了通信之后相互之间能够交互信息和数据的时候就变得很有意思了。 节点之间进行通信的一个常用方法就是使用话题(topic)话题表示的是一个定义了类型的消息流比方说摄像机产生的数据可能就会被发送到一个叫做image的话题上类型是Image的图片类型。 1、话题概述 话题是一种通过发布(publish)与订阅(subscribe)进行通信的机制这在分布式系统中是一种很常见的数据交换方式节点在发送数据到话题上之前需要先声明(advertise)话题名和消息类型然后与roscore建立一个连接roscore将共享它的订阅者与分享者列表接着就可以发布数据到这个话题上了。对于想要从话题上接收消息的节点来说需要通过向roscore发出请求来订阅这个话题订阅之后该话题上所有的消息都会被转发到这个请求的节点上这样发布者跟订阅者就建立起了直接的连接。 它们之间的连接在 Ubuntu18.04版本安装ROS及出现错误的处理方法 这篇文章里面有更详细地讲解有兴趣的可以去了解下。 需要注意的是同一个话题上的所有消息必须是同一类型的。另外话题的名字最好是能够体现发送的是什么消息比方说在PR2机器人上面 /wide_stereo/right/image_color 的这个话题可以直观的了解到发送的右边相机的彩色图像数据。 2、话题声明 2.1、准备工作 在声明话题之前需要先有一个工作区对于初次接触的朋友更多初始化工作区与包的详细操作可以查阅ROS新建工作区(workspace)与包(package)编译的实践(C示例) 我们创建一个test包 catkin_create_pkg test rospy 接着在src目录里面新建一个topic_publisher.py文件代码如下 import rospy from std_msgs.msg import Int32 # ROS标准消息包rospy.init_node(topic_publisher) # 初始化节点 pub rospy.Publisher(counter,Int32) # 发布前先声明话题名称与消息类型 rate rospy.Rate(2) # 速率(Hz) count 0 while not rospy.is_shutdown():pub.publish(count)count 1rate.sleep() 代码很好理解初始化节点和声明话题然后就是在rospy没有关闭前每秒钟发布2次数据其中rate.sleep()就是休息指定频率的间隔时间。 由于我们需要运行这个文件所以需要能够执行的权限 chmod ux topic_publisher.py 查看下文件可以看到有了可执行权限(-rwxrw-r--) ls -l topic_publisher.py 我们从from std_msgs.msg import Int32可以知道有了一个标准消息包std_msgs所以我们需要告诉ROS的构建系统在package.xml文件里面添加依赖项(dependency) cd ~/catkin_ws/src/test gpedit package.xml depend packagestd_msgs / 添加了依赖项之后来到工作区根目录进行编译  cd ~/catkin_ws catkin_make 这样就将test包以及话题发布的Python文件构建好了。 2.2、发布话题 前面有介绍这个rostopic话题命令的使用在使用命令前先启动节点管理器roscore直接输入roscore命令回车即可 重新开一个终端运行这个节点 rosrun test topic_publisher.py 出现错误 import-im6.q16: not authorized rospy error/constitute.c/WriteImage/1037. from: cant read /var/mail/std_msgs.msg /home/yahboom/catkin_ws/src/test/src/topic_publisher.py: line 4: syntax error near unexpected token topic_publisher /home/yahboom/catkin_ws/src/test/src/topic_publisher.py: line 4: rospy.init_node(topic_publisher) 看起来上面Python的代码有误是没有被授权的意思实质是没有指定解释器这里需要告知ROS系统这是一个Python文件 cd ~/catkin_ws/src/test/src gedit topic_publisher.py 在代码最上面添加#!/usr/bin/env python 然后再次运行命令即可 rosrun test topic_publisher.py 我们来看下rostopic在测试和维护当中会经常使用到的命令的用法。 2.2.1、rostopic list 再开一个终端输入命令rostopic list可以看到多出了一个counter话题 /counter /rosout /rosout_agg 查看话题上面发布的消息rostopic echo counter -n 5 data: 527 --- data: 528 --- data: 529 --- data: 530 --- data: 531 如果不加-n 5就是一直打印下去直到按下CtrlC终止 2.2.2、rostopic hz 检验它是否按照我们期望的速率来发布消息 rostopic hz counter subscribed to [/counter] average rate: 2.003     min: 0.499s max: 0.499s std dev: 0.00000s window: 2 average rate: 1.997     min: 0.499s max: 0.502s std dev: 0.00098s window: 4 average rate: 2.000     min: 0.498s max: 0.502s std dev: 0.00140s window: 6 average rate: 2.000     min: 0.498s max: 0.502s std dev: 0.00118s window: 8 2.2.3、rostopic info 查看已声明的话题rostopic info counter Type: std_msgs/Int32 Publishers:   * /topic_publisher (http://YAB:45599/) Subscribers: None 这表明counter话题承载的类型是std_msgs/Int32并且由topic_publisher声明运行在YAB主机上并且通过TCP端口45599来通信Subscribers: None表示当前还没有订阅者。 2.2.4、rostopic find 通过类型查询所有话题rostopic find std_msgs/Int32 /counter 类型需要给出包名(std_msgs)/消息类型(Int32) 更多rostopic命令的用法可以查看帮助rostopic -h rostopic is a command-line tool for printing information about ROS Topics. Commands:     rostopic bw    display bandwidth used by topic 显示按话题使用的带宽     rostopic delay    display delay of topic from timestamp in header 显示标题中时间戳的话题延迟     rostopic echo    print messages to screen 将消息打印到屏幕     rostopic find    find topics by type 按类型查找话题     rostopic hz    display publishing rate of topic 显示话题的发布频率     rostopic info    print information about active topic 打印有关活动话题的信息     rostopic list    list active topics 列出活动话题     rostopic pub    publish data to topic 向话题发布数据     rostopic type    print topic or field type 打印话题或字段类型 Type rostopic command -h for more detailed usage, e.g. rostopic echo -h 3、订阅话题 有了发布话题之后现在来写一个订阅的话题topic_subscriber.py代码如下 #!/usr/bin/env python import rospy from std_msgs.msg import Int32 # ROS标准消息包# 定义个回调函数 def callback(msg):print(msg.data)rospy.init_node(topic_subscriber) # 初始化节点 pub rospy.Subscriber(counter,Int32,callback) # 多一个回调函数 rospy.spin() 代码可以看到大同小异关键区别在于订阅的代码使用了回调函数因为ROS是一个事件驱动的系统所以在ROS中将会看到大量使用回调函数。这里的订阅只要每次有消息来时就会调用相应的回调函数并使用接收到的消息作为它的参数。这里使用rospy.spin()将程序的运行交给ROS避免使用上面发布话题中的while循环的一种捷径ROS并不是必须要接管程序的主线程。 同样的这个文件因为要去执行它所以添加一个可执行权限chmod ux topic_subscriber.py rosrun test topic_subscriber.py 850 851 852 853 854 855 ... 可以正常的接收到发布者发布的消息。然后我们使用可视化工具rqt_graph来看下它们之间的关系如下图 可以看到发布者(/topic_publisher)通过话题(/counter)将消息传给订阅者(/topic_subscriber) 也可以使用命令行进行消息发布rostopic pub counter std_msgs/Int32 9999999 这样就插播一条值为9999999的消息传给了订阅者。 现在我们来看下话题的状态信息rostopic info counter Type: std_msgs/Int32 Publishers:   * /topic_publisher (http://YAB:34725/)  * /rostopic_3918_1692005474115 (http://YAB:45641/) Subscribers:   * /topic_subscriber (http://YAB:42075/) 可以看到这里出现两个发布者其中一个就是命令行的也出现了一个订阅者恩没有问题 4、锁存话题 在ROS中消息是短暂的意味着订阅可能存在丢失消息的问题当然上面这个例子发送频率比较高可能没什么影响因为马上有新的消息被发送过来不过对于有些场景频繁发送消息也不是一个好主意。 比方说一个节点通过map话题发送地图(数据类型nav_msgs/OccupancyGrid)一般来说地图在一段时间内是不会发生改变并且只会在节点加载完地图之后发送一次如果另外一个节点需要这个地图就永远都无法获取到了。 因为地图通常很大我们也不想经常发送解决办法可以将频率调低不过这里的频率应该设置多大也是一个技巧性的问题。 所以这里提供了一个不错的解决方案使用锁存也就是将话题标记为锁存的时候订阅者在完成订阅之后将会自动获取话题上最后一条消息。代码很简单添加一个参数即可  pub rospy.Publisher(counter,Int32,latchTrue) 在低版本上的参数是latched所以在新的版本上就会报下面这样的错误  Traceback (most recent call last):   File /home/yahboom/catkin_ws/src/test/src/topic_one.py, line 6, in module     pub rospy.Publisher(counter,Int32,latchedTrue)TypeError: __init__() got an unexpected keyword argument latched 需要将latched更改成latch。  5、自定义消息类型 ROS有丰富的内置消息类型比如上面的std_msgs包定义了一些基本的类型这些类型数据构成的定长或变长数组在Python中经过底层的通信反序列化处理得到元组(tuple)并且可以设置成元组或列表(list)。 5.1、基本消息类型 ROS中C与Python的基本消息类型以及如何序列化表格如下 ROS消息类型序列化结果C类型C类型备注boolUnsigned 8-bit integeruint8_tboolint8Signed 8-bit integerint8_tintuint8Unsigned 8-bit integeruint8_tuint8_tuint8[]在Python中是string表示int16Signed 16-bit integerint16_tintuint16Unsigned 16-bit integeruint16_tintint32Signed 32-bit integerint32_tintuint32Unsigned 32-bit integeruint32_tintint64Signed 64-bit integerint64_tlonguint64Unsigned 64-bit integeruint64_tlongfloat3232-bit IEEE floatfloatfloatfloat6464-bit IEEE floatdoublefloatstringASCII stringstd::stringstringROS不支持Unicode,请使用UTF-8timesecs/nsecs unsigned 32-bit intsros::Timerospy.Timeduration 可以看到C比Python有更多的原生数据类型需要注意的是C节点和Python节点之间交换数据的时候需要注意一些取值范围的问题比如说C中的Uint8表示无符号整数当Python中的小于0或大于255的数值传过来时就解释成一个8位无符号整数这就会导致一些无法预测的bug所以说在Python中使用范围受限的ROS类型时一定要小心。 有的时候这些内置消息类型不够用我们需要自己定义一些消息这些自定义的数据类型在ROS同样是“一等公民”跟内置消息数据类型并无差别对待。 5.2、定义新消息 在ROS中自定义消息是用ROS包中的msg目录中的消息定义文件来说明然后catkin_make编译成与语言有关的实现版本这样就可以在代码中使用自定义类型了先来看一个定义复数的一个例子看下具体是怎么操作的 5.2.1、msg文件 消息文件的定义很简单直观类型 名称 cd ~/catkin_ws/src/test mkdir msg cd msg gedit Complex.msg 定义实部和虚部内容如下 float32 real float32 imaginary 5.2.2、修改package.xml 为了让ROS生成语言相关的消息代码我们需要告知构建系统新消息的定义所以需要对package.xml和CMakeLists.txt文件进行修改。 编辑package.xml文件 cd ~/catkin_ws/src/test gedit package.xml 添加以下两个节点 build_dependmessage_generation/build_depend run_dependmessage_runtime/run_depend 后面编译的时候如果出错 CMake Error at /opt/ros/melodic/share/catkin/cmake/catkin_package.cmake:224 (message):   catkin_package() DEPENDS on the catkin package message_runtime which must   therefore be listed as a run dependency in the package.xml 属于版本问题将节点名称run_depend修改为exec_depend即可 5.2.3、修改CMakeLists.txt 接着编辑CMakeLists.txt文件gedit CMakeLists.txt 添加message_generation让catkin能够找到message_generation包 find_package(catkin REQUIRED COMPONENTS rospy std_msgs message_generation) 运行时使用消息 catkin_package(CATKIN_DEPENDS message_runtime) 告诉catkin我们想要编译它们 add_message_files(FILES Complex.msg) 以及将下面这个注释去掉 generate_messages(    DEPENDENCIES    std_msgs  ) 5.2.4、编译 定义好了之后catkin就知道了如何编译了接下来就回到工作区根目录进行编译 cd ~/catkin_ws catkin_make 编译成功没有问题。我们也可以来看下这个消息编译后的代码当然文件所在路径不同点取决于你的Python版本 cd ~/catkin_ws/devel/lib/python2.7/dist-packages/test/msg cat _Complex.py 代码如下 # This Python file uses the following encoding: utf-8 autogenerated by genpy from test/Complex.msg. Do not edit. import codecs import sys python3 True if sys.hexversion 0x03000000 else False import genpy import structclass Complex(genpy.Message):_md5sum 54da470dccf15d60bd273ab751e1c0a1_type test/Complex_has_header False # flag to mark the presence of a Header object_full_text float32 real float32 imaginary __slots__ [real,imaginary]_slot_types [float32,float32]def __init__(self, *args, **kwds):Constructor. Any message fields that are implicitly/explicitlyset to None will be assigned a default value. The recommenduse is keyword arguments as this is more robust to future messagechanges. You cannot mix in-order arguments and keyword arguments.The available fields are:real,imaginary:param args: complete set of field values, in .msg order:param kwds: use keyword arguments corresponding to message field namesto set specific fields.if args or kwds:super(Complex, self).__init__(*args, **kwds)# message fields cannot be None, assign default values for those that areif self.real is None:self.real 0.if self.imaginary is None:self.imaginary 0.else:self.real 0.self.imaginary 0.def _get_types(self):internal API methodreturn self._slot_typesdef serialize(self, buff):serialize message into buffer:param buff: buffer, StringIOtry:_x selfbuff.write(_get_struct_2f().pack(_x.real, _x.imaginary))except struct.error as se: self._check_types(struct.error(%s: %s when writing %s % (type(se), str(se), str(locals().get(_x, self)))))except TypeError as te: self._check_types(ValueError(%s: %s when writing %s % (type(te), str(te), str(locals().get(_x, self)))))def deserialize(self, str):unpack serialized message in str into this message instance:param str: byte array of serialized message, strif python3:codecs.lookup_error(rosmsg).msg_type self._typetry:end 0_x selfstart endend 8(_x.real, _x.imaginary,) _get_struct_2f().unpack(str[start:end])return selfexcept struct.error as e:raise genpy.DeserializationError(e) # most likely buffer underfilldef serialize_numpy(self, buff, numpy):serialize message with numpy array types into buffer:param buff: buffer, StringIO:param numpy: numpy python moduletry:_x selfbuff.write(_get_struct_2f().pack(_x.real, _x.imaginary))except struct.error as se: self._check_types(struct.error(%s: %s when writing %s % (type(se), str(se), str(locals().get(_x, self)))))except TypeError as te: self._check_types(ValueError(%s: %s when writing %s % (type(te), str(te), str(locals().get(_x, self)))))def deserialize_numpy(self, str, numpy):unpack serialized message in str into this message instance using numpy for array types:param str: byte array of serialized message, str:param numpy: numpy python moduleif python3:codecs.lookup_error(rosmsg).msg_type self._typetry:end 0_x selfstart endend 8(_x.real, _x.imaginary,) _get_struct_2f().unpack(str[start:end])return selfexcept struct.error as e:raise genpy.DeserializationError(e) # most likely buffer underfill_struct_I genpy.struct_I def _get_struct_I():global _struct_Ireturn _struct_I _struct_2f None def _get_struct_2f():global _struct_2fif _struct_2f is None:_struct_2f struct.Struct(2f)return _struct_2f 可以看到生成的这个消息里面的函数主要就是做序列化和反序列化操作序列化(封包)消息到缓冲区然后反序列化(解包)到消息实例中。其他一些相关信息也解释下 _md5sum 54da470dccf15d60bd273ab751e1c0a1 MD5校验和这个主要是ROS用它来确保消息是正确版本。每次修改消息文件可能都需要重新catkin_make编译因为可能存在其他文件引用了此消息类型比如C就是将这个MD5校验和编译进了可执行文件所以需要再次编译对于Python的字节码文件(.pyc)也需要再次编译保证它们的校验和能够匹配起来。_type test/Complex 类型定义 _full_text float32 real float32 imaginary__slots__ [real,imaginary] _slot_types [float32,float32] 这里就是实部与虚部定义的类型。 6、使用自定义消息 上面的消息被定义好了之后接下来我们来看下如何使用它。 6.1、消息发布 cd ~/catkin_ws/src/test/src gedit message_publisher.py #!/usr/bin/env python import rospy from test.msg import Complex from random import randomrospy.init_node(message_publisher) pub rospy.Publisher(complex,Complex) rate rospy.Rate(2) while not rospy.is_shutdown():msg Complex()msg.real random()msg.imaginary random()pub.publish(msg)rate.sleep() 代码跟原来差不多没什么区别将自定义的Complex类型跟导入其他标准类型一样导入然后就可以创建消息类的实例了有了实例就可以给里面的字段赋值了。 6.2、消息订阅 有了消息发布的代码之后来写一个订阅的跟前面的方法一样也是使用回调函数来触发 cd ~/catkin_ws/src/test/src gedit message_subscriber.py #!/usr/bin/env python import rospy from test.msg import Complexdef callback(msg):print(Real:,msg.real)print(Imaginary:,msg.imaginary)rospy.init_node(message_subscriber) sub rospy.Subscriber(complex,Complex,callback) rospy.spin() 最后也添加执行权限chmod ux message_subscriber.py 然后开三个终端分别输入以下命令 roscore rosrun test message_publisher.py rosrun test message_subscriber.py 输出结果如下 (Real:, 0.7348452806472778) (Imaginary:, 0.24286778271198273) (Real:, 0.8839530348777771) (Imaginary:, 0.4728539288043976) (Real:, 0.45228102803230286) (Imaginary:, 0.9694715142250061) (Real:, 0.7523669004440308) (Imaginary:, 0.17689673602581024) 6.3、rosmsg命令 先来看下这条消息有关的命令的帮助rosmsg -h rosmsg is a command-line tool for displaying information about ROS Message types. Commands:     rosmsg show    Show message description 显示消息定义     rosmsg info    Alias for rosmsg show 是show的别名     rosmsg list    List all messages 列出所有消息     rosmsg md5    Display message md5sum 显示MD5校验和     rosmsg package    List messages in a package 列出包中所有消息     rosmsg packages    List packages that contain messages 列出包含消息的所有包 Type rosmsg command -h for more detailed usage 查看这个Complex消息内容rosmsg show Complex [test/Complex]: float32 real float32 imaginary 验证MD5校验和的值 rosmsg md5 Complex [test/Complex]: 54da470dccf15d60bd273ab751e1c0a1 恩没有问题可以看到输出的内容跟代码里面的是一样的。 如果一个消息包含另一个消息也可以递归显示出来比如rosmsg show PointStamped [geometry_msgs/PointStamped]: std_msgs/Header header   uint32 seq   time stamp   string frame_id geometry_msgs/Point point   float64 x   float64 y   float64 z 包含header和point都是ROS类型 列举定义了消息的所有包rosmsg packages actionlib actionlib_msgs actionlib_tutorials bond control_msgs controller_manager_msgs diagnostic_msgs dynamic_reconfigure gazebo_msgs geometry_msgs map_msgs nav_msgs pcl_msgs roscpp rosgraph_msgs rospy_tutorials sensor_msgs shape_msgs smach_msgs std_msgs stereo_msgs test tf tf2_msgs theora_image_transport trajectory_msgs turtle_actionlib turtlesim visualization_msgs 列举test包定义的消息rosmsg package test  test/Complex 列举传感器包定义的消息rosmsg package sensor_msgs  sensor_msgs/BatteryState sensor_msgs/CameraInfo sensor_msgs/ChannelFloat32 sensor_msgs/CompressedImage sensor_msgs/FluidPressure sensor_msgs/Illuminance sensor_msgs/Image sensor_msgs/Imu sensor_msgs/JointState sensor_msgs/Joy sensor_msgs/JoyFeedback sensor_msgs/JoyFeedbackArray sensor_msgs/LaserEcho sensor_msgs/LaserScan sensor_msgs/MagneticField sensor_msgs/MultiDOFJointState sensor_msgs/MultiEchoLaserScan sensor_msgs/NavSatFix sensor_msgs/NavSatStatus sensor_msgs/PointCloud sensor_msgs/PointCloud2 sensor_msgs/PointField sensor_msgs/Range sensor_msgs/RegionOfInterest sensor_msgs/RelativeHumidity sensor_msgs/Temperature sensor_msgs/TimeReference 查看其中相机的消息定义rosmsg show sensor_msgs/CameraInfo std_msgs/Header header   uint32 seq   time stamp   string frame_id uint32 height uint32 width string distortion_model float64[] D float64[9] K float64[9] R float64[12] P uint32 binning_x uint32 binning_y sensor_msgs/RegionOfInterest roi   uint32 x_offset   uint32 y_offset   uint32 height   uint32 width   bool do_rectify 7、发布者与订阅者协同工作 前面是单个的发布者和订阅者但是节点也可以同时是一个发布者和订阅者或者拥有多个订阅和发布。实际上在ROS中节点最常做的事情就是传递消息并在消息上进行计算一起来看一个例子 cd ~/catkin_ws/src/test/src #发布者 gedit doubler_pub.py#!/usr/bin/env python import rospy from std_msgs.msg import Int32 import randomrospy.init_node(doubler_pub) pub rospy.Publisher(number,Int32) rate rospy.Rate(2) while not rospy.is_shutdown():num random.randint(1,9)pub.publish(num)rate.sleep() 添加执行权限chmod ux doubler_pub.py 运行rosrun test doubler_pub.py 这里就订阅上面的发布然后做加倍处理之后再发布也就是同时拥有了订阅和发布的功能 cd ~/catkin_ws/src/test/src #加倍操作 gedit doubler.py #!/usr/bin/env python import rospy from std_msgs.msg import Int32rospy.init_node(doubler) def callback(msg):print(msg.data)doubled msg.data * 2pub.publish(doubled)sub rospy.Subscriber(number,Int32,callback) pub rospy.Publisher(doubled,Int32) rospy.spin() 添加执行权限chmod ux doubler.py 运行rosrun test doubler.py 订阅者gedit doubler_sub.py #!/usr/bin/env python import rospy from std_msgs.msg import Int32def callback(msg):print(msg.data)rospy.init_node(doubler_sub) sub rospy.Subscriber(doubled,Int32,callback) rospy.spin() 添加执行权限chmod ux doubler_sub.py 运行rosrun test doubler_sub.py 如下图 这里的加倍操作就是在接收到新数据之后才发布也就是说这个节点就是起到一个信息计算处理的一个作用然后将加倍的数据发布出去。 最后做一个订阅者查看下结果输出比对发现确实是将数据做了加倍处理。
http://www.hkea.cn/news/14524245/

相关文章:

  • 网站维护更新费用学校文化建设聚奇网站
  • 如何建设网站的外链网站招聘栏怎么做
  • wordpress影视网站网站建设打造营销型网站
  • 淘宝 网站建设镇江网站建设个
  • dedecms 招聘网站wordpress分类二级域名
  • 诚信档案建设网站首页建设部门的网站
  • 网站备案手机号wordpress+小米
  • 吉安网站only网站建设分析
  • 搜索引擎优化的主要工作优化设计答案六年级上册语文
  • 移动网站 做优化可以做软件的网站有哪些内容吗
  • 公司做网站一般多少钱茶艺馆网站
  • 企业网站制造si设计公司
  • 二次元动漫网站设计方案公司宣传册设计模板
  • 最佳磁力搜索引擎seo建站是什么意思
  • 哪些建材网站可以做宣传网站后台ftp
  • 外国大气网站设计刷网站关键词排名原理
  • 好网站的标准商业网点的定义
  • 萝岗区营销型网站建设和15岁女儿做很舒服网站
  • 陕西网站建设企业国外免费建站网站搭建
  • asp.net 当前网站做购物平台网站 民治
  • h5响应式网站建设方案提供网站建设课程报告
  • 装饰公司怎么做微网站一键配置wordpress
  • 潮牌衣服网站建设可行性分析wordpress导航主题模板下载地址
  • 如何确认建设银行网站不是假的网页设计美工培训
  • 制作一个网站要多少钱淮北建投网站
  • 海南网站开发公司宁波网站建设公司怎么报价
  • 深圳网站托管公司莱芜一中贴吧
  • 网站icp备案证明wordpress termux
  • 自己做一个网站需要多少钱专门做中式服装平台的网站
  • 网站里面发消息怎么做超链接如何细分行业 做网站赚钱