小鱼 ROS 2 新书上线!点击链接查看, 新书配套视频点击链接查看。
提问前必看的发帖注意事项—— 提问前必看!不符合要求的问题拒绝回答!!
社区使用指南—如何添加标签修改密码
怎么在microROS中创建两个服务端?
-
自定义了两个消息接口文件MultiNum.srv和CountNum.srv,重新编译后在libmicroros下也有了这两个接口的头文件:
然后编写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)); }
然后连接上代理,打开终端输入这些命令:
只有一个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。
-
@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
-
@小鱼 我让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))); //让执行器运行一段时间,处理任何可用的句柄 }
但还是不行,终端里显示只有一个服务端,然后我问他是什么原因,他说的确会这样,给了我两个解决这个问题的网页链接:
链接文本
链接文本
好像的确能解决,但我没看懂该怎么操作 ...麻烦小鱼帮看看 -
@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
-
@小鱼 我把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 里的数值都改了,然后构建,上传,还是不行...... -
@378718608 确认是否有重新 构建,删掉 libmicroros