サービス通信も ROS では非常に一般的な通信モードであり、リクエスト レスポンスモードに基づいた応答メカニズムです。つまり、ノード A が別のノード B にリクエストを送信し、ノード B が処理リクエストを受信して応答結果を生成して A に返します。
srvファイル
サービス通信にはsrvファイルを使用する必要があり、srvファイルにはリクエストデータとレスポンスデータの種類が定義されています。
1.srvファイルを定義する
具体的な実装: 関数パッケージの下に新しい srv ディレクトリを作成し、.srv ファイルを追加します。
.srv ファイルの内容は次のとおりです。
# 客户端请求时发送的数据
int8 num
---
# 服务端响应时发送的数据
int32 result
2. 設定ファイルの編集
package.xmlにコンパイルの依存関係と実行の依存関係を追加します。
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
<!--
exce_depend 以前对应的是 run_depend 现在非法
-->
CMakeLists.txt srv 関連の構成を編集する
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs
add_service_files(
FILES
AddInts.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
3. コンパイル
コンパイルされた中間ファイルを表示します。
C++ は中間ファイル (.../workspace/devel/include/package name/xxx.h) を呼び出す必要があります。
4. vscodeの設定
c_cpp_properies.json ファイルを構成し、中間ファイルのパスを「incluedePath」にコピーします。
{
"configurations": [
{
"browse": {
"databaseFilename": "",
"limitSymbolsToIncludedHeaders": true
},
"includePath": [
"/opt/ros/noetic/include/**",
"/usr/include/**",
"/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径
],
"name": "ROS",
"intelliSenseMode": "gcc-x64",
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}
1. ROS基本データ型のサービス通信実装
1. ROS形式データのサービス通信実装
ケース: クライアントが整数データを送信し、サーバーが整数データの二次演算を実装します。
サーバー側の実装
#include "ros/ros.h"
#include "std_msgs/Int8.h"
#include "int_server_client/int_server_client.h"
bool doReq(int_server_client::int_server_client::Request& req,
int_server_client::int_server_client::Response& res)
{
res.result = pow(req.num,2);
// ROS_INFO("接受到的数据为:%d",req.num);
// ROS_INFO("处理后的数据为:%d",res.result);
return true;
}
int main(int argc, char *argv[])
{
/* code */
//解决乱码问题
setlocale(LC_ALL,"");
//初始化ros节点
ros::init(argc,argv,"server");
//句柄
ros::NodeHandle nh;
//创建server对象
ros::ServiceServer server;
server = nh.advertiseService("intServer",doReq);
ros::spin();
return 0;
}
クライアントの実装
#include "ros/ros.h"
#include "std_msgs/Int8.h"
#include "int_server_client/int_server_client.h"
int main(int argc, char *argv[])
{
/* code */
//解决乱码问题
setlocale(LC_ALL,"");
//初始化ros节点
ros::init(argc,argv,"server");
//句柄
ros::NodeHandle nh;
//创建client对象
ros::ServiceClient client;
client = nh.serviceClient<int_server_client::int_server_client>("intServer");
//等待服务端启动
client.waitForExistence();
//组织数据
int_server_client::int_server_client ai;
ai.request.num = 10;
//发送请求
bool flag = client.call(ai);
if (flag == 1)
{
ROS_INFO("处理后的数据为%d",ai.response.result);
}
else
{
ROS_INFO("请求失败!");
}
ros::spin();
return 0;
}
起動ファイル
<launch>
<node pkg="int_server_client" type="int_server" name="intServer" output="screen"/>
<node pkg="int_server_client" type="int_client" name="intClint" output="screen"/>
</launch>
2.パラメータ伝送に動的パラメータ伝送を用いたROS整形データのサービス通信の実装
サーバー側の実装は前のセクションと同じですが、クライアント側の実装が異なります。クライアント側の実装では、端末から入力されたパラメーターを取得し、計算と応答のためにサーバーに渡す必要があります。
クライアントの実装
#include "ros/ros.h"
#include "std_msgs/Int8.h"
#include "int_server_client/int_server_client.h"
int main(int argc, char *argv[])
{
/* code */
// argc 是指命令行输入参数的个数(以空白符分隔),默认包含一个程序名
if (argc != 2)
{
ROS_ERROR("请提交一个整数");
return 1;
}
//ROS_INFO("%s",argv[1]);
//解决乱码问题
setlocale(LC_ALL,"");
//初始化ros节点
ros::init(argc,argv,"server");
//句柄
ros::NodeHandle nh;
//创建client对象
ros::ServiceClient client;
client = nh.serviceClient<int_server_client::int_server_client>("intServer");
//等待服务端启动
client.waitForExistence();
//组织数据
int_server_client::int_server_client ai;
//atoi()将字符串转换为整形
ai.request.num = atoi(argv[1]);
//发送请求
bool flag = client.call(ai);
if (flag == 1)
{
ROS_INFO("处理后的数据为%d",ai.response.result);
}
else
{
ROS_INFO("请求失败!");
}
ros::spin();
return 0;
}
走る
前のセクションとは異なり、このセクションでは、クライアントはターミナルに渡されたパラメータを取得する必要があるため、ターミナルでサーバーとクライアントを別々に実行する必要があります。
コマンドは次のとおりです。
rosrun 功能包名 节点名 参数
注: 最初に roscore コマンドを開始する必要があります
3. ros string型データのサービス通信実装
サーバー側の実装
#include "ros/ros.h"
#include "string_server_client/string_srv.h"
bool doReq(string_server_client::string_srvRequest& req,
string_server_client::string_srvResponse& res)
{
ROS_INFO("名字:%s",req.name.c_str());
ROS_INFO("年龄:%s",req.age.c_str());
ROS_INFO("地址:%s",req.address.c_str());
std::stringstream ss;
ss<< req.name.c_str()<<"来自"<<req.address.c_str()<<"今年"<<req.age.c_str()<<"岁";
res.msg = ss.str();
}
int main(int argc, char *argv[])
{
/* code */
//乱码问题
setlocale(LC_ALL,"");
//初始化ros节点
ros::init(argc,argv,"server");
//句柄
ros::NodeHandle nh;
//创建服务端对象
ros::ServiceServer server;
server = nh.advertiseService("stringServerClient",doReq);
ros::spin();
return 0;
}
クライアントの実装
#include "ros/ros.h"
#include "string_server_client/string_srv.h"
int main(int argc, char *argv[])
{
/* code */
//解决乱码
setlocale(LC_ALL,"");
//判断参数数量是否正确
if (argc!=4)
{
ROS_INFO("参数数量不正确,请重新输入");
return 1;
}
//初始化ros节点
ros::init(argc,argv,"server");
//句柄
ros::NodeHandle nh;
//客户端对象
ros::ServiceClient client;
client = nh.serviceClient<string_server_client::string_srv>("stringServerClient");
string_server_client::string_srv clientData;
clientData.request.name = argv[1];
clientData.request.age = argv[2];
clientData.request.address = argv[3];
//等待服务启动
client.waitForExistence();
bool flag = client.call(clientData);
if (flag==1)
{
ROS_INFO("响应的数据为:");
ROS_INFO("%s",clientData.response.msg.c_str());
}
return 0;
}