
一.掌握点掌握 ROS服务通信一问一答同步阻塞模式独立编写服务客户端代码调用 turtlesim 自带/spawn服务自动生成第二只乌龟分清服务端、客户端区分服务与话题通信差异。二.核心理论知识点话题 vs 服务话题单向持续数据流非阻塞适合传感器实时数据乌龟位姿、速度指令服务一问一答同步阻塞通信需要反馈结果适合触发式动作生成 / 删除乌龟角色区分服务端turtlesim_node提供/spawn服务接收请求、完成任务并返回结果客户端手写程序主动发起请求**关键规则**允许多个客户端同时调用同一个服务同一个服务名称只能存在一个服务端不能重复启动。三.实操完整流程1.在功能包src目录新建 turtle_spawn_client.cpp编写服务客户端代码2.代码核心组成//引入ROS核心头文件ros初始化、节点句柄、客户端、日志打印都依赖它#includeros/ros.h//引入Spawn服务消息头文件调用/spawn生成乌龟专用#includeturtlesim/Spawn.hintmain(intargc,char**argv){// 1.初始化ROS节点// argc,argv固定写法用于支持命令行传参// spawn_client_nodeROS系统内部节点名称rosnode list可以看到ros::init(argc,argv,spawn_client_node);// 创建节点句柄nh相当于程序和roscore通信的“通道”发布、订阅、服务都需要它setlocale(LC_ALL,zh_CN.UTF-8);ros::NodeHandle nh;// 2.创建服务客户端对象// nh.serviceClient消息类型(服务名称)// turtlesim::Spawn使用的服务消息类型// /spawn要连接的服务turtlesim自带生成乌龟服务ros::ServiceClient clientnh.serviceClientturtlesim::Spawn(/spawn);// 3.实例化服务消息对象// 服务消息分为两部分request 请求数据、response 返回结果turtlesim::Spawn srv;// 设置请求参数生成乌龟坐标、朝向、名字srv.request.x4.0;srv.request.y4.0;srv.request.theta0;srv.request.nameturtle2;// ROS日志打印绿色普通信息ROS_INFO(等待 /spawn 服务上线...);// 阻塞函数一直等待直到/spawn服务启动成功代码才向下运行// 解决问题先启动客户端、后打开turtlesim造成调用失败client.waitForExistence();ROS_INFO(发起生成乌龟请求...);// 发起同步服务调用【重点】// 程序会卡在这一行等待服务端处理并返回结果阻塞// 调用成功返回true失败返回falseboolresultclient.call(srv);if(result){// srv.response 存放服务返回的数据// .c_str()把C字符串转为C语言字符串满足ROS_INFO打印要求ROS_INFO(生成成功乌龟名称%s,srv.response.name.c_str());}else{// ERROR级别日志红色警告ROS_ERROR(生成乌龟失败);}return0;}nh.serviceClient消息类型(服务名) 创建客户端turtlesim::Spawn srv; 承载请求 request 和响应 response 数据client.waitForExistence()阻塞等待服务上线解决启动顺序问题client.call(srv)发送请求同步阻塞等待服务端返回结果3.修改CMakeLists.txt添加编译规则add_executable(可执行文件名 cpp源码路径)target_link_libraries链接库4.编译工作空间 catkin_make刷新环境变量多终端顺序启动测试roscore → turtlesim_node → 自定义客户端节点四.易错点turtlesim::Spawn模板参数不能删除指定通信的数据格式三层名称不要混淆cpp 文件名、CMake 生成的可执行程序名、ros::init内部节点名三者互相独立waitForExistence()仅仅检测服务是否存在不会发送请求真正执行功能依靠client.call()若删除waitForExistence()先启动客户端、后启动乌龟仿真call 直接返回 false调用失败服务客户端代码不需要 ros::spin()重复运行客户端创建同名乌龟调用会失败进入错误分支。