在开发板A6460PM1上通过ROS2-humble在RVIZ与Gazebo中完成智能小车的仿真

开发板 A6490PM1 上通过ROS2-humble在RVIZ与Gazebo中完成智能小车的仿真

对开发板 A6490PM1 进行刷机操作并安装Aidlux

具体过程见以下网址

刷机教程:http://192.168.110.201:36666/guide/hardware/development-board/A6490PM1-user-manual

使用VNC完成远程连接,进入ubantu 22.04系统,并安装ROS2-humble

完成刷机及aidlux的安装后,根据教程获得手中开发板的ip地址后在浏览器上通过ip:8000进入aidlux桌面系统,密码为aidlux,桌面系统如下所示,

点击桌面底部的应用中心图标

进入应用中心后点击顶部的机器人选项,下载ubantu Desktop,安装完成后打开该应用,通过获得的ip地址和端口号通过VNC进行远程连接进入ubantu系统。

ROS2-humble、RVIZ、gazebo等软件的下载

ros2-humble、gazebo可通过aidlux桌面系统的应用中心下载,也可在ubantu系统中完成安装

ubanturos2-humble、gazebo、vescode的安装过程如下所示

ros2-humble我们可以通过国内大佬小鱼开发的一键安装完成安装,感谢小鱼的一键安装。

通过按住键盘上的ctrl+alt+t打开终端,在终端中输入以下命令,密码为aidlux

wget http://fishros.com/install -O fishros && . fishros

这里我们输入1(安装ROS),按下回车

如上图所示,首先输入1(更换系统源再继续安装)并按下回车,接着继续选择1(仅更换系统源)并按下回车,接着就可以看见安装ROS相关选项,这里可以选择要安装的humble版本,我们按下1选择humble版本,然后再按下1(选择桌面版)并按下回车,接着等待安装工具自动完成ros的安装

vscode及微信等软件也可通过以上同样的方法安装

gazebo的安装我们也通过命令行完成安装,在一个新的终端中我们输入以下命令

sudo apt install gazebo

除了安装gazebo外,也可以下载一些模型文件到系统的gazebo配置目录下,文件可以直接从github上克隆,命令如下所示

$ mkdir -p ~/.gazebo
$ cd ~/.gazebo
$ git clone https://gitee.com/ohhuo/gazebo_models.git ~/.gazebo/models
	$ rm -rf ~/.gazebo/models/.git #删除 .git 防止误识别为模型

启动gazebo的命令如下所示

gazebo

一些其他工具的安装

colcon构建工具

colcon是一个命令行工具,用于改进编译,测试和使用多个软件包的工作流程。它实现过程自动化,处理需求并设置环境以便于使用软件包。ROS2中便是使用colcon作为包构建工具的,但是ROS2中没有默认安装colcon,需要自行安装,安装命令如下:

sudo apt install python3-colcon-common-extensions

使用URDF文件完成小车建模,并在RVIZ中完成可视化显示

以下内容的代码均来自以下gitee仓库

chapt(1)/chapt/src/moxing/urdf/second.urdf.xacro · lenxiii/test - 码云 - 开源中国 (gitee.com)

使用gazebo仿真的第一步是完成对机器人的建模,目前几乎所有的仿真平台都支持URDF格式,使用URDF文件可以通过代码描述模型的外形物理体积,运动惯性,物理属性,运动限制等內容。RVIZ可以将以URDF编写的小车模型描述文件进行可视化处理,以下内容为一个使用URDF格式编写的机器人模型示例部分文件,文件名为second.urdf.xacro

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="first_robot">
		<!--机器人模型身体部分 -->
        <link name="base_link">
        	<!--部件外观描述-->
            <visual >
            	<!--沿自己几何中心的坐标偏移和旋转-->
                <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
                <!--几何形状-->
                <geometry>
                	<!--圆柱体 半径0.1m 高0.112m-->
                    <cylinder radius="0.1" length="0.12"/>
                </geometry>
                <!--材质标签 颜色白色 透明度为0.5-->
                <material name="white">
                    <color rgba="1.0 1.0 1.0 0.5"/>
                </material>
            </visual>
        </link>
        <!--机器人模型轮子部分-->
        <!--机器人模型左边轮子部分-->
        <link name="left_wheel_link">
            <visual>
                <origin xyz="0.0 0.0 0.0" rpy="1.57079 0 0"/>
                <geometry>
                	<!--圆柱体 半径0.04m 高0.032m-->
                    <cylinder radius="0.04" length="0.032"/>
                </geometry>
                <material name="black">
                    <color rgba="0.0 0.0 0.0 0.5""/>
                </material>
            </visual>
        </link>
        <!--机器人模型右边轮子部分-->
         <link name="right_wheel_link">
            <visual>
                <origin xyz="0 0 0" rpy="1.57079 0 0" />
                <geometry>
                    <cylinder length="0.04" radius="0.032" />
                </geometry>
                <material name="black">
                    <color rgba="0.0 0.0 0.0 0.8"/>
                </material>
            </visual>
            

        <!--机器人模型关节部分-->
        <joint name="lift_joint" type="revolute">
        	<!--子部件相当于父部件的平移和旋转-->
            <origin xyz="0 0.10 -0.06" rpy="0.0 0.0 0.0"/>
            <!--父部件(子部件连接的部件)-->
            <parent link="base_link"/>
            <!--子部件-->
            <child link="left_wheel_link"/>
            <!--定义旋转轴方向,绕y轴旋转-->
            <axis xyz="0.0 1.0 0.0"/>
            <!--对关节的运动限制 lower(最小角度)  upper(最大角度)  effort(最大扭矩)  velocity(最大速度)-->
            <limit lower="0.0" upper="0.0" effort="0.0" velocity="0.0"/>
        </joint>
        
        <joint name="right_wheel_joint" type="continuous">
            <parent link="base_link" />
            <child link="right_wheel_link" />
            <origin xyz="0 -0.10 -0.06" />
            <axis xyz="0 1 0" />
        </joint>
</robot>

第一行<?xml version="1.0"?>表示这是一个 XML 处理指令的开始,XML 的版本号为 1.0,URDF使用XMLExtensible Markup Language可扩展标记语言)描述机器人的几何结构,传感器等信息。

第二至第三行中包含了三段不同含义的代码<robot></robot>URDFXACRO文件的根元素,用于描述机器人模型,所有的URDF文件几乎都要写在这对标签当中。

name="first_robot"定义了机器人的名称(first_robot),在ROS中用于标识该模型。

xmlns:xacro="http://www.ros.org/wiki/xacro这句话声明了一个XML命名空间,关联到XACRO的官方文档页面。作用是告诉解析器该文件使用了Xacro的宏功能(如变量、循环、条件等),而不仅是普通URDF。简单来说URDF文件中引入Xacro后便可以使用xacro编写宏,使机器人的建模更加简便由于篇幅原因本文对于Xacro版本的URDF文件不做过多介绍。

编写完成的URDF文件通过使用launch文件完成在RVIZ中的启动,launch文件示例如下

# 导入必要的ROS 2启动模块和功能包
from launch import LaunchDescription
from launch_ros.actions import Node
from launch_ros.parameter_descriptions import ParameterValue
from launch.actions import DeclareLaunchArgument
from launch.substitutions import Command,LaunchConfiguration
import os
from ament_index_python.packages import get_package_share_directory

def generate_launch_description():
    # 声明一个启动参数,用于指定URDF文件的路径
    # 默认路径为moxing功能包下的urdf/first.urdf.xacro文件
    model_path=DeclareLaunchArgument(
        name='model',default_value=
         os.path.join(get_package_share_directory
                     ("moxing"),"urdf","first.urdf.xacro"),
        description="URDF文件路径"
                     )
    # 使用xacro工具解析URDF文件,生成机器人描述参数
    robot_description=ParameterValue(Command(["xacro ",LaunchConfiguration("model")]))
    # 创建joint_state_publisher_gui节点,用于发布关节状态并提供GUI界面
    joint_state_publisher_gui = Node(
    package="joint_state_publisher_gui",
    executable="joint_state_publisher_gui",
    parameters=[{"robot_description": robot_description}],  # 直接传递参数
)
    # 创建robot_state_publisher节点,用于发布机器人状态
    robot_state_publisher = Node(
    package="robot_state_publisher",
    executable="robot_state_publisher",
    parameters=[{"robot_description": robot_description}],
    output="screen",  # 可选:打印调试信息
)
    # 创建rviz2节点,用于可视化机器人模型
    rviz2_node=Node(
        package="rviz2",
        executable="rviz2",
        name="rviz2",
        output="screen",
    )
    # 返回LaunchDescription对象,包含所有声明的节点和参数
    return LaunchDescription(
        [
        # 声明一个启动参数,用于指定是否使用仿真时间(如Gazebo)
         DeclareLaunchArgument(
        "use_sim_time",
        default_value="false",
        description="Use simulation (Gazebo) clock if true",
    ),
            model_path,# 添加URDF文件路径参数
            robot_state_publisher,# 添加机器人状态发布节点
            joint_state_publisher_gui,# 添加关节状态发布GUI节点
            rviz2_node,# 添加RViz2可视化节点

        ]
    )

启动后RVIZ会自动启动如下图所示

此时的RVIZ 中没有任何模型是正常的,接下来点击左下角的add按钮在弹出的窗口中选择robotmodel选项

随后在左侧的robotmodel的选项中将Description Source的选项选为Topic,其次在下面的Description Topic中选择/robot_description完成以上操作后便可以在RVIZ的中间看见一块白色物体,这是正常现象

RVIZ左侧边框的最上方有一个Fixed Frame的选项,在其中选择你在URDf文件中建立的任意一个link部件便可以正常显示URDf建立的机器人模型,完成以上操作后也可以加入add模块,添加方式与robotmodel一致,添加完成后,你便可以看见各个link部件的坐标轴

以上便是在RVIZ中显示URDF描述的机器人模型的步骤,接下来我们将会把机器人模型加入到gazebo仿真世界中

将机器人模型放入自定义gazebo仿真世界中

使用gazebo构建世界

在终端中输入gazebo启动的gazebo界面如图所示,启动后的gazebo世界默认加载空世界,界面如图所示

我们可以通过界面左上角的insert向空世界中加入之前在github上克隆的模型

除了可以使用已经加载好的模型,在gazebo中也可以实现手动画墙,设计自己的房间,接下来我们就来设计一个房间。

首先在gazebo左上角的edit的选项中点击Building Editor


简单的完成了一个封闭房间的设计后在左上角的file中选择Exit Building Editor选项会弹出如下窗口提示是否保存墙体文件,我们点击save and Exit选项

点击之后会弹出如下界面

定义世界的名称,并选择保存的文件地址完成后点击choose ,最后点击save即可在gazebo界面中看见建好的房间模型。

同样,我们也可以在建好的房间模型中加入一些其他的模型,完成后便可以在filesave world as 选项将我们的世界模型保存下下来,下次使用gazebo命令加世界路径便可以直接加载世界模型

gazebo中加载机器人模型

gazebo使用的是sdf格式,而机器人建模时使用的是URDF格式,所以要在gazebo中显示机器人模型就需要将urdf文件转换为sdf我们可以通过gazebo-ros-pkgs完成这一转换,安装命令如下

$ sudo apt install ros-humbl-gazebo-ros-pkg

安装好后使用以下launch文件启动gazebo并加载机器人模型

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

def generate_launch_description():
    # 声明一个启动参数 `model`,用于指定URDF/Xacro文件路径
    # 默认值为包 `moxing` 中 `urdf/second.urdf.xacro` 文件的路径
    model_path = DeclareLaunchArgument(
        name="model",
        default_value=os.path.join(
            get_package_share_directory("moxing"),
            "urdf",
            "second.urdf.xacro"
        ),
        description="URDF 文件路径",
    )
    # 设置Gazebo世界文件的默认路径
    # 路径指向包 `moxing` 中 `world/room1.world` 文件
    default_world_path = os.path.join(
        get_package_share_directory("moxing"),
        "world",
        "room1.world"
    )
   
    # 启动Gazebo仿真环境
    # 使用 `gazebo_ros` 包的 `gazebo.launch.py` 启动文件
    # 并传入世界文件路径 (`room1.world`) 和设置 `verbose` 为 `true`(输出详细日志)
    gazebo_launch = launch.actions.IncludeLaunchDescription(
        PythonLaunchDescriptionSource([get_package_share_directory(
            "gazebo_ros"), '/launch', '/gazebo.launch.py']
        ),
        launch_arguments=[('world', default_world_path), ('verbose', 'true')]
    )
    # 在Gazebo中生成机器人模型
    # 使用 `gazebo_ros` 包的 `spawn_entity.py` 节点
    # 参数:
    #   `-topic /robot_description`:从 `/robot_description` 话题获取机器人URDF
    #   `-entity robot1`:在Gazebo中生成的实体名称
    spawn_action = launch_ros.actions.Node(
        package="gazebo_ros",
        executable="spawn_entity.py",
        arguments=['-topic', '/robot_description', '-entity', 'robot1']
    )
    # 解析Xacro文件生成URDF描述
    # 使用 `xacro` 命令处理 `model` 参数指定的文件
    # 结果存储在 `robot_description` 中,类型为字符串
    robot_description = ParameterValue(
        Command(["xacro ", LaunchConfiguration("model")]),
        value_type=str
    )
    # 启动 `robot_state_publisher` 节点
    # 该节点发布机器人的TF(Transform)信息
    # 参数:
    #   `source_list: ["/joint_states"]`:订阅Gazebo发布的关节状态
    #   `robot_description`:传入解析后的URDF描述
    robot_state_publisher = Node(
        package="robot_state_publisher",
        executable="robot_state_publisher",
        parameters=[{
            "source_list": ["/joint_states"],  # 确保订阅 Gazebo 的关节数据
            "robot_description": robot_description
        }],
        output="screen",  # 输出日志到屏幕
    )
    # 启动 `joint_state_publisher_gui` 节点(GUI版本)
    # 提供一个可视化界面,用于手动调整关节状态(如调试用)
    joint_state_publisher_gui = Node(
        package="joint_state_publisher",
        executable="joint_state_publisher",
        name="joint_state_publisher_gui",  # 节点名称
    )

    # 启动RViz2可视化工具
    # 加载包 `moxing` 中 `rviz/model.rviz` 的配置文件
    rviz2_node = Node(
        package="rviz2",
        executable="rviz2",
        name="rviz2",
        output="screen",
        arguments=['-d', os.path.join(
            get_package_share_directory("moxing"),
            'rviz', 'model.rviz'
        )]
    )
    # 返回所有要启动的节点和动作
    return launch.LaunchDescription([
        model_path,  # 声明模型路径参数
        robot_state_publisher,  # 发布机器人TF
        joint_state_publisher_gui,  # 关节状态发布(GUI)
        gazebo_launch,  # 启动Gazebo
        spawn_action,  # 在Gazebo中生成机器人
        # 注意:`rviz2_node` 当前被注释掉,如需使用需取消注释
    ])

接着便可以在gazebo的世界中我们的机器人模型已经放入世界了

URDF文件中除了描述机器人模型的外观也可以使用gazebo插件模拟传感器的工作,例如IMU和雷达。

以上便是如何在开发板 A6490PM1 上通过ROS2-humble在RVIZ与Gazebo中完成智能小车的仿真的全部内容

5 个赞

膜拜大佬

2 个赞

6666666,6666666666666666,66666666666666666,6666666666