鱼香ROS社区
    • 版块
    • 最新
    • 未解决
    • 已解决
    • 群组
    • 注册
    • 登录
    紧急通知:禁止一切关于政治&VPN翻墙等话题,发现相关帖子会立马删除封号
    提问前必看的发帖注意事项: 社区问答规则(小鱼个人)更新 | 高质量帖子发布指南

    ros2自定义客户端中spin_until_future_complete的问题

    已定时 已固定 已锁定 已移动
    ROS 2相关问题
    ros2 service
    3
    13
    3.3k
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 小鱼小
      小鱼 技术大佬 @Lorry
      最后由 编辑

      @Lorry 这个可以看下动手学ROS2中关于服务客户端编写 的介绍。重点在SharedFuture对象上,通过它的成员函数wait_for()可以实现等待结果有效,但是你应该注意的是这会阻塞线程。

      • https://fishros.com/d2lros2/#/humble/chapt3/get_started/5.服务之RCLCPP实现

      发送服务请求

      3.1.2 async_send_request

      接着我们来看看发送请求的API,地址

      替代文字

      我们这里要用的是这个函数async_send_request()同时传入两个参数

      • request,请求的消息,这里用于放a,b两个数。
      • CallBack,回调函数,异步接收服务器的返回的函数。

      SharedFuture

      这个又臭又长的参数确实让人惊了下,函数的参数是客户端AddTwoInts类型的SharedFuture对象,这个对象的定义如下

      image-20220606230244527

      可以看到其又是利用C++11的新特性std::shared_future创建的SharedResponse类模板。

      类模板 std::shared_future 提供访问异步操作结果的机制,类似 std::future ,除了允许多个线程等候同一共享状态。

      我们具体看看std::shared_future的API

      image-20220606231019702

      新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

      LorryL 1 条回复 最后回复 回复 引用 0
      • LorryL
        Lorry @小鱼
        最后由 编辑

        @小鱼 小鱼,我大概明白上面方法的意思。但是在实践上有些蒙(原谅我基础有点差)
        动手学ROS2中代码:

        // 3.发送异步请求,然后等待返回,返回时调用回调函数
        client_->async_send_request(
        request, std::bind(&ServiceClient01::result_callback_, this,
        std::placeholders::_1));
        
        void result_callback_(
        rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedFuture result_future) 
        {
            auto response = result_future.get();
            RCLCPP_INFO(this->get_logger(), "计算结果:%ld", response->sum);
          }
        

        其中,SharedFuture是在回调中使用,回调中如果使用了wait_for(),也不能够实现同步获取response吧?我其实是想实现客户端发送请求,然后同步获取响应,这能实现吗?

        小鱼小 1 条回复 最后回复 回复 引用 0
        • 小鱼小
          小鱼 技术大佬 @Lorry
          最后由 小鱼 编辑

          @Lorry 在 ros2自定义客户端中spin_until_future_complete的问题 中说:

          client_->async_send_reques

          注意这个函数有返回值,返回的就是future

          新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

          LorryL 3 条回复 最后回复 回复 引用 0
          • LorryL
            Lorry @小鱼
            最后由 编辑

            @小鱼 这一点我忽略了😿

            1 条回复 最后回复 回复 引用 0
            • LorryL
              Lorry @小鱼
              最后由 编辑

              @小鱼 小鱼,使用wait_for()确实能让线程等待,但是最终接收到的数据的状态一直都是timeout。
              其中,我客户端相关代码:

              auto result=Client_->async_send_request(request);
                  std::future_status status =result.wait_for(100ms);
                  if (status == std::future_status::timeout)//子线程还没执行完
              	{
              		RCLCPP_INFO(this->get_logger(),"Time out,Failed!");
              	}
              	else if (status == std::future_status::ready)//子线程已执行完
              	{
              		RCLCPP_INFO(this->get_logger(),"Ready.....");
              	}
              

              我监测了服务端用于处理请求的耗时,大概是5~20ms之间,客户端等待100ms应该能成功接收到返回的response。不知道为什么每次等待100ms,status 一直都是std::future_status::timeout。(是我代码写错了?😂 )

              小鱼小 1 条回复 最后回复 回复 引用 0
              • LorryL
                Lorry @小鱼
                最后由 编辑

                @小鱼 我对服务端的回调函数的定义也有些疑问,rclpy的定义方式中,会将response作为返回值,在将response赋值后进行回调,如

                def add_two_ints_callback(self, request, response):
                    response.sum = request.a + request.b
                    self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
                        return response
                

                而rclcpp中,并没有指定返回值,只是将response赋值,如:

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

                那response是在赋值后直接发送给client了吗?

                小鱼小 1 条回复 最后回复 回复 引用 0
                • 小鱼小
                  小鱼 技术大佬 @Lorry
                  最后由 编辑

                  @Lorry 在 ros2自定义客户端中spin_until_future_complete的问题 中说:

                  不知道为什么每次等待100ms

                  std::future_status status =result.wait_for(100ms);

                  你的代码是这样写的呀,可以不传参试试

                  新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                  LorryL 2 条回复 最后回复 回复 引用 0
                  • 小鱼小
                    小鱼 技术大佬 @Lorry
                    最后由 编辑

                    @Lorry 两者不同是因为编程语言限制,c++可以直接传指针,给指针赋值,而python直接将对象返回比较直接。

                    新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                    1 条回复 最后回复 回复 引用 0
                    • LorryL
                      Lorry @小鱼
                      最后由 编辑

                      @小鱼 我找到解决办法了。我代码中是通过定时器完成定时的客户端请求,所以是在定时循环中发起的async_send_request(request)。当不指定定时器的回调组时,result.wait_for(100ms)一定会等待100ms,并且状态一定是std::future_status::timeout。我后来指定了定时器的回调组rclcpp::CallbackGroupType::MutuallyExclusive,wait_for函数就能正常接收到服务端的返回信息。
                      其实我之前一直以为MutuallyExclusive回调组和不指定回调组的效果一样,看来还要再去看看回调组的原理(对了,wait_for函数必须要传参才行,不传参的是wait)

                      小鱼小 1 条回复 最后回复 回复 引用 0
                      • LorryL
                        Lorry @小鱼
                        最后由 编辑

                        @小鱼 贴一下timer部分的代码,有同样问题的可以看一下

                        callback_group_timer=this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
                            Timer_ = this->create_wall_timer(
                              5000ms, std::bind(&S7ClinetNode::time_callback, this),callback_group_timer);
                        
                        1 1 条回复 最后回复 回复 引用 0
                        • 小鱼小
                          小鱼 技术大佬 @Lorry
                          最后由 编辑

                          @Lorry ☺️好嘞

                          新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                          1 条回复 最后回复 回复 引用 0
                          • 1
                            18801286624 @Lorry
                            最后由 编辑

                            @Lorry 在 ros2自定义客户端中spin_until_future_complete的问题 中说:

                            @小鱼 贴一下timer部分的代码,有同样问题的可以看一下

                            callback_group_timer=this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
                                Timer_ = this->create_wall_timer(
                                  5000ms, std::bind(&S7ClinetNode::time_callback, this),callback_group_timer);
                            

                            现在遇到了同样的问题,也是result.wait_for一定会等待100ms,并且状态一定是timeout,区别是我是在订阅话题的回调函数中发起的客户端请求,请问有有办法可以解决吗?

                            1 条回复 最后回复 回复 引用 0
                            • 第一个帖子
                              最后一个帖子
                            皖ICP备16016415号-7
                            Powered by NodeBB | 鱼香ROS