目录
一、定义
二、xacro 文件常见组成部分
1. 命名空间声明
2. 定义宏
3. 调用宏
4. 定义参数
5. 条件语句
6. 转换 xacro 文件为 urdf
7. gazebo标签
三、代码示例
1. gazebo标签使用(仿真参数配置)
2. 引用仿真配置并定义机器人模型(结构)
四、加载仿真模型(含传感器的机器人)
1. 编写launch文件。
2. 实际效果。
一、定义
通俗来说,
xacro
就是urdf
文件的一种“进阶版”,它是用来简化和优化机器人的描述文件,使得多个机器人可以共享同样的部件和结构,避免重复编写相同的代码。假设你有很多机器人,它们的结构相似,比如都有轮子、传感器、臂部等部件。每次你需要为这些机器人写
urdf
文件时,都要重复描述每个部件(比如轮子、关节、传感器等)。这样写非常繁琐且容易出错。
xacro
的作用 :就是通过封装和参数化这些部件,使得你可以更方便地重用已有的结构,只需要少量的修改就可以生成不同机器人的urdf
文件。类似C语言中函数的封装。
二、xacro
文件常见组成部分
1. 命名空间声明
该命名空间的定义使得文件中的
xacro
特性能够正常工作,让你在模型中使用宏和其他xacro
相关的功能。<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="robot">
2. 定义宏
宏用于封装可复用的结构,例如机器人关节、链接等。你可以定义一个宏并在多个地方调用它,宏可以带有参数,这样就可以创建不同配置的部件。
<xacro:macro name="wheel" params="name x_offset y_offset"><!-- 定义轮子的link和joint --> </xacro:macro>
3. 调用宏
宏定义完成后,可以在
xacro
文件的任意位置调用宏来生成相应的部件。调用时,可以传递参数值来定制生成的部件。<xacro:wheel name="right_wheel" x_offset="0.1" y_offset="-0.09"/> <xacro:wheel name="left_wheel" x_offset="0.1" y_offset="0.09"/>
4. 定义参数
你可以在
xacro
文件中定义变量(参数),这些变量可以在宏中使用,也可以传递给其它部分。这使得配置变得更加灵活和动态。在这个例子中,
wheel_radius
是一个参数,表示轮子的半径。在后续的代码中,可以直接使用这个参数。<xacro:property name="wheel_radius" value="0.025"/>
5. 条件语句
xacro
支持条件语句,你可以根据不同的条件生成不同的机器人模型或某些部件。例如,如果你希望某个部件只有在某个参数为true
时才创建,你可以使用xacro:if
和xacro:else
。<xacro:if value="${robot_type == 'mobile'}"><!-- 如果是移动机器人,添加特定部件 --> </xacro:if>
6. 转换 xacro 文件为 urdf
你可以使用 ROS 提供的工具来将
xacro
文件转换为 URDF 文件,生成的 URDF 文件可以直接用于机器人仿真、控制等。rosrun xacro xacro mybot.xacro > mybot.urdf
7. gazebo标签
在 XACRO 文件中,
<gazebo>
标签用于定义与 Gazebo 仿真环境 相关的设置和插件。Gazebo 是一个强大的仿真工具,用于模拟机器人、传感器以及与环境的交互。当你在 XACRO 中使用gazebo
标签时,通常是为了控制仿真中的物理属性、传感器和控制插件。这里将不再过多介绍该标签的用法,详细请查看其他博客。
三、代码示例
1. gazebo标签使用(仿真参数配置)
功能:用于描述一些物体以及传感器在gazebo仿真中的一些数据,例如摩擦系数、速度等等。
mybot_gazebo.xacro
<?xml version="1.0"?> <robot name="mybot" xmlns:xacro="http://ros.org/wiki/xacro"><!-- 定义了3个参数:激光、相机和IMU的可视化开关 --><xacro:arg name="laser_visual" default="false"/><xacro:arg name="camera_visual" default="false"/><xacro:arg name="imu_visual" default="false"/><!-- Gazebo仿真环境中为 base_link 设置物理材质 --><gazebo reference="base_link"><material>Gazebo/DarkGrey</material> <!-- 使用 DarkGrey 材质 --></gazebo><!-- 为左轮设置物理属性,包括摩擦系数、刚度等 --><gazebo reference="left_wheel_link"><mu1>0.5</mu1> <!-- 摩擦系数 --><mu2>0.5</mu2> <!-- 摩擦系数 --><kp>500000.0</kp> <!-- 刚度 --><kd>10.0</kd> <!-- 阻尼 --><minDepth>0.001</minDepth> <!-- 最小深度 --><maxVel>1.0</maxVel> <!-- 最大速度 --><fdir1>1 0 0</fdir1> <!-- 摩擦方向 --><material>Gazebo/DarkGrey</material> <!-- 使用 DarkGrey 材质 --></gazebo><!-- 为右轮设置物理属性 --><gazebo reference="right_wheel_link"><mu1>0.5</mu1> <!-- 摩擦系数 --><mu2>0.5</mu2> <!-- 摩擦系数 --><kp>500000.0</kp> <!-- 刚度 --><kd>10.0</kd> <!-- 阻尼 --><minDepth>0.001</minDepth> <!-- 最小深度 --><maxVel>1.0</maxVel> <!-- 最大速度 --><fdir1>1 0 0</fdir1> <!-- 摩擦方向 --><material>Gazebo/FlatBlack</material> <!-- 使用 FlatBlack 材质 --></gazebo><!-- 为球形支撑轮设置物理属性 --><gazebo reference="ball_wheel_link"><mu1>0.1</mu1> <!-- 摩擦系数 --><mu2>0.1</mu2> <!-- 摩擦系数 --><kp>500000.0</kp> <!-- 刚度 --><kd>100.0</kd> <!-- 阻尼 --><minDepth>0.001</minDepth> <!-- 最小深度 --><maxVel>1.0</maxVel> <!-- 最大速度 --><material>Gazebo/FlatBlack</material> <!-- 使用 FlatBlack 材质 --></gazebo><!-- 定义 IMU 传感器的Gazebo设置 --><gazebo reference="imu"><sensor type="imu" name="imu"><always_on>true</always_on> <!-- IMU 始终开启 --><visualize>$(arg imu_visual)</visualize> <!-- 根据 imu_visual 参数来显示/隐藏 IMU --></sensor><material>Gazebo/FlatBlack</material> <!-- 使用 FlatBlack 材质 --></gazebo><!-- 定义机器人控制插件,用于ROS控制 --><gazebo><plugin name="mybot_controller" filename="libgazebo_ros_diff_drive.so"><commandTopic>cmd_vel</commandTopic> <!-- 控制命令话题 --><odometryTopic>odom</odometryTopic> <!-- 里程计话题 --><odometryFrame>odom</odometryFrame> <!-- 里程计坐标系 --><odometrySource>world</odometrySource> <!-- 里程计数据来源 --><publishOdomTF>true</publishOdomTF> <!-- 是否发布里程计TF --><robotBaseFrame>base_footprint</robotBaseFrame> <!-- 机器人基座坐标系 --><publishWheelTF>false</publishWheelTF> <!-- 是否发布轮子坐标系 --><publishTf>true</publishTf> <!-- 是否发布TF --><publishWheelJointState>true</publishWheelJointState> <!-- 是否发布轮子的关节状态 --><legacyMode>false</legacyMode> <!-- 是否使用旧版控制模式 --><updateRate>30</updateRate> <!-- 控制更新率(30Hz) --><leftJoint>left_wheel_joint</leftJoint> <!-- 左轮的关节 --><rightJoint>right_wheel_joint</rightJoint> <!-- 右轮的关节 --><wheelSeparation>0.180</wheelSeparation> <!-- 轮子间距 --><wheelDiameter>0.05</wheelDiameter> <!-- 轮子直径 --><wheelAcceleration>10</wheelAcceleration> <!-- 轮子的加速度 --><wheelTorque>100</wheelTorque> <!-- 轮子的最大扭矩 --><rosDebugLevel>na</rosDebugLevel> <!-- 不使用ROS调试 --></plugin></gazebo><!-- 定义IMU插件 --><gazebo><plugin name="imu_plugin" filename="libgazebo_ros_imu.so"><alwaysOn>true</alwaysOn> <!-- 始终开启 --><bodyName>imu</bodyName> <!-- 传感器所在的身体名称 --><frameName>imu</frameName> <!-- 传感器的框架名称 --><topicName>imu</topicName> <!-- 传感器数据发布话题 --><serviceName>imu_service</serviceName> <!-- 服务名称 --><gaussianNoise>0.0</gaussianNoise> <!-- 高斯噪声 --><updateRate>0</updateRate> <!-- 更新频率 --><imu><noise><type>gaussian</type> <!-- 噪声类型:高斯噪声 --><rate><mean>0.0</mean> <!-- 速率噪声均值 --><stddev>2e-4</stddev> <!-- 速率噪声标准差 --><bias_mean>0.0000075</bias_mean> <!-- 偏置均值 --><bias_stddev>0.0000008</bias_stddev> <!-- 偏置标准差 --></rate><accel><mean>0.0</mean> <!-- 加速度噪声均值 --><stddev>1.7e-2</stddev> <!-- 加速度噪声标准差 --><bias_mean>0.1</bias_mean> <!-- 加速度偏置均值 --><bias_stddev>0.001</bias_stddev> <!-- 加速度偏置标准差 --></accel></noise></imu></plugin></gazebo><!-- 激光传感器设置 --><gazebo reference="base_laser_link"><material>Gazebo/FlatBlack</material> <!-- 使用 FlatBlack 材质 --><sensor type="ray" name="rplidar_sensor"><pose>0 0 0 0 0 0</pose> <!-- 激光传感器的姿态 --><visualize>$(arg laser_visual)</visualize> <!-- 根据 laser_visual 参数来显示/隐藏激光传感器 --><update_rate>7</update_rate> <!-- 更新频率(7Hz) --><ray><scan><horizontal><samples>720</samples> <!-- 扫描样本数 --><resolution>0.5</resolution> <!-- 扫描分辨率 --><min_angle>0.0</min_angle> <!-- 最小角度 --><max_angle>6.28319</max_angle> <!-- 最大角度 --></horizontal></scan><range><min>0.120</min> <!-- 最小测距 --><max>12.0</max> <!-- 最大测距 --><resolution>0.015</resolution> <!-- 距离分辨率 --></range><noise><type>gaussian</type> <!-- 噪声类型:高斯噪声 --><mean>0.0</mean> <!-- 噪声均值 --><stddev>0.01</stddev> <!-- 噪声标准差 --></noise></ray><!-- 激光控制插件 --><plugin name="gazebo_ros_rplidar_controller" filename="libgazebo_ros_laser.so"><topicName>scan</topicName> <!-- 激光扫描数据话题 --><frameName>base_laser_link</frameName> <!-- 激光传感器的坐标框架 --></plugin></sensor></gazebo><!-- 摄像头传感器设置 --><gazebo reference="base_camera_link"><sensor type="camera" name="csi Camera"><always_on>true</always_on> <!-- 摄像头始终开启 --><visualize>$(arg camera_visual)</visualize> <!-- 根据 camera_visual 参数来显示/隐藏相机 --><camera><horizontal_fov>1.085595</horizontal_fov> <!-- 水平视场角 --><image><width>640</width> <!-- 图像宽度 --><height>480</height> <!-- 图像高度 --><format>R8G8B8</format> <!-- 图像格式 --></image><clip><near>0.03</near> <!-- 最近剪裁距离 --><far>100</far> <!-- 最远剪裁距离 --></clip></camera><!-- 摄像头控制插件 --><plugin name="camera_controller" filename="libgazebo_ros_camera.so"><alwaysOn>true</alwaysOn> <!-- 始终开启 --><updateRate>30.0</updateRate> <!-- 更新频率(30Hz) --><cameraName>/</cameraName> <!-- 摄像头名称 --><frameName>base_camera_link</frameName> <!-- 相机坐标框架 --><imageTopicName>image_raw</imageTopicName> <!-- 图像话题 --><cameraInfoTopicName>camera_info</cameraInfoTopicName> <!-- 相机信息话题 --><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></sensor></gazebo></robot>
2. 引用仿真配置并定义机器人模型(结构)
功能:这段代码描述了一个机器人(
mybot
)的 物理模型和结构,代码通过定义多个链接(link
)和关节(joint
)来描述机器人的组成部分,包括主体、轮子、支撑轮、激光雷达等。当我们构建不同的机器人模型时,都可以引用之前的仿真配置。注意:这两个文件中的
<robot name="mybot" xmlns:xacro="http://ros.org/wiki/xacro">
中的name
字段应该一致。mybot1.xacro
<?xml version="1.0"?> <!-- 定义机器人模型文件 --> <robot name="mybot" xmlns:xacro="http://ros.org/wiki/xacro"> <!-- 引入外部Xacro文件,包含 Gazebo 模拟器的配置 --><xacro:include filename="$(find my_package)/xacro/mybot_gazebo.xacro" /> <!-- 定义 base_footprint 链接,通常用于表示机器人的地面接触点 --><link name="base_footprint"/><!-- 定义机器人基座的固定关节,连接 base_footprint 和 base_link --><joint name="base_joint" type="fixed"> <parent link="base_footprint"/> <child link="base_link"/> <origin rpy="0 0 0" xyz="0 0 0"/> <!-- 关节的位置和方向 --></joint> <!-- 定义 base_link 链接,表示机器人的基座部分 --><link name="base_link"> <inertial> <!-- 惯性属性 --><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 惯性坐标原点 --><mass value="0.1"/> <!-- 质量 --><inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.001" /> <!-- 惯性矩阵 --></inertial><visual> <!-- 可视化属性 --><geometry> <box size="0.25 0.16 0.05"/> <!-- 形状为长方体,定义机器人的基座大小 --></geometry> <!-- 几何形状 --><origin rpy="0 0 0" xyz="0 0 0"/> <!-- 可视化原点 --><material name="blue"> <color rgba="0 0 0.8 1"/> <!-- 设置颜色为蓝色 --></material> </visual> <collision> <!-- 碰撞检测属性 --><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 碰撞检测的原点 --><geometry> <!-- 几何形状 --><box size="0.25 0.16 0.05"/> <!-- 碰撞体形状为长方体,大小与可视化相同 --></geometry></collision></link> <!-- 定义右侧车轮的链接 --><link name="right_wheel_link"> <inertial> <!-- 惯性属性 --><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 惯性坐标原点 --><mass value="0.1"/> <!-- 质量 --><inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001" /> <!-- 惯性矩阵 --></inertial><visual> <!-- 可视化属性 --><geometry> <!-- 几何形状 --> <cylinder length="0.02" radius="0.025"/> <!-- 车轮的形状为圆柱 --></geometry> <material name="black"> <color rgba="0 0 0 1"/> <!-- 设置车轮颜色为黑色 --></material> </visual> <collision><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 碰撞检测的原点 --><geometry><cylinder length="0.02" radius="0.025"/> <!-- 碰撞体为圆柱 --></geometry></collision></link> <!-- 定义右车轮的旋转关节,允许车轮持续旋转 --><joint name="right_wheel_joint" type="continuous"> <axis xyz="0 0 -1"/> <!-- 旋转轴是 Z 轴负方向 --><parent link="base_link"/> <!-- 父链接是基座链接 --><child link="right_wheel_link"/> <!-- 子链接是右车轮链接 --><origin rpy="1.5707 0 0" xyz=" 0.1 -0.09 -0.03"/> <!-- 关节的位置和方向 --></joint> <!-- 定义左侧车轮的链接 --><link name="left_wheel_link"> <inertial> <!-- 惯性属性 --><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 惯性坐标原点 --><mass value="0.1"/> <!-- 质量 --><inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001" /> <!-- 惯性矩阵 --></inertial><visual> <!-- 可视化属性 --><geometry> <!-- 几何形状 --><cylinder length="0.02" radius="0.025"/> <!-- 车轮的形状为圆柱 --></geometry> <material name="black"> <color rgba="0 0 0 1"/> <!-- 设置车轮颜色为黑色 --></material> </visual> <collision><origin xyz="0 0 0" rpy="0 0 0"/><geometry><cylinder length="0.02" radius="0.025"/> <!-- 碰撞体为圆柱 --></geometry></collision> </link> <!-- 定义左车轮的旋转关节 --><joint name="left_wheel_joint" type="continuous"> <axis xyz="0 0 -1"/> <!-- 旋转轴是 Z 轴负方向 --><parent link="base_link"/> <!-- 父链接是基座链接 --><child link="left_wheel_link"/> <!-- 子链接是左车轮链接 --><origin rpy="1.5707 0 0" xyz="0.1 0.09 -0.03"/> <!-- 关节的位置和方向 --></joint> <!-- 定义一个球形支撑轮 --><link name="ball_wheel_link"> <inertial> <!-- 惯性属性 --><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 惯性坐标原点 --><mass value="0.1"/> <!-- 质量 --><inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0" /> <!-- 惯性矩阵 --></inertial><visual> <!-- 可视化属性 --><geometry> <!-- 几何形状 --><sphere radius="0.025"/> <!-- 球形轮子 --></geometry> <material name="black"> <color rgba="0 0 0 1"/> <!-- 设置轮子颜色为黑色 --></material> </visual> <collision><origin xyz="0 0 0" rpy="0 0 0"/> <!-- 碰撞检测的原点 --><geometry><sphere radius="0.025"/> <!-- 碰撞体为球形 --></geometry></collision> </link> <!-- 定义球形支撑轮的固定关节 --><joint name="ball_wheel_joint" type="fixed"> <axis xyz="0 0 1"/> <!-- 旋转轴是 Z 轴 --><parent link="base_link"/> <child link="ball_wheel_link"/> <origin rpy="0 0 0" xyz="-0.10 0 -0.03"/> <!-- 关节的位置和方向 --></joint> <!-- 定义IMU传感器 --><link name="imu"> <visual> <geometry> <box size="0.01 0.01 0.01"/> <!-- 小方块表示IMU传感器 --></geometry> <material name="white"> <color rgba="1 1 1 1"/> <!-- 设置颜色为白色 --></material> </visual> </link> <!-- 定义IMU传感器的固定关节 --><joint name="imu_joint" type="fixed"> <parent link="base_link"/> <child link="imu"/> <origin xyz="0.08 0 0.025"/> <!-- 关节的位置和方向 --></joint> <!-- 定义摄像头 --><link name="base_camera_link"> <visual> <!-- 可视化属性 --><geometry> <!-- 几何形状 --><box size="0.02 0.03 0.03"/> <!-- 以方块形式表示摄像头 --></geometry> <material name="white"> <color rgba="1 1 1 1"/> <!-- 设置颜色为白色 --></material> </visual> </link> <!-- 定义摄像头的固定关节 --><joint name="camera_joint" type="fixed"> <parent link="base_link"/> <child link="base_camera_link"/> <origin xyz="0.1 0 0.025"/> <!-- 关节的位置和方向 --></joint> <!-- 定义激光雷达 --><link name="base_laser_link"> <visual> <!-- 可视化属性 --><geometry> <!-- 几何形状 --> <cylinder length="0.06" radius="0.04"/> <!-- 激光雷达为圆柱形状 --></geometry> <material name="white"> <color rgba="1 1 1 1"/> <!-- 设置颜色为白色 --></material> </visual> </link> <!-- 定义激光雷达的固定关节 --><joint name="laser_joint" type="fixed"> <parent link="base_link"/> <child link="base_laser_link"/> <origin xyz="0 0.0 0.06"/> <!-- 位置在机器人顶部 --></joint> </robot>
四、加载仿真模型(含传感器的机器人)
1. 编写launch文件。
最终我们运行的mybot1.xacro ,里面包含了机器人的模型和仿真配置文件。编写launch文件来启动仿真模型。代码中的gazebo_world.launch文件在下面文章中有介绍。ROS实践-虚拟仿真平台Stage/Gazebo(虚实结合)
https://blog.csdn.net/qq_48361010/article/details/146096746?sharetype=blogdetail&sharerId=146096746&sharerefer=PC&sharesource=qq_48361010&spm=1011.2480.3001.8118
simulation_robot.launch
<launch><!-- 定义机器人模型位置的参数:x_pos、y_pos 和 z_pos,默认值为0 --><arg name="x_pos" default="0.0"/> <!-- 机器人在 x 轴上的位置 --><arg name="y_pos" default="0.0"/> <!-- 机器人在 y 轴上的位置 --><arg name="z_pos" default="0.0"/> <!-- 机器人在 z 轴上的位置 --><!-- 设置仿真时间使用真实时间(/use_sim_time 为 true),通常用于 Gazebo 仿真 --><param name="/use_sim_time" value="true" /> <!-- 引入 Gazebo 仿真世界启动文件 (gazebo_world.launch),该文件定义了Gazebo世界环境 --><include file="$(find my_package)/launch/gazebo_world.launch"/><!-- 通过 xacro 文件生成机器人的 URDF 描述,并加载到 ROS 参数服务器中 --><param name="robot_description" command="$(find xacro)/xacro --inorder $(find my_package)/xacro/mybot1.xacro" /><!-- 启动 Gazebo 插件,将机器人模型(URDF)添加到 Gazebo 仿真环境中 --><node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model mybot.xacro -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" /><!-- 启动 robot_state_publisher 节点,用于发布机器人状态(例如各个关节的位置) --><node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" /> </launch>
注意: