研究生养成计划5.14

第 9 章 机器人导航(实体)

第7章内容介绍了在仿真环境下的机器人导航,第8章内容介绍了两轮差速机器人的软硬件实现,如果你已经按照第8章内容构建了自己的机器人平台,那么就可以尝试将仿真环境下的导航功能迁移到机器人实体了,本章就主要介绍该迁移过程的实现,学习内容如下:

  • 比较仿真环境与真实环境的导航实现;
  • 介绍VScode远程开发的实现;
  • 实体机器人导航实现。

预期达成学习目标:

  • 了解仿真环境与真实环境下导航实现的区别;
  • 能够搭建VScode远程开发环境;
  • 能够实现实体机器人的建图与导航。

9.1 概述

实体机器人导航与仿真环境下的导航核心实现基本一致,主要区别在于导航实现之前,基本环境的搭建有所不同,比如:导航场景、传感器、机器人模型等,大致区别如下:

仿真环境实体机器人
导航场景依赖于gazebo搭建的仿真环境依赖于现实环境
传感器在gazebo中通过插件来模拟一些列传感器,比如:雷达、摄像头、编码器....使用的是真实的传感器
机器人模型依赖于机器人模型,以实现仿真环境下的机器人的显示,通过robot_state_publisher、joint_state_publisher实现机器人各部件的坐标变换。机器人模型不是必须的,如果不使用机器人可以通过static_transform_publisher发布导航必须的坐标变换;如果使用机器人模型也可以借助 robot_state_publisher、joint_state_publisher 发布坐标变换,当然后者可以在rviz中显示机器人模型,更友好。

总体而言,在实体机器人导航中,可以完全脱离 gazebo,而机器人模型是否使用,可以按需选择。

除此之外,实体机器人导航的开发环境也发生了改变,程序最终需要被部署在机器人端,我们可以在本地开发,然后通过ssh上传至机器人,或者也可以通过VScode的远程开发插件直接在机器人端编写程序。

9.2 VScode远程开发P75-76

在第8章,我们介绍了ssh远程连接的使用,借助于于ssh可以远程操作树莓派端,但是也存在诸多不便,比如:编辑文件内容时,需要使用vi编辑器,且在一个终端内,无法同时编辑多个文件,本节将介绍一较为实用的功能——VSCode远程开发,我们可以在VScode中以图形化的方式在树莓派上远程开发程序,比ssh的使用更方便快捷,可以大大提高程序开发效率。

1.准备工作

VScode远程开发依赖于ssh,请首先按照8.5.3内容配置ssh远程连接。

2.为VScode安装远程开发插件

启动VScode,首先点击侧边栏的扩展按钮,然后在扩展:商店的搜索栏输入Remote Development并点击同名插件,最后在右侧显示区中点击安装

3.配置远程连接

步骤1:使用快捷键ctrl + shift + p打开命令输入窗口,并输入Remote-SSH:Connect to Host...,弹出列表中选择与之同名的选项。

步骤2:步骤1完成将弹出一个新的命令窗口如下,选择下拉列表中的 Add New SSH Host

步骤3:步骤2完成又将弹出一个新的命令窗口,在其中输入:ssh ubuntu@192.168.43.164,其中,ubuntu需要替换为你的登录账号,192.18.43.164 则替换为你的树莓派的ip地址。

步骤4:选择步骤3完成后的弹窗列表中的第一个选项(或直接回车),即可完成配置,配置成果后会有提示信息。

4.使用

步骤1:继续使用快捷键ctrl + shift + p打开命令输入窗口,并输入Remote-SSH:Connect to Host...,此时列表中将显示步骤3中配置的ip地址,直接选择,选择后,VScode将打卡一个新的窗口。

或者,也可以点击侧边栏的远程资源管理器,在弹出的服务器列表中选择要连接的服务器,并右击,选择在本窗口或新窗口中实现远程连接。

步骤2:选择菜单栏的文件下的打开文件夹,在弹窗列表中选择需要打开的文件夹并点击确定即可。

最终,我们就可以像操作本地文件一样实现远程开发了。

9.3 导航实现

本节介绍实体机器人导航的基本实现流程。该流程实现与7.2节内容类似,主要内容仍然集中在SLAM、地图服务、定位与路径规划,本节内容不再重复介绍7.2节中各个知识点的实现细节,而是注重知识点应用。

实体机器人导航实现流程如下:

  1. 准备工作;
  2. SLAM实现;
  3. 地图服务;
  4. 定位实现;
  5. 路径规划;

本节最后还会将导航与SLAM结合,实现自主移动的SLAM建图。

9.3.1 导航实现01_准备工作

1.1分布式架构

分布式架构搭建完毕且能正常运行,在PC端可以远程登陆机器人端。

1.2功能包安装

