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') |
关键点:
DeclareLaunchArgument必须添加到LaunchDescription中才会生效。LaunchConfiguration只是占位符,不是 Python 字符串或布尔值,不能直接用于if判断。- 如果没有
DeclareLaunchArgument,LaunchConfiguration仍可读取外部传参,但没有默认值,也不会出现在--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"/>
浙公网安备 33010602011771号