技巧

  • 多屏显示时启动Gazebo:Gazebo将出现在鼠标指针所在的那块屏幕上
  • 重置模拟状态 rosservice call /gazebo/reset_simulation "{}"

Launch file

  • 使用ROS launch
  • 参数
    • 默认启动后即开始仿真,可以通过参数使得其启动后暂停 <arg name="paused" value="false"/>
    • 是否显示界面 <arg name="gui" value="true"/>

*.world file

<?xml version="1.0" ?>
<sdf version="1.5">
    <world name="default">
        <include>
            <uri>model://ground_plane</uri>
        </include>
        <include>
            <uri>model://sun</uri>
        </include>
        <include>
            <uri>model://obstacle</uri>
            <name>obstacle_1</name>
            <pose>0 0 0 0 0 0</pose>
        </include>
        <include>
            <uri>model://obstacle</uri>
            <name>obstacle_2</name>
            <pose>0 0 1 0 0 0</pose>
        </include>
        <include>
            <uri>model://robot</uri>
            <name>robot</name>
            <pose>-2.0 1.0 0 0 0 0</pose>
        </include>
    </world>
</sdf>
 

SDF与URDF

  • SDF与URDF的关系:
    • URDF描述机器人,SDF描述机器人以外的外部世界
  • 若在.world文件中对模型配置了<pose>属性,它将覆盖模型的sdf中的<pose>属性

传感器

添加相机

  • 参考教程
  • 在world文件中添加相机:
    <?xml version='1.0' encoding='utf-8'?>
    <sdf version="1.5">
      <model name='camera1'>
        <static>true</static>
        <pose>1 0 0.3 0 0 3.1415926</pose>
        <link name='link'>
          <visual name='visual'>
            <geometry>
              <box>
                <size>0.1 0.1 0.1</size>
              </box>
            </geometry>
          </visual>
          <sensor name='camera1' type='camera'>
            <camera>
              <save enabled="false">
                <path>/tmp/camera_save</path>
              </save>
              <horizontal_fov>1.047</horizontal_fov>
              <image>
                <width>1920</width>
                <height>1080</height>
              </image>
              <clip>
                <near>0.1</near>
                <far>100</far>
              </clip>
            </camera>
            <always_on>1</always_on>
            <update_rate>30</update_rate>
            <!--insert the plugin to convert image data to rostopic here-->
          </sensor>
        </link>
      </model>
    </sdf>
  • 将相机捕获数据转发至rostopic: 在<sensor>中插入
    <plugin name="camera_controller" filename="libgazebo_ros_camera.so">
        <alwaysOn>true</alwaysOn>
        <updateRate>0.0</updateRate>
        <cameraName>/test_camera/camera</cameraName>
        <imageTopicName>image_raw</imageTopicName>
        <cameraInfoTopicName>camera_info</cameraInfoTopicName>
        <frameName>camera</frameName>
        <hackBaseline>0.07</hackBaseline>
        <distortionK1>0.0</distortionK1>
        <distortionK2>0.0</distortionK2>
        <distortionK3>0.0</distortionK3>
        <distortionT1>0.0</distortionT1>
        <distortionT2>0.0</distortionT2>
    </plugin>
    需使用plugin进行转发
  • 在rViz中查看:Add->By topic->/test_camera/camera(topic名)->image_raw->选择Imageraw

开发

使用自定义mesh(未测试)

  • 需要在package.xml中定义gazebo model/mesh path路径(<export>标签中的部分)
    ...
    <build_depend>gazebo_dev</build_depend>
    <exec_depend>gazebo_ros</exec_depend>
    <exec_depend>xacro</exec_depend>
    <depend>pluginlib</depend>
    <depend>urdf</depend>
 
    <export>
        <!--Export gazebo models and worlds-->
        <gazebo_ros gazebo_model_path="${prefix}/models"/>
        <gazebo_ros gazebo_resource _path="${prefix}/worlds"/>
    </export>
</package>

Gazebo直接向ROS提供的数据

获取运行时模型/link姿态

通过rostopic查看
  • ,可以通过/gazebo/model_states访问模型状态,通过/gazebo/link_states访问link状态
    • 模型/link姿态数据:
      • gazebo_msgs.msgModelStates的格式发布于/gazebo/model_states
      • gazebo_msgs.msgLinkStates的格式发布于/gazebo/link_states
      • 分为三个部分,name,pose,twist
    • 示例(修改自gazebo_link_pose.py):
    #!/usr/bin/env python
     
    import rospy
    from gazebo_msgs.msg import LinkStates
    from geometry_msgs.msg import Pose
     
    class GazeboLinkPose:
      link_name = ''
      link_pose = Pose()
      def __init__(self):
     
        self.states_sub = rospy.Subscriber("/gazebo/link_states", LinkStates, self.callback)
     
      def callback(self, data):
        try:
          ...
          # data.name provides the list of names
          # find the index of your link by the name
          # data.pose provides the list of poses (use the index here for the corresponding pose)
          # data.twist provides the list of twists
        except ValueError:
          pass
     
    if __name__ == '__main__':
      try:
        rospy.init_node('gazebo_link_pose', anonymous=True)
        gp = GazeboLinkPose()
     
        rate = rospy.Rate(10)
        while not rospy.is_shutdown():
          rate.sleep()
     
      except rospy.ROSInterruptException:
        pass
通过rosservice查看
  • 参考命令为(以获取link的状态为例)
    rosservice call /gazebo/get_link_state "link_name:'link_1'
    reference_frame:'world'"
  • 参考代码(以获取link的状态为例):
    from gazebo_msgs.srv import GetLinkState
     
    rospy.wait_for_service('/gazebo/get_link_state')
    try:
        read_state = rospy.ServiceProxy('/gazebo/get_link_state', GetLinkState)
        state = read_state(link_name='link_1')
    注:如果需要获取model的信息,需要将代码中的五处”link”替换为”model”。 实例化rospy.ServiceProxy和read_state之间不能使用try/except。

修改运行时模型/link姿态

  • 参考:官方教程
  • 修改数据使用rostopic (Gazebo Subscribed Topics) 如果只pub一次数据,不一定会被Gazebo响应。在官方教程中采用了-r 20这个参数(Rate=20hz,默认为10hz)。 不清楚响应的机理,实测在rostopic pub -r 20 /gazebo/set_model_state gazebo_msgs/ModelState 'YOURMESSAGE CONTENT'之后若干秒Gazebo才有响应。
    • 模型: /gazebo/set_model_state,数据类型gazebo_msgs/ModelState(注意没有s)
    • link:/gazebo/set_link_state,数据类型gazebo_msgs/LinkState
  • 修改数据使用或rosservice
    rospy.wait_for_service('/gazebo/set_model_state')
    try:
        set_state = rospy.ServiceProxy('/gazebo/set_model_state', SetModelState)
        state = ModelState()
        state.model_name = 'link_1'
        state.pose = SOMEPOSE
        print(state)
        resp = set_state(state)
     
    except rospy.ServiceException as e:
        pass

参考

编写插件plugin

other tools