Ubuntu18.04上ROS开发环境搭建

  在Ubuntu18.04上搭建ROS开发环境,主要使用的编辑器是VS Code,借助VS Code中的ROS插件进行开发,利用catkin_tool工具进行工程文件的管理和编译。

安装VS Code

  在VS Code官网下载deb包,然后使用dpkg进行手动安装,不建议使用软件商店中的版本,因为软件商店中的版本使用自带的输入法或者谷歌输入法无法输入中文。

安装ROS插件

  在VS Code的扩展商店中搜索简体中文插件和ROS插件并安装:

安装ROS

  在ROS的安装指导页面选择适合自己的版本进行安装,这里以18.04LTS为例进行安装

  • 选择操作系统
      这里我们直接选择Ubuntu操作系统:
  • 1.设置安装的软件源
      使用以下命令设置软件源:

    sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
  • 2.设置密钥
      使用以下命令设置安装密钥:

    curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

      如果提示找不到curl命令,则根据提示安装curl即可,安装命令如下:

    sudo apt install curl

      如果提示gpg: 找不到有效的 OpenPGP 数据。,原因为网络无法连接到github,通过修改hosts的方法可以解决,修改方法看这里,具体修改的内容参考这个教程
      修改hosts后重新执行命令即可。

  • 3.更新apt
      使用以下命令更新apt的安装源

    sudo apt update
  • 4.执行安装命令
      使用下面的命令进行安装,推荐使用完整版的安装命令(以下为完整安装):

    sudo apt install ros-melodic-desktop-full
  • 5.添加环境配置脚本
      使用以下命令将ROS的环境初始化脚本添加进bash中,这样每一次启动终端就会自动运行这个配置过程。

    echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
    source ~/.bashrc

      如果你使用不同的ROS版本或者环境,则每次使用前需要手动启动当前使用的.bash设置,如下所示:

    source /opt/ros/melodic/setup.bash
  • 6.安装用于构建ROS包的依赖
      首先,使用以下命令安装各种需要用到的工具:

    sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential

      然后,使用以下命令来初始化安装的工具和依赖包:

    sudo rosdep init
    rosdep update

      如果这一步执行过程中出现The read operation timed out报错,请翻墙或者使用流量数据等方式完成该命令。
      这个步骤命令的执行能否成功很依赖网络环境,比较玄学,如果一次没有成功,另选一个时间再尝试。

  • 7.解决rosdep init连接超时问题
      rosdep init主要是下载一个名为20-default.list的文件,然后rosdep update通过20-default.list文件中的链接获取并加载相应的参数。所以,我们可以将相应的文件下载到本地,然后都使用本地文件链接执行相应的命令。
      首先,将依赖的文件下载到本地,我已经将需要的文件保存在gitee的仓库中,可以通过以下命令下载到本地:

    # 使用cd ~命令回到用户所在的文件夹(建议放在用户文件夹是为了保证访问权限)中,即/home/用户名/
    cd ~
    # 使用git clone命令将文件下载到本地的/home/用户名/myrosdep文件夹中
    git clone https://gitee.com/SAquarius/rosdistro.git myrosdep

      然后,我们可以手动创建20-default.list文件,如果还没有文件路径,则需要手动一层一层创建,路径如下:

    /etc/ros/rosdep/sources.list.d/20-default.list

      文件内容设置如下(如果成功执行了init命令,则已经存在本文件了,修改内容即可):

    # os-specific listings first
    yaml file:/home/你的用户名/myrosdep/rosdep/osx-homebrew.yaml osx
    # generic
    yaml file:/home/你的用户名/myrosdep/rosdep/base.yaml
    yaml file:/home/你的用户名/myrosdep/rosdep/python.yaml
    yaml file:/home/你的用户名/myrosdep/rosdep/ruby.yaml
    gbpdistro file:/home/你的用户名/myrosdep/releases/fuerte.yaml fuerte

      注意,这里请将“你的用户名”改为自己机器上的用户名。
      修改以下文件中的路径为本地路径(请使用自己熟悉的编辑工具,我自己用的是vim):
      ① 需要修改的第一个文件

    sudo vim /usr/lib/python2.7/dist-packages/rosdep2/sources_list.py
    # 将下面的链接修改为本地路径,如下所示:
    DEFAULT_SOURCES_LIST_URL = 'file:/etc/ros/rosdep/sources.list.d/20-default.list'

      ② 需要修改的第二个文件

    sudo vim /usr/lib/python2.7/dist-packages/rosdep2/rep3.py
    # 将下面的链接修改为本地路径,如下所示:
    REP3_TARGETS_URL = 'file:/home/你的用户名/myrosdep/releases/targets.yaml'

      ③ 需要修改的第三个文件

    sudo vim /usr/lib/python2.7/dist-packages/rosdistro/__init__.py
    # 将下面的链接修改为本地路径,如下所示:
    DEFAULT_INDEX_URL = 'file:/home/你的用户名/myrosdep/index-v4.yaml'

      修改完成后,再重新执行rosdep update就可以发现可以正常命中每一个文件。文件路径一定不要错,最好自己检查确认一遍。如果文件路径错误,执行命令的时候会报错找不到文件,那么找到对应的文件修改然后重新运行即可。

