CHH3213 / Note-Ubuntu_CHH3213

ubuntu系统CHH3213上做的笔记
0 stars 0 forks source link

51. gazebo相关问题说明 #51

Open CHH3213 opened 2 years ago

CHH3213 commented 2 years ago

3、gazebo 关闭 client 界面

在做强化学习训练时,打开 gazebo 界面可能会使训练比较耗时,因此关闭 client 界面也许是一种比较好的方法。

gazebo 平台第三视角关闭方法如下:

$ roscd gazebo_ros
$ cd launch
$ sudo gedit empty_world.launch

在打开的文件中将value=true改为<arg name="gui" value="false"/>

若上面方法还不能关闭界面,在 launch 启动文件里面,找到所有相关联的启动文件,将上面的修改方法在 launch 里面也执行一遍。

5、gazebo 仿真时间加速

主要遇到的问题是在进行 DQN 训练时,由于机器性能及每步飞行时间等原因,训练时长较久,因此能够在仿真中修改一些配置,使得仿真的时间比现实时间更快。

主要是通过修改 world 文件里面的一些物理属性,来实现仿真时间加速的效果,若需要加速时,还是在重新测试比较好,我修改为如下代码后,较之前能有 3 倍左右的提升速度,并且没有使用 rospy.sleep(2) 函数,而是使用的 rospy.Rate(0.46).sleep() 来代替。

<physics name='default_physics' default='0' type='ode'>
  <real_time_update_rate>0</real_time_update_rate>
  <max_step_size>0.002</max_step_size>
  <real_time_factor>1</real_time_factor>
</physics>

通过修改 max_step_size 的值能对 gazebo 进行加速,一般修改的时候 real_time_update_rate 设置为 0。

Max_step_size:0.001(默认值)

Real_time_update_rate:1(默认值)

Real_time_update_rate:1000(默认值)

参考网址:http://gazebosim.org/tutorials?tut=modifying_world&cat=build_world

6、gazebo 添加定制模型

以前都是自己制作的一些简单模型导入到 gazebo 仿真世界中,但想加载一些特定的模型时,不一定能自己制作出来,这时可以下载3D Warehouse网站上做好的模型,导入到 gazebo 仿真直接中即可

例如,这样的模型则不一定能自己制作出来

因此,我们可以在3D Warehouse上搜索关键词,然后找到想要的模型,点击进去后,以 Collada File 文件形式下载即可。

(1)下载完后,解压,解压后更改 dae 的名字。然后在 gazebo_model_path 的文件夹目录下创建相对应的模型文件,主要包括 model.config、model.sdf 文件和 mesh 文件夹(文件夹下只有 dae 文件)

其中,model.sdf 文件内容如下:

<?xml version="1.0" ?>
<sdf version="1.4">
  <model name="Arc">
    <pose>0 5 0 0 0 0</pose>
    <static>true</static>
    <link name="link">
      <inertial>
        <mass>0.1</mass>
      </inertial>
      <collision name="collision">
        <geometry>
          <box>
            <size>10 10 0.2</size>
          </box>
        </geometry>
      </collision>

      <visual name="visual">
        <geometry>
          <mesh>
            <!--uri>model://marker/meshes/artag_01.dae</uri-->
            <uri>model://arc/meshes/arc.dae</uri>
            <!-- <scale> 0.01 0.01 0.01 </scale>-->
          </mesh>
        </geometry>
      </visual>
    </link>
  </model>
</sdf>

(2)测试

创建 arc.world 文件,并将如下内容拷贝进去

<?xml version="1.0"?>
<sdf version="1.4">
  <world name="default">
    <include>
      <uri>model://ground_plane</uri>
    </include>
    <include>
      <uri>model://sun</uri>
    </include>
<!--
    <model name="arc">
      <pose>0 0 0  0 0 0</pose>
      <static>true</static>
      <link name="body">
        <visual name="visual">
          <geometry>
            <mesh>
              <uri>file://arc.dae</uri>
              <scale> 0.03 0.03 0.03</scale>
            </mesh>

          </geometry>
        </visual>
      </link>
    </model>