在机器人端安装导航所需功能包:

  • 安装 gmapping 包(用于构建地图):sudo apt install ros-<ROS版本>-gmapping

  • 安装地图服务包(用于保存与读取地图):sudo apt install ros-<ROS版本>-map-server

  • 安装 navigation 包(用于定位以及路径规划):sudo apt install ros-<ROS版本>-navigation

新建功能(包名自定义,比如:nav),并导入依赖: gmapping map_server amcl move_base

1.3机器人模型以及坐标变换

机器人的不同部件有不同的坐标系,我们需要将这些坐标系集成进同一坐标树,实现方案有两种:

  1. 不同的部件相对于机器人底盘其位置都是固定的,可以通过发布静态坐标变换以实现集成;
  2. 可以通过加载机器人URDF文件结合 robot_state_publisher、joint_state_publisher实现不同坐标系的集成。

方案1在上一章中已做演示,接下来介绍方案2的实现。

1.3.1 创建机器人模型相关的功能包

创建功能包:catkin_create_pkg mycar_description urdf xacro

1.3.2 准备机器人模型文件

在功能包下新建 urdf 目录,编写具体的 urdf 文件(机器人模型相关URDF文件的编写可以参考第6章内容),示例如下:

文件car.urdf.xacro用于集成不同的机器人部件,内容如下:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">

    <xacro:include filename="car_base.urdf.xacro" />
    <xacro:include filename="car_camera.urdf.xacro" />
    <xacro:include filename="car_laser.urdf.xacro" />

</robot>

文件car_base.urdf.xacro机器人底盘实现,内容如下:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">

    <xacro:property name="footprint_radius" value="0.001" />
    <link name="base_footprint">
        <visual>
            <geometry>
                <sphere radius="${footprint_radius}" />
            </geometry>
        </visual>
    </link>


    <xacro:property name="base_radius" value="0.1" />
    <xacro:property name="base_length" value="0.08" />
    <xacro:property name="lidi" value="0.015" />
    <xacro:property name="base_joint_z" value="${base_length / 2 + lidi}" />
    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="0.1" length="0.08" />
            </geometry>

            <origin xyz="0 0 0" rpy="0 0 0" />

            <material name="baselink_color">
                <color rgba="1.0 0.5 0.2 0.5" />
            </material>
        </visual>

    </link>

    <joint name="link2footprint" type="fixed">
        <parent link="base_footprint"  />
        <child link="base_link" />
        <origin xyz="0 0 0.055" rpy="0 0 0" />
    </joint>



    <xacro:property name="wheel_radius" value="0.0325" />
    <xacro:property name="wheel_length" value="0.015" />
    <xacro:property name="PI" value="3.1415927" />
    <xacro:property name="wheel_joint_z" value="${(base_length / 2 + lidi - wheel_radius) * -1}" />


    <xacro:macro name="wheel_func" params="wheel_name flag">

        <link name="${wheel_name}_wheel">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}" />
                </geometry>

                <origin xyz="0 0 0" rpy="${PI / 2} 0 0" />

                <material name="wheel_color">
                    <color rgba="0 0 0 0.3" />
                </material>
            </visual>

        </link>

        <joint name="${wheel_name}2link" type="continuous">
            <parent link="base_link"  />
            <child link="${wheel_name}_wheel" />

            <origin xyz="0 ${0.1 * flag} ${wheel_joint_z}" rpy="0 0 0" />
            <axis xyz="0 1 0" />
        </joint>

    </xacro:macro>

    <xacro:wheel_func wheel_name="left" flag="1" />
    <xacro:wheel_func wheel_name="right" flag="-1" />



    <xacro:property name="small_wheel_radius" value="0.0075" />
    <xacro:property name="small_joint_z" value="${(base_length / 2 + lidi - small_wheel_radius) * -1}" />

    <xacro:macro name="small_wheel_func" params="small_wheel_name flag">
        <link name="${small_wheel_name}_wheel">
            <visual>
                <geometry>
                    <sphere radius="${small_wheel_radius}" />
                </geometry>

                <origin xyz="0 0 0" rpy="0 0 0" />

                <material name="wheel_color">
                    <color rgba="0 0 0 0.3" />
                </material>
            </visual>

        </link>

        <joint name="${small_wheel_name}2link" type="continuous">
            <parent link="base_link"  />
            <child link="${small_wheel_name}_wheel" />

            <origin xyz="${0.08 * flag} 0 ${small_joint_z}" rpy="0 0 0" />
            <axis xyz="0 1 0" />
        </joint>

    </xacro:macro >
    <xacro:small_wheel_func small_wheel_name="front" flag="1"/>
    <xacro:small_wheel_func small_wheel_name="back" flag="-1"/>

</robot>

