ros2 visualize & launch

ros2 run robot_state_publisher robot_state_publisher --ros-args -p robot_description:="$(xacro /home/user/ros2/arduinobot_ws/src/arduinobot_description/urdf/arduinobot_urdf.xacro)"
# all the movable joints of our robots
ros2 run joint_state_publisher_gui joint_state_publisher_gui
# open rviz2 visulize
ros2 run rviz2 rviz2

use launch file
display.launch.py

from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import DeclareLaunchArgument
import os
from ament_index_python.packages import get_package_share_directory
from launch_ros.parameter_descriptions import ParameterValue
from launch.substitutions import Command, LaunchConfiguration

def generate_launch_description():
# ==========================================
# 第一步:声明启动参数
# ==========================================
# DeclareLaunchArgument 的作用:声明一个可在命令行动态配置的参数
# - name: 参数名
# - default_value: 默认值(不传参时使用)
# - description: 参数说明(ros2 launch --show-args 时显示)
model_arg = DeclareLaunchArgument(
name=“model”,
default_value=os.path.join(
get_package_share_directory(“arduinobot_description”),
“urdf”, “arduinobot_urdf.xacro”),
description=“Absolute path to the robot URDF file”
)

# ==========================================
# 第二步:处理 URDF(Xacro → URDF)
# ==========================================
# LaunchConfiguration("model"): 获取参数的运行时值(占位符)
# Command(["xacro ", ...]): 执行 shell 命令,这里用于运行 xacro 转换
# ParameterValue(...): 将命令输出包装为 ROS 参数可接受的格式
#
# 整个过程等价于在终端执行:xacro /path/to/robot.xacro
# 然后将输出的 URDF 字符串赋给 robot_description 参数
robot_description = ParameterValue(
    Command(["xacro ", LaunchConfiguration("model")])
)

# ==========================================
# 第三步:定义要启动的节点
# ==========================================

# robot_state_publisher: 将 URDF 发布到 /robot_description 话题,
# 并根据 /joint_states 话题发布 TF 变换
robot_state_publisher = Node(
    package="robot_state_publisher",
    executable="robot_state_publisher",
    parameters=[{"robot_description": robot_description}]
)

# joint_state_publisher_gui: 提供 GUI 滑块控制非固定关节
joint_state_publisher_gui = Node(
    package="joint_state_publisher_gui",
    executable="joint_state_publisher_gui"
)

# RViz2: 3D 可视化工具
rviz_node = Node(
    package="rviz2",
    executable="rviz2",
    name="rviz2",
    output="screen",
    arguments=["-d", os.path.join(
        get_package_share_directory("arduinobot_description"),
        "rviz", "display.rviz")]
)

# ==========================================
# 第四步:组装 LaunchDescription 并返回
# ==========================================
# 注意:DeclareLaunchArgument 必须添加到 LaunchDescription 中才会生效
return LaunchDescription([
    model_arg,
    robot_state_publisher,
    joint_state_publisher_gui,
    rviz_node
])

cmd

ros2 launch arduinobot_description display.launch.py

三、核心概念深度解析

3.1 DeclareLaunchArgument vs LaunchConfiguration

这是 Launch 文件中最常被混淆的两个概念:

概念 作用 类比
DeclareLaunchArgument 声明参数(名称、默认值、描述) 函数定义参数:def func(model='default.xacro')
LaunchConfiguration 读取参数的运行时值(占位符) 函数体内使用参数:print(model)
命令行传参 model:=xxx 覆盖默认值 调用函数时传参:func(model='xxx')

关键点

  1. DeclareLaunchArgument 必须添加到 LaunchDescription 中才会生效。
  2. LaunchConfiguration 只是占位符,不是 Python 字符串或布尔值,不能直接用于 if 判断。
  3. 如果没有 DeclareLaunchArgumentLaunchConfiguration 仍可读取外部传参,但没有默认值,也不会出现在 --show-args 列表中。

3.2 数据流示意

命令行: ros2 launch … model:=/other/path.xacro

DeclareLaunchArgument(name=“model”, default_value=“/default/path.xacro”)

LaunchConfiguration(“model”) → 运行时得到 “/other/path.xacro”

Command(["xacro ", LaunchConfiguration(“model”)]) → 执行 xacro /other/path.xacro

ParameterValue(Command(…)) → URDF 字符串

Node 参数: {“robot_description”: URDF字符串}


gazebo launch

需要先在axcro中添加质点惯性张量和collision,collision复制stl文件即可

from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import DeclareLaunchArgument, SetEnvironmentVariable, IncludeLaunchDescription
import os
from ament_index_python.packages import get_package_share_directory, get_package_prefix
from launch_ros.parameter_descriptions import ParameterValue
from launch.substitutions import Command, LaunchConfiguration
from launch.launch_description_sources import PythonLaunchDescriptionSource

def generate_launch_description():
    model_arg=DeclareLaunchArgument(
        name="model",
        default_value=os.path.join(get_package_share_directory("arduinobot_description"),"urdf","arduinobot_urdf.xacro"),
        description="Absolute path to the robot URDF file"
    )

    """
    set enviromental variable so that it can properly load
    and visualize robot's urdf model
    """
    env_var = SetEnvironmentVariable("GAZEBO_MODEL_PATH",os.path.join(get_package_prefix("arduinobot_description"),"share"))
    """
        convert xacro to plain urdf
        LaunchConfiguration read the content of model argument which full path of axcro model
        robot_description will be full plain urdf model
    """
    robot_description = ParameterValue(Command(["xacro ", LaunchConfiguration("model")]))
    # all the nodes want to start
    robot_state_publisher = Node(
        package="robot_state_publisher",
        executable="robot_state_publisher",
        parameters=[{"robot_description":robot_description}]
    )
    """
    gazebo has 2 modules server and client, need launch
    """
    start_gazebo_server = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(os.path.join(get_package_share_directory("gazebo_ros"),"launch","gzserver.launch.py"))
    )
    start_gazebo_client = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(os.path.join(get_package_share_directory("gazebo_ros"),"launch","gzclient.launch.py"))
    )
    # appear our bot
    spawn_robot = Node(
        package="gazebo_ros",
        executable="spawn_entity.py",
        arguments=["-entity","arduinobot","-topic", "robot_description"]
    )

    return LaunchDescription([
        env_var,
        model_arg,
        robot_state_publisher,
        start_gazebo_server,
        start_gazebo_client,
        spawn_robot
    ])

gazebo

transmission this tag indicates the presense of machanical transmission connects each motor of robot to each link of arm.
all movable links will be actuated by the same motor with same mechanical.

<!-- the number of the joint to which transmission refers to -->
<xacro:macro name="default_transmission" params="number">
    <transmission name="transmission_${number}">
        <!-- simulation of transmission logic -->
        <plugin>transmission_interface/SimpleTransmission</plugin>
        <joint name="joint_${number}" role="joint1">
            <!-- one degree of the motor corresponds to one degree of the robot arm -->
            <mechanicalReduction>1.0</mechanicalReduction>
        </joint>
        <actuator name="motor_${number}" role="actuator1">
          
        </actuator>
    </transmission>
</xacro:macro>

<xacro:default_transmission number="1"/>
<xacro:default_transmission number="2"/>
<xacro:default_transmission number="3"/>
<xacro:default_transmission number="4"/>
posted @ 2025-07-15 22:45  fangshuo  阅读(80)  评论(0)    收藏  举报