安装catkin_tools工具

  使用以下命令安装catkin_tools工具:

//Ubuntu 18.04使用下面的命令
sudo apt install python-catkin-tools python-osrf-pycommon
//Ubuntu 20.04使用下面的命令
sudo apt install python3-catkin-tools python3-osrf-pycommon

创建简单的ROS工程

创建我们的工作空间

  工作空间的概念可以这样理解:我们创建一个文件夹为我们的工作空间,在这个工作空间下我们用来组织、管理、编译我们的工程文件。
  使用以下命令创建我们的工作空间,为了跟好的理解这个过程,我会将命令拆分讲解:

  • 1.选择一个合适的位置创建我们的工作空间文件夹
      这里我在/home/ubuntu/learnROS下进行操作,这个文件夹已经提前创建好了,专门存放学习ROS的一些内容。
      使用以下命令创建并初始化我们的工作空间:

    //-p 参数可以同时创建子文件夹src
    //工作空间为ROSWokdSpace(可以根据自己情况取名)
    //src用于存放源文件
    mkdir -p ROSWorkSpace/src
    //进入到工作空间下
    cd ROSWorkSpace
    //使用catkin tools工具初始化工作空间
    catkin init

      执行效果如下:

  • 2.初步编译ROS工作空间
      我们通过初步的编译ROS工作空间,使其产生相应的文件目录,然后再VS Code中启动,便可以自动识别ROS工作空间。

    //初步编译工作空间
    catkin build
    //使用VS Code打开并自动识别工作空间
    code .

      执行效果如下:

创建我们的第一个包(单节点)

  在src文件夹上右键,选择Create Catkin Package创建一个包,输入包的名称和包所需要的依赖。如下图所示:

//说明
//这里我们的包名暂时起名为Helloworld
//基础的依赖有roscpp rospy std_msgs
//依赖之间使用空格分开




  然后自动生成相关的文件,如下图所示:

创建一个简单的节点

  在我们创建的包的src文件夹中创建源文件helloworld.cpp,最终会生成一个节点,连续输出三句Hello World!,其编辑内容如下:

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
  //初始化节点
  ros::init(argc, argv, "talker");
  //创建节点句柄
  ros::NodeHandle n;
  //循环3次输出hello world
  for(int i=0;i<3;i++){
    ROS_INFO("Hello World!\n");
  }
  return 0;
}

  如果头文件出现了红色波浪线提示,重新启动窗口即可。
  修改CMakeLists.txt文件,在文件中添加如下两行:

add_executable(SayHelloWorld src/helloworld.cpp)
target_link_libraries(SayHelloWorld ${catkin_LIBRARIES})

  以上添加的语句中,第一行表示将src中的helloworld.cpp文件编译成SayHelloWorld的可执行文件;第二行表示将生成可执行文件时要连接到catkin的相关库文件。
  如果不会使用CMakeLists.txt,可以参考教程,学习cmake工具的使用和CMakeLists文件的编写规则。

配置环境变量

  使用以下命令执行工作空间中devel/setup.bash来配置环境变量,也可以通过将命令永久加入用户的./bashrc中,保证每次启动终端都会自动执行配置命令。
  手动执行:

//在工作空间下执行
source devel/setup.bash

  添加到bashrc中,每次启动终端自动执行:

//注意:以下使用的的路径需要是完整路径
echo "source /home/ubuntu/learnROS/ROSWorkSpace/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc

编译工程并运行节点

  使用catkin build命令编译工程:

