您现在的位置是:首页 >其他 >【ROS】ROS2编程示例:话题订阅-发布-C++版网站首页其他

【ROS】ROS2编程示例:话题订阅-发布-C++版

郭老二 2024-07-19 00:01:01
简介【ROS】ROS2编程示例:话题订阅-发布-C++版

1、准备

1)安装ROS2
【ROS】Ubuntu22.04安装ROS2(Humble Hawksbill)

2)ROS2命令
【ROS】ROS2命令行工具详解

3)配置工作空间
【ROS】ROS2中的概念和名词解释中第一节:工作空间 workspace

4)ROS2源码及官方示例:

https://github.com/ros2
https://github.com/ros2/examples

2、编辑

2.1 创建功能包

cd ~/ros/src
mkdir laoerExample
cd laoerExample
ros2 pkg create --build-type ament_cmake cPubSub

注意:创建功能包时一定要先创建好目录,进入相应的目录后创建,不要使用下面的方法,否则会在编译时报错

cd ~/ros/src
ros2 pkg create --build-type ament_cmake laoerExample/cPubSub

解决方法参见博文最后的错误处理一节

2.2 编辑源码

2.2.1 发布者

官方示例源码

#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using namespace std::chrono_literals;

class MinimalPublisher : public rclcpp::Node
{
  public:
    /* 公共构造函数将节点命名为minimal_publisher,并将count_初始化为0 */
    MinimalPublisher()
    : Node("minimal_publisher"), count_(0)
    {
      /* 初始化发布者publisher_ ,使用String消息类型、主题名称topic和在发生备份时限制消息所需的队列大小10 */
      publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);

      /* 初始化timer_,设置timer_callback函数每500ms执行一次 */
      timer_ = this->create_wall_timer(500ms, std::bind(&MinimalPublisher::timer_callback, this));
    }

  private:
    /* 定义定时器回调函数 */
    void timer_callback()
    {
      /* 打印并发布字符串信息 */
      auto message = std_msgs::msg::String();
      message.data = "Hello, world: " + std::to_string(count_++);
      RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
      publisher_->publish(message);
    }

    /* 计时器、发布者和计数器字段的声明 */
    rclcpp::TimerBase::SharedPtr timer_;
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
    size_t count_;
};

int main(int argc, char * argv[])
{
  /* 初始化ROS2 */
  rclcpp::init(argc, argv);

  /* 运行节点MinimalPublisher */
  rclcpp::spin(std::make_shared<MinimalPublisher>());

  /* 退出ROS2 */
  rclcpp::shutdown();
  return 0;
}

2.2.2 订阅者
官方示例源码

#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

/* 占位符,代替回调函数中的第一个参数 */
using std::placeholders::_1;


/* 继承rclcpp:: node创建节点类MinimalSubscriber */
class MinimalSubscriber : public rclcpp::Node
{
  public:
    /* 公共构造函数将节点命名为minimal_subscriber */
    MinimalSubscriber()
    : Node("minimal_subscriber")
    {
      /* 初始化订阅者subscription_  ,使用String消息类型、主题名称topic和在发生备份时限制消息所需的队列大小10,
         订阅话题回调函数topic_callback */
      subscription_ = this->create_subscription<std_msgs::msg::String>(
      "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
    }

  private:
    /* 定义订阅话题回调函数 */
    void topic_callback(const std_msgs::msg::String & msg) const
    {
      /* 打印话题消息的字符串信息 */
      RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg.data.c_str());
    }

    /* 订阅者字段的声明 */
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};

int main(int argc, char * argv[])
{
  /* 初始化ROS2 */
  rclcpp::init(argc, argv);

  /* 运行节点MinimalSubscriber*/
  rclcpp::spin(std::make_shared<MinimalSubscriber>());

  /* 退出ROS2 */
  rclcpp::shutdown();
  return 0;
}

2.3 添加依赖配置

路径:~/ros/src/laoerExample/cPubSub/package.xml

修改package.xml,添加依赖:rclcpp和std_msgs

<build_depend>rclcpp</build_depend>
<build_depend>std_msgs</build_depend>

<exec_depend>rclcpp</exec_depend>
<exec_depend>std_msgs</exec_depend>

完整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>cPubSub</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="lesen@todo.todo">lesen</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>

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

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

