You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

修改要点

  1. 移除timer_->cancel()和result.wait_for()的阻塞逻辑,保持定时器正常的2秒调度
  2. 为每个请求创建独立的request对象,避免多请求共享同一对象导致数据覆盖
  3. 使用async_send_request的回调重载,在responseCallback中处理响应,不阻塞主线程的spin循环
  4. 添加异常捕获,处理服务调用失败的情况

内容的提问来源于stack exchange,提问作者Oscar Pf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 00:12:33