spin()接口对节点的作用
spin翻译为汉语是旋转,但是在ros2中翻译理解为旋转不号理解;
本意应该理解为循环;因为spin的作用就是创建执行器开启循环检测消息和事件,接收到消息和事件之后执行与之对应的回调函数;
而循环会导致阻塞;那么执行器的循环会一直占用CPU资源吗?
ros::spin() enters a loop, calling message callbacks as fast as possible. Don't worry though, if there's nothing for it to do it won't use much CPU. ros::spin() will exit once ros::ok() returns false, which means ros::shutdown() has been called, either by the default Ctrl-C handler, the master telling us to shutdown, or it being called manually.
ros::spin() 进入一个循环,尽可能快地调用消息回调。不过别担心,如果它什么都不做,它不会使用太多的CPU。一旦 ros::ok() 返回 false,ros::spin() 将退出,这意味着 ros::shutdown() 已被调用,要么被默认的 Ctrl-C 处理程序调用,要么由主机告诉我们关闭,要么被手动调用。
可见执行器内部的循环通过循环检测ros::ok()接口判断是否退出或者继续循环;
ros2中的执行器
Executor负责从节点中收集待处理的回调,并决定执行它们的顺序和时间。
ros2执行器使用底层操作系统的一个或多个线程来调用(订阅、定时器、服务服务器、动作服务器等的)回调。
注意:是使用,不是生成线程,这个底层操作系统的线程指的是内核的线程---待确定;
也就是ros2中,回调函数的注册是通过在主线程中调用相关的接口完成注册的,但是回调函数的执行并不由主线程来执行,而是由底层操作系统的线程来执行。
ros2执行器本质上是一个类;
spin接口在内部创建的就是SingleThreadExecutor这个类的执行器对象;
spin的3种接口类型
spin
spin()首先创建一个单线程执行器进入一个无限循环,会尽可能快地执行消息的回调。但是,不需要担心CPU占用问题,因为没事干的时候,它并不怎么消耗CPU资源。
spin内部用于创建单线程执行器:
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
executor.spin();
将节点加入执行器,执行执行器的spin开始检测消息和时间,然后执行相应的回调函数,直到节点关闭;
spin_some
Create a default single-threaded executor and execute any immediately available work.
创建一个SingleThreadedExecutor执行器,会去(话题订阅)缓冲区中查看有没有回调函数。如果有,就马上处理一个回调函数并退出;否则,就退出这个接口,执行后续的代码。
这个接口会立马检测回调并执行返回;
spin_until_future_complete
源码:
template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = int64_t,
typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
std::shared_ptr<NodeT> node_ptr,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::spin_until_future_complete(node_ptr->get_node_base_interface(), future, timeout);
}
三个参数:
节点,期望的返回对象,超时时间;
默认要一直等待期望的结果返回。
期望的结果返回就执行器便退出;执行主线程后续代码;
#include <chrono>
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
using namespace std::chrono_literals;
class ServiceClient_01:public rclcpp::Node{
public:
ServiceClient_01(std::string name):Node(name){
RCLCPP_INFO(this->get_logger(),"I am service client 01: %s",name.c_str());
client_=this->create_client<example_interfaces::srv::AddTwoInts>("add_tow_ints_srv");
}
auto sendRequest(std::shared_ptr<example_interfaces::srv::AddTwoInts_Request> request){
//1,等待server上线
while(!client_->wait_for_service(1s)){
//failed,检查rclcpp状态
if(!rclcpp::ok()){
RCLCPP_INFO(this->get_logger(),"interrupted while waiting for service.");
break;
}
RCLCPP_INFO(this->get_logger(),"Wainting for the server to work...");
}
//2,构造请求
// int n1=0,n2=0;
// std::cin>>n1>>n2;
// auto request=std::make_shared<example_interfaces::srv::AddTwoInts_Request>();
// request->a=n1;
// request->b=n2;
//3,发送请求
auto result=client_->async_send_request(request);
return result;
}
// void responseCallback(example_interfaces::srv::AddTwoInts::Response::SharedPtr result){
// //auto response=result_future.get();
// RCLCPP_INFO(this->get_logger(),"Caculate result: %ld",result->sum);
// }
void responseCallback(std::future<example_interfaces::srv::AddTwoInts::Response::SharedPtr> result_future){
auto response=result_future.get();
RCLCPP_INFO(this->get_logger(),"Caculate result: %ld",response->sum);
}
private:
rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client_{};
//回调函数
// void _responseCallback(rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedFuture result_future){
// auto response=result_future.get();
// RCLCPP_INFO(this->get_logger(),"Caculate result: %ld",response->sum);
// }
};
int main(int argc,char** argv){
rclcpp::init(argc,argv);
auto node=std::make_shared<ServiceClient_01>("service_client_01");
auto request=std::make_shared<example_interfaces::srv::AddTwoInts_Request>();
std::cin>>request->a>>request->b;
auto result=node->sendRequest(request);
//rclcpp::spin(node);
if(rclcpp::spin_until_future_complete(node,result)==rclcpp::FutureReturnCode::SUCCESS){
//node->responseCallback(result.future.get());
node->responseCallback(std::move(result.future));
}
rclcpp::shutdown();
return 0;
}