创建节点
本节我们将创建一个控制节点和一个被控节点。
控制节点创建一个话题发布者publisher,发布控制命令(command)话题,接口类型为字符串(string),控制接点通过发布者发布控制命令(前进、后退、左转、右转、停止)。
被控节点创建一个订阅者subscribe,订阅控制命令,收到控制命令后根据命令内容打印对应速度出来。
创建publisher
依次输入下面的命令,创建chapt3_ws工作空间、example_topic_rclcpp功能包和topic_publisher_01.cpp。
cd d2lros2/
mkdir -p chapt3/chapt3_ws/src
cd chapt3/chapt3_ws/src
ros2 pkg create example_topic_rclcpp --build-type ament_cmake --dependencies rclcpp
touch example_topic_rclcpp/src/topic_publisher_01.cpp
接着采用面向对象方式写一个最简单的节点。
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class TopicPublisher01 : public rclcpp::Node
{
public:// 构造函数,有一个参数为节点名称TopicPublisher01(std::string name) : Node(name){RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());// 创建发布者command_publisher_ = this->create_publisher<std_msgs::msg::String>("command", 10);}private:// 声明话题发布者rclcpp::Publisher<std_msgs::msg::String>::SharedPtr command_publisher_;
};int main(int argc, char **argv)
{rclcpp::init(argc, argv);/*创建对应节点的共享指针对象*/auto node = std::make_shared<TopicPublisher01>("topic_publisher_01");/* 运行节点,并检测退出信号*/rclcpp::spin(node);rclcpp::shutdown();return 0;
}
修改CMakeLists.txt
add_executable(topic_publisher_01 src/topic_publisher_01.cpp)
ament_target_dependencies(topic_publisher_01 rclcpp)install(TARGETStopic_publisher_01DESTINATION lib/${PROJECT_NAME}
)
编写发布者
学习使用API文档
想要创建发布者,只需要调用node的成员函数create_publisher并传入对应的参数即可。
rclcpp: rclcpp: ROS Client Library for C++ (www.ros2.org)
导入消息接口
依次做完这三步
CMakeLists.txt 新增
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)add_executable(topic_publisher_01 src/topic_publisher_01.cpp)
ament_target_dependencies(topic_publisher_01 rclcpp **std_msgs**)
packages.xml 新增
<buildtool_depend>ament_cmake</buildtool_depend><depend>rclcpp</depend><depend>std_msgs</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend>
代码文件topic_publisher_01.cpp 新增
#include "std_msgs/msg/string.hpp"class TopicPublisher01 : public rclcpp::Node
编译
cd chapt3/chapt3_ws/
colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_publisher_01
使用定时器定时发布数据
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class TopicPublisher01 : public rclcpp::Node
{
public:// 构造函数,有一个参数为节点名称TopicPublisher01(std::string name) : Node(name){RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());// 创建发布者command_publisher_ = this->create_publisher<std_msgs::msg::String>("command", 10);// 创建定时器,500ms为周期,定时发布timer_ = this->create_wall_timer(std::chrono::milliseconds(500), std::bind(&TopicPublisher01::timer_callback, this));}private:void timer_callback(){// 创建消息std_msgs::msg::String message;message.data = "forward";// 日志打印RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());// 发布消息command_publisher_->publish(message);}// 声名定时器指针rclcpp::TimerBase::SharedPtr timer_;// 声明话题发布者指针rclcpp::Publisher<std_msgs::msg::String>::SharedPtr command_publisher_;
};int main(int argc, char **argv)
{rclcpp::init(argc, argv);/*创建对应节点的共享指针对象*/auto node = std::make_shared<TopicPublisher01>("topic_publisher_01");/* 运行节点,并检测退出信号*/rclcpp::spin(node);rclcpp::shutdown();return 0;
}
定时器
定时器是ROS2中的另外一个常用功能,通过定时器可以实现按照一定周期调用某个函数以实现定时发布等逻辑。
定时器对应的类是 rclcpp::TimerBase,调用create_wall_timer将返回其共享指针。
创建定时器时传入了两个参数,这两个参数都利用了C++11的新特性。
std::chrono::milliseconds(500),代表500ms,chrono是c++ 11中的时间库,提供计时,时钟等功能。
std::bind(&TopicPublisher01::timer_callback, this),bind() 函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的。
编写订阅者
topic_subscribe_01.cpp
cd chapt3_ws/src/example_topic_rclcpp
touch src/topic_subscribe_01.cpp
topic_subscribe_01.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class TopicSubscribe01 : public rclcpp::Node
{
public:TopicSubscribe01(std::string name) : Node(name){RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());// 创建一个订阅者订阅话题command_subscribe_ = this->create_subscription<std_msgs::msg::String>("command", 10, std::bind(&TopicSubscribe01::command_callback, this, std::placeholders::_1));}private:// 声明一个订阅者rclcpp::Subscription<std_msgs::msg::String>::SharedPtr command_subscribe_;// 收到话题数据的回调函数void command_callback(const std_msgs::msg::String::SharedPtr msg){double speed = 0.0f;if(msg->data == "forward"){speed = 0.2f;}RCLCPP_INFO(this->get_logger(), "收到[%s]指令,发送速度 %f", msg->data.c_str(),speed);}
};int main(int argc, char **argv)
{rclcpp::init(argc, argv);/*创建对应节点的共享指针对象*/auto node = std::make_shared<TopicSubscribe01>("topic_subscribe_01");/* 运行节点,并检测退出信号*/rclcpp::spin(node);rclcpp::shutdown();return 0;
}
CMakeLists.txt
add_executable(topic_subscribe_01 src/topic_subscribe_01.cpp)
ament_target_dependencies(topic_subscribe_01 rclcpp std_msgs)install(TARGETS
topic_subscribe_01DESTINATION lib/${PROJECT_NAME}
)
packages.xml
不改动,同一个功能包,已经添加了。
编译
cd chapt3/chapt3_ws/
colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_subscribe_01
手动运行测试
ros2 topic pub /command std_msgs/msg/String "{data: forward}"
运行测试
第一个终端
source install/setup.bash
ros2 run example_topic_rclcpp topic_subscribe_01
第二个终端
source install/setup.bash
ros2 run example_topic_rclcpp topic_publisher_01