【ROS2学习笔记】Gazebo 仿真与 XACRO 模型

前言

本系列博文是本人的学习笔记,自用为主,不是教程,学习请移步其他大佬的相关教程。前几篇学习资源来自鱼香ROS大佬的详细教程,适合深入学习,但对本人这样的初学者不算友好,后续笔记将以@古月居的ROS2入门21讲为主,侵权即删。

一、学习目标

  1. 理解 Gazebo 的核心价值 ------ 没有实物机器人时,也能做物理仿真(模拟运动、环境交互)
  2. 掌握 Gazebo 的安装与基础启动(解决离线模型加载问题)
  3. 学会用 XACRO 优化 URDF(解决 URDF 重复代码多、维护难的痛点)
  4. 掌握 Gazebo 仿真模型的必备配置(惯性、碰撞、传动、控制器插件)
  5. 能独立完成 "移动机器人 Gazebo 仿真 + 键盘控制" 的完整流程
  6. 了解下一代仿真器 Ignition 的基本使用

二、Gazebo 是什么?

2.1 一句话定义:机器人的 "虚拟试验场"

Gazebo 是 ROS 生态中最常用的三维物理仿真平台,能模拟真实世界的物理规则(重力、摩擦力、碰撞),让虚拟机器人在虚拟环境中运动,就像在真实世界一样。

2.2 为什么需要 Gazebo?(解决初学者的痛点)

痛点场景 Gazebo 的解决方案 例子
没有实物机器人 用虚拟机器人做开发、测试 没买移动机器人,也能调试导航算法
实物测试危险 / 成本高 模拟高危场景(如碰撞、悬崖) 测试无人机避障,不用担心摔机
需要重复测试相同场景 保存 / 加载仿真环境,精确复现测试条件 每次测试都用同一个 "客厅" 环境
需要模拟复杂环境 加载地图、障碍物、光照等环境元素 模拟火星表面环境,测试火星车运动

三、Gazebo 基础:安装与启动

3.1 安装步骤(以 ROS2 Humble 为例)

1. 安装 Gazebo 核心包

打开终端,执行命令:

复制代码
# 安装ROS2 Humble对应的Gazebo包(包含核心功能和ROS接口)
sudo apt install ros-humble-gazebo-*
2. 解决 "离线模型加载慢" 问题(关键!)

Gazebo 第一次启动时会在线下载模型(如桌子、椅子),速度很慢,建议提前下载离线模型:

  1. 下载离线模型包(GitHub 链接):

    复制代码
    git clone https://github.com/osrf/gazebo_models.git ~/.gazebo/models
  2. 等待下载完成(约 1GB,耐心等待),之后启动 Gazebo 会直接加载本地模型。

3. 验证安装

启动 Gazebo 空环境,测试是否正常:

复制代码
# 启动Gazebo(带ROS2接口)
ros2 launch gazebo_ros gazebo.launch.py
  • 预期效果:弹出 Gazebo 窗口,显示空旷的仿真环境(地面是网格),无报错。

3.2 Gazebo 窗口基础操作

操作需求 鼠标 / 键盘操作
旋转视角 按住鼠标左键拖动
平移视角 按住鼠标中键拖动
缩放视角 滚动鼠标滚轮
选中物体(如机器人) 单击鼠标左键
移动选中物体 按住鼠标右键拖动
关闭 Gazebo 关闭窗口,或终端按Ctrl+C

四、XACRO:优化 URDF 的 "编程化工具"

URDF 虽然能描述机器人,但存在重复代码多、参数难维护的问题(比如 4 个轮子要写 4 遍相同代码)。XACRO(XML Macro)是 URDF 的升级版本,支持 "编程化" 特性,让模型编写更高效。

4.1 XACRO 的核心优势(对比 URDF)

