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>
或者在创建功能包时,不要加入路径信息