文件car_camera.urdf.xacro机器人摄像头实现,内容如下:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">

    <xacro:property name="camera_length" value="0.02" /> 
    <xacro:property name="camera_width" value="0.05" /> 
    <xacro:property name="camera_height" value="0.05" /> 
    <xacro:property name="joint_camera_x" value="0.08" />
    <xacro:property name="joint_camera_y" value="0" />
    <xacro:property name="joint_camera_z" value="${base_length / 2 + camera_height / 2}" />

    <link name="camera">
        <visual>
            <geometry>
                <box size="${camera_length} ${camera_width} ${camera_height}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black">
                <color rgba="0 0 0 0.8" />
            </material>
        </visual>
    </link>

    <joint name="camera2base" type="fixed">
        <parent link="base_link" />
        <child link="camera" />
        <origin xyz="${joint_camera_x} ${joint_camera_y} ${joint_camera_z}" rpy="0 0 0" />
    </joint>

</robot>

文件car_laser.urdf.xacro机器人雷达实现,内容如下:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">

    <xacro:property name="support_radius" value="0.01" />
    <xacro:property name="support_length" value="0.15" />

    <xacro:property name="laser_radius" value="0.03" />
    <xacro:property name="laser_length" value="0.05" />

    <xacro:property name="joint_support_x" value="0" />
    <xacro:property name="joint_support_y" value="0" />
    <xacro:property name="joint_support_z" value="${base_length / 2 + support_length / 2}" />

    <xacro:property name="joint_laser_x" value="0" />
    <xacro:property name="joint_laser_y" value="0" />
    <xacro:property name="joint_laser_z" value="${support_length / 2 + laser_length / 2}" />

    <link name="support">
        <visual>
            <geometry>
                <cylinder radius="${support_radius}" length="${support_length}" />
            </geometry>
            <material name="yellow">
                <color rgba="0.8 0.5 0.0 0.5" />
            </material>
        </visual>

    </link>

    <joint name="support2base" type="fixed">
        <parent link="base_link" />
        <child link="support"/>
        <origin xyz="${joint_support_x} ${joint_support_y} ${joint_support_z}" rpy="0 0 0" />
    </joint>
    <link name="laser">
        <visual>
            <geometry>
                <cylinder radius="${laser_radius}" length="${laser_length}" />
            </geometry>
            <material name="black">
                <color rgba="0 0 0 0.5" />
            </material>
        </visual>

    </link>

    <joint name="laser2support" type="fixed">
        <parent link="support" />
        <child link="laser"/>
        <origin xyz="${joint_laser_x} ${joint_laser_y} ${joint_laser_z}" rpy="0 0 0" />
    </joint>
</robot>
1.3.3 在launch文件加载机器人模型

launch 文件(文件名称自定义,比如:car.launch)内容示例如下:

<launch>
    <param name="robot_description" command="$(find xacro)/xacro $(find mycar_description)/urdf/car.urdf.xacro" />
    <node pkg="joint_state_publisher" name="joint_state_publisher" type="joint_state_publisher" />
    <node pkg="robot_state_publisher" name="robot_state_publisher" type="robot_state_publisher" />
</launch>

为了使用方便,还可以将该文件包含进启动机器人的launch文件中,示例如下:

<launch>
        <include file="$(find ros_arduino_python)/launch/arduino.launch" />
        <include file="$(find usb_cam)/launch/usb_cam-test.launch" />
        <include file="$(find rplidar_ros)/launch/rplidar.launch" />
        <!-- 机器人模型加载文件 -->
        <include file="$(find mycar_description)/launch/car.launch" />
</launch>
1.4结果演示

不使用机器人模型时,机器人端启动机器人(使用包含TF坐标换的launch文件),从机端启动rviz,在rviz中添加RobotModel与TF组件,rviz中结果(此时显示机器人模型异常,且TF中只有代码中发布的坐标变换):

使用机器人模型时,机器人端加载机器人模型(执行上一步的launch文件)且启动机器人,从机端启动rviz,,在rviz中添加RobotModel与TF组件rviz中结果(此时显示机器人模型,且TF坐标变换正常):

后续,在导航时使用机器人模型。

解决的bug:如果在 ROS 中创建功能包时忘记添加依赖,可以通过以下步骤补救:

1.手动编辑 package.xml 文件

<!-- 在 package.xml 中添加缺失的依赖 -->
<!-- 编译依赖 -->
<build_depend>依赖包名</build_depend>
<!-- 运行时依赖 -->
<exec_depend>依赖包名</exec_depend>
<!-- 导出依赖(供其他包使用) -->
<build_export_depend>依赖包名</build_export_depend>

2. 更新 CMakeLists.txt(可选)

如果依赖项需要在编译阶段链接(如 C++ 库),还需修改 CMakeLists.txt

find_package(catkin REQUIRED
  COMPONENTS
    roscpp
    std_msgs  # 添加缺失的依赖包名
)

3. 安装依赖项

在 ROS 工作空间根目录下运行:

rosdep install --from-paths src --ignore-src -y

该命令会根据 package.xml 自动安装缺失的系统级依赖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值