こんにちは、プペウアです。普段はC言語、C++、データ構造アルゴリズムを中心に更新しています...興味のある方はフォローしてください!がっかりしませんよ。
この章では、サービス通信を介してノードのデータ交換とROS関連の命令を実現する方法を紹介します。
この章では、サービス通信を介してノードのデータ交換とROS関連の命令を実現する方法を紹介します。
0. サービスコミュニケーションの概念
ros では、ノードは特定のサービスを取得したいと考えています (例:現時点ではノードはカメラ データを取得したいと考えており、ノードはカメラにリクエストを送信する必要があり、カメラはメッセージに従ってデータ タイプを返すことができます)これは、基本的なサービス通信の使用シナリオです。
リクエストとレスポンスの方法で異なるノード間のデータ対話を実現します。
この段階ではこれが何を意味するかを理解する必要はありませんが、次のことだけを理解する必要があります。
クライアントクライアント/サーバーサーバーは、自身の情報を rosmaster に順次登録し、同じトピックを通じて照合します。
- サーバーとクライアントの起動に順序は必要ありません
- サーバーとクライアントの両方で複数を持つことができます
- サーバーとクライアントが接続されると、rosmaster は必要なくなります。つまり、 rosmasterは接続を試行するときのみ必要になります。
1. srv メッセージをカスタマイズする
srv メッセージは、サーバーとクライアント間の通信のためのデータ キャリアです。使用可能なデータ型は std_msgs のデータ型と一致しますが、独自に定義する必要があります。
手順は大まかに以下のとおりです。
- 必要に応じて srv 形式のメッセージを定義する
- 設定ファイルを変更する
- 中間ファイルと参照をコンパイルおよび生成する
1.1 srvフォーマットメッセージの定義
これは2 つの数値の加算を実現するため、独自に定義した srv メッセージ フォーマットです。このように定義されています。
このうち、上段はクライアントクライアントが送信する電文フォーマット、下段はサーバが応答する電文フォーマットである。
# 客户端请求
int32 num1
int32 num2
---
# 服务端响应
int32 ans
1.2 設定ファイルを変更する
- msg の定義と同様に、最初に関数パッケージ ディレクトリのpackage.xmlを変更する必要があります。
ここで、54 行目の message_generation はコンパイル時のメッセージ パッケージ
、59 行目の message_runtime は実行時のメッセージ パッケージです。 - CMakeList でこれらの場所を見つけて変更します
# 1.编译时的依赖包 find_package(catkin REQUIRED COMPONENTS rospy std_msgs message_generation ) # 2.加入自己定义的srv文件名字 add_service_files( FILES Addints.srv ) # 3.编译包时的消息依赖 generate_messages( DEPENDENCIES std_msgs ) # 4.加入message_runtime,但官网没有这一步似乎也可以. catkin_package(**chmod +x py文件** CATKIN_DEPENDS rospy std_msgs message_runtime )
- コンパイル後、このパスに新しくコンパイルされたミドルウェアが表示されます。
その後呼び出すメソッドは次のとおりです。
import * を行う理由については、まずコンパイルされたファイルがどのようになるかを確認します。# from packagename.srv import *
srv ミドルウェアが生成され、3 つのクラスが表示されます。この 3 つのクラスは後で使用する必要があるため、通常は直接インポートされます*
2. カスタム Srv サービス通信クライアントの Python 実装:
まず、クライアントとして何をする必要があるかを分析しましょう。
- rosノードを初期化する
- リクエストオブジェクトを作成し、コミュニケーショントピックを設定する
- リクエストレスポンス、レスポンス結果の取得
import rospy
import lesson3_srv.srv import *
rospy.init_node("sum_client")
client=rospy.ServiceProxy("sum2",Addints)
if(len(sys.argv)!=3):
rospy.logerr("参数不对")
sys.exit(1)
num=int(sys.argv[1])
num2=int(sys.argv[2])
response=client.call(num,num2)
rospy.loginfo("%d",response.ans)
ここでは、最初に rospy パッケージとメッセージ タイプがインポートされ、ノード情報とトピックが初期化されます。
サービスを要求するオブジェクトserviceprovy(トピック、srvメッセージ)が作成されます。
受信パラメータは処理されました。 clint.call 戻り値の型は、カスタム メッセージ タイプ、 call (srv のパラメータ)
の形式です。最後に返されたメッセージを処理します
これはクライアント実装です。もちろん、サーバー実装が完了した後、いくつかの最適化コンテンツがあります。
3. カスタム Srv サービス通信サーバーの Python 実装:
まず、サーバーとして何をする必要があるかを分析しましょう。
- ノードを初期化する
- サブスクリプショントピックを設定する
- メッセージを処理するためのコールバック関数を設定する
import rospy
from lesson3_srv.srv import *
def doNum(request):
num1=request.num1
num2=request.num2
sum=num1+num2
response=AddintsResponse()
response.ans=sum
rospy.loginfo("%d %d %d",request.num1,request.num2,response.ans)
return response
rospy.init_node("sum")
server=rospy.Service("sum2",Addints,doNum)
rospy.spin()
スターターパッケージはこちら
次に、サービス (トピック名、srv メッセージ タイプ、コールバック関数)を通じてサービス オブジェクトを作成します。
クライアントから渡されたデータは、コールバック関数のパラメータとして使用されます。
まずそれを取り出し、AddintsResponse メソッドを通じて戻りオブジェクトを作成し、ans を変更して戻ります。このときの戻り値はクライアントに渡されます
4. クライアントの最適化
ここのクライアントには非常に小さな問題があります。サーバーが起動した後にのみ通信できます。サーバーが起動しておらず、クライアントが先に起動すると、エラーが発生します。Ros は公式に 2 つの解決策を提供しています。2 つのうちの 1 つを選択してください。
# rospy.wait_for_service(话题名称)
# client.wait_for_service()
したがって、改善されたクライアント コードは次のようになります。
import rospy
import sys
from lesson3_srv.srv import *
rospy.init_node("sum_client")
client=rospy.ServiceProxy("sum2",Addints)
if(len(sys.argv)!=3):
rospy.logerr("参数不对")
sys.exit(1)
num=int(sys.argv[1])
num2=int(sys.argv[2])
#client.wait_for_service()
rospy.wait_for_service("sum2")
response=client.call(num,num2)
rospy.loginfo("%d",response.ans)
5. 起動して実行する
- まず実行権限chmod +x py ファイルを追加します
- 次に、CMakeList.txt を構成します。
catkin_install_python( PROGRAMS scripts/demo01_server.py scripts/demo01_client.py DESTINATION ${ CATKIN_PACKAGE_BIN_DESTINATION} )
-
rosrun lesson3_srv demo01_client.py rosrun lesson3_srv demo01_server.py
実行効果: 2 3 を渡すと戻り値は 5 になります
ここまででサービス通信の内容は終わりです