创建模板

在这里我们创建一个c++版本的标准的 ros2 节点模板。

ros2 pkg  create mynode  --build-type ament_cmake --dependencies rclcpp

在标准的ros2 节点模板下,生成的 CMakeLists.txt 模板文件如下:

cmake_minimum_required(VERSION 3.8)
project(mynode)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

在标准的ros2 节点模板下,生成的 package.xml 模板文件如下:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>mynode</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="zhangxiaouse@163.com">aikejiao</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

创建入口文件

在例子中,我们依赖了一些外部消息包,并创建了完成的node节点。

#mynode.hpp
#include "rclcpp/rclcpp.hpp"
#引入sensor_msgs依赖
#include "sensor_msgs/msg/joint_state.hpp"

class MyNode : public rclcpp::Node
{
public:
    MyNode();
    ~MyNode();

private:
    rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr joint_state_sub_;
    rclcpp::Publisher<sensor_msgs::msg::JointState>::SharedPtr joint_state_pub_;

    void joint_state_callback(const sensor_msgs::msg::JointState::SharedPtr msg);
};
#mynode.cpp
#include "mynode/mynode.hpp"

MyNode::MyNode()
    : Node("my_node")
{
    RCLCPP_INFO(this->get_logger(), "Hello, world!");
}

MyNode::~MyNode()
{
    RCLCPP_INFO(this->get_logger(), "Goodbye, world!");
}

void MyNode::joint_state_callback(const sensor_msgs::msg::JointState::SharedPtr msg)
{
    RCLCPP_INFO(this->get_logger(), "Receive Joint state message");
    joint_state_pub_->publish(*msg);
}
#main.cpp
#include "mynode/mynode.hpp"

int main(int argc, char *argv[])
{
    rclcpp::init(argc, argv);
    auto node = std::make_shared<MyNode>();
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

编辑 CMakeLists.txt

与原来生成的CMakeLists.txt 模板文件,我们增加设置将节点编译为可执行文件和依赖关系。

cmake_minimum_required(VERSION 3.8)
project(mynode)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

#新增开始
#找到sensor_msgs包
find_package(sensor_msgs REQUIRED)
#新增结束

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()
#新增开始
#编译为可执行文件,编译后会生成mynode可执行文件
add_executable(mynode src/main.cpp src/mynode.cpp)
#为特定目标设置包含目录,$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>为构建时的包含目录,#$<INSTALL_INTERFACE:include>为安装后的包含目录。
target_include_directories(mynode PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>
)
#添加ROS2依赖关系,将mynode节点链接到rclcpp和sensor_msgs库。
ament_target_dependencies(mynode rclcpp sensor_msgs)
#安装文件
install(TARGETS
  mynode
  DESTINATION lib/${PROJECT_NAME})
#安装目录
install(DIRECTORY include/${PROJECT_NAME}
  DESTINATION include)

install(DIRECTORY launch
  DESTINATION share/${PROJECT_NAME})
#新增结束
ament_package()

编辑 package.xml

与原来生成的package.xml 模板文件,我们增加节点运行时的依赖关系。

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>mynode</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="zhangxiaouse@163.com">aikejiao</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  #新增开始:运行时依赖
  <depend>sensor_msgs</depend>
  #新增结束
  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

为什么需要修改两个文件

在例子中,我们在CMakeList.txtpackage.xml文件中都增加了对sensor_msgs的依赖,这是因为在CMake中,通过find_package(sensor_msgs REQUIRED)来查找这个包,而package.xml中的依赖声明会确保在编译前正确配置依赖路径,以保证在构建时sensor_msgs包可用。