ROS客户端无法接收服务响应 求问题排查帮助
ROS服务客户端无法接收响应问题排查
我是ROS初学者,尝试开发一个客户端,每2秒发送一次随机生成的两个整数相加的服务请求。服务端能够接收请求并返回计算结果,但客户端似乎无法接收到该响应,恳请帮助排查问题。这是我第一次提问,若有不当之处敬请谅解!
客户端代码
#include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" #include <chrono> #include <cstdlib> #include <memory> #include<stdlib.h> //用于rand() #include<time.h> //用于rand() using namespace std::chrono_literals; using namespace rclcpp; class MyClient: public Node { public : //构造函数 MyClient() : Node("add_two_ints_client"), counter_(0) { RCLCPP_INFO(this->get_logger(), "Hey add_two_ints_client"); // 在节点中打印信息 client = this->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints"); // 创建客户端 //while (!client->wait_for_service(1s)) if (!client->wait_for_service(3s)) { RCLCPP_INFO(this->get_logger(), "service not available, waiting again..."); rclcpp::shutdown(); } request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>(); // 初始化请求(可选) timer_ = create_wall_timer(std::chrono::seconds(2), bind(&MyClient::timerCallback, this)); // 因为在类中所以使用bind,this指代MyClient对象 } //析构函数 ~MyClient() { RCLCPP_INFO(this->get_logger(), "Bye add_two_ints_client"); // 在节点中打印信息 } private: void timerCallback() { counter_++; request->a = (long long int)(rand()%20); request->b = (long long int)(rand()%10); RCLCPP_INFO(this->get_logger(), "Request %d -> 求和: %ld + %ld", counter_, request->a, request->b); auto result = client->async_send_request(request); // 发送请求 timer_->cancel(); // 停止回调的定时器 // 等待异步任务完成,超时时间5秒 auto wait_result = result.wait_for(std::chrono::seconds(5)); if (wait_result == std::future_status::ready) // 获取服务响应 { RCLCPP_INFO(this->get_logger(), "结果: %ld\n\n", result.get()->sum); timer_->reset(); // 重启定时器 } else if (wait_result == std::future_status::timeout) // 未收到响应,触发超时 { RCLCPP_INFO(this->get_logger(), "等待超时。错误。退出。"); rclcpp::shutdown(); } } TimerBase::SharedPtr timer_; int counter_; rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client; std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request; }; int main(int argc, char **argv) { srand(time(NULL)); rclcpp::init(argc, argv); auto node = std::make_shared<MyClient>(); // 创建节点 rclcpp::spin(node); rclcpp::shutdown(); return 0; }
服务端代码
#include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" #include <memory> void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request, std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response) { response->sum = request->a + request->b; RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld", request->a, request->b); RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum); } // 计算两数之和并打印信息,这是绑定到服务的函数 int main(int argc, char **argv) { rclcpp::init(argc, argv); std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_server"); // 创建节点 rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service = node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", &add); // 创建服务 RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add two ints."); // 在控制台打印信息 rclcpp::spin(node); // 启动节点 rclcpp::shutdown(); }
终端输出示例
客户端
[INFO] [1690571647.514563437] [add_two_ints_client]: Hey add_two_ints_client [INFO] [1690571649.515272716] [add_two_ints_client]: Request 1 -> 求和: 5 + 4 [INFO] [1690571654.515567553] [add_two_ints_client]: 等待超时。错误。退出。 [INFO] [1690571654.517240678] [add_two_ints_client]: Bye add_two_ints_client
服务端
[INFO] [1690571649.515536003] [rclcpp]: Incoming request a: 5 b: 4 [INFO] [1690571649.515564808] [rclcpp]: sending back response: [9]
问题原因与解决方案
问题分析
客户端代码中,timerCallback函数里调用result.wait_for()阻塞了定时器回调线程,而ROS的rclcpp::spin需要处理传入的服务响应,但此时回调线程被阻塞,无法处理响应队列中的消息,导致std::future一直处于未就绪状态,最终触发超时。此外,提前调用timer_->cancel()也打乱了定时器的正常调度逻辑。
修改后的客户端代码
改用异步回调方式处理服务响应,避免阻塞回调线程:
#include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" #include <chrono> #include <cstdlib> #include <memory> #include<stdlib.h> #include<time.h> using namespace std::chrono_literals; using namespace rclcpp; class MyClient: public Node { public : MyClient() : Node("add_two_ints_client"), counter_(0) { RCLCPP_INFO(this->get_logger(), "Hey add_two_ints_client"); client = this->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints"); if (!client->wait_for_service(3s)) { RCLCPP_INFO(this->get_logger(), "service not available, exiting..."); rclcpp::shutdown(); } timer_ = create_wall_timer(std::chrono::seconds(2), bind(&MyClient::timerCallback, this)); } ~MyClient() { RCLCPP_INFO(this->get_logger(), "Bye add_two_ints_client"); } private: void timerCallback() { counter_++; auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>(); request->a = (long long int)(rand()%20); request->b = (long long int)(rand()%10); RCLCPP_INFO(this->get_logger(), "Request %d -> 求和: %ld + %ld", counter_, request->a, request->b); // 异步回调处理响应,不阻塞线程 client->async_send_request( request, std::bind(&MyClient::responseCallback, this, std::placeholders::_1) ); } void responseCallback(rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedFuture future) { try { auto response = future.get(); RCLCPP_INFO(this->get_logger(), "结果: %ld\n\n", response->sum); } catch (const std::exception& e) { RCLCPP_ERROR(this->get_logger(), "服务调用失败: %s", e.what()); } } TimerBase::SharedPtr timer_; int counter_; rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client; }; int main(int argc, char **argv) { srand(time(NULL)); rclcpp::init(argc, argv); auto node = std::make_shared<MyClient>(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }
修改要点
- 移除
timer_->cancel()和result.wait_for()的阻塞逻辑,保持定时器正常的2秒调度 - 为每个请求创建独立的
request对象,避免多请求共享同一对象导致数据覆盖 - 使用
async_send_request的回调重载,在responseCallback中处理响应,不阻塞主线程的spin循环 - 添加异常捕获,处理服务调用失败的情况
内容的提问来源于stack exchange,提问作者Oscar Pf
相关产品推荐
相关产品推荐

