ros2-control系列教程(1) 建模-手把手写一个差速小车项目

lion
1
2025-05-16

@TOC

前言

前文我们简要介绍了ros2-control的一些基本概念,纸上谈兵终为空,我们在本系列的教程会手把手带大家做一个两轮差速小车的项目,带大家体验如何运用ros2-control这一框架,是如何与实际物理硬件联系起来的。关于差速小车,其实官方的GitHub仓库里面有相应的例程,不过写的比较全面复杂,不适合初学者读懂,不过大家可以看看这个例子,并且到手即用体验一下: DiffBot — ROS2_Control

本文教程的对应源码也完全开源供大家学习,如果您觉得对您有帮助,希望能得到个start鼓励一下: 教程开源代码

那么这一小节,我们先从建立差速小车的模型开始吧!

环境

  • ros2版本 Humble
  • WSL2-Ubuntu-22.04

创建工作空间

mkdir diff_test_ws/src -p && cd diff_test_ws/src/

创建功能包

ros2 pkg create --build-type ament_cmake diff_test_control

这下我们目录里面就有diff_test_control这个文件夹,接这我们在文件夹下面新建description文件夹用来存放机器人的描述相关的文件

URDF建模

URDF(Unified Robot Description Format)是统一机器人描述格式,URDF使用XML格式描述机器人文件。关于这部分内容,大家可以自行在其他ROS教程上面学习,讲的应该要比我详细的多。

description文件夹下面新建urdf文件夹用来存放我们的urdf文件,这里我们直接使用官方例子里面的机器人模型。值得一提的是,官方用的Xacro写的,Xacro是urdf的定义和生成工具,URDF默认格式是纯文本的,我们并不能在其中加入计算公式和定义,用URDF定义一个机器人模型会导致整个文件非常冗长,有点类似Makefile和Cmake的关系。你按照Xacro提供的方式定义可以复用的模型描述块,之后就可以直接调用这些描述。

源文件过长有点不便展示,感兴趣可以直接去项目里面阅读

image-20240213034319443

macro是xacro里面类似函数的概念,我们可以在其他xacro里面调用写好的macro,name后面相当于函数名,params相当于参数了。

我们在urdf文件夹下面建立了三个文件,分别是diffbot.urdf.xacrodiffbot.materials.xacrodiffbot_description.urdf.xacro,后面两个写成了macro,用于给diffbot.urdf.xacro调用,内容如下:

<?xml version="1.0"?>
<!-- Basic differential drive mobile base -->
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="diffdrive_robot">
  <xacro:arg name="prefix" default="" />
  <xacro:arg name="use_mock_hardware" default="false" />

  <!-- 导入基本的几何形状 -->
  <xacro:include filename="$(find diff_test_control)/urdf/diffbot_description.urdf.xacro" />

  <!-- 导入RVIZ里面颜色显示 -->
  <xacro:include filename="$(find diff_test_control)/urdf/diffbot.materials.xacro" />

  <xacro:diffbot prefix="$(arg prefix)" />
</robot>

其中xacro:include就是类似c语言的include包含文件,调用我们之前写的macro只需要xacro:name,name为macro的名字,例如xacro:diffbot,这样我们就可以把前面写好的macro分模块进行增加或者删减。大家可能会有个疑问,就是文件路径为什么少了层description,这里是因为我在cmake里面把这些描述文件导入install空间时没有加入description

install(
  DIRECTORY  description/ros2_control description/urdf description/launch description/rviz
  DESTINATION share/diff_test_control
)

RVIZ可视化

ok,模型我们建(copy)完了,接下来我们把它放入RVIZ进行可视化试试看吧!在description文件夹下新建launch,写一个launch的脚本文件如下

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition
from launch.substitutions import Command, FindExecutable, LaunchConfiguration, PathJoinSubstitution

from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare


def generate_launch_description():
    # Declare arguments
    declared_arguments = []
    declared_arguments.append(
        DeclareLaunchArgument(
            "description_file",
            default_value="diffbot.urdf.xacro",
            description="URDF/XACRO description file with the robot.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "gui",
            default_value="true",
            description="Start Rviz2 and Joint State Publisher gui automatically \
        with this launch file.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "prefix",
            default_value='""',
            description="Prefix of the joint names, useful for \
        multi-robot setup. If changed than also joint names in the controllers' configuration \
        have to be updated.",
        )
    )

    # Initialize Arguments
    description_file = LaunchConfiguration("description_file")
    gui = LaunchConfiguration("gui")
    prefix = LaunchConfiguration("prefix")

    # Get URDF via xacro
    robot_description_content = Command(
        [
            PathJoinSubstitution([FindExecutable(name="xacro")]),
            " ",
            PathJoinSubstitution(
                [FindPackageShare("diff_test_control"), "urdf", description_file]
            ),
            " ",
            "prefix:=",
            prefix,
        ]
    )
    robot_description = {"robot_description": robot_description_content}

    rviz_config_file = PathJoinSubstitution(
        [FindPackageShare("diff_test_control"), "rviz", "diffbot_view.rviz"]
    )

    joint_state_publisher_node = Node(
        package="joint_state_publisher_gui",
        executable="joint_state_publisher_gui",
        condition=IfCondition(gui),
    )
    robot_state_publisher_node = Node(
        package="robot_state_publisher",
        executable="robot_state_publisher",
        output="both",
        parameters=[robot_description],
    )
    rviz_node = Node(
        package="rviz2",
        executable="rviz2",
        name="rviz2",
        output="log",
        arguments=["-d", rviz_config_file],
        condition=IfCondition(gui),
    )

    nodes = [
        joint_state_publisher_node,
        robot_state_publisher_node,
        rviz_node,
    ]

    return LaunchDescription(declared_arguments + nodes)

