机器人SDF模型
- link
- link的一级pose
- 材质
- plugin
- 话题信息通信
- 键盘操作plugin
- Sensor传感器
- imu
不算教学,个人的记录
sdf的格式跟urdf有所不同,必须是完整的一个包括,比如< pose></ pose>这样前一个后一个,urdf中是有< orign xyz=‘0 0 0’ rpy=‘0 0 0’>的写法的,也就是没< orign>< /orign>这样写。sdf中需要注意。
下面是一个两轮小车的模型sdf文件,算是一个标准基础例子。
<?xml version='1.0'?>
<sdf version='1.9'>
<model name='diff_drive_robot'>
<!-- 主车身(立方体) -->
<link name='base_link'>
<!-- 这个pose写的是右轮在整个model的零点的相对位置 -->
<pose>1 0 0 0 0 0</pose>
<!-- 物理属性必须要写,urdf中是可以不写的 -->
<inertial>
<mass>5.0</mass>
<inertia>
<ixx>0.104167</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.104167</iyy>
<iyz>0</iyz>
<izz>0.083333</izz>
</inertia>
</inertial>
<collision name='base_collision'>
<geometry>
<box>
<size>0.3 0.2 0.1</size> <!-- 长宽高:30cm x 20cm x 10cm -->
</box>
</geometry>
<surface>
<friction>
<ode>
<mu>0.5</mu>
<mu2>0.5</mu2>
</ode>
</friction>
</surface>
</collision>
<visual name='base_visual'>
<geometry>
<box>
<size>0.3 0.2 0.1</size>
</box>
</geometry>
<material>
<ambient>0.8 0.2 0.2 1</ambient>
<diffuse>0.8 0.2 0.2 1</diffuse>
</material>
</visual>
</link>
<!-- 左轮 -->
<link name='left_wheel'>
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.05</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.05</iyy>
<iyz>0</iyz>
<izz>0.1</izz>
</inertia>
</inertial>
<collision name='left_wheel_collision'>
<geometry>
<cylinder>
<radius>0.1</radius> <!-- 轮径20cm -->
<length>0.05</length> <!-- 厚度5cm -->
</cylinder>
</geometry>
</collision>
<visual name='left_wheel_visual'>
<geometry>
<cylinder>
<radius>0.1</radius>
<length>0.05</length>
</cylinder>
</geometry>
<material>
<ambient>0.3 0.3 0.3 1</ambient>
<diffuse>0.3 0.3 0.3 1</diffuse>
</material>
</visual>
</link>
<joint name='left_wheel_joint' type='revolute'>
<parent>base_link</parent>
<child>left_wheel</child>
<axis>
<xyz>0 1 0</xyz> <!-- Y轴为旋转轴 -->
<limit>
<lower>-1e9</lower> <!-- 无限旋转 -->
<upper>1e9</upper>
</limit>
</axis>
<pose>-0.15 0 -0.05 0 0 0</pose> <!-- 左偏移15cm -->
</joint>
<!-- 右轮(结构与左轮对称) -->
<link name='right_wheel'>
<!-- 这个pose写的是右轮在整个model的零点的相对位置,如果加了relative_to=‘base_link’,那就是相对base_link的位置 -->
<pose>1 0 0 0 0 0</pose>
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.05</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.05</iyy>
<iyz>0</iyz>
<izz>0.1</izz>
</inertia>
</inertial>
<collision name='right_wheel_collision'>
<geometry>
<cylinder>
<radius>0.1</radius> <!-- 轮径20cm -->
<length>0.05</length> <!-- 厚度5cm -->
</cylinder>
</geometry>
</collision>
<visual name='right_wheel_visual'>
<geometry>
<cylinder>
<radius>0.1</radius>
<length>0.05</length>
</cylinder>
</geometry>
<material>
<ambient>0.3 0.3 0.3 1</ambient>
<diffuse>0.3 0.3 0.3 1</diffuse>
</material>
</visual>
</link>
<joint name='right_wheel_joint' type='revolute'>
<parent>base_link</parent>
<child>right_wheel</child>
<axis>
<xyz>0 1 0</xyz> <!-- Y轴为旋转轴 -->
<limit>
<lower>-1e9</lower> <!-- 无限旋转 -->
<upper>1e9</upper>
</limit>
</axis>
<pose>0.15 0 -0.05 0 0 0</pose> <!-- 左偏移15cm -->
</joint>
</model>
</sdf>
查看sdf文件是否有效,gazebo能检测到并且输出
link
link的一级pose
给了base_link和左轮右轮的pose,这是相对整个model的零点的位置,也就是左轮的0 0 0 0 0 0处,因为三个link都是写在了< model> < /model>中,所以 也是相对模型零点的位置。
<link name='base_link'>
<pose>0 0 1 0 0 0</pose>
<link name='left_wheel'>
<pose>0 0 0 0 0 0</pose>
<link name='right_wheel'>
<pose>1 0 0 0 0 0</pose>
整体都有位移,三个都改为0 0 1 0 0 0了
一般机器人都是写的有关节和链接,如果只用pose表示相对位置,只改了一个部件,那这个部件就会相对整个机器人发生位移,但是这个部件的子链接又没有位移就会扰乱了机器人模型,所以对一个完整的机器人,我会在pose里写一个relative_to=‘’
<link name='left_wheel'>
<pose relative_to='base_link'>0 -0.125 0 1.57 0 0</pose>
<link name='right_wheel'>
<pose relative_to='base_link'>0 0.125 0 1.57 0 0</pose>
材质
材质文件的保存形式,原来的sdf文件没定义纹理,可以自己创建material文件夹以及下面的scripts文件夹写纹理脚本文件,texture文件夹是纹理图片。
两种写法
<script>
<uri>model://B2Z1/materials/scripts/gazebo.material</uri>
<name>Gazebo/Grey</name>
</script>
<!-- 只要求显示的话可以自己写,也不用脚本 -->
<material>
<shader type='pixel'/>
<ambient>0.3 0.3 0.3 1</ambient>
<diffuse>1 1 1 1</diffuse>
<specular>1 1 1 1</specular>
<emissive>0 0 0 1</emissive>
<shininess>90</shininess>
</material>
plugin
常见插件类型
- 传感器插件(如摄像头、激光雷达)
- 控制器插件(关节控制、机器人运动控制)
- 物理引擎插件(自定义物理行为)
- 系统插件(全局逻辑,如环境光照控制)
话题信息通信
为了与ros2进行通信的功能,写plugin引出gz topic话题,然后转换成ros2 topic话题
到官方文档中查看可以使用的接口
gz::sim::systems Namespace Reference
看到joint的控制器这里,可以看到给出了sdf中可写的内容
<!-- JointController 插件 -->
<plugin name="joint_controller" filename="gz-sim-joint-controller-system">
<!-- 必须参数 -->
<joint_name>your_joint</joint_name> <!-- 要控制的关节名称 -->
<!-- 可选参数 -->
<use_force_commands>false</use_force_commands> <!-- 是否使用力控制模式,默认 velocity 模式 -->
<use_actuator_msg>false</use_actuator_msg> <!-- 是否使用 actuator 消息,默认 false -->
<actuator_number>0</actuator_number> <!-- 执行器索引,默认 0 -->
<topic>/your_topic</topic> <!-- 命令话题,默认自动生成 -->
<sub_topic>your_subtopic</sub_topic> <!-- 子话题,默认自动生成 -->
<initial_velocity>0</initial_velocity> <!-- 初始速度 -->
<!-- 力控制模式下的 PID 参数(可选) -->
<p_gain>1.0</p_gain>
<i_gain>0.0</i_gain>
<d_gain>0.0</d_gain>
<i_max>1.0</i_max>
<i_min>-1.0</i_min>
<cmd_max>1000.0</cmd_max>
<cmd_min>-1000.0</cmd_min>
<cmd_offset>0.0</cmd_offset>
</plugin>
找到插件文件的存放路径发现这里有插件,在plugin中的filename填的就是插件文件名的部分,去掉lib和.so的格式
filename=“gz-sim-joint-controller-system” → 实际加载的库文件为 libgz-sim-joint-controller-system.so
能实现外部与仿真模型进行消息控制,< topic>和< sub_topic>非常重要, 主要就是自定义一个话题名成为gz topic,这样就有了接口,然后使用ros_gz_bridge进行转换让ros2代码进行操控消息数据
键盘操作plugin
监听特定输入消息,当匹配到预设条件时,自动发布指定的输出消息,在仿真中实现 “事件触发响应” 的机制,16777234是一个按键的对应码,类似c++中按键有对应的ASCII码那样。通过话题/cmd_vel输出速度数据。
<plugin filename="gz-sim-triggered-publisher-system"
name="gz::sim::systems::TriggeredPublisher">
<input type="gz.msgs.Int32" topic="/keyboard/keypress">
<match field="data">16777234</match>
</input>
<output type="gz.msgs.Twist" topic="/cmd_vel">
linear: {x: 0.0}, angular: {z: 0.5}
</output>
</plugin>
Sensor传感器
相机、imu、激光雷达是比较常用的
imu
看官方文档,说是plugin项放在world里就行,sensor项放在link中
<link name='imu_link'>
<pose relative_to='base_link'>0 0 0.125 0 0 0</pose>
<inertial>
<mass>0.1</mass>
<inertia>
<ixx>0.0001</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.0001</iyy>
<iyz>0</iyz>
<izz>0.0001</izz>
</inertia>
</inertial>
<visual name='imu_visual'>
<geometry>
<box>
<size>0.05 0.05 0.02</size>
</box>
</geometry>
<material>
<shader type='pixel'/>
<script>
<uri>model://joint/materials/scripts/gazebo.material</uri>
<name>Gazebo/Blue</name>
</script>
</material>
</visual>
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>10</update_rate>
<topic>imu</topic>
<visualize>true</visualize>
</sensor>
</link>
<!-- IMU传感器配置 -->
<plugin filename="libgz-sim-imu-system.so" name="gz::sim::systems::Imu">
</plugin>
# 查看话题有没有imu
gz topic -l
# 查看imu 的具体信息
gz topic -e -t /imu