catkin build

  效果如下:
  先运行roscore,在新终端运行setup.bash,通过包名+节点名称运行创建的节点,效果如下:

//运行roscore
roscore

//新终端运行setup.bash,如果已经永久加入bash命令,则不需要手动执行
source devel/setup.bash

//运行节点
rosrun Helloworld SayHelloWorld

  执行效果如下:

Debug-断点调试(单节点)

  • 1.使用F5按键生成默认的调试json配置文件
      按下F5后,选择gdb调试器g++生成器,然后VS Code会在.vscode文件夹中生成主要的两个json文件:launch.jsontasks.json。此时,由于还没有配置好两个文件的内容,所以会提示报错,点击中止即可。
  • 2.编辑tasks.json文件
      tasks.json文件是用于在终端中运行一组命令的配置文件,内容如下:

    {
    "options": {
        "cwd": "${workspaceFolder}",
    },
    "tasks": [
        {
            "type": "shell",
            "label": "roscore",
            "command": "roscore",
            "isBackground": true,
            "problemMatcher":"$roscore",
            "presentation": {
                "echo": false,
                "reveal": "silent",
                "focus": false,
                "panel": "new",
                "showReuseMessage": true,
                "clear": false
            }
        },
        {
            "type": "shell",
            "label": "catkin build",
            "command":"catkin build --cmake-args -DCMAKE_BUILD_TYPE=Debug",
        },
        {
            "type": "shell",
            "label": "source",
            "command":"source",
            "args": [
                "devel/setup.bash",
            ],
        },
        {
            "label": "Build and PreRos",
            "dependsOrder": "sequence",
            "dependsOn":[
                "catkin build",
                "roscore",
                "source"
            ],
        }
    ],
    "version": "2.0.0"
    }

      由于,这个文件内不允许注释,所以在下面简单介绍一下文件中所给出的字段含义:

    //以下为字段说明,请复制使用上面的json文件
    {
    "options": {                                //任务执行的文件路径
      "cwd": "${workspaceFolder}",
    },
    "tasks": [                                  //任务内容
      {                                       //花括号包括的一个任务说明
          "type": "shell",                    //任务类型为shell终端命令
          "label": "roscore",                 //任务的名称为roscore
          "command": "roscore",               //任务要执行的命令为roscore
          "isBackground": true,               //任务为后台任务,roscre启动master节点,要一直有
          "problemMatcher":"$roscore",        //问题捕获器,ros插件安装好后可以直接用定义好的,检测到roscre启动后自动转为后台运行
          "presentation": {                   //任务描述
              "echo": false,                  //不在终端中重复打印执行的命令了
              "reveal": "silent",             //只有出现错误或者警告时才将rocore终端窗口置为最前
              "focus": false,                 
              "panel": "new",                 //使用一个新窗口执行这个任务,以免和其他的发生冲突
              "showReuseMessage": true,
              "clear": false
          }
      },
      {                                       //使用catkin build命令构建功能包
          "type": "shell",                    //如果非系统变量中的命令使用shell类型,command需要包含所有的额外参数
          "label": "catkin build",            //任务名称
          "command":"catkin build --cmake-args -DCMAKE_BUILD_TYPE=Debug",
      },                                      //任务参数,调试时需要生成有debug信息的可执行文件
      {
          "type": "shell",                    //设置bash      
          "label": "source",
          "command":"source",
          "args": [
              "devel/setup.bash",
          ],
      },
      {                                       //组合任务标签
          "label": "Build and PreRos",        //任务名称
          "dependsOrder": "sequence",         //执行任务按照顺序方式
          "dependsOn":[
              "catkin build",                 //执行的任务名称
              "roscore",
              "source"
          ],
      }
    ],
    "version": "2.0.0"
    }
  • 3.编辑launch.json
      launch.json文件可以认为是一个启动器的配置文件,需要改的字段不是很多,内容如下:

    {
    "version": "0.2.0",
    "configurations": [
        {
            "name": "ROS Debug",                                                //任务名称,可以自己起名字
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/devel/lib/Helloworld/SayHelloWorld", //要调试的可执行文件路径,这里生成的可执行文件再devel/lib中
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",                                        //命令运行的文件路径
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                } 
            ],                                                                  //前置任务,我们需要先build工程之后再debug,
            "preLaunchTask": "Build and PreRos",                                //这里的名字就是tasks.json中的那个顺序执行标签名
            "miDebuggerPath": "/usr/bin/gdb"                                    //gdb的路径
        }
    ]
    }
  • 4.修改Build类型
      我们需要使用cmake将可执行文件编译成带Debug信息的可执行文件,所以可以通过修改CMakeLists.txt中的Build类型,或者再tasks.json的build命令中加入相应的参数。
      方法一:修改CMakeLists.txt
      在文件中添加以下内容,设置Build类型:

    set(CMAKE_BUILD_TYPE Debug)


      方法二:修改tasks.json中catkin build命令
      将这个命令更改为带参数的命令,给底层的cmake提供编译类型参数,部分内容如下:

    {
    "type": "shell",
    "label": "catkin build",
    "command":"catkin build --cmake-args -DCMAKE_BUILD_TYPE=Debug",
    },

      catkin build命令的具体使用可以用以下命令查看:

    catkin build --help
  • 5.设置断点并启动调试
      在cpp文件上设置断点,使用F5启动调试,可以看到自动启动新的终端,执行catkin build指令、roscore终端和source指令,并停留在断点处,然后我们就可以使用debug工具栏进行调试。