rviz文件夹下是启动rviz2的一些配置文件,除此之外还启动了robot_state_publisher功能包用于发布机器人的模型状态,joint_state_publisher_gui功能包用于提供关节的图形交互拖拽条。

接着我们返回工作空间顶层,输入

colcon build
source install/setup.bash
ros2 launch diff_test_control view_robot.launch.py 

接下来就能看见小车在rviz里面的可视化,我们拖动gui的交互条也能控制车轮的转动。

image-20240213042807126

ros2-control建模

我们在用URDF对我们机器人进行建模的时候,会有很多Link和Joint,但是并不是所有Joint都是我们可以控制对象。我们同样使用URDF传递给ros2-control框架我们需要控制的Joint的信息。下面是两轮差速小车传递给硬件资源管理器(Resource Manager)的URDF了,硬件资源管理器会根据这段描述,加载对应的硬件组件,前面的URDF只是给RVIZ可视化使用的,有没有都不会影响ros2-control的框架运行,下面才是决定控制的关键描述信息:

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">

  <xacro:macro name="diffbot_ros2_control" params="name prefix use_mock_hardware">

    <ros2_control name="${name}" type="system">
        <hardware>
          <plugin>diff_test_control/DiffBotSystemHardware</plugin>
        </hardware>
      <joint name="${prefix}left_wheel_joint">
        <command_interface name="velocity"/>
        <state_interface name="position"/>
        <state_interface name="velocity"/>
      </joint>
      <joint name="${prefix}right_wheel_joint">
        <command_interface name="velocity"/>
        <state_interface name="position"/>
        <state_interface name="velocity"/>
      </joint>
    </ros2_control>

  </xacro:macro>

</robot>

type="system"指定了硬件的类型,如前文所说,除了system还有sensor和actuator

<hardware>
    <plugin>diff_test_control/DiffBotSystemHardware</plugin>
</hardware>

这句话指定了所选用的硬件组件,这个硬件组件是我们自己写的,以插件(也就是动态库)的方式提供,我们可以修改URDF就可以选择我们最终想要的配置,这也是ros2-control框架灵活性的体现。

我们传递给硬件资源管理器还有command_interfacestate_interface这两个概念,state_interface是只读的,command_interface是可读可写的,比如我控制差速小车的车轮,只需要给出速度的控制命令即可,但是小车的状态除了转速,还有位置,上小节我们拖动GUI交互条控制小车轮子位置进行转动也是位置。除了velocityposition之外,还有加速度acceleration和力effort

除此之外还可以指定一些参数,比如指定初始速度为0<param name="initial_velocity">0</param>

把xacro宏添加到主xacro后就变成了这样

<?xml version="1.0"?>
<!-- Basic differential drive mobile base -->
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="diffdrive_robot">
  <xacro:arg name="prefix" default="" />
  <xacro:arg name="use_mock_hardware" default="false" />

  <!-- 导入基本的几何形状 -->
  <xacro:include filename="$(find diff_test_control)/urdf/diffbot_description.urdf.xacro" />

  <!-- 导入RVIZ里面颜色显示 -->
  <xacro:include filename="$(find diff_test_control)/urdf/diffbot.materials.xacro" />

  <!-- 导入 ros2_control 描述部分 -->
  <xacro:include filename="$(find diff_test_control)/ros2_control/diffbot.ros2_control.xacro" />

  <xacro:diffbot prefix="$(arg prefix)" />

  <xacro:diffbot_ros2_control
    name="DiffBot" prefix="$(arg prefix)" use_mock_hardware="$(arg use_mock_hardware)"/>

</robot>

总结

本文完成了对一个两轮差速小车的建模工程,讲述了如何用urdf语言描述ros2_control,但是在ros2_control的urdf里面涉及到了硬件组件的概念,这个我们将会在下文进行详细介绍。

如果对其中有问题不清楚,欢迎大家给我私信留言或者加入我创建的一个小的交流群一起学习交流QQ-536788289

写作不易,如果对您有帮助,麻烦点个star★★★加个关注吧!我会继续努力分享更多ROS2小知识
版权声明:本文为博主机器小狗史努比原创文章,未经博主允许不得转载。

动物装饰