Practice of ROS new workspace (workspace) and package (package) compilation (C++ example)

The ROS workspace is a directory used to store ROS work packages. These work packages contain various files of ROS programs, including source code, configuration files, and message files. So the essence of the workspace is a folder, which is used to store the packages that will be introduced next and the files needed to build these packages. Many ROS workspaces can be created, and they are all independent of each other, running specific programs in their respective workspaces, which avoids unrelated programs being put together, and also follows the design concept of loose coupling . The benefits are obvious. Putting the same functions together makes it easy to debug.

1. ROS workspace

New workspace (directory)

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src

Specify -p to create multiple non-existing directories, that is, all directories in this path, if they do not exist, they will be created. In addition, to create a new workspace, we generally create it under the root directory of the current user  ~/

Initialize workspace

catkin_init_workspace
#Creating symlink "/home/yahboom/catkin_ws/src/CMakeLists.txt" pointing to "/opt/ros/melodic/share/catkin/cmake/toplevel.cmake"

The essence here is to create a symbolic link pointing to toplevel.cmake . The result of this is to make the entire system visible.

After the workspace is created and initialized, create some other workspace files:

cd ~/catkin_ws
catkin_make

The command catkin_make will compile all nodes and keep all dependencies up to date. Let's check which directories are added to the src directory: ls

build  devel  src

There is an additional build and devel directory. The build directory is where catkin stores libraries and executable programs when using C++. If we use Python, we can ignore the contents of the build , and the devel mainly focuses on the setup.bash file . , running these files causes the system to use the workspace and the code it contains.
To configure with the following command, append (>>) setup.bash to .bashrc :

echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc

The workspace is so pleasantly newly built. Next, in order to get familiar with a comprehensive point, use C++ to do a compilation, and see what related operations need to be done.

2. ROS package

The name of "package", the software in Ubuntu also exists in the form of a package, but the package in ROS is different from the package in Ubuntu. Since it is specifically about the robot operating system, the "package" mentioned later refers to ROS Package, if it is an Ubuntu package, it will specifically indicate that it is an Ubuntu package.
The command to create the package:

catkin_create_pkg tony_code rospy

This catkin_create_pkg command,  also appeared in the previous article, the introduction of the compilation of the ROS robot operating system Catkin and the use of common commands , is a very common command.

This successfully creates a new package named tony_code , which contains CMakeLists.txt and package.xml files, and a src folder to store the actual source code. This package depends on the existing rospy package. If your package It also depends on other packages, which can be listed on the command line.

A directory structure of this workspace is roughly as follows:

|---catkin_ws/
|------build/
|------devel/
|------src/
         |----CMakeLists.txt
         |----tony_code/
             |----CMakeLists.txt  package.xml  src
         |----Other/
             |----CMakeLists.txt  package.xml  src

There will be several CMakeLists.txt here that need to be distinguished. In addition to one under the src directory of the root directory of the workspace, each package also has a CMakeLists.txt

2.1、CMakeLists.txt

As mentioned above, in addition to a CMakeLists.txt in the workspace , each package also has one. When we compile the package, we modify the CMakeLists.txt under the corresponding package.

This is very simple for readers who are familiar with Make . This file defines how to compile the source code in the work package.
Let's check the contents of the CMakeLists.txt file in the new package tony_code : cat CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)
project(tony_code)

## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  rospy
)

## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)


## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()

################################################
## Declare ROS messages, services and actions ##
################################################

## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
##   your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
##   * add a build_depend tag for "message_generation"
##   * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
##   * If MSG_DEP_SET isn't empty the following dependency has been pulled in
##     but can be declared for certainty nonetheless:
##     * add a exec_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
##   * add "message_generation" and every package in MSG_DEP_SET to
##     find_package(catkin REQUIRED COMPONENTS ...)
##   * add "message_runtime" and every package in MSG_DEP_SET to
##     catkin_package(CATKIN_DEPENDS ...)
##   * uncomment the add_*_files sections below as needed
##     and list every .msg/.srv/.action file to be processed
##   * uncomment the generate_messages entry below
##   * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)

## Generate messages in the 'msg' folder
# add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# )

