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

    怎么在microROS中创建两个服务端?

    已定时 已固定 已锁定 已移动
    MicroROS
    microros ros2 esp32
    2
    6
    824
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 3787186083
      早 安
      最后由 编辑

      自定义了两个消息接口文件MultiNum.srv和CountNum.srv,重新编译后在libmicroros下也有了这两个接口的头文件:
      62295dd9d425d08c3c92d23ddb4970c7.png
      然后编写main.cpp,代码如下:

      #include <Arduino.h>
      #include <micro_ros_platformio.h>
      
      #include <rcl/rcl.h>
      #include <rclc/rclc.h>
      #include <rclc/executor.h>
      
      #include <fishbot_interfaces/srv/multi_num.h> // 添加接口
      #include <fishbot_interfaces/srv/count_num.h>
      
      rclc_executor_t executor;
      rclc_executor_t executor_2;
      
      rclc_support_t support;
      rcl_allocator_t allocator;
      rcl_node_t node;
      
      // 定义服务
      rcl_service_t service;
      rcl_service_t service_2;
      
      // 服务请求和返回消息定义
      fishbot_interfaces__srv__MultiNum_Request req;
      fishbot_interfaces__srv__MultiNum_Response res;
      
      fishbot_interfaces__srv__CountNum_Request req_2;
      fishbot_interfaces__srv__CountNum_Response res_2;
      
      // 服务回调函数
      void service_callback(const void *req, void *res)
      {
        fishbot_interfaces__srv__MultiNum_Request *req_in = (fishbot_interfaces__srv__MultiNum_Request *)req;
        fishbot_interfaces__srv__MultiNum_Response *res_in = (fishbot_interfaces__srv__MultiNum_Response *)res;
        // 计算
        res_in->result = req_in->c * req_in->d;
      }
      
      void service_callback_2(const void *req_2, void *res_2)
      {
        fishbot_interfaces__srv__CountNum_Request *req_in = (fishbot_interfaces__srv__CountNum_Request *)req_2;
        fishbot_interfaces__srv__CountNum_Response *res_in = (fishbot_interfaces__srv__CountNum_Response *)res_2;
        // 计算
        res_in->result_2 = req_in->a + req_in->b;
      }
      
      void setup()
      {
        Serial.begin(115200);
        // 设置通过串口进行MicroROS通信
        set_microros_serial_transports(Serial);
        // 延时时一段时间,等待设置完成
        delay(2000);
        // 初始化内存分配器
        allocator = rcl_get_default_allocator();
        // 创建初始化选项
        rclc_support_init(&support, 0, NULL, &allocator);
        // 创建节点
        rclc_node_init_default(&node, "test05", "", &support);
        // 使用默认配置创建服务
        rclc_service_init_default(&service, &node, ROSIDL_GET_SRV_TYPE_SUPPORT(fishbot_interfaces, srv, MultiNum), "/multi_num");
        rclc_service_init_default(&service_2, &node, ROSIDL_GET_SRV_TYPE_SUPPORT(fishbot_interfaces, srv, CountNum), "/count_num");
      
        // 创建执行器
        rclc_executor_init(&executor, &support.context, 1, &allocator);
        // 执行器添加服务
        rclc_executor_add_service(&executor, &service, &req, &res, service_callback);
      
        rclc_executor_init(&executor_2, &support.context, 1, &allocator);
        rclc_executor_add_service(&executor_2, &service_2, &req_2, &res_2, service_callback_2);
      }
      
      void loop()
      {
        delay(100);
        // 循环处理数据
        rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
        rclc_executor_spin_some(&executor_2, RCL_MS_TO_NS(100));
      }
      

      然后连接上代理,打开终端输入这些命令:
      6d59d28b8613c7821251c316916b450c.png
      只有一个multinum的服务端,而且这个服务端测试是正常的,另一个countnum服务端则没有。

      如果在main.cpp中修改这两个服务端的创建顺序:

      // 使用默认配置创建服务
        rclc_service_init_default(&service_2, &node, ROSIDL_GET_SRV_TYPE_SUPPORT(fishbot_interfaces, srv, CountNum), "/count_num");
        rclc_service_init_default(&service, &node, ROSIDL_GET_SRV_TYPE_SUPPORT(fishbot_interfaces, srv, MultiNum), "/multi_num");
      

      最后在终端里就是只有countnum,而没有multinum。

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

        @378718608 在 怎么在microROS中创建两个服务端? 中说:

        rclc_executor_init(&executor_2, &support.context, 1, &allocator);
        rclc_executor_add_service(&executor_2, &service_2, &req_2, &res_2, service_callback_2);

        用一个 executor

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

        3787186083 1 条回复 最后回复 回复 引用 0
        • 3787186083
          早 安 @小鱼
          最后由 编辑

          @小鱼 我让new bing写了一段两个服务端的代码,用的是一个executor:

          #include <Arduino.h>
          #include <micro_ros_platformio.h>//引入micro-ROS Arduino的头文件,提供micro-ROS的功能
          #include <stdio.h> //引入标准输入输出的头文件,提供printf等函数
          #include <rcl/rcl.h> //引入ROS客户端库的头文件,提供ROS的基本功能
          #include <rcl/error_handling.h> //引入ROS错误处理的头文件,提供错误处理的函数
          #include <rclc/rclc.h> //引入ROS客户端库辅助功能的头文件,提供简化的API
          #include <rclc/executor.h> //引入ROS执行器的头文件,提供执行器的功能
          #include <std_srvs/srv/set_bool.h> //引入标准服务类型的头文件,提供SetBool服务的定义
          
          //changed!
          rcl_service_t service1; //定义第一个服务变量
          rcl_service_t service2; //定义第二个服务变量
          std_srvs__srv__SetBool_Request req1; //定义第一个服务的请求变量
          std_srvs__srv__SetBool_Request req2; //定义第二个服务的请求变量
          std_srvs__srv__SetBool_Response res1; //定义第一个服务的响应变量
          std_srvs__srv__SetBool_Response res2; //定义第二个服务的响应变量
          
          rclc_executor_t executor; //定义执行器变量
          rclc_support_t support; //定义支持变量,用于存储初始化选项等信息
          rcl_allocator_t allocator; //定义分配器变量,用于分配内存空间
          rcl_node_t node; //定义节点变量
          
          #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}} //定义一个宏,用于检查函数返回值是否为RCL_RET_OK,如果不是则进入错误循环。RCCHECK可以检查代码中是否有错误发生,并及时处理
          #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}} //定义一个宏,用于检查函数返回值是否为RCL_RET_OK,如果不是则什么也不做。RCL_RET_OK是一个枚举常量,表示函数执行成功。RCSOFTCHECK可以检查代码中是否有错误发生,但不会中断程序的运行
          
          void error_loop(){ //定义一个错误循环函数,用于在发生错误时闪烁LED灯
            while(1){
              digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
              delay(100);
            }
          }
          
          void service_callback1(const void * req, void * res){ //定义第一个服务的回调函数,用于处理请求并返回响应
            std_srvs__srv__SetBool_Request * req_in = (std_srvs__srv__SetBool_Request *) req; //将请求转换为SetBool类型
            std_srvs__srv__SetBool_Response * res_in = (std_srvs__srv__SetBool_Response *) res; //将响应转换为SetBool类型
          
            res_in->success = true; //设置响应的成功标志为真
            res_in->message.data = (char*) malloc(20 * sizeof(char)); //为响应的消息分配内存空间
            sprintf(res_in->message.data, "Status: %d", req_in->data); //将请求中的数据格式化为字符串,并存储在响应的消息中
            res_in->message.size = strlen(res_in->message.data); //设置响应的消息大小为字符串长度
          
            digitalWrite(LED_BUILTIN, req_in->data); //根据请求中的数据设置LED灯的状态
          }
          
          void service_callback2(const void * req, void * res){ //定义第二个服务的回调函数,用于处理请求并返回响应
            std_srvs__srv__SetBool_Request * req_in = (std_srvs__srv__SetBool_Request *) req; //将请求转换为SetBool类型
            std_srvs__srv__SetBool_Response * res_in = (std_srvs__srv__SetBool_Response *) res; //将响应转换为SetBool类型
          
            res_in->success = true; //设置响应的成功标志为真
            res_in->message.data = (char*) malloc(20 * sizeof(char)); //为响应的消息分配内存空间
            sprintf(res_in->message.data, "Status: %d", req_in->data); //将请求中的数据格式化为字符串,并存储在响应的消息中
            res_in->message.size = strlen(res_in->message.data); //设置响应的消息大小为字符串长度
          
            digitalWrite(LED_BUILTIN, !req_in->data); //根据请求中的数据设置LED灯的状态,与第一个服务相反
          }
          
          void setup() {
            Serial.begin(115200); // 设置超过115200波特率,无法连接到Agent代理
            // 设置通过串口进行MicroROS通信
            set_microros_serial_transports(Serial);
          
            // set_microros_transports(); //设置micro-ROS的传输方式,根据配置文件自动选择
          
            pinMode(LED_BUILTIN, OUTPUT); //设置LED灯引脚为输出模式
            digitalWrite(LED_BUILTIN, HIGH); //设置LED灯为高电平,即关闭
            delay(2000); //延时2秒
          
            allocator = rcl_get_default_allocator(); //获取默认的分配器
          
            //create init_options
            RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); //使用默认的分配器初始化支持变量
          
            // create node
            RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support)); //使用支持变量创建一个节点,节点名为"micro_ros_arduino_node"
          
            // create first service
            RCCHECK(rclc_service_init_default(
              &service1,
              &node,
              ROSIDL_GET_SRV_TYPE_SUPPORT(std_srvs, srv, SetBool),
              "/service1")); //使用节点和服务类型创建第一个服务,服务名为"/service1"
          
            // create second service
            RCCHECK(rclc_service_init_default(
              &service2,
              &node,
              ROSIDL_GET_SRV_TYPE_SUPPORT(std_srvs, srv, SetBool),
              "/service2")); //使用节点和服务类型创建第二个服务,服务名为"/service2"
          
            // create executor
            RCCHECK(rclc_executor_init(&executor, &support.context, 2, &allocator)); //使用支持变量和分配器创建一个执行器,执行器可以处理两个句柄
            RCCHECK(rclc_executor_add_service(&executor, &service1, &req1, &res1, service_callback1)); //将第一个服务添加到执行器中,指定请求、响应和回调函数
            RCCHECK(rclc_executor_add_service(&executor, &service2, &req2, &res2, service_callback2)); //将第二个服务添加到执行器中,指定请求、响应和回调函数
          }
          
          void loop() {
            delay(100); //延时100毫秒
            RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100))); //让执行器运行一段时间,处理任何可用的句柄
          }
          

          但还是不行,终端里显示只有一个服务端,然后我问他是什么原因,他说的确会这样,给了我两个解决这个问题的网页链接:
          链接文本
          链接文本
          好像的确能解决,但我没看懂该怎么操作😷 ...麻烦小鱼帮看看

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

            @378718608 修改下microros配置文件位置在工程的,.pio\libdeps\featheresp32\micro_ros_platformio\metas\colcon.meta里面,

            {
                "names": {
                    "rmw_microxrcedds": {
                        "cmake-args": [
                            "-DRMW_UXRCE_MAX_NODES=1",
                            "-DRMW_UXRCE_MAX_PUBLISHERS=10",
                            "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=5",
                            "-DRMW_UXRCE_MAX_SERVICES=1",
                            "-DRMW_UXRCE_MAX_CLIENTS=1",
                            "-DRMW_UXRCE_MAX_HISTORY=4",
                            "-DRMW_UXRCE_TRANSPORT=custom"
                        ]
                    },
                    "microxrcedds_client":{
                            "cmake-args": [
                                "-DUCLIENT_CUSTOM_TRANSPORT_MTU=1024",
                            ]
                    }
                }
            }
            
            

            "-DRMW_UXRCE_MAX_SERVICES=1",

            1改为2

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

            3787186083 1 条回复 最后回复 回复 引用 0
            • 3787186083
              早 安 @小鱼
              最后由 编辑

              @小鱼 我把colcon.meta里的"-DRMW_UXRCE_MAX_SERVICES=1"改成了2,然后构建,上传,但service list里面还是只有一个服务端。
              我把 pio\libdeps\featheresp32\micro_ros_platformio\metas\ 里面的colcon.meta,colcon_lowmem.meta,colcon_verylowmem.meta,和 pio\libdeps\featheresp32\micro_ros_platformio\ci\custom.meta 里的数值都改了,然后构建,上传,还是不行......

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

                @378718608 确认是否有重新 构建,删掉 libmicroros

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

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