创建我们的第二个包(多节点)

  在src文件夹上右键,选择Create Catkin Package创建一个包,输入包的名称和包所需要的依赖。操作步骤和创建第一个包类似:

//说明
//这里我们的包名暂时起名为add
//基础的依赖有roscpp rospy std_msgs
//依赖之间使用空格分开

  然后自动生成相关的文件,如下图所示:

  这里第二个包主要实现C/S模型,使用客户端节点向服务器发送请求数据(两个整数),然后服务端将两个数字相加,并返回数字的和,因此需要定义相应的srv。

创建并定义srv

  创建文件夹srv用于存放srv的定义文件,定义文件的名称为AddTwoInts.srv,其内容如下:

int64 a
int64 b
---
int64 sum

修改package.xml文件

  因为ROS需要按照srv的定义将其转化为相应的C++代码,所以需要添加消息生成器的依赖,修改的效果展示如下:

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>message_generation</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>message_runtime</exec_depend>

创建生成节点的cpp文件

客户端节点

  客户端节点需要接收两个参数,然后将其传给服务端,源文件的名称为add_two_ints_client.cpp,其代码如下:

#include "ros/ros.h"
#include "add/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_client");
  if (argc != 3)
  {
    ROS_INFO("usage: add_two_ints_client X Y");
    return 1;
  }

  ros::NodeHandle n;
  ros::ServiceClient client = n.serviceClient<add::AddTwoInts>("add_two_ints");
  add::AddTwoInts srv;                                  //创建一个服务请求
  srv.request.a = atoll(argv[1]);                       //a为数字中的第一个
  srv.request.b = atoll(argv[2]);                       //b为数字中的第二个
  if (client.call(srv))                                 //调用服务,如果成功返回ture,否则返回失败
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  else{
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

  其中引用的AddTwoInts.h头文件为编译过程中自动根据srv定义自动生成的,所以第一次创建cpp文件会有找不到头文件的波浪线提示,暂时可以不用处理。

服务端节点

  服务端需要计算客户端传入的两个参数的和,然后返回给客户端,源文件的名称为add_two_ints_server.cpp,其代码如下:

#include "ros/ros.h"
#include "add/AddTwoInts.h"

bool addtwonum(add::AddTwoInts::Request  &req,
         add::AddTwoInts::Response &res)
{
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", addtwonum);
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}

配置CMakeLists.txt文件

  • 配置find_package项
      添加message_generaton包,最终配置内容如下:

    find_package(catkin REQUIRED COMPONENTS
    roscpp
    rospy
    std_msgs
    message_generation
    )
  • 配置add_service_files项
      添加自定义的srv文件,内容如下:

    add_service_files(
    FILES
    AddTwoInts.srv
    )
  • 配置generate_messages项
      添加自定义服务类型生成器依赖如下,内容如下:

    generate_messages(
    DEPENDENCIES
    std_msgs
    )
  • 配置生成相应的可执行文件
      添加生成的可执行文件名称,链接相应的库,添加需要的依赖,内容如下:

    #客户端节点
    add_executable(add_two_ints_client src/add_two_ints_client.cpp)
    target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
    add_dependencies(add_two_ints_client add_gencpp)
    #服务端节点
    add_executable(add_two_ints_server src/add_two_ints_server.cpp)
    target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
    add_dependencies(add_two_ints_server add_gencpp)

编译并运行

编译

  使用catkin build命令编译功能包,可以通过指定包名单独编译某一个包:

catkin build add

  编译命令执行效果如下:

运行

  这里已经提前将工作区的环境配置setup.bash添加到./bashrc中了,所以可以跳过source步骤。
  先在终端中启动roscore,然后启动服务节点,再启动客户端节点并传入参数,执行效果如下:

  • 运行roscore
  • 运行服务节点
  • 运行客户端节点

Debug-断点调试(多节点)

编写launch文件

  在功能包目录中创建launch文件夹,然后在其中创建launch文件,命名为addproject.launch,其内容如下:

<launch>
    <node pkg="add" name="add_server" type="add_two_ints_server" output="screen"></node>
    <node pkg="add" name="add_client" type="add_two_ints_client" output="screen" args="15 20" ></node>
</launch>

  ROS中的launch文件编写方法请参考官方文档或其他教程。

配置VS Code调试文件
  • settings.json文件
      需要保证该文件中的配置正确,包含两个与python相关的路径,一个为ROS环境的路径,一个为工作空间的路径,如下所示:

    {
    "python.autoComplete.extraPaths": [
        "/home/ubuntu/learnROS/ROSWorkSpace/devel/lib/python2.7/dist-packages",
        "/opt/ros/melodic/lib/python2.7/dist-packages"
    ],
    "python.analysis.extraPaths": [
        "/opt/ros/melodic/lib/python2.7/dist-packages",
        "/home/ubuntu/learnROS/ROSWorkSpace/devel/lib/python2.7/dist-packages"
    ]
    }
  • tastks.json文件
      该文件用于自动编译和启动roscore。如果只需要编辑某个包,则需要指定catkin build命令的包名,并指定为debug模式编译。如果选择手动执行编译和roscore的启动,那么这个文件不是必须项目:

    {
    "options": {
        "cwd": "${workspaceFolder}",
    },
    "tasks": [
        {
            "type": "shell",
            "label": "roscore",
            "command": "roscore",
            "isBackground": true,
            "problemMatcher":"$roscore",
            "presentation": {
                "echo": false,
                "reveal": "silent",
                "focus": false,
                "panel": "new",
                "showReuseMessage": true,
                "clear": false
            }
        },
        {
            "type": "shell",
            "label": "catkin build",
            "command":"catkin build add --cmake-args -DCMAKE_BUILD_TYPE=Debug",
        },
        {
            "label": "Build and PreRos",
            "dependsOrder": "sequence",
            "dependsOn":[
                "catkin build",
                "roscore"
            ],
        }
    ],
    "version": "2.0.0"
    }

      :这里已经提前将source devel/setup.bash命令加入到./bashrc中了。

  • launch.json文件
      使用F5并在弹出的菜单栏中选择ROS可以快捷创建launch.json文件;也可以手动创建,然后使用“添加配置”按钮选择ROS:Launch模板,如下图所示:

      然后将其中的"target"字段修改为功能包中launch文件的绝对路径,如下所示:

    {
    "configurations": [
        {
            "name": "ROS: Launch",
            "type": "ros",
            "request": "launch",
            "target": "/home/ubuntu/learnROS/ROSWorkSpace/src/add/launch/addproject.launch",
            "preLaunchTask": "Build and PreRos"
        }
    ]
    }

      如果使用了自动编译和启动roscore的task.json文件,那么这里需要设置preLaunchTask字段为前置任务的名称;如果选择手动编辑和启动roscore,则不需要preLaunchTask字段。

设置断点并启动调试

  在需要调试的cpp文件上打好断点,然后在调试界面选择要启动的调试项目,也就是launch.json文件中的name字段,此处为ROS:Launch,点击运行按钮或者使用F5启动调试,过程如下:

  然后,我们可以看到VS Code自动启动了编译过程,roscore和launch文件中的两个节点,并在断点处停止:

  使用调试工具栏中的按钮可以切换当前启动的节点或使用调试导航按钮进行调试。
  VS Code任务配置文件编写方法和配置文件请参考VS Code使用手册,更加深入地学习ROS请参考官方文档或者其他教程。


当珍惜每一片时光~