-->
    <model name='arc'>
      <static>1</static>
      <link name='arc_link'>
        <pose frame=''>0 0 0 0 -0 0</pose>
        <collision name='collision'>
          <geometry>
            <mesh>
              <uri>model://arc/meshes/arc.dae</uri>
              <scale>0.03 0.03 0.03</scale>
            </mesh>
          </geometry>

        </collision>
        <visual name='visual'>
          <geometry>
            <mesh>
              <uri>model://arc/meshes/arc.dae</uri>
              <scale>0.03 0.03 0.03</scale>
            </mesh>
          </geometry>
        </visual>
        <gravity>1</gravity>
      </link>
      <pose frame=''>0 0 0.05 0 0 0</pose>
    </model>
  </world>
</sdf>
说明:上面代码中注销掉的部分如 `file://arc.dae`是以文件形式导入,而后面`model://arc/meshes/arc.dae`是以 sdf 形式导入。

需要注意的是:需要使用` <scale>0.03 0.03 0.03</scale>`来对模型进行调节大小 

(3)显示

运行 gazebo arc.world

参考网址:http://gazebosim.org/tutorials?tut=import_mesh#PreparetheMesh

https://answers.ros.org/question/42529/how-to-import-collada-dae-files-into-gazebo-rosfuerte/

7、Gazebo 场景纹理图重置

主要是我在做强化学习(DQN)训练的过程中,需要将纹理时常更换,因此在网上查找相关教程,最终实现了 gazebo 的场景重置

先看代码,后面在进行解释,该代码是从训练的代码中截取的部分,需要的内容全部都在了

#coding=utf8

from geometry_msgs.msg import Pose
from gazebo_msgs.srv import *
import rospy

import roslib;roslib.load_manifest('test')

class DQN():
    def __init__(self):
        self.pubModelStates = rospy.Subscriber('gazebo/model_states',ModelStates,self.get_model_pos)
        self.database_model_name = 
        ["asphalt1","asphalt2","asphalt3","asphalt4",
        "brick1","brick2","brick3","brick4",
        ]

    #重置特定模型位置
    def (self):
        rospy.wait_for_service('/gazebo/set_model_state')
        set_state_service = rospy.ServiceProxy('/gazebo/set_model_state',SetModelState)
        objstate = SetModelStateRequest()

        #set quadrotor pose
        objstate.model_state.model_name = 'quadrotor'
        objstate.model_state.pose.position.x = 5
        objstate.model_state.pose.position.y = 0
        objstate.model_state.pose.position.z = 0
        objstate.model_state.pose.orientation.w = 1
        objstate.model_state.pose.orientation.x = 0
        objstate.model_state.pose.orientation.y = 0
        objstate.model_state.pose.orientation.z = 0
        objstate.model_state.twist.linear.x = 0.0
        objstate.model_state.twist.linear.y = 0.0
        objstate.model_state.twist.linear.z = 0.0
        objstate.model_state.twist.angular.x = 0.0
        objstate.model_state.twist.angular.y = 0.0
        objstate.model_state.twist.angular.z = 0.0
        objstate.model_state.reference_frame = "world"

        result = set_state_service(objstate)

    #获取特定模型位置
    def get_model_pos(self):
        get_state_service = rospy.ServiceProxy('/gazebo/get_model_state',GetModelState)
        model = GetModelStateRequest()
        model.model_name = 'quadrotor'
        objstate = get_state_service(model)
        state = (objstate.pose.position.x,objstate.pose.position.y,objstate.pose.position.z)
        print('pos',state)

    #删除模型文件
    def delete_sdf_model(self):
        rospy.wait_for_service('gazebo/delete_model')
        delete_model_service = rospy.ServiceProxy('gazebo/delete_model',DeleteModel)
        objstate = DeleteModelRequest()
        objstate.model_name = "grass7_plane"
        if objstate.model_name in self.database_model_name:
            try:
                delete_model_service(objstate)
                print('delete model success')
            except Exception as e:
                print("delete model failed")

            self.spawn_sdf_model()

    #重置模型文件
    def spawn_sdf_model(self):
        rospy.wait_for_service('gazebo/spawn_sdf_model')
        spawn_model_service = rospy.ServiceProxy('gazebo/spawn_sdf_model',SpawnModel)
        with open("/home/cug/qlab_ws/src/qlab/qlab/qlab_gazebo/models/asphalt1/model.sdf","r") as f:
            model_xml = f.read()
        #model_name model_xml robot_namespace initial_pose reference_frame
        objstate = SpawnModelRequest()
        objstate.model_name = "asphalt1"
        objstate.model_xml = model_xml
        objstate.robot_namespace = ""

        pose = Pose()
        pose.position.x = 0.222657 
        pose.position.y = -0.204052
        pose.position.z =  0
        objstate.initial_pose = pose
        objstate.reference_frame = "world"
        try:
            #spawn_model_service("asphalt1_plane",model_xml,"",pose,"world")
            spawn_model_service(objstate)
            print('spawn model success')
        except Exception as e:
            print('spawn model failed') 