2.4 修改编译配置

路径:~/ros/src/laoerExample/cPubSub/CMakeLists.txt
1)设置功能包编译工程名

project(cPubSub)

2)添加需要搜索的依赖:rclcpp和std_msgs

find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

3)添加可执行程序、对应的源码和依赖项

add_executable(talker src/cPub.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
add_executable(listener src/cSub.cpp)
ament_target_dependencies(listener rclcpp std_msgs)

4)添加安装相关的配置

install(TARGETS
	talker
	listener
	DESTINATION lib/${PROJECT_NAME})

5)完整的CMakeLists.txt 如下:

cmake_minimum_required(VERSION 3.8)
project(cPubSub)

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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_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()
  
add_executable(talker src/cPub.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
add_executable(listener src/cSub.cpp)
ament_target_dependencies(listener rclcpp std_msgs)

install(TARGETS
  talker
  listener
  DESTINATION lib/${PROJECT_NAME})

ament_package()

3、编译

在工作空间根目录中编译:

cd ~/ros
~/ros$ colcon build

4、运行

在终端1中运行监听者:

source install/setup.sh 
ros2 run cPubSub listener

在终端2中运行发布者:

source install/setup.sh 
ros2 run cPubSub talker

终端2输出打印信息:

[INFO] [1685584069.664099791] [minimal_publisher]: Publishing: 'Hello, world: 0'
[INFO] [1685584070.164132203] [minimal_publisher]: Publishing: 'Hello, world: 1'
[INFO] [1685584070.664138610] [minimal_publisher]: Publishing: 'Hello, world: 2'
……

终端1输出打印信息:

[INFO] [1685584069.664645713] [minimal_subscriber]: I heard: 'Hello, world: 0'
[INFO] [1685584070.164559773] [minimal_subscriber]: I heard: 'Hello, world: 1'
[INFO] [1685584070.664552715] [minimal_subscriber]: I heard: 'Hello, world: 2'
……

5、测试

1)查看节点信息
在终端3中查看节点信息,运行命令:ros2 node list

~/ros$ ros2 node list
/minimal_publisher
/minimal_subscriber

对应源码中定义节点时:

MinimalPublisher() : Node("minimal_publisher"), count_(0)

2)查看话题信息
在终端3中查看话题信息,运行命令:ros2 topic list

~/ros$ ros2 topic list 
/parameter_events
/rosout
/topic

话题topic对应源码创建话题时:

publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);

3)查看节点连接信息,运行命令:rqt_graph
在这里插入图片描述

6、错误处理

6.1 arget names may not contain a slash

1)错误信息

CMake Error at /opt/ros/humble/share/ament_cmake_core/cmake/ament_cmake_uninstall_target-extras.cmake:40 (add_custom_target):
  add_custom_target called with invalid target name
  "laoerExample/cPubSub_uninstall".  Target names may not contain a slash.

2)原因
在创建功能包时,对包名加入了路径信息,如下

ros2 pkg create --build-type ament_cmake laoerExample/cPubSub

导致在CMakeLists.txt中定义目标名称时,自动加入了路径,从而产生了反斜杠,最终导致cmake不能识别而报错:

project(laoerExample/cPubSub)

3)解决方法
去掉路径描述

project(cPubSub)

或者在创建功能包时,不要加入路径信息

6.2 CMake Error at …… package.xml

1)错误信息

CMake Error at /opt/ros/humble/share/ament_cmake_core/cmake/core/ament_package_xml.cmake:95 (message):
  execute_process(/usr/bin/python3.10
  /opt/ros/humble/share/ament_cmake_core/cmake/core/package_xml_2_cmake.py
  /home/lesen/ros/src/laoerExample/cPubSub/package.xml
  /home/lesen/ros/build/cPubSub/ament_cmake_core/package.cmake) returned
  error code 1

2)原因
在创建功能包时,对包名加入了路径信息,如下

ros2 pkg create --build-type ament_cmake laoerExample/cPubSub

导致在package.xml中定义name标签时,自动加入了路径,从而产生了反斜杠,最终导致ackage_xml_2_cmake.py脚本不能识别而报错:

<name>laoerExample/cPubSub</name>

3)解决方法
去掉路径描述

<name>cPubSub</name>

或者在创建功能包时,不要加入路径信息

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。