# ROS1に関する雑記 ## ROSシステム構成 ### ノード - 1プロセス1ノード - rosの基本はノード間のデータ通信 - 各ノードはメッセージという型でデータを他ノードに送る - データを受けたノードは処理結果を次のノードに渡すことで全体のシステムが動作する ### トピック - データ通信の経路 - ノードのデータ送信 : パブリッシュ - ノードのデータ受信 : サブスクライブ - パブリッシュの前にトピック名とデータ形式の宣言をアドバタイズする必要がある - 同じトピックに複数のノードがデータを送受信できる - 型はmsgファイルに記述 - 型は使用言語に依存しないデータ形式の表現になっている ### サービス - サービスを提供しているノードに引数を渡し,関数の実行結果を戻り値として受け取ることができる - 呼び出される側のノードは遠隔呼び出しができる関数としてサービス名とデータ形式の宣言をアドバタイズする - 呼び出す側のノードは遠隔呼び出しとしてサービスをコールする - 型はsrvファイルに記述 - msgファイルと同様の内容に加えて引数と戻り値の二つの形式を定義する必要がある(関数としての利用を基本としているため) #### サービスとトピックの違い - サービス(必要なときだけ回っとけ) - 双方向のメッセージの要求/応答. - 同期式通信のため,要求があった時のみデータを送受信. - 一回限りのメッセージ送信(サービスの要求を応答が完了すると,ノード間の接続は切断). - トピック(ずっと回れーーー) - 一方方向のメッセージの送信/受信. - 非同期通信なので,常にデータの送受信. - 一度の接続で継続的にメッセージの送受信が可能. ### ROSマスタ - ノード,トピック,サービスの名前登録を行う - それぞれのノードが他のノードから見えるようにする - 通信するノード名とトピック名・サービス名が対応付けられた後はノード同士がP2P - roscoreで起動 - ROSマスタとノード間の通信はXML-RPC - 環境変数ROS_MASTER_URIによって通信用ポートが決められている - 異なるROSマスタが存在する場合はそれぞれ独立したROSネットワークを構築する ### パラメーターサーバ - 設定データを複数のノードで共有するためのサーバ - 各ノードのパラメータをパラメータサーバで一括して管理できる - ノードとの通信はXML-RPC ### 名前空間 - トピック,サービス,パラメータの名前を決定するときに意識するべき - ノード,トピック,サービス,パラメータのそれぞれの名前は階層的な名前空間で管理される - 名前空間を分けることで複数のプログラム間の名前の衝突を回避できる - 名前は名前解決によって実際の名前に対応付け(読み替え)られる - 名前の記述 - 相対名 : - 標準的的に使う記述 - ノードが位置する名前空間の相対的な名前として読み替えられる - 絶対名 : - 先頭に/ - 絶対的な名前 - 名前解決による読み替えはない - - プライベート名 - 先頭に~ - 相対名より一段深い - ノード名のプライベートな名前空間に読み替え |ノード|相対名|絶対名|プライベート名| |-|-|-|-| |/node1|bar → bar|/bar → /bar|~bar → /node1/bar| |/ns/node2|bar → /ns/bar|/bar → /bar|~bar → /ns/node2/bar| |/ns/node3|foo/bar → /ns/foo/bar|/foo/bar → /bar|~bar → /ns/node3/foo/bar| - 上の表はそれぞれのノードがリソース(トピックorサービスorパラメータ)にアクセスする際の名前解決 - →左側のリソース(トピックorサービスorパラメータ)名は→右側のように名前解決される ### リマップ - ノードの立ち上げ時にコマンドに追加することでノード名を変更する - ソースコード内のノード名を書き換えずに変更が可能 - launchファイル内にも記述できる ## rosのパッケージ内構成 - CMakeLists.txt : CMakeのビルドファイル - package.xml : パッケージのマニフェストファイル - include : ヘッダファイルを置くディレクトリ - src : ソースファイルを置くディレクトリ - オプション - msg : メッセージ型の定義ファイルを置くディレクトリ - srv : サービス型の定義ファイルを置くディレクトリ ## ROSファイル構成 ### launch - [launchファイルを調べる](http://rosrosrosrosros.blogspot.com/2013/06/3dsensorlaunch1.html) ### xml - xmlのバージョン指定 - ドキュメント内の使用する文字のエンコーディングを指定 - キュメントがその内容に関して、外部ドキュメント型定義(DTD)などの外部情報に依存しているかどうかを示す ``` <?xml version="1.0"?> <?xml version="1.0"? encoding="UTF-8"> <?xml version="1.0"? standalone="yes"?> ``` ### launchタグ - タグで囲った範囲内のノードを一斉起動 ``` <launch> <!-- your_definition --> </launch> ``` ### nodeタグ - launchしたいノードの情報を記述 - pkg="mypackage" : ノードのパッケージ - type="nodetype" : ノードの実行ファイル - name="nodename" : ノード名 - 名前は名前空間を含まない - 代わりにns属性を使用 - args="arg1 arg2 arg3"(optional) : ノードに引数を渡す - machine="machine-name"(optional) : マシン指定 - 指定したマシン上のノードを起動 - respawn="true"(optional) : リスポン - それが終了した場合、自動的にノードを再起動 - respawn_delay : リスポンディレイ - それが終了して一定時間後、自動的にノードを再起動 - required="true"(optional) : リクワイヤ - ノードが死亡した場合、全体roslaunchを殺す - ns="foo"(optional) : 名前空間 - 'foo'に名前空間内のノードを起動 - clear_params="true|false"(optional) : パラメータ初期化 - 打ち上げ前ノードのプライベート空間ですべてのパラメータを削除 - output="log|screen"(optional) : 出力 - screenで画面にinfo,warn,error等を出力 - デフォルトは 'log' - cwd="ROS_HOME|node"(optional) - 'node'の場合、ノードの作業ディレクトリをノードの実行ファイルと同じディレクトリに設定 - デフォルトは 'ROS_HOME' - launch-prefix="prefix arguments"(optional) - 引数ノードの起動引数を先頭に追加 #### argタグ - 引数を設定paramでパラメータに設定 #### includeタグ - 現在のファイル=別のroslaunch XMLファイルをインクルード #### groupタグ - ノードを起動する名前空間を指定 - これによって同じノード名でも1つのroscore上に存在できる #### paramタグ - そのノードのプライベートパラメータを設定 #### rosparamタグ - ROSのパラメータサーバからパラメータをロードし、ダンプ ## ROSツール ### 可視化・デバッグツール - rqt_graph : ノード状態の可視化 - ノードとトピックの接続を可視化 ``` rosrun rqt_graph rqt_graph ``` ``` rqt_graph ``` - ノード : 楕円 - トピック : 四角 - rqt_plot : メッセージのグラフプロット - メッセージの値を時系列で二次元プロット ``` rosrun rqt_plot rqt_plot [/topic_name/msg_variable] ``` ``` rqt_plot [/topic_name/msg_variable] ``` - トピック名とメッセージの変数を指定して起動可能 - 指定せずに起動したのちtopicから追加することも可能 - 複数のトピック,変数を重ねて表示可能 - RViz : 三次元データの可視化 - 三次元モデル,座標系,測定した三次元点群などを表示可能 - 自分で新たな表示形式などのプラグインを追加することも可能 ``` rosrun rviz rviz ``` ``` rviz ``` - 設定 - Fixed frame : データを表示する際の基準とする座標系の設定 - add : 表示するトピックを追加する - Target frame : 追跡するフレームの設定 これらの設定はメニューからrvizファイルの保存可能 - 操作 - 2D Pose Estimate - 2D Nav Goal - Publish Point これらはクリックやドラッグで位置や方向を規定のトピックに配信する - rosbag : ROSメッセージの記録と再生 - 通信しているメッセージをbagファイルに記録し保存したbagファイルを再生できる - メッセージを記録するがノードの構成等を保存するわけではない - 再生時はrosbagノードが全てのトピックを配信する - **記録** - トピック名を指定して記録 ``` rosbag record /topic_name_1 /topic_name_2 ... ``` - 全てのトピックを記録 ``` rosbag record -a ``` - 全てのトピックを名前を指定して記録 ``` rosbag record -a -O file_name ``` - **再生** - bugファイルを指定して再生 ``` rosbag play file_name.bag ``` - bugファイルを指定してループ再生 ``` rosbag play file_name.bag -l ``` - bugファイルを記録した時刻で再生 ``` rosparam set use_sim_time true rosbag play file_name.bag --clock ``` - bugファイルをn倍速で再生 ``` rosbag play file_name.bag --clock -r n ``` ## tf - 非同期に配信されるフレーム(座標系)の位置関係の取得 - フレーム間のツリー構造を構築 ### tfの動作概念 - ブロードキャスタ - 異なる2つのフレーム間の相対位置を配信する - リスナ - 異なる2つのフレーム間の相対位置を取得する ### tfで使用するデータ形式 - Quaternion : 方向 - Vector3 : 三次元ベクトル - Point : 点の三次元座標 - Pose : PointとQuaternionで三次元座標と方向を表現 - Transform : Vector3とQuaternionで平行移動と回転の組み合わせを表現 ## ROSコマンド ### - catkin_create_pkg パッケージネーム 依存パッケージ : 新しいパッケージの作成 - catkin_make : パッケージのビルド - rosdep : パッケージが要求するシステムの依存関係のインストール ### ros以外のコマンド - pwd : 現在のディレクトリの絶対パスの取得 ```pwd``` ### rosbashコマンド - roscd : ディレクトリ移動 ```roscd pakage_name``` ```roscd log``` - rospd : ディレクトリ移動と移動ログの表示 ```rospd pakage_name``` - rosd : ディレクトリ移動ログの表示 ```rosd``` - rosls : ディレクトリ内のファイルの表示 ```rosls pakage_name``` - rosed : パッケージ内のファイルの編集(デフォルトでvim) ```rosed pakage_name file_name``` - roscp : ファイルのコピー ```roscp pakage_name file_name``` ### 起動コマンド - roscore : ROSの起動 ```roscore``` - rosrun : ノードの起動 ```rosrun pakage_name executable_file_name``` - roslanch : launchファイルを起動するコマンド ```roslaunch [package_name] launch_name.launch``` ### 情報取得コマンド - rospack : パッケージに関する情報(場所,依存関係)を取得 ```rospack find pakage_name``` : パッケージの絶対パス取得 ```rospack depends1 package_name``` : 直接依存の関係取得 ```rospack depends pakage_name``` : 関節含めた依存関係の再帰的取得 - rosnode : ノードに関する情報を取得するコマンド ```rosnode list``` : 起動しているノード一覧を表示 ```rosnode info /node_name``` : 各トピック名とメッセージ型,サービス名などが表示される. ```rosnode ping /node_name``` : ノードの通信をpingで調べられる.応答時間が表示される. - rostopic : トピックに関する情報取得 ```rostopic list``` : 起動ノードの一覧 ```rostopic list -v``` : メッセージ型,ノード数も表示 ```rostopic info /topic_name``` : メッセージ型,ノード名の表示 ```rostopic type /topic_name``` : メッセージ型の表示 ```rostopic hz /topic_name``` : トピックの配信周期 ```rostopic pub /topic_name msg_type msg_data``` : コマンドでトピックをパブリッシュ. - ```rostopic pub -r 1 -v /test_topic std_msgs/String '{data: "test string"}'``` ```rostopic echo /topic_name``` : トピックをsubして表示. - ```rostopic echo /test_topic``` - rosmsg : メッセージの型情報取得 ```rosmsg list``` : メッセージ型の一覧表示 ```rosmsg show msg_type``` : メッセージ型の定義を表示 ```rostopic type /topic_name``` | rosmsg show : トピック名からメッセージ型の定義の直接表示 - rosservice : サービスに関する情報取得 ```rosservice list``` : サービスの一覧表示 ```rosservice info /service_name``` : サービス型,サービスを提供しているノードの表示 ```rosservice type /service_name``` : サービス型の表示 ```rosservice call /service_name srv_data``` : コマンドでサービスをコール - rossrv : サービス型に関する情報を取得するコマンド ```rossrv list``` : サービス型の一覧表示. ```rossrv show srv_type``` : サービス型の定義を表示.[rosservice type]などで取得したサービス型を指定する. ```rosservice type /service_name | rossrv show``` : サービス名からサービス型の定義を直接表示できる. - rosparam : パラメータサーバを操作するコマンド.(roscoreを実行した状態) ```rosparam list``` : パラメータサーバに登録されているパラメータの一覧表示. ```rosparam set /parameter_name param_data``` : コマンドラインからパラメータの設定. ```rosparam get /parameter_name``` : パラメータを取得して表示. ```rosparam get /``` : すべてのパラメータ表示 ```rosparam dump file_name [namespace]``` : 現在のパラメータをYAML形式のファイルに保存. ```rosparam load file_name ][namespace]``` : YAML形式のファイルに保存したパラメータを読み込むことができる. ## ROS_C++ - イニシャライズ - ros::init : ノードのイニシャライズ ```ros::init(argc, argv, "node_name");``` - 指定したノードのイニシャライズ - ros::NodeHandle : ```ros::NodeHandle nh;``` - nhでノードハンドラの取得 - **パブリッシュ** - nh.advertise : トピックのアドバタイズ ``` ros::Publisher pub_name = nh.advertise<autoware_msgs::Lane>("topic_name", 1000,true); ``` - pub_nameにautoware_msgs::Lane型のtopicをtopic_nameでアドバタイズ(最大キューは1000) - pub_name.publish : トピックのパブリッシュ ```pub_name.publish(variable_name);``` - pub_nameのトピックでvariable_nameのメッセージをパブリッシュ - **サブスクライブ** - nh.subscribe : トピックのサブスクライブ ``` ros::Subscriber sub_name = nh.subscribe("topic_name", 1, callback_name); ``` - ros::Subscriber型のsub_nameにtopic_nameをサブスクライブ更新があった場合はcallback_nameというコールバック関数を実行 - **サービス** - nh.advertiseService : サービスの宣言 - ros::ServiceServer service = nh.advertiseService("service_name", service_callback); - void service_callback(req) : サービスのコールバック関数 - この中にサービス時の処理を書く - return : サービスの戻り値を返す - nh.serviceClient : サービスクライアントの宣言 ``` ros::ServiceClient client = nh.serviceClient<beginner_tutorials::AddTwoInts>("service_name"); ``` - サービスクライアントをbeginner_tutorials::AddTwoInts型で宣言 - client.call : サービスのコール - res = client.call(srv); - 指定したサービスのコール - **パラメータ** - パラメータの取得フラグ - パラメータの所得 - **その他** ## ROS_Python - **注意** - pythonをrosrunコマンドで起動するには一行目に以下を追加する ```#!/usr/bin/env/python``` - chmodによる実行権限の付与を忘れない事 - **イニシャライズ** - rospy.init_node : ノードのイニシャライズ ```rospy.init_node('node_name',anonymous=Ture/False)``` - ノード名が重複すると古い方が停止して新しい方が立ち上がる - anonymousをTrueにするとノード名重複を避けるように文字が追加される - **パブリッシュ** - rospy.Publisher : トピックのアドバタイズ ``` pub_name = rospy.Publisher('topic_name',std_msgs.msg.String,queue_size=10) ``` - std_msgs.msg.String型のメッセージとして - バッファ容量を10でアドバタイズ - pub_name.publish() : トピックのパブリッシュ ```pub_name.publish(str_msg)``` - pub_nameでアドバタイズされたトピックに変数str_msgをパブリッシュ - **サブスクライブ** - rospy.subscriber() : トピックのサブスクライブ ```rospy.subscriber('topic_name',std_msgs.String,callback)``` - std_msgs.String型のトピックをサブスクライブ - トピックが更新されるとcallbackという名のコールバック関数を呼び出す - def callback(data) : サブスクライバのコールバック関数 - トピックが更新されたときに行いたい処理をここに記述 - **サービス** - rospy.Service() : サービスの宣言 ``` rospy.Service('service_name',std_srvs.srv.Trigger,service_callback) ``` - std_srvs.srv.Trigger型のサービスを宣言 - コールされたときにコールバック関数が実行される - コールバック関数からリターンされる - def service_callback(req) : サービスのコールバック関数 - この中にサービス時の処理を書く - return : サービスの戻り値を返す - rospy.wait_for_service() : サービスの起動まち ```rospy.wait_for_service('service_name')``` - serviceの起動を待つ - rospy.ServiceProxy() : サービスのコール ```srv_prox = rospy.ServiceProxy('service_name',std_srvs.srv.Trigger)``` - std_srvs.srv.Trigger型のサービスをsrv_proxにコール - res = srv_prox(a,b) - a,bを引く数とした関数としてサービスを実行し戻り値をresに格納 - rospy.ServiceException : サービスが応答しない場合に出力されるエラー - サービス関係の例外処理に使用 ``` return std_srvs.srv.TriggerResponse(success = True,message = '%s_%s: service called for %s'%(rospy.get_name(),tm,param_str)) ``` - サービスの戻り値として各種変数を返す - サービスのコールバック関数の中に実装 - **パラメータ** - rospy.has_param : パラメータ取得フラグ ```rospy.has_param('param_name')``` - パラメータが取得できているかどうかTrue/False - rospy.get_param : パラメータの取得 ```param = rospy.get_param('param_name')``` - 指定したパラメータの取得 - **その他** - rospy.Rate() : 処理の周波数設定 ```rospy.Rate(1)``` - ループの周波数を1Hzに設定 - rate.sleep() : ディレイ - rospy.Rate()で定めた周波数になるように待機 ## ビルド・依存パッケージの追加 ### ビルドシステム - catkin_make : catkinで拡張されたCMakeList.txtの中身を実行 - cmake : CMakeList.txtの中身を実行 - make : makefileのコマンドを実行 ### パッケージのビルド - rosdep install pakage_name : 依存関係のインストール - rosdep update : rosdepのキャッシュ情報をアップデート - catkin_make : ビルド ### 依存パッケージの追加 - catkin_create_pkgを実行した際に加えていないパッケージを追加するには以下のファイルを書き換える必要がある - package.xml - build_dependタグ部 - run_dependタグ部 - CMakeList.txt - find_pakage() ## ROSプログラムのデバッグ - エラーメッセージを検索する - コンパイル時に複数のエラーが出ている場合まず最初のエラーに対処 - 実行はできるが結果が意図通りでない場合は可視化によるデバッグ - pythonなら一行目の#!/usr/bin/env pythonが抜けてないかチェック - gdb?? ## 以下メモ 配置 : 立ちあげたいプログラムが入っているパッケージに、launchディレクトリを作成.この中に .launchファイルを作成する xml : 多様な情報を「情報の意味」と「情報の内容」に分けてテキストで記述する方法 roscoreが立ち上がっていない場合は自動でroscoreも立ち上げてくれる ### 新出単語 - bloom リリースの自動化? - wstool ソースコードのオンライン更新 - ヘッダファイル : Cでは「.h」のファイルに書き込まれるライブラリ.Pythonで言うmosuleのようなもの - マニフェスト - catkin_make install - rosbuild - プロセス - ノード - DTD : スキーマ言語の一つ,XMLファイルとかSGMLファイルの構造を表現するときに使う. - ros.get_time() : 現在時刻を取得する - queue_size = 10 - ログを指定した数まで保存しておきますよ - callback - 常にSubscriberは受信しており、そこに新しい値が入ってきた時にcallback関数を呼び出して、新しい値を入れてあげる。 - 遠隔手続き呼出し(RPC) - イベントドリブン:何かイベントが発生して、それに対応してプログラムが動くことをイベントドカレント以下のディレクトリ構造をみれるコマンドです。リブン(event 容がまとまっている作業をひとつの手続きとしたもの - XML-RPC:遠隔手続き呼び出し(RPC)プロトコルの一種である,エンコード(符号化)にXMLを採用し、転送機構にHTTPを採用している.詳しくは[Perl で XML-RPC を始めよう 第 1 回:Web サービスに XML-RPC を使用する](https://www.ibm.com/developerworks/jp/webservices/library/ws-xpc1/index.html)を参照.![](https://i.imgur.com/b78qDbw.png) - **コールバック関数とは** : ROSにおけるコールバック関数とはサブスクライバの中身が更新されたときに実行される関数。ソフトウェアの構成によっては重要な時もそうでないときもある - **トピックの更新を待つ** : ros::spin(); - **ros::Duration**:Timeクラスで使用する期間表現。 - **ros::Time**:時間表現。 ウォールクロック時間またはROSクロック時間を表すことができます。 ## ros commands #### 出力 - logに保存,設定によってターミナルに出力 - ros.logerror() : 赤で表示 - ros.warm() : オレンジで表示 - ros.loginfo() : 白で表示 --- ## msgs - **geometry_msgs**:点、ベクトル、およびポーズなどの共通のジオメトリプリミティブのメッセージを提供します。 - **visualization_msgs**:ビジュアライゼーション固有のデータを扱う、rvizなどの上位パッケージで使用されるメッセージのセット - **std_msgs**:標準ROSメッセージは、プリミティブデータタイプを表す共通メッセージタイプおよびマルチアレイなどの他の基本メッセージ構成を含む。 --- ### ROSの座標変換TFについて 参考記事 めっっっっっっっちゃ参考になる [ROSの座標変換TFについて](https://memo.soarcloud.com/ros%E3%81%AE%E5%BA%A7%E6%A8%99%E5%A4%89%E6%8F%9Btf%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/) tprint, base_link,base_laser等の座標(データは「フレーム」の表現を使用)は使われる ![](https://i.imgur.com/RivnQEe.jpg) |パラメータ|意味| |-|-| |map|名前のとおり、ロボットが位置するワールド座標。| |odom|mapレイヤの次にくる、オドメトリ(odometry・距離計)と真のワールド座標のずれを表現する。| |base_link|オドメトリodomでのロボット位置。ローカル座標。| |base_footprint|地上でのbase_linkの投影ですが、但しz値は異なる。ローカル座標。| |base_laser|レーザスキャナSlam Lidarの位置。ローカル座標。| ### TF変換 TFは分散システム前提の座標変換のライブラリであり、2フレーム間の位置姿勢関係の報告(transform_broad_caster)を受けて。全てのフレームを絡むツリーを構築して、ツリーをたどって知りたい位置姿勢を取得する(transform_listener)ような仕組みとなる。以下はフレームツリーの例。 ![](https://i.imgur.com/AIWTeZN.jpg) 位置姿勢の表現について、位置はx,y,z(m)、 姿勢はQuaternionにて表示する。詳細はこちら。また、TF変換にtfとtf2パッケージがあり、tf2はtf_staticトピックに静的なフレームを追加できる。tf_staticトピックで受け取った変換は時間に関わらずに利用可能。