if __name__ == "__main__":
    rospy.init_node('test')
    dqn = DQN()
    dqn.delete_sdf_model()
    dqn.set_model_pos()
    dqn.get_model_pos(
说明:gazebo 场景重置,主要用到两个 rosservice,分别是`gazebo/delete_model`和`gazebo/spawn_sdf_model `

在重置的过程中,首先需要先删除模型,即调用gazebo/delete_model服务,然后在重新生成,这时需要找到想要生成的模型的 sdf 文件所在位置,然后读取并调用gazebo/spawn_sdf_model服务,即可实现 gazebo 场景纹理图的重置

主要需要查看的帮助信息是

(1)roservice list:查找相关 service 服务

(2)rosservice info [service_name]:查找对应服务的数据类型

对其中一个进行解释说明:如

objstate = SpawnModelRequest()
objstate.model_name = "asphalt1"
objstate.model_xml = model_xml
objstate.robot_namespace = ""

pose = Pose()
pose.position.x = 0.222657 
pose.position.y = -0.204052
pose.position.z =  0
objstate.initial_pose = pose
objstate.reference_frame = "world"

这里就和/gazebo/spawn_sdf_model 里面的 Args 对应,分别是 model_name、model_xml、robot_namespace、initial_pose、reference_frame

又如:

#重置特定模型位置
    def (self):
        rospy.wait_for_service('/gazebo/set_model_state')
        set_state_service = rospy.ServiceProxy('/gazebo/set_model_state',SetModelState)
        objstate = SetModelStateRequest()

        #set quadrotor pose
        objstate.model_state.model_name = 'quadrotor'
        objstate.model_state.pose.position.x = 5
        objstate.model_state.pose.position.y = 0
        objstate.model_state.pose.position.z = 0
        objstate.model_state.pose.orientation.w = 1
        objstate.model_state.pose.orientation.x = 0
        objstate.model_state.pose.orientation.y = 0
        objstate.model_state.pose.orientation.z = 0
        objstate.model_state.twist.linear.x = 0.0
        objstate.model_state.twist.linear.y = 0.0
        objstate.model_state.twist.linear.z = 0.0
        objstate.model_state.twist.angular.x = 0.0
        objstate.model_state.twist.angular.y = 0.0
        objstate.model_state.twist.angular.z = 0.0
        objstate.model_state.reference_frame = "world"
JLer666 commented 2 years ago

您好,我也在gazebo仿真平台上做强化学习训练,但是苦于无人交流,现在遇到几个问题能与你一起讨论一下吗? 我的gazebo环境做了10倍加速,为了在仿真中达到10hz的控制频率,我需要实际100hz的状态回调,但是我测试发现/gazebo/model_states话题回调的频率不稳定,偶尔会出现30-40ms的回调间隔。这让我十分苦恼,并且使用回调不能保证回调反馈的状态是上次step动作作用后导致的,还需做额外的同步才能得到正确的sarsa。 想问下您在这部分是怎么做的?

CHH3213 commented 2 years ago

您好,我也在gazebo仿真平台上做强化学习训练,但是苦于无人交流,现在遇到几个问题能与你一起讨论一下吗? 我的gazebo环境做了10倍加速,为了在仿真中达到10hz的控制频率,我需要实际100hz的状态回调,但是我测试发现/gazebo/model_states话题回调的频率不稳定,偶尔会出现30-40ms的回调间隔。这让我十分苦恼,并且使用回调不能保证回调反馈的状态是上次step动作作用后导致的,还需做额外的同步才能得到正确的sarsa。 想问下您在这部分是怎么做的?

您好,我现在用gazebo仿真并没有做加速的操作,因为这样在我这边好像模拟仿真与实物的差距会更大,导致迁移变得更难。回调的频率我也碰到过不稳定的情况,我一般是设置比较小的一个频率值,例如频率一般稳定在60hz,我可能只固定频率为50hz。另外回调不能保证回调反馈的状态是上次step动作作用后导致的,我的一个粗暴的做法时同一个动作话题重复发送几次,这样比较能保证回调反馈的状态是上次step动作作用后导致的。希望能给您帮助。 @JLer666

JLer666 commented 2 years ago

非常感谢您的回复!之前确实在网上查到说如果gazebo做仿真加速将会导致一些不正常的行为,但是不做加速数据的采集实在是太慢了。我在使用ElegantRL框架,训练端到端的on policy agent,现在训练一次需要接近10万个eps,如果不加速我训练一次的时间需要超过200小时,由于我现在还在改进测试的阶段需要经常从头训练,这么长的训练时长无法接受,在后期算法验证确实没问题后会专门在不加速环境下训练。对于状态同步的问题,我现在的做法是在step中pub了本次的act后sleep 100ms,先调用暂停仿真服务再调用/gazebo/get_model_state服务去得到机器人的状态,这样至少能保证我得到的状态一定是这个100ms后的状态。我还有一个问题,我想只做规划的策略agent(在仿真中不考虑控制问题,只考虑机器人的运动学约束),所以希望在我pub act后的100ms后仿真中的机器人一定能达到我的期望act,我查资料找到如果在参数中不指定gazebo_ros_control的pid_gains,gazebo将会直接使用我们的期望动作设定到对应的关节上,但是我不论加或不加pid_gains都达不到我想要的效果(或许是我的pid没调好?) ,您知道有什么方法可以做到吗? 再次感谢您的回复 @CHH3213

CHH3213 commented 2 years ago

非常感谢您的回复!之前确实在网上查到说如果gazebo做仿真加速将会导致一些不正常的行为,但是不做加速数据的采集实在是太慢了。我在使用ElegantRL框架,训练端到端的on policy agent,现在训练一次需要接近10万个eps,如果不加速我训练一次的时间需要超过200小时,由于我现在还在改进测试的阶段需要经常从头训练,这么长的训练时长无法接受,在后期算法验证确实没问题后会专门在不加速环境下训练。对于状态同步的问题,我现在的做法是在step中pub了本次的act后sleep 100ms,先调用暂停仿真服务再调用/gazebo/get_model_state服务去得到机器人的状态,这样至少能保证我得到的状态一定是这个100ms后的状态。我还有一个问题,我想只做规划的策略agent(在仿真中不考虑控制问题,只考虑机器人的运动学约束),所以希望在我pub act后的100ms后仿真中的机器人一定能达到我的期望act,我查资料找到如果在参数中不指定gazebo_ros_control的pid_gains,gazebo将会直接使用我们的期望动作设定到对应的关节上,但是我不论加或不加pid_gains都达不到我想要的效果(或许是我的pid没调好?) ,您知道有什么方法可以做到吗? 再次感谢您的回复 @CHH3213

您好,不好意思,这个我不太清楚唉。您之后要是知道怎么做了,方便的话可以再回复我一下,谢谢~@JLer666