机器人组件结构
一个典型的机器人可以由多个 link
和 joint
组成,连接各个部件。以下是一个简单的机器人模型,由6个 link
和5个 joint
构成:
Robot Links(机器人部件):
- left_wheel_link: 左轮
- base_link: 躯体
- right_wheel_link: 右轮
- imu_link: IMU(惯性测量单元)
- laser_link: 雷达
- caster_link: 支撑轮
Robot Joints(机器人关节):
- left_wheel_joint: 左轮与躯体之间的旋转关节
- right_wheel_joint: 右轮与躯体之间的旋转关节
- imu_joint: IMU与躯体之间的连接关节
- laser_joint: 雷达与躯体之间的连接关节
- caster_joint: 支撑轮与躯体之间的连接关节
整体概括
robot
-
定义:
robot
元素是URDF文件的根元素,定义了整个机器人的结构。所有的link
(链接)和joint
(关节)元素都包含在该元素中。每个URDF文件只能有一个robot
元素。 -
主要属性:
name
属性指定机器人模型的名称。 -
格式:
<robot name="robot_name"> </robot>
Link
link
是机器人模型中的基本组成部分,通常表示机器人的各个部件,如车轮、传感器、躯体等。每个 link
包含其几何形状、材质、碰撞属性等。
常用子标签:
-
visual: 用于定义物理外观的几何形状。常用几何形状有:
- : 长方体,使用
size
属性定义长、宽、高。 - : 圆柱体,使用
radius
和length
属性定义半径和高度。 - : 球体,使用
radius
属性定义半径。 - : 用于导入第三方模型,
filename
属性指定模型文件路径。
举例:
<visual> <geometry> <box size="1 1 1"/> </geometry> </visual>
- : 长方体,使用
-
origin: 定义物体的坐标系原点,相对于父对象的位置。常用属性为
xyz
(位置)和rpy
(姿态,单位为弧度)。举例:
<origin xyz="0 0 0" rpy="0 0 0"/>
-
material: 设置物体的材质,使用
color
属性来指定颜色和透明度(rgba
)。举例:
<material name="white"> <color rgba="1.0 1.0 1.0 0.5"/> </material>
-
collision: 定义碰撞检测的几何形状,通常与
visual
类似,但用于仿真。 -
inertial: 定义物体的惯性参数(质量、惯性矩阵等),用于动态仿真。
Joint
joint
连接机器人中的不同 link
,定义了它们之间的运动关系。每个 joint
包含多个属性,描述关节类型、旋转轴、运动范围等。
常用关节类型:
- revolute: 旋转关节,沿一个固定轴旋转,适用于需要角度限制的情况(例如舵机)。
- prismatic: 滑动关节,允许沿某一轴线移动,适用于有位置限制的情况。
- continuous: 连续旋转关节,绕轴无限旋转,适用于如轮子的旋转。
- fixed: 固定关节,不允许运动,通常用于将两个
link
固定在一起。
不常用关节类型:
- screw:螺旋关节,结合了旋转和平移的运动。
- planar: 平面关节,允许在二维平面内进行运动。
- floating: 浮动关节,允许在三维空间内进行自由的平移和旋转。
常用子标签:
- parent: 父
link
的名称,定义该关节的起始link
。 - child: 子
link
的名称,定义该关节的结束link
。 - origin: 定义
parent
和child
之间的相对位置与姿态。 - axis: 定义旋转或滑动关节的运动轴。
举例:
<joint name="left_wheel_joint" type="revolute">
<parent link="base_link"/>
<child link="left_wheel_link"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
</joint>
传感器和视觉元素
- 传感器:可以通过
sensor
元素添加各种传感器(如相机、激光雷达等)。 - 视觉:可以为每个
link
添加visual
元素,控制物体的颜色、材质和纹理.
<sensor type="camera" name="camera_link">
<origin xyz="0 0 1" rpy="0 0 0"/>
<camera>
<horizontal_fov value="1.0"/>
<image width="640" height="480"/>
</camera>
</sensor>
urdf的构建
功能包的构建
-
ros2 pkg create fishbot_description --build-type ament_python
创建urdf文件和launch文件
-
cd fishbot_description && mkdir urdf && cd urdf touch fishbot_base.urdf cd .. && mkdir launch && cd launch touch display_rviz2.launch.py
fishbot_base.urdf
-
<?xml version="1.0"?> <robot name="fishbot"> <!-- base link --> <link name="base_link"> <visual> <origin xyz="0 0 0.0" rpy="0 0 0"/> <geometry> <cylinder length="0.12" radius="0.10"/> </geometry> </visual> </link> <!-- laser link --> <link name="laser_link"> <visual> <origin xyz="0 0 0" rpy="0 0 0"/> <geometry> <cylinder length="0.02" radius="0.02"/> </geometry> <material name="black"> <color rgba="0.0 0.0 0.0 0.8" /> </material> </visual> </link> <!-- laser joint --> <joint name="laser_joint" type="fixed"> <parent link="base_link" /> <child link="laser_link" /> <origin xyz="0 0 0.075" /> </joint> </robot>
display_rviz2.launch.py
-
import os from launch import LaunchDescription from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from launch_ros.substitutions import FindPackageShare def generate_launch_description(): package_name = 'fishbot_description' urdf_name = 'fishbot_base.urdf' ld = LaunchDescription() pkg_share = FindPackageShare(package=package_name).find(package_name) urdf_model_path = os.path.join(pkg_share , f'urdf/{urdf_name}') robot_state_publisher_node = Node( package='robot_state_publisher', executable='robot_state_publisher', arguments=[urdf_model_path] ) joint_state_publisher_node = Node( package='joint_state_publisher_gui', executable='joint_state_publisher_gui', name='joint_state_publisher_gui', arguments=[urdf_model_path] ) rviz2_node = Node( package='rviz2', executable='rviz2', name = 'rviz2', output='screen' ) ld.add_action(robot_state_publisher_node) ld.add_action(joint_state_publisher_node) ld.add_action(rviz2_node) return ld
导入必要的模块
import os from launch import LaunchDescription from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from launch_ros.substitutions import FindPackageShare
LaunchDescription
: 用于定义和管理要启动的节点。LaunchConfiguration
: 可用于在启动时传递配置参数(虽然在此例中未使用)。Node
: 用于定义一个 ROS 2 节点,指定它的包和可执行文件。FindPackageShare
: 查找一个包的共享目录,通常用来查找 URDF 等文件。
定义启动描述
def generate_launch_description(): package_name = 'fishbot_description' urdf_name = 'fishbot_base.urdf' ld = LaunchDescription()
generate_launch_description
: 启动文件的核心函数,负责返回启动的所有描述信息。package_name
和urdf_name
: 定义了要加载的包名和 URDF 文件名。
查找 URDF 文件路径
pkg_share = FindPackageShare(package=package_name).find(package=package_name) urdf_model_path = os.path.join(pkg_share , f'urdf/{urdf_name}')
FindPackageShare
: 查找指定包的共享目录。这里通过该方法找到fishbot_description
包的目录,并拼接出 URDF 文件的路径。- 路径拼接: 使用
os.path.join()
来确保跨平台的路径兼容性。
定义并启动节点
robot_state_publisher_node = Node( package='robot_state_publisher', executable='robot_state_publisher', arguments=[urdf_model_path] ) joint_state_publisher_node = Node( package='joint_state_publisher_gui', executable='joint_state_publisher_gui', name='joint_state_publisher_gui', arguments=[urdf_model_path] ) rviz2_node = Node( package='rviz2', executable='rviz2', name='rviz2', output='screen' )
- 每个
Node
对象代表一个 ROS 2 节点。你需要指定:package
: 包名executable
: 可执行文件名arguments
: 节点需要的参数或文件路径(这里是 URDF 模型路径)
将节点添加到启动描述中
ld.add_action(robot_state_publisher_node) ld.add_action(joint_state_publisher_node) ld.add_action(rviz2_node) return ld
add_action
: 将节点添加到LaunchDescription
中,指示 ROS 2 启动时运行这些节点。
难点解析
LaunchConfiguration
的使用:用于动态地从启动时传递的参数中读取配置。虽然在该示例中未使用,但通常用于需要在启动时指定的参数,如 URDF 文件路径等。- URDF 文件路径拼接:使用
os.path.join()
而不是直接字符串拼接,可以确保在不同操作系统上都能正确处理路径分隔符。
setup.py
-
import os from glob import glob from setuptools import find_packages, setup package_name = 'fishbot_description' setup( name=package_name, version='0.0.0', packages=find_packages(exclude=['test']), #packages=[package_name] data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), (os.path.join('share',package_name,'launch'),glob('launch/*.launch.py')), (os.path.join('share',package_name,'urdf'),glob('urdf/**')), ], install_requires=['setuptools'], zip_safe=True, maintainer='dw', maintainer_email='dw@todo.todo', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ ], }, )
主要是在这里修改(date_files)
-
原来
-
data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ],
-
-
后来
-
data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), (os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')), (os.path.join('share', package_name, 'urdf'), glob('urdf/**')), ],
-
同时注意一下packages
- 在humble中是
packages=[package_name],
-
编译运行
-
在
~/.zshrc
中添加source ~/ros2_ws/install/setup.zsh
-
然后在工作空间中(不是功能包)执行
-
colcon build source ~/.zshrc ros2 launch fishbot_description display_rviz2.launch.py
-