## Generate services in the 'srv' folder
# add_service_files(
#   FILES
#   Service1.srv
#   Service2.srv
# )

## Generate actions in the 'action' folder
# add_action_files(
#   FILES
#   Action1.action
#   Action2.action
# )

## Generate added messages and services with any dependencies listed here
# generate_messages(
#   DEPENDENCIES
#   std_msgs  # Or other packages containing msgs
# )

################################################
## Declare ROS dynamic reconfigure parameters ##
################################################

## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
##   * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
##   * add "dynamic_reconfigure" to
##     find_package(catkin REQUIRED COMPONENTS ...)
##   * uncomment the "generate_dynamic_reconfigure_options" section below
##     and list every .cfg file to be processed

## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
#   cfg/DynReconf1.cfg
#   cfg/DynReconf2.cfg
# )

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES tony_code
#  CATKIN_DEPENDS rospy
#  DEPENDS system_lib
)

###########
## Build ##
###########

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)

## Declare a C++ library
# add_library(${PROJECT_NAME}
#   src/${PROJECT_NAME}/tony_code.cpp
# )

## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/tony_code_node.cpp)

## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )

#############
## Install ##
#############

# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# catkin_install_python(PROGRAMS
#   scripts/my_python_script
#   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark executables for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
# install(TARGETS ${PROJECT_NAME}_node
#   RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark libraries for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
# install(TARGETS ${PROJECT_NAME}
#   ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
#   LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
#   RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
# )

## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
#   DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
#   FILES_MATCHING PATTERN "*.h"
#   PATTERN ".svn" EXCLUDE
# )

## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
#   # myfile1
#   # myfile2
#   DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )

#############
## Testing ##
#############

## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_tony_code.cpp)
# if(TARGET ${PROJECT_NAME}-test)
#   target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()

## Add folders to be run by python nosetests
# catkin_add_nosetests(test)

From the content of the CMakeLists.txt text, we also roughly understand that it is used to describe the configuration information for building one or more software projects. By editing the configuration, CMake can automatically generate build scripts based on the project configuration information to compile, test and install software item.
According to your own needs, remove the comments if you need to use them. For example, in the configuration, you need to add the directory of the header file, and then open include_directories

When using opencv , you need to include the header file /usr/local/include/opencv/cv.h . We include its directory: include_directories(/usr/local/include) Add when calling the function:  #include "opencv/cv.h"

Other configurations will be explained later when they are needed. 

2.2、package.xml 

This package.xml file contains the meta-information of the working package, such as package name, version number, dependencies, etc.
Let's check the contents of this file: cat package.xml

<?xml version="1.0"?>
<package format="2">
  <name>tony_code</name>
  <version>0.0.0</version>
  <description>The tony_code package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
  <maintainer email="[email protected]">yahboom</maintainer>


  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <license>TODO</license>


  <!-- Url tags are optional, but multiple are allowed, one per tag -->
  <!-- Optional attribute type can be: website, bugtracker, or repository -->
  <!-- Example: -->
  <!-- <url type="website">http://wiki.ros.org/tony_code</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="[email protected]">Jane Doe</author> -->


  <!-- The *depend tags are used to specify dependencies -->
  <!-- Dependencies can be catkin packages or system dependencies -->
  <!-- Examples: -->
  <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
  <!--   <depend>roscpp</depend> -->
  <!--   Note that this is equivalent to the following: -->
  <!--   <build_depend>roscpp</build_depend> -->
  <!--   <exec_depend>roscpp</exec_depend> -->
  <!-- Use build_depend for packages you need at compile time: -->
  <!--   <build_depend>message_generation</build_depend> -->
  <!-- Use build_export_depend for packages you need in order to build against this package: -->
  <!--   <build_export_depend>message_generation</build_export_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use exec_depend for packages you need at runtime: -->
  <!--   <exec_depend>message_runtime</exec_depend> -->
  <!-- Use test_depend for packages you need only for testing: -->
  <!--   <test_depend>gtest</test_depend> -->
  <!-- Use doc_depend for packages you need only for building documentation: -->
  <!--   <doc_depend>doxygen</doc_depend> -->
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>rospy</build_depend>
  <build_export_depend>rospy</build_export_depend>
  <exec_depend>rospy</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

