Xacro 和 SDF 是进行复杂机器人系统开发与高级仿真的关键技能
Xacro(XML Macros)是ROS中用于简化URDF建模的宏语言,通过参数化、模块化和数学计算功能提高建模效率。它支持属性定义(xacro:property)、宏模板(xacro:macro)、数学表达式和条件逻辑(xacro:if),能有效解决URDF的代码重复问题。SDF(Simulation Description Format)则是Gazebo仿真器的标准格式,相比URDF支持更复
详细讲解 Xacro(XML Macros)和 SDF(Simulation Description Format),这两个在机器人建模与仿真中至关重要的技术。
第一部分:Xacro 详解
1. Xacro 概述
Xacro(XML Macros)是 ROS 提供的 XML 宏语言,用于生成 URDF 文件。它解决了纯 URDF 的代码重复、缺乏参数化等问题,是复杂机器人建模的标准工具。
核心优势:
- 参数化:使用变量替代硬编码数值
- 模块化:通过文件包含复用组件
- 可计算:支持数学表达式
- 条件逻辑:根据参数生成不同结构
- 代码复用:宏定义避免重复代码
2. Xacro 语法详解
2.1 属性定义(<xacro:property>)
用于定义常量或计算值,可在文档任意位置使用 ${} 引用。
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="my_robot">
<!-- 基本数值属性 -->
<xacro:property name="pi" value="3.14159265359"/>
<xacro:property name="wheel_radius" value="0.05"/>
<xacro:property name="wheel_width" value="0.02"/>
<!-- 字符串属性 -->
<xacro:property name="wheel_material" value="rubber"/>
<!-- 列表/向量属性(通过字符串解析) -->
<xacro:property name="chassis_size" value="0.5 0.3 0.1"/>
<!-- 属性可在定义后使用 -->
<link name="wheel">
<visual>
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_width}"/>
</geometry>
</visual>
</link>
</robot>
2.2 宏定义(<xacro:macro>)
定义可复用的模板,支持参数传递。
<!-- 基础宏语法 -->
<xacro:macro name="macro_name" params="param1 param2 param3='default_value'">
<!-- 宏体,可使用传入的参数 -->
</xacro:macro>
<!-- 调用宏 -->
<xacro:macro_name param1="value1" param2="value2"/>
完整示例:通用轮子宏
<xacro:macro name="wheel" params="prefix side radius width mass xyz rpy">
<!-- 连杆定义 -->
<link name="${prefix}_wheel_link">
<visual>
<origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
<geometry>
<cylinder radius="${radius}" length="${width}"/>
</geometry>
<material name="black"/>
</visual>
<collision>
<origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
<geometry>
<cylinder radius="${radius}" length="${width}"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
<mass value="${mass}"/>
<!-- 圆柱体惯性公式:Ixx=Iyy=m(3r²+h²)/12, Izz=mr²/2 -->
<inertia ixx="${mass*(3*radius*radius + width*width)/12}"
ixy="0"
ixz="0"
iyy="${mass*(3*radius*radius + width*width)/12}"
iyz="0"
izz="${mass*radius*radius/2}"/>
</inertial>
</link>
<!-- 关节定义 -->
<joint name="${prefix}_wheel_joint" type="continuous">
<parent link="chassis"/>
<child link="${prefix}_wheel_link"/>
<origin xyz="${xyz}" rpy="${rpy}"/>
<axis xyz="0 0 1"/>
</joint>
<!-- 传动装置 -->
<transmission name="${prefix}_wheel_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="${prefix}_wheel_joint">
<hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
</joint>
<actuator name="${prefix}_wheel_motor">
<hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<!-- Gazebo 属性 -->
<gazebo reference="${prefix}_wheel_link">
<mu1>1.0</mu1>
<mu2>1.0</mu2>
<material>Gazebo/Black</material>
</gazebo>
</xacro:macro>
<!-- 调用宏创建四个轮子 -->
<xacro:wheel prefix="front_left" side="left" radius="${wheel_radius}"
width="${wheel_width}" mass="0.5"
xyz="0.2 0.15 0.05" rpy="0 0 0"/>
<xacro:wheel prefix="front_right" side="right" radius="${wheel_radius}"
width="${wheel_width}" mass="0.5"
xyz="0.2 -0.15 0.05" rpy="0 0 0"/>
<xacro:wheel prefix="rear_left" side="left" radius="${wheel_radius}"
width="${wheel_width}" mass="0.5"
xyz="-0.2 0.15 0.05" rpy="0 0 0"/>
<xacro:wheel prefix="rear_right" side="right" radius="${wheel_radius}"
width="${wheel_width}" mass="0.5"
xyz="-0.2 -0.15 0.05" rpy="0 0 0"/>
2.3 数学表达式
Xacro 支持完整的 Python 数学运算:
<xacro:property name="a" value="2"/>
<xacro:property name="b" value="3"/>
<!-- 基本运算 -->
${a + b} <!-- 加法: 5 -->
${a - b} <!-- 减法: -1 -->
${a * b} <!-- 乘法: 6 -->
${a / b} <!-- 除法: 0.666... -->
${a // b} <!-- 整除: 0 -->
${a % b} <!-- 取模: 2 -->
${a ** b} <!-- 幂运算: 8 -->
<!-- 三角函数(弧度) -->
${sin(pi/2)} <!-- 1.0 -->
${cos(0)} <!-- 1.0 -->
${tan(pi/4)} <!-- 1.0 -->
${atan2(y, x)} <!-- 反正切 -->
<!-- 数学函数 -->
${abs(-5)} <!-- 5 -->
${round(3.7)} <!-- 4 -->
${floor(3.7)} <!-- 3 -->
${ceil(3.2)} <!-- 4 -->
${sqrt(16)} <!-- 4 -->
${pow(2, 3)} <!-- 8 -->
<!-- 条件表达式 -->
${a if a > b else b} <!-- 三元运算符 -->
<!-- 字符串操作 -->
${'prefix_' + link_name} <!-- 字符串拼接 -->
2.4 条件语句(<xacro:if> / <xacro:unless>)
根据条件选择性生成代码:
<xacro:property name="use_lidar" value="true"/>
<xacro:property name="wheel_num" value="4"/>
<!-- if: 条件为真时执行 -->
<xacro:if value="${use_lidar}">
<xacro:include filename="$(find my_robot)/urdf/lidar.xacro"/>
<xacro:lidar_sensor parent="chassis" xyz="0 0 0.5"/>
</xacro:if>
<!-- unless: 条件为假时执行(相当于 if not) -->
<xacro:unless value="${wheel_num == 4}">
<!-- 如果不是四轮,添加支撑轮 -->
<link name="caster_wheel">
...
</link>
</xacro:unless>
<!-- 复杂条件 -->
<xacro:if value="${wheel_num > 2 and use_lidar}">
<!-- 多条件判断 -->
</xacro:if>
2.5 文件包含(<xacro:include>)
模块化组织代码,提高复用性:
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="complex_robot">
<!-- 包含通用材料定义 -->
<xacro:include filename="$(find my_robot)/urdf/materials.xacro"/>
<!-- 包含通用宏库 -->
<xacro:include filename="$(find my_robot)/urdf/wheel.xacro"/>
<xacro:include filename="$(find my_robot)/urdf/arm.xacro"/>
<xacro:include filename="$(find my_robot)/urdf/sensors.xacro"/>
<!-- 包含参数配置文件 -->
<xacro:include filename="$(find my_robot)/config/robot_params.yaml"/>
<!-- 注意:yaml 加载需要 xacro 的特定语法 -->
<!-- 使用包含的宏 -->
<xacro:wheel prefix="left" .../>
<xacro:arm dof="6" .../>
</robot>
YAML 参数加载(高级):
# config/robot_params.yaml
wheel:
radius: 0.05
width: 0.02
mass: 0.5
chassis:
length: 0.6
width: 0.4
height: 0.2
mass: 5.0
<!-- 在 xacro 中加载 yaml -->
<xacro:property name="yaml_file" value="$(find my_robot)/config/robot_params.yaml"/>
<xacro:property name="props" value="${xacro.load_yaml(yaml_file)}"/>
<!-- 使用 yaml 参数 -->
<xacro:property name="wheel_radius" value="${props['wheel']['radius']}"/>
2.6 块参数(<xacro:insert_block>)
传递 XML 块作为参数,实现更灵活的模板:
<!-- 定义接受块参数的宏 -->
<xacro:macro name="sensor_mount" params="name parent *origin">
<joint name="${name}_joint" type="fixed">
<xacro:insert_block name="origin"/>
<parent link="${parent}"/>
<child link="${name}_link"/>
</joint>
<link name="${name}_link">
<visual>
<geometry>
<cylinder radius="0.02" length="0.05"/>
</geometry>
</visual>
</link>
</xacro:macro>
<!-- 调用时传递 origin 块 -->
<xacro:sensor_mount name="camera" parent="chassis">
<origin xyz="0.3 0 0.1" rpy="0 0 0"/>
</xacro:sensor_mount>
2.7 属性块(<xacro:property> 配合 <xacro:block>)
<!-- 定义 XML 块属性 -->
<xacro:property name="default_inertial">
<inertial>
<mass value="1"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
</xacro:property>
<!-- 在宏中使用 -->
<xacro:macro name="simple_link" params="name">
<link name="${name}">
<xacro:insert_block name="default_inertial"/>
<visual>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</visual>
</link>
</xacro:macro>
3. Xacro 高级技巧
3.1 递归宏(构建链式结构)
<!-- 递归构建机械臂链 -->
<xacro:macro name="arm_segment" params="prefix parent i total_length">
<xacro:property name="segment_length" value="${total_length / 3}"/>
<link name="${prefix}_link_${i}">
<visual>
<geometry>
<cylinder radius="0.05" length="${segment_length}"/>
</geometry>
</visual>
</link>
<joint name="${prefix}_joint_${i}" type="revolute">
<parent link="${parent}"/>
<child link="${prefix}_link_${i}"/>
<origin xyz="0 0 ${segment_length}" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-1.57" upper="1.57" effort="10" velocity="1"/>
</joint>
<!-- 递归调用直到达到指定数量 -->
<xacro:if value="${i < 3}">
<xacro:arm_segment prefix="${prefix}" parent="${prefix}_link_${i}"
i="${i+1}" total_length="${total_length}"/>
</xacro:if>
</xacro:macro>
<!-- 启动递归 -->
<xacro:arm_segment prefix="arm" parent="base_link" i="1" total_length="0.9"/>
3.2 命名空间与作用域
<!-- 局部属性(仅在宏内有效) -->
<xacro:macro name="scoped_example" params="value">
<xacro:property name="local_var" value="${value * 2}"/>
<!-- local_var 只在宏定义内可用 -->
<link name="link_${local_var}"/>
</xacro:macro>
<!-- 全局属性 -->
<xacro:property name="global_var" value="10"/>
4. Xacro 编译与调试
# 基本编译
rosrun xacro xacro robot.xacro > robot.urdf
# 指定参数
rosrun xacro xacro robot.xacro wheel_radius:=0.1 use_lidar:=true > robot.urdf
# 查看展开后的结果(不保存文件)
rosrun xacro xacro robot.xacro
# 调试模式(显示行号)
rosrun xacro xacro --debug robot.xacro
# ROS2 命令
xacro robot.xacro -o robot.urdf
xacro robot.xacro wheel_radius:=0.1 > robot.urdf
第二部分:SDF 详解
1. SDF 概述
SDF(Simulation Description Format)是 Gazebo 仿真器的原生描述格式,比 URDF 更通用、更强大,支持:
- 完整仿真世界:多机器人、环境、光照、物理属性
- 闭链机构:并联机器人、四连杆等
- 丰富传感器:摄像头、激光雷达、IMU、力传感器等
- 高级物理:软体、流体、电磁等
- 插件系统:C++ 插件扩展仿真行为
版本演进:
- SDF 1.4-1.6:Gazebo 经典版
- SDF 1.7+:Ignition Gazebo(现 Gazebo Sim)
2. SDF 基本结构
<?xml version="1.0"?>
<sdf version="1.9">
<!-- 可以是 world 或 model -->
<!-- 世界定义 -->
<world name="default">
<!-- 物理引擎、场景、光照、模型实例等 -->
</world>
<!-- 或模型定义 -->
<model name="robot">
<!-- 连杆、关节、传感器等 -->
</model>
</sdf>
3. SDF Model 详解
3.1 基本模型结构
<?xml version="1.0"?>
<sdf version="1.9">
<model name="mobile_robot" canonical_link="chassis">
<!-- 静态模型(不参与动力学) -->
<static>false</static>
<!-- 自碰撞开关 -->
<self_collide>true</self_collide>
<!-- 允许自动禁用(性能优化) -->
<allow_auto_disable>true</allow_auto_disable>
<!-- 位姿(相对于世界或父模型) -->
<pose>0 0 0.5 0 0 0</pose>
<!-- ========== 连杆 ========== -->
<link name="chassis">
<pose>0 0 0 0 0 0</pose> <!-- 相对于模型坐标系 -->
<inertial>
<pose>0 0 0.1 0 0 0</pose>
<mass>5.0</mass>
<inertia>
<ixx>0.208</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.342</iyy>
<iyz>0</iyz>
<izz>0.458</izz>
</inertia>
</inertial>
<!-- 视觉 -->
<visual name="chassis_visual">
<pose>0 0 0 0 0 0</pose>
<geometry>
<box>
<size>0.6 0.4 0.2</size>
</box>
</geometry>
<material>
<ambient>0.5 0.5 0.5 1</ambient>
<diffuse>0.5 0.5 0.5 1</diffuse>
<specular>0.1 0.1 0.1 1</specular>
</material>
</visual>
<!-- 碰撞 -->
<collision name="chassis_collision">
<pose>0 0 0 0 0 0</pose>
<geometry>
<box>
<size>0.6 0.4 0.2</size>
</box>
</geometry>
<!-- 表面属性 -->
<surface>
<friction>
<ode>
<mu>0.5</mu>
<mu2>0.5</mu2>
<slip1>0</slip1>
<slip2>0</slip2>
</ode>
</friction>
<contact>
<ode>
<soft_cfm>0</soft_cfm>
<soft_erp>0.2</soft_erp>
<kp>100000</kp>
<kd>1</kd>
</ode>
</contact>
</surface>
</collision>
<!-- 传感器直接附着在连杆上 -->
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>100</update_rate>
<visualize>true</visualize>
<topic>imu</topic>
<imu>
<angular_velocity>
<x>
<noise type="gaussian">
<mean>0</mean>
<stddev>0.01</stddev>
</noise>
</x>
<y>
<noise type="gaussian">
<mean>0</mean>
<stddev>0.01</stddev>
</noise>
</y>
<z>
<noise type="gaussian">
<mean>0</mean>
<stddev>0.01</stddev>
</noise>
</z>
</angular_velocity>
</imu>
</sensor>
</link>
<!-- ========== 关节 ========== -->
<joint name="left_wheel_joint" type="revolute">
<parent>chassis</parent>
<child>left_wheel</child>
<pose>0.2 0.25 0 0 1.5707 0</pose> <!-- 关节坐标系 -->
<axis>
<xyz>0 0 1</xyz>
<limit>
<lower>-1e16</lower>
<upper>1e16</upper>
<effort>10</effort>
<velocity>10</velocity>
</limit>
<dynamics>
<damping>0.1</damping>
<friction>0.1</friction>
</dynamics>
</axis>
<physics>
<ode>
<cfm_damping>true</cfm_damping>
<implicit_spring_damper>true</implicit_spring_damper>
</ode>
</physics>
</joint>
<!-- 插件 -->
<plugin name="diff_drive" filename="libDiffDrivePlugin.so">
<left_joint>left_wheel_joint</left_joint>
<right_joint>right_wheel_joint</right_joint>
<wheel_separation>0.5</wheel_separation>
<wheel_radius>0.1</wheel_radius>
<topic>cmd_vel</topic>
</plugin>
</model>
</sdf>
3.2 SDF 关节类型
| 类型 | 说明 | 自由度 |
|---|---|---|
revolute |
旋转关节(有限位) | 1 |
prismatic |
滑动关节 | 1 |
ball |
球关节(3D旋转) | 3 |
universal |
万向节(2轴旋转) | 2 |
screw |
螺旋关节(旋转+平移耦合) | 1 |
gearbox |
齿轮传动 | 1 |
fixed |
固定连接 | 0 |
continuous |
连续旋转 | 1 |
闭链结构示例(四连杆):
<link name="link1">...</link>
<link name="link2">...</link>
<link name="link3">...</link>
<link name="link4">...</link>
<!-- 开链部分 -->
<joint name="joint1" type="revolute">
<parent>link1</parent>
<child>link2</child>
</joint>
<joint name="joint2" type="revolute">
<parent>link2</parent>
<child>link3</child>
</joint>
<!-- 闭链:link3 通过 link4 连接回 link1 -->
<joint name="joint3" type="revolute">
<parent>link3</parent>
<child>link4</child>
</joint>
<joint name="joint4" type="revolute">
<parent>link4</parent>
<child>link1</child> <!-- 闭环! -->
</joint>
4. SDF World 详解
<?xml version="1.0"?>
<sdf version="1.9">
<world name="my_world">
<!-- 物理引擎配置 -->
<physics name="default_physics" default="true" type="ode">
<max_step_size>0.001</max_step_size>
<real_time_factor>1</real_time_factor>
<real_time_update_rate>1000</real_time_update_rate>
<ode>
<solver>
<type>quick</type>
<iters>50</iters>
<sor>1.3</sor>
</solver>
<constraints>
<cfm>0</cfm>
<erp>0.2</erp>
<contact_max_correcting_vel>100</contact_max_correcting_vel>
<contact_surface_layer>0.001</contact_surface_layer>
</constraints>
</ode>
</physics>
<!-- 场景属性 -->
<scene>
<ambient>0.4 0.4 0.4 1</ambient>
<background>0.7 0.7 0.7 1</background>
<shadows>true</shadows>
<grid>false</grid>
</scene>
<!-- 光照 -->
<light name="sun" type="directional">
<pose>0 0 10 0 0 0</pose>
<cast_shadows>true</cast_shadows>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.2 0.2 0.2 1</specular>
<attenuation>
<range>1000</range>
<constant>0.9</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<direction>-0.5 0.1 -0.9</direction>
</light>
<!-- 地面平面 -->
<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<surface>
<friction>
<ode>
<mu>100</mu>
<mu2>50</mu2>
</ode>
</friction>
</surface>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.8 0.8 0.8 1</specular>
</material>
</visual>
</link>
</model>
<!-- 包含外部模型 -->
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
<!-- 实例化自定义模型 -->
<include>
<uri>model://my_robot</uri>
<name>robot1</name>
<pose>0 0 0.5 0 0 0</pose>
</include>
<include>
<uri>model://my_robot</uri>
<name>robot2</name>
<pose>2 0 0.5 0 0 0</pose>
</include>
<!-- 直接内联模型定义 -->
<model name="box_obstacle">
<pose>1 1 0.5 0 0 0</pose>
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
<material>
<ambient>1 0 0 1</ambient>
</material>
</visual>
</link>
</model>
<!-- 插件 -->
<plugin name="world_plugin" filename="libWorldPlugin.so"/>
</world>
</sdf>
5. SDF 传感器详解
5.1 摄像头(Camera)
<sensor name="camera" type="camera">
<pose>0.1 0 0.5 0 0 0</pose>
<camera>
<horizontal_fov>1.047</horizontal_fov> <!-- 60度 -->
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
<far>100</far>
</clip>
<distortion>
<k1>0.0</k1>
<k2>0.0</k2>
<k3>0.0</k3>
<p1>0.0</p1>
<p2>0.0</p2>
<center>0.5 0.5</center>
</distortion>
<noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.007</stddev>
</noise>
</camera>
<always_on>true</always_on>
<update_rate>30</update_rate>
<visualize>true</visualize>
<topic>camera/image</topic>
</sensor>
5.2 激光雷达(GPU Ray / Ray)
<sensor name="lidar" type="gpu_ray"> <!-- 或 ray 用于 CPU 版本 -->
<pose>0 0 0.5 0 0 0</pose>
<ray>
<scan>
<horizontal>
<samples>640</samples>
<resolution>1</resolution>
<min_angle>-1.396263</min_angle> <!-- -80度 -->
<max_angle>1.396263</max_angle> <!-- +80度 -->
</horizontal>
<vertical>
<samples>16</samples>
<resolution>1</resolution>
<min_angle>-0.261799</min_angle>
<max_angle>0.261799</max_angle>
</vertical>
</scan>
<range>
<min>0.08</min>
<max>10.0</max>
<resolution>0.01</resolution>
</range>
<noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.01</stddev>
</noise>
</ray>
<always_on>true</always_on>
<update_rate>20</update_rate>
<visualize>true</visualize>
<topic>scan</topic>
</sensor>
5.3 深度相机(Depth Camera)
<sensor name="depth_camera" type="depth_camera">
<camera>
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
</image>
<clip>
<near>0.1</near>
<far>10</far>
</clip>
</camera>
<always_on>true</always_on>
<update_rate>30</update_rate>
<visualize>true</visualize>
<topic>depth_camera</topic>
</sensor>
5.4 力/力矩传感器(Force Torque)
<sensor name="ft_sensor" type="force_torque">
<pose>0 0 0 0 0 0</pose>
<force_torque>
<frame>sensor</frame> <!-- 或 child/parent -->
<measure_direction>child_to_parent</measure_direction>
</force_torque>
<always_on>true</always_on>
<update_rate>100</update_rate>
<visualize>true</visualize>
<topic>ft_sensor</topic>
</sensor>
6. SDF 插件系统
插件是 SDF 的强大扩展机制,用 C++ 编写:
<!-- 模型插件 -->
<plugin name="model_plugin" filename="libModelPlugin.so">
<parameter1>value1</parameter1>
<parameter2>value2</parameter2>
</plugin>
<!-- 世界插件 -->
<world>
<plugin name="world_plugin" filename="libWorldPlugin.so"/>
</world>
<!-- 传感器插件 -->
<sensor>
<plugin name="sensor_plugin" filename="libSensorPlugin.so"/>
</sensor>
常用内置插件:
| 插件 | 功能 | 参数 |
|---|---|---|
DiffDrivePlugin |
差速驱动 | 左右轮关节、轮距、轮径 |
SkidSteerDrivePlugin |
skid-steer 驱动 | 四个轮关节 |
LiftDragPlugin |
升力/阻力(无人机) | 表面面积、空气密度 |
BuoyancyPlugin |
浮力 | 流体密度、重力 |
BatteryPlugin |
电池仿真 | 容量、电压、消费功率 |
7. URDF 与 SDF 转换
# URDF → SDF(Gazebo 经典版)
gz sdf -p robot.urdf > robot.sdf
# 使用 ROS 包路径
gz sdf -p $(rospack find my_robot)/urdf/robot.urdf > robot.sdf
# SDF → URDF(有限支持,闭链会丢失)
# 通常需要手动转换或使用特定工具
转换注意事项:
| 特性 | URDF→SDF | SDF→URDF |
|---|---|---|
| 闭链结构 | 不支持(报错) | 丢失闭环 |
| 传动装置 | 转为 joint 属性 | 需手动添加 |
| Gazebo 标签 | 直接转换 | 保留 |
| 传感器 | 支持 | 支持 |
| 插件 | 支持 | 支持 |
| 多机器人 | 包装为 model | 仅提取单个 model |
8. 完整示例:SDF 移动机器人
<?xml version="1.0"?>
<sdf version="1.9">
<model name="diff_drive_robot">
<static>false</static>
<self_collide>true</self_collide>
<!-- 底盘 -->
<link name="base_link">
<pose>0 0 0.1 0 0 0</pose>
<inertial>
<mass>2.0</mass>
<inertia>
<ixx>0.02167</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.02167</iyy>
<iyz>0</iyz>
<izz>0.04</izz>
</inertia>
</inertial>
<visual name="base_visual">
<geometry>
<box>
<size>0.4 0.3 0.1</size>
</box>
</geometry>
<material>
<ambient>0.2 0.6 0.8 1</ambient>
</material>
</visual>
<collision name="base_collision">
<geometry>
<box>
<size>0.4 0.3 0.1</size>
</box>
</geometry>
</collision>
</link>
<!-- 左轮 -->
<link name="left_wheel">
<pose>0 0.2 0.05 0 1.5707 0</pose>
<inertial>
<mass>0.5</mass>
<inertia>
<ixx>0.00079</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.00079</iyy>
<iyz>0</iyz>
<izz>0.00125</izz>
</inertia>
</inertial>
<visual name="left_wheel_visual">
<geometry>
<cylinder>
<radius>0.05</radius>
<length>0.04</length>
</cylinder>
</geometry>
<material>
<ambient>0.1 0.1 0.1 1</ambient>
</material>
</visual>
<collision name="left_wheel_collision">
<geometry>
<cylinder>
<radius>0.05</radius>
<length>0.04</length>
</cylinder>
</geometry>
<surface>
<friction>
<ode>
<mu>1.0</mu>
<mu2>1.0</mu2>
<slip1>0.01</slip1>
<slip2>0.01</slip2>
</ode>
</friction>
</surface>
</collision>
</link>
<!-- 右轮(类似定义) -->
<link name="right_wheel">
<pose>0 -0.2 0.05 0 1.5707 0</pose>
<!-- 与左轮对称... -->
</link>
<!-- 万向轮(支撑) -->
<link name="caster">
<pose>-0.15 0 0.025 0 0 0</pose>
<visual name="caster_visual">
<geometry>
<sphere>
<radius>0.025</radius>
</sphere>
</geometry>
</visual>
<collision name="caster_collision">
<geometry>
<sphere>
<radius>0.025</radius>
</sphere>
</geometry>
</collision>
</link>
<!-- 左轮关节 -->
<joint name="left_wheel_joint" type="revolute">
<parent>base_link</parent>
<child>left_wheel</child>
<pose>0 0.2 0.05 0 0 0</pose>
<axis>
<xyz>0 0 1</xyz>
<limit>
<lower>-1e16</lower>
<upper>1e16</upper>
</limit>
</axis>
</joint>
<!-- 右轮关节 -->
<joint name="right_wheel_joint" type="revolute">
<parent>base_link</parent>
<child>right_wheel</child>
<pose>0 -0.2 0.05 0 0 0</pose>
<axis>
<xyz>0 0 1</xyz>
<limit>
<lower>-1e16</lower>
<upper>1e16</upper>
</limit>
</axis>
</joint>
<!-- 万向轮关节 -->
<joint name="caster_joint" type="ball">
<parent>base_link</parent>
<child>caster</child>
<pose>-0.15 0 0.025 0 0 0</pose>
</joint>
<!-- 差速驱动插件 -->
<plugin name="diff_drive" filename="libDiffDrivePlugin.so">
<left_joint>left_wheel_joint</left_joint>
<right_joint>right_wheel_joint</right_joint>
<wheel_separation>0.4</wheel_separation>
<wheel_radius>0.05</wheel_radius>
<odom_topic>odom</odom_topic>
<cmd_vel_topic>cmd_vel</cmd_vel_topic>
<publish_odom>true</publish_odom>
<publish_odom_tf>true</publish_odom_tf>
<update_rate>50</update_rate>
</plugin>
</model>
</sdf>
9. 总结对比
| 特性 | Xacro | SDF |
|---|---|---|
| 本质 | URDF 的宏预处理器 | 完整的仿真描述格式 |
| 输出 | URDF/XML | SDF/XML |
| 主要用途 | ROS 机器人描述 | Gazebo 仿真 |
| 闭链支持 | 否(继承 URDF 限制) | 是 |
| 多机器人 | 否 | 是 |
| 世界描述 | 否 | 是 |
| 参数化 | 是(强大) | 有限(1.7+ 支持一些) |
| 传感器定义 | 基础 | 丰富 |
| 物理属性 | 基础 | 详细 |
| 最佳实践 | ROS 控制 + Gazebo 仿真 | 纯仿真环境、复杂机构 |
协作流程:
Xacro(参数化建模)→ URDF(ROS 标准)→ SDF(Gazebo 仿真)
↓
直接用于:MoveIt、RViz、ros_control
掌握 Xacro 和 SDF 是进行复杂机器人系统开发与高级仿真的关键技能。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)