特性 URDF 的问题 XACRO 的解决方案 小白类比
重复代码多 4 个轮子要写 4 遍<link><joint> 宏定义(xacro:macro),写 1 次复用 4 次 像函数定义,调用时传参数就行
参数难修改 改轮子半径要找遍所有相关代码 常量定义(xacro:property),改 1 处全生效 像编程中的全局变量,改变量值即可
无计算能力 轮距 = 2× 轮中心 y 坐标,需手动算 支持数学计算(${a+b}),自动算结果 像 Excel 公式,输入表达式自动计算
大文件难维护 整个机器人写在 1 个 URDF 里,找代码麻烦 文件包含(xacro:include),分模块管理 像 C 语言的#include,分文件写代码

4.2 XACRO 核心语法

1. 常量定义(xacro:property

作用 :定义不变的参数(如轮子半径、底盘质量),方便后续修改。语法

复制代码
<!-- 定义常量:名字="参数名",值="参数值" -->
<xacro:property name="M_PI" value="3.1415926"/>  <!-- 圆周率 -->
<xacro:property name="wheel_radius" value="0.06"/> <!-- 轮子半径0.06米 -->
<xacro:property name="base_mass" value="1.0"/>    <!-- 底盘质量1千克 -->

<!-- 调用常量:用${参数名} -->
<geometry>
  <!-- 圆柱体半径=wheel_radius(调用常量) -->
  <cylinder radius="${wheel_radius}" length="0.025"/>
</geometry>
2. 数学计算(${表达式}

作用 :自动计算参数(如轮距 = 2× 轮子 y 坐标),避免手动计算错误。支持运算+ - * / ()(优先级),自动转浮点数。例子

复制代码
<!-- 定义轮子中心到底盘中心的y距离 -->
<xacro:property name="wheel_joint_y" value="0.19"/>

<!-- 轮距=2×wheel_joint_y(左右轮之间的距离) -->
<xacro:property name="wheel_separation" value="${2 * wheel_joint_y}"/>

<!-- 调用计算结果(Gazebo差速控制器用) -->
<wheel_separation>${wheel_separation}</wheel_separation>
3. 宏定义(xacro:macro

作用 :将重复的代码(如轮子的<link><joint>)封装成 "模块",调用时传参数即可。语法

复制代码
<!-- 1. 定义宏:name=宏名,params=参数(多个参数用空格分隔) -->
<xacro:macro name="wheel" params="prefix reflect">
  <!-- prefix:轮子前缀(如left/right),reflect:左右对称(1/-1) -->
  
  <!-- 关节:名字=prefix_wheel_joint(如left_wheel_joint) -->
  <joint name="${prefix}_wheel_joint" type="continuous">
    <!-- 位置:y=reflect×wheel_joint_y(左右轮对称,reflect=1是左轮,-1是右轮) -->
    <origin xyz="0 ${reflect*wheel_joint_y} -0.05" rpy="0 0 0"/>
    <parent link="base_link"/>
    <child link="${prefix}_wheel_link"/> <!-- 连杆名=prefix_wheel_link -->
    <axis xyz="0 1 0"/> <!-- 绕y轴旋转 -->
  </joint>

  <!-- 连杆:名字=prefix_wheel_link -->
  <link name="${prefix}_wheel_link">
    <visual>
      <origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/> <!-- 旋转90度,让圆柱体立起来 -->
      <geometry>
        <cylinder radius="${wheel_radius}" length="0.025"/> <!-- 调用常量 -->
      </geometry>
    </visual>
  </link>
</xacro:macro>

<!-- 2. 调用宏:传参数prefix和reflect -->
<xacro:wheel prefix="left" reflect="1"/>  <!-- 左轮:reflect=1(y正方向) -->
<xacro:wheel prefix="right" reflect="-1"/> <!-- 右轮:reflect=-1(y负方向) -->
4. 文件包含(xacro:include

作用 :将大模型拆分成多个小文件(如底盘、相机、雷达),方便维护。语法

复制代码
<!-- 主文件:mbot_gazebo.xacro -->
<?xml version="1.0"?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <!-- 包含底盘模块文件(路径:learning_gazebo/urdf/mbot_base_gazebo.xacro) -->
  <xacro:include filename="$(find learning_gazebo)/urdf/mbot_base_gazebo.xacro" />
  
  <!-- 调用底盘宏(在mbot_base_gazebo.xacro中定义) -->
  <xacro:mbot_base_gazebo/>
</robot>

4.3 XACRO 安装与验证

1. 安装 XACRO 工具
复制代码
sudo apt install ros-humble-xacro
2. 验证 XACRO 文件(转 URDF)

XACRO 文件不能直接用,需要转成 URDF 格式,命令:

复制代码
# 格式:xacro 输入XACRO文件 > 输出URDF文件
xacro learning_gazebo/urdf/mbot_gazebo.xacro > mbot_gazebo.urdf
  • 若没有报错,生成mbot_gazebo.urdf,说明 XACRO 语法正确。

五、Gazebo 仿真模型配置(关键!URDF→Gazebo 可用)

XACRO 模型还需要添加物理参数Gazebo 专属配置,否则加载到 Gazebo 会飘起来、不能动。核心配置有 4 步:

5.1 1. 完善物理参数(惯性 + 碰撞)

Gazebo 是物理仿真,必须给每个<link>惯性(inertial)碰撞(collision)

  • 惯性(inertial):描述物体的质量和惯性(如底盘重 1kg,转动时的阻力),没有会飘起来;
  • 碰撞(collision):描述物体的碰撞形状(简化版,比如用长方体代替复杂外壳),没有会穿模。
例子(用 XACRO 宏定义惯性):
复制代码
<!-- 定义圆柱体惯性宏:m=质量,r=半径,h=长度 -->
<xacro:macro name="cylinder_inertial_matrix" params="m r h">
  <inertial>
    <mass value="${m}" /> <!-- 质量 -->
    <!-- 惯性矩阵(公式固定,不用记,代入参数即可) -->
    <inertia ixx="${m*(3*r*r+h*h)/12}" ixy="0" ixz="0"
             iyy="${m*(3*r*r+h*h)/12}" iyz="0"
             izz="${m*r*r/2}" /> 
  </inertial>
</xacro:macro>

<!-- 调用宏:底盘惯性(质量1kg,半径0.2m,长度0.16m) -->
<link name="base_link">
  <collision>
    <geometry>
      <cylinder radius="${base_radius}" length="${base_length}"/> <!-- 碰撞形状=底盘形状 -->
    </geometry>
  </collision>
  <!-- 调用惯性宏 -->
  <xacro:cylinder_inertial_matrix m="${base_mass}" r="${base_radius}" h="${base_length}" />
</link>

5.2 2. 添加 Gazebo 颜色标签(gazebo

URDF 的颜色(material)在 Gazebo 中不生效,需要用<gazebo>标签重新设置:

复制代码
<!-- 格式:<gazebo reference="link名"> 配置Gazebo属性 -->
<gazebo reference="base_link">
  <material>Gazebo/Blue</material> <!-- Gazebo预设颜色:蓝色 -->
</gazebo>
<gazebo reference="left_wheel_link">
  <material>Gazebo/Gray</material> <!-- 轮子颜色:灰色 -->
</gazebo>
  • Gazebo 预设颜色:Gazebo/RedGazebo/GreenGazebo/BlueGazebo/Gray等。

5.3 3. 配置传动装置(transmission

传动装置是 "电机" 和 "关节" 的桥梁,告诉 Gazebo "哪个关节由哪个电机驱动":

复制代码
<transmission name="left_wheel_joint_trans">
  <type>transmission_interface/SimpleTransmission</type> <!-- 简单传动类型 -->
  <joint name="left_wheel_joint" > <!-- 关联的关节:左轮关节 -->
    <!-- 硬件接口:速度控制(控制关节的角速度) -->
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  </joint>
  <actuator name="left_wheel_joint_motor"> <!-- 电机名字 -->
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
    <mechanicalReduction>1</mechanicalReduction> <!-- 减速比:1=无减速 -->
  </actuator>
</transmission>

5.4 4. 添加 Gazebo 控制器插件(gazebo plugin

控制器插件负责 "计算电机速度",比如移动机器人的差速控制器 (根据cmd_vel指令,计算左右轮的角速度):

复制代码
<gazebo>
  <!-- 差速控制器插件:文件名固定,不用改 -->
  <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
    <update_rate>30</update_rate> <!-- 控制频率:30Hz -->
    <left_joint>left_wheel_joint</left_joint> <!-- 左轮关节名 -->
    <right_joint>right_wheel_joint</right_joint> <!-- 右轮关节名 -->
    <wheel_separation>${2*wheel_joint_y}</wheel_separation> <!-- 轮距(左右轮距离) -->
    <wheel_diameter>${2*wheel_radius}</wheel_diameter> <!-- 轮子直径 -->
    <max_wheel_torque>20</max_wheel_torque> <!-- 最大扭矩(防止电机过载) -->
    <command_topic>cmd_vel</command_topic> <!-- 接收速度指令的话题:/cmd_vel -->
    <publish_odom>true</publish_odom> <!-- 发布里程计信息 -->
    <odometry_topic>odom</odometry_topic> <!-- 里程计话题名:/odom -->
    <robot_base_frame>base_footprint</robot_base_frame> <!-- 机器人基础坐标系 -->
  </plugin>
</gazebo>
  • 关键:command_topic="cmd_vel"表示插件会订阅/cmd_vel话题,接收速度指令(线速度 x、角速度 z)。

六、实战:移动机器人 Gazebo 仿真(完整流程)

6.1 步骤 1:创建功能包与文件结构

复制代码
learning_gazebo/          # 功能包名
├── urdf/                # XACRO文件
│   ├── mbot_gazebo.xacro          # 主XACRO文件(包含底盘)
│   └── mbot_base_gazebo.xacro     # 底盘XACRO文件(含物理参数、插件)
├── launch/              # Launch文件
│   └── load_urdf_into_gazebo.launch.py  # 启动仿真的Launch
└── worlds/              # Gazebo世界文件(可选,默认是空环境)
    └── neighborhood.world  # 小区环境(示例)

6.2 步骤 2:解析 Launch 文件(load_urdf_into_gazebo.launch.py

Launch 文件一键启动所有节点(Gazebo、加载模型、发布 TF),代码带详细注释:

python 复制代码
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch_ros.actions import Node

def generate_launch_description():
    # 1. 获取功能包路径(自动找到learning_gazebo的位置)
    package_name = 'learning_gazebo'
    pkg_path = get_package_share_directory(package_name)
    
    # 2. 世界文件路径(可选:用自定义环境,如小区;默认是空环境,可注释)
    world_file_path = 'worlds/neighborhood.world'
    world_path = os.path.join(pkg_path, world_file_path)  

    # 3. 机器人初始位置(x=0, y=0, z=0,朝向yaw=0)
    spawn_x = '0.0'
    spawn_y = '0.0'
    spawn_z = '0.0'
    spawn_yaw = '0.0'

    # 4. 包含底盘XACRO的Launch(若有单独的底盘Launch,可包含)
    mbot_launch = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([os.path.join(
            pkg_path, 'launch', 'mbot.launch.py'  # 底盘Launch(可选,无则注释)
        )]),
        launch_arguments={'use_sim_time': 'true', 'world': world_path}.items()  # 启用仿真时间
    )

    # 5. 启动Gazebo(加载世界环境)
    gazebo_launch = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([os.path.join(
            get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py'
        )])
    )

    # 6. 加载机器人模型到Gazebo(关键节点:spawn_entity)
    spawn_robot = Node(
        package='gazebo_ros',
        executable='spawn_entity.py',
        arguments=[
            '-topic', 'robot_description',  # 从/robot_description话题获取模型
            '-entity', 'mbot',             # 机器人在Gazebo中的名字
            '-x', spawn_x, '-y', spawn_y, '-z', spawn_z, '-Y', spawn_yaw  # 初始位置
        ],
        output='screen'  # 打印日志到终端
    )

    # 7. 启动关节状态发布节点(带GUI,可拖动关节)
    joint_state_pub = Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui'
    )

    # 8. 启动机器人状态发布节点(发布TF树,Gazebo需要)
    robot_state_pub = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        arguments=[os.path.join(pkg_path, 'urdf', 'mbot_gazebo.xacro')]  # 传入XACRO文件
    )

    # 返回所有节点(顺序:先启动Gazebo,再加载模型)
    return LaunchDescription([
        joint_state_pub,
        robot_state_pub,
        gazebo_launch,
        spawn_robot,
        # mbot_launch  # 若有底盘Launch,取消注释
    ])

6.3 步骤 3:启动仿真与控制

1. 编译功能包
复制代码
cd dev_ws  # 进入ROS工作空间
colcon build --packages-select learning_gazebo  # 编译功能包
source install/setup.bash  # 加载环境变量
2. 启动 Gazebo 仿真
复制代码
ros2 launch learning_gazebo load_urdf_into_gazebo.launch.py
  • 预期效果:Gazebo 窗口加载机器人模型(蓝色底盘 + 灰色轮子),无报错。
3. 启动键盘控制(新终端)

Gazebo 的差速控制器订阅/cmd_vel话题,需要用键盘发布速度指令:

复制代码
# 安装键盘控制包(若未安装)
sudo apt install ros-humble-teleop-twist-keyboard
# 启动键盘控制
ros2 run teleop_twist_keyboard teleop_twist_keyboard 
4. 控制机器人运动

根据终端提示,用键盘按键控制:

  • i:前进(线速度 x=0.5m/s)
  • ,(逗号):后退(线速度 x=-0.5m/s)
  • j:左转(角速度 z=1rad/s)
  • l:右转(角速度 z=-1rad/s)
  • k:停止
5. 虚拟机用户注意!(避坑)

若在虚拟机中运行 Gazebo 卡顿或黑屏,需关闭硬件加速:

复制代码
# 临时关闭(当前终端生效)
export SVGA_VGPU10=0
# 永久关闭(写入.bashrc)
echo "export SVGA_VGPU10=0" >> ~/.bashrc
source ~/.bashrc

七、下一代仿真器:Ignition Gazebo

Gazebo 的下一代版本叫Ignition,渲染效果更好、仿真更流畅,安装和启动更简单:

7.1 安装 Ignition

复制代码
sudo apt install ros-humble-ros-ign  # ROS2 Humble对应版本

7.2 启动示例(RGBD 相机仿真)

复制代码
ros2 launch ros_ign_gazebo_demos rgbd_camera_bridge.launch.py
  • 预期效果:弹出 Ignition 窗口(带相机和立方体),同时启动 RViz 显示相机图像。

7.3 官方文档

更多 Ignition 使用方法:https://www.ignitionrobotics.org/

八、附录:完整 XACRO 模型解析(mbot_base_gazebo.xacro

关键代码逐段注释,帮助小白理解:

复制代码
<?xml version="1.0"?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">

    <!-- 1. 常量定义:机器人所有固定参数(改这里全生效) -->
    <xacro:property name="M_PI" value="3.1415926"/> <!-- 圆周率 -->
    <xacro:property name="base_mass"   value="1" />  <!-- 底盘质量1kg -->
    <xacro:property name="base_radius" value="0.20"/> <!-- 底盘半径0.2m -->
    <xacro:property name="base_length" value="0.16"/> <!-- 底盘长度0.16m -->

    <xacro:property name="wheel_mass"   value="0.2" /> <!-- 轮子质量0.2kg -->
    <xacro:property name="wheel_radius" value="0.06"/> <!-- 轮子半径0.06m -->
    <xacro:property name="wheel_length" value="0.025"/> <!-- 轮子宽度0.025m -->
    <xacro:property name="wheel_joint_y" value="0.19"/> <!-- 轮子关节y坐标(距底盘中心) -->
    <xacro:property name="wheel_joint_z" value="0.05"/> <!-- 轮子关节z坐标(距底盘底部) -->

    <xacro:property name="caster_mass"    value="0.2" /> <!-- 万向轮质量0.2kg -->
    <xacro:property name="caster_radius"  value="0.015"/> <!-- 万向轮半径0.015m -->
    <xacro:property name="caster_joint_x" value="0.18"/> <!-- 万向轮关节x坐标(距底盘中心) -->

    <!-- 2. 颜色定义(URDF用) -->
    <material name="yellow"><color rgba="1 0.4 0 1"/></material>
    <material name="black"><color rgba="0 0 0 0.95"/></material>
    <material name="gray"><color rgba="0.75 0.75 0.75 1"/></material>

    <!-- 3. 惯性宏定义(复用) -->
    <!-- 球体惯性宏(万向轮用) -->
    <xacro:macro name="sphere_inertial_matrix" params="m r">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
                     iyy="${2*m*r*r/5}" iyz="0" 
                     izz="${2*m*r*r/5}" />
        </inertial>
    </xacro:macro>

    <!-- 圆柱体惯性宏(底盘、轮子用) -->
    <xacro:macro name="cylinder_inertial_matrix" params="m r h">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${m*(3*r*r+h*h)/12}" ixy="0" ixz="0"
                     iyy="${m*(3*r*r+h*h)/12}" iyz="0"
                     izz="${m*r*r/2}" /> 
        </inertial>
    </xacro:macro>

    <!-- 4. 轮子宏定义(左轮、右轮复用) -->
    <xacro:macro name="wheel" params="prefix reflect">
        <!-- 轮子关节(continuous:无限旋转) -->
        <joint name="${prefix}_wheel_joint" type="continuous">
            <origin xyz="0 ${reflect*wheel_joint_y} ${-wheel_joint_z}" rpy="0 0 0"/>
            <parent link="base_link"/>
            <child link="${prefix}_wheel_link"/>
            <axis xyz="0 1 0"/> <!-- 绕y轴旋转 -->
        </joint>

        <!-- 轮子连杆 -->
        <link name="${prefix}_wheel_link">
            <visual>
                <origin xyz="0 0 0" rpy="${M_PI/2} 0 0" /> <!-- 旋转90度,圆柱体立起 -->
                <geometry><cylinder radius="${wheel_radius}" length="${wheel_length}"/></geometry>
                <material name="gray" />
            </visual>
            <collision> <!-- 碰撞形状=外观形状 -->
                <origin xyz="0 0 0" rpy="${M_PI/2} 0 0" />
                <geometry><cylinder radius="${wheel_radius}" length="${wheel_length}"/></geometry>
            </collision>
            <xacro:cylinder_inertial_matrix m="${wheel_mass}" r="${wheel_radius}" h="${wheel_length}" />
        </link>

        <!-- Gazebo颜色配置 -->
        <gazebo reference="${prefix}_wheel_link"><material>Gazebo/Gray</material></gazebo>

        <!-- 传动装置(电机→关节) -->
        <transmission name="${prefix}_wheel_joint_trans">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="${prefix}_wheel_joint" >
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${prefix}_wheel_joint_motor">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
                <mechanicalReduction>1</mechanicalReduction>
            </actuator>
        </transmission>
    </xacro:macro>

    <!-- 5. 万向轮宏定义(前轮、后轮复用) -->
    <xacro:macro name="caster" params="prefix reflect">
        <joint name="${prefix}_caster_joint" type="fixed"> <!-- fixed:固定,不旋转 -->
            <origin xyz="${reflect*caster_joint_x} 0 ${-(base_length/2 + caster_radius)}" rpy="0 0 0"/>
            <parent link="base_link"/>
            <child link="${prefix}_caster_link"/>
        </joint>

        <link name="${prefix}_caster_link">
            <visual><geometry><sphere radius="${caster_radius}" /></geometry><material name="black" /></visual>
            <collision><geometry><sphere radius="${caster_radius}" /></geometry></collision>
            <xacro:sphere_inertial_matrix m="${caster_mass}" r="${caster_radius}" />
        </link>

        <gazebo reference="${prefix}_caster_link"><material>Gazebo/Black</material></gazebo>
    </xacro:macro>

    <!-- 6. 底盘宏定义(主宏,包含所有部件) -->
    <xacro:macro name="mbot_base_gazebo">
        <!-- 基础坐标系(base_footprint:机器人与地面的接触点) -->
        <link name="base_footprint">
            <visual><geometry><box size="0.001 0.001 0.001" /></geometry></visual>
        </link>
        <gazebo reference="base_footprint"><turnGravityOff>false</turnGravityOff></gazebo>

        <!-- 连接base_footprint和base_link -->
        <joint name="base_footprint_joint" type="fixed">
            <origin xyz="0 0 ${base_length/2 + caster_radius*2}" rpy="0 0 0" />        
            <parent link="base_footprint"/>
            <child link="base_link" />
        </joint>

        <!-- 底盘连杆 -->
        <link name="base_link">
            <visual>
                <geometry><cylinder length="${base_length}" radius="${base_radius}"/></geometry>
                <material name="yellow" />
            </visual>
            <collision><geometry><cylinder length="${base_length}" radius="${base_radius}"/></geometry></collision>
            <xacro:cylinder_inertial_matrix m="${base_mass}" r="${base_radius}" h="${base_length}" />
        </link>
        <gazebo reference="base_link"><material>Gazebo/Blue</material></gazebo>

        <!-- 调用轮子宏(左轮、右轮) -->
        <xacro:wheel prefix="left"  reflect="1"/>
        <xacro:wheel prefix="right" reflect="-1"/>

        <!-- 调用万向轮宏(前轮、后轮) -->
        <xacro:caster prefix="front" reflect="-1"/>
        <xacro:caster prefix="back"  reflect="1"/>

        <!-- 7. Gazebo差速控制器插件(核心) -->
        <gazebo>
            <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
                <update_rate>30</update_rate>
                <left_joint>left_wheel_joint</left_joint>
                <right_joint>right_wheel_joint</right_joint>
                <wheel_separation>${wheel_joint_y*2}</wheel_separation> <!-- 轮距=2×y坐标 -->
                <wheel_diameter>${2*wheel_radius}</wheel_diameter> <!-- 直径=2×半径 -->
                <max_wheel_torque>20</max_wheel_torque>
                <max_wheel_acceleration>1.0</max_wheel_acceleration>
                <command_topic>cmd_vel</command_topic> <!-- 接收速度指令 -->
                <publish_odom>true</publish_odom> <!-- 发布里程计 -->
                <odometry_topic>odom</odometry_topic>
                <robot_base_frame>base_footprint</robot_base_frame>
            </plugin>
        </gazebo> 
    </xacro:macro>

</robot>

九、复习要点总结(小白必背)

  1. Gazebo 核心:物理仿真平台,需添加惯性、碰撞、传动、插件才能用;
  2. XACRO 核心语法
    • 常量:xacro:property(定义参数);
    • 宏:xacro:macro(复用代码,如轮子);
    • 计算:${表达式}(自动算轮距、直径);
    • 包含:xacro:include(分模块管理);
  3. Gazebo 模型四步配置
    1. 加惯性(inertial):防飘;
    2. 加碰撞(collision):防穿模;
    3. 加 Gazebo 颜色(gazebo标签):显式正确;
    4. 加传动 + 插件:让机器人动起来;
  4. 仿真流程 :编译→启动 Launch→键盘控制(teleop_twist_keyboard);
  5. 避坑点:离线模型下载、虚拟机关闭硬件加速、XACRO 转 URDF 验证语法。

掌握这些,就能独立用 Gazebo 做移动机器人的仿真开发,后续可扩展导航、SLAM 等算法!

vi .bashrc 这个怎么用gredit打开

首先纠正一个小拼写:你说的 "gredit" 应该是 Linux 下的图形化文本编辑器 gedit (GNOME 桌面默认编辑器),下面分步骤教你用 gedit 打开 .bashrc 文件,小白也能轻松操作:

一、核心命令:用 gedit 打开 .bashrc

.bashrc 是用户主目录下的隐藏文件 (文件名以.开头),直接用 gedit 加文件路径即可打开,步骤如下:

1. 打开终端
  • 方法 1:桌面环境下,按 Ctrl + Alt + T 快捷键(通用 Linux 快捷键,比如 Ubuntu、Linux Mint 都适用);
  • 方法 2:从应用菜单找到 "终端"(Terminal)图标,点击打开。
2. 输入 gedit 命令

在终端中直接输入以下命令,按下回车:

复制代码
gedit ~/.bashrc
  • 命令解释:
    • gedit:调用图形化文本编辑器;
    • ~:代表你的用户主目录 (比如你的用户名是 ubuntu~ 就对应 /home/ubuntu);
    • /.bashrc:指定要打开的文件(. 开头表示隐藏文件,必须写全,不能漏了.)。
3. 编辑与保存
  • 按下回车后,会弹出 gedit 编辑器窗口,里面就是 .bashrc 的内容,直接编辑即可(比如添加 ROS 环境变量、自定义别名等);
  • 编辑完成后,按 Ctrl + S 保存,或点击窗口左上角的 "保存" 按钮;
  • 关闭 gedit 窗口即可。

二、关键补充:修改 .bashrc 后生效

修改 .bashrc 后(比如添加了 source /opt/ros/humble/setup.bash),需要让修改立即生效,否则新打开的终端不会加载新配置,执行以下命令:

复制代码
source ~/.bashrc

三、特殊情况:如果终端不在主目录,怎么办?

如果你的终端当前路径不是主目录(比如在 ~/dev_ws 下),直接输入 gedit .bashrc 会报错 "找不到文件",这时候有两种解决方法:

  1. 方法 1:用绝对路径 (推荐,不管当前路径在哪都能用):

    复制代码
    gedit ~/.bashrc
  2. 方法 2:先回到主目录,再打开

    复制代码
    cd ~  # 回到主目录
    gedit .bashrc  # 再打开文件

四、注意:纯命令行环境无法用 gedit!

如果你的 Linux 是纯命令行界面 (没有图形桌面,比如服务器系统),gedit 无法使用(因为它是图形化工具),这时候才需要用 vi .bashrcvim .bashrc 编辑。但只要你的系统有桌面(比如 Ubuntu 桌面版),用上面的 gedit 方法绝对可行。

相关推荐
悠哉悠哉愿意2 小时前
【ROS2学习笔记】节点篇:ROS 2编程基础
笔记·学习·ros2
我命由我123453 小时前
Photoshop - Photoshop 工具栏(2)矩形框选工具
经验分享·笔记·学习·ui·photoshop·ps·美工
序属秋秋秋3 小时前
《C++进阶之C++11》【异常】
c++·笔记·学习·c++11·异常·新特性
张书名6 小时前
《强化学习数学原理》学习笔记6——贝尔曼最优方程的压缩性质
笔记·学习
悠哉悠哉愿意6 小时前
【ROS2学习笔记】话题通信篇:话题通信项目实践——系统状态监测与可视化工具
笔记·学习·ros2
hssfscv6 小时前
JAVA学习笔记——9道综合练习习题+二维数组
java·笔记·学习
charlie11451419110 小时前
精读 C++20 设计模式:行为型设计模式 — 访问者模式
c++·学习·设计模式·访问者模式·c++20
长路归期无望10 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
知识分享小能手11 小时前
微信小程序入门学习教程,从入门到精通,微信小程序常用API(上)——知识点详解 + 案例实战(4)
前端·javascript·学习·微信小程序·小程序·html5·微信开放平台