This file contains a set of metadata about the new package. Let’s introduce the nodes respectively:

name : The name of the package, this node cannot be modified! !
version : the version number of the package
description : a short description of the package's functionality
maintainer : the maintainer of the package and the person who fixes the bug, multiple people
license : the license
url : the URL of the package
author : the author of the package
buildtool_depend : the build tool , in ROS, it is basically catkin
build_depend : dependency
export : information required by tools other than catkin

3. Compile C++

With the knowledge above, we use C++ to write the simplest node, then compile it, and get familiar with the whole process and the errors encountered.

3.1, Create a new minimal package

According to the above introduction, create a new package, here the name is minimal

cd ~/catkin_ws/src
catkin_create_pkg minimal rospy

3.2. C++ code

After creating the package, we create a C++ file in the src directory under the minimal package

cd minimal/src
gedit minimal.cpp

The content of minimal.cpp is as follows

#include <ros/ros.h>

int main(int argc,char **argv)
{
    ros::init(argc,argv,"minimal");
    ros::NodeHandle n;
    ros::spin();
    return 0;
}

This is the simplest ROS node written in C++, including a ROS header file.
ros::init(argc,argv,"minimal"); Initialize the node and name it minimal, which is equivalent to the namespace
ros::NodeHandle n; Create a node handle to create topics, services and actions. In Python, there is no need to explicitly create a node handle in this way, because the Python interface of ROS can implicitly implement
ros::spin(); it has been waiting for the scheduling of ROS. If it is simple to understand, such as processing the callback function when subscribing, it will always The meaning of cyclic subscription. Of course, you will encounter a function like ros::spinOnce(); in the later stage , which means the same thing, but this is usually placed in a loop.

3.3. Modify CMakeLists.txt

Then the configuration file is modified. It is still necessary to pay attention here. The CMakeLists.txt file under the minimal package is used.

cd ~/catkin_ws/src/minimal
gedit CMakeLists.txt

Modify the following three places and remove the comments to make it effective:

find_package(catkin REQUIRED rospy)

add_executable(minimal src/minimal.cpp)

target_link_libraries(minimal ${catkin_LIBRARIES})

3.4, compile

After configuring, we start compiling:

cd ~/catkin_ws
catkin_make

When compiling here, it should be noted that you need to return to the root directory of the workspace to compile.
Although three places have been modified, the compilation still reports the following error. The header file ros/ros.h cannot be found . This is a very common error:

Scanning dependencies of target minimal
[ 50%] Building CXX object minimal/CMakeFiles/minimal.dir/src/minimal.cpp.o
/home/yahboom/catkin_ws/src/minimal/src/minimal.cpp:1:10: fatal error: ros/ros.h: No such file or directory
 #include <ros/ros.h>
          ^~~~~~~~~~~
compilation terminated.
minimal/CMakeFiles/minimal.dir/build.make:62: recipe for target 'minimal/CMakeFiles/minimal.dir/src/minimal.cpp.o' failed
make[2]: *** [minimal/CMakeFiles/minimal.dir/src/minimal.cpp.o] Error 1
CMakeFiles/Makefile2:431: recipe for target 'minimal/CMakeFiles/minimal.dir/all' failed
make[1]: *** [minimal/CMakeFiles/minimal.dir/all] Error 2
Makefile:140: recipe for target 'all' failed
make: *** [all] Error 2
Invoking "make -j2 -l2" failed

3.5, compilation error handling

For the above compilation error, it is also introduced above. There are header files here, so you need to open include_directories

include_directories(include ${catkin_INCLUDE_DIRS}) 

Then compile again, still error, start the node manager roscore , it can be started normally, so the environment variable configuration is no problem. The reason is that C++ is used here , so this roscpp dependency package is needed, and the modification is as follows:

find_package(catkin REQUIRED COMPONENTS rospy roscpp) 

Then compile again without any problem. As shown in the picture:

In this way, the compiled minimal executable program is placed in ~/catkin_ws/devel/lib/minimal/minimal

Guess you like

Origin blog.csdn.net/weixin_41896770/article/details/132273124