環境
この記事は以下の環境で動いています。
項目 | 値 |
---|---|
CPU | Core i5-8250U |
Ubuntu | 20.04 |
ROS | noetic |
インストールについてはROS講座02 インストールを参照してください。
またこの記事のプログラムはgithubにアップロードされています。ROS講座11 gitリポジトリを参照してください。
概要
このページはROSチュートリアルのシンプルな配信者(Publisher)と購読者(Subscriber)を書く(C++)とほぼ同等の内容です。このシリーズの流儀で少し書き直しています。
Pub & Sub通信
ROSのメインコンセプトはプロセス間でデータ通信です。ROSのプログラムの最小単位はROSノードです(基本的にに1つのROSノードは1プロセスに対応します)。ROSノードは単純な処理を行い、ロボットの複雑な処理は多数のROSノードが通信しあって共同で実行します。本来プロセス間通信を行うのは意外と面倒ですが、ROSフレームワークではPub&Sub型の通信が用意されています。各経路には名前がついて区別され、ROSトピック呼びます。
以下の図の例ではbasic_simple_talker
という名前のROSノードが送信をして、basic_simple_listener
という名前のROSノードが受信をします。この2つはchatter
という名前の付いたROSトピックの経路でデータの送受信をします。また受け渡しをするデータの型はROSメッセージと呼びます。今回使ったものは文字列を送るstd_msgs::String
型です。基本的なデータ型としてstd_msgs::Float64
やstd_msgs::Int32
があったり、カメラ画像を表すsensor_msgs::Image
やパスを表すnav_msgs::Path
等があります。
前準備
ROSのプログラムを作るまでの前準備を行います。
- ROSのインストール
- catkin_wsの作成
- ROSパッケージの作成
この3つはROS講座02 インストールで解説しているのでそちらをご覧ください。
今回は~/catkin_ws
にあるcatkin_wsの中のbasic_lecture
というROSパッケージの中にプログラム作るということを前提に解説します。
ソースファイル
Publisherのコーディング
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char** argv)
{
ros::init(argc, argv, "basic_simple_talker");
ros::NodeHandle nh;
ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 10);
ros::Rate loop_rate(10);
while (ros::ok())
{
std_msgs::String msg;
msg.data = "hello world!";
ROS_INFO("publish: %s", msg.data.c_str());
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
-
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 10);
でROSのPublisherを作成します。- 通信するROSトピックの名前は
chatter
- 通信するROSトピックの型は
std_msgs::String
- 最後の引数の数字はバッファーサイズです。基本的に10程度の値を入れておけば十分です。
- 通信するROSトピックの名前は
Subscriberのコーディング
#include <ros/ros.h>
#include <std_msgs/String.h>
void chatterCallback(const std_msgs::String& msg)
{
ROS_INFO("subscribe: %s", msg.data.c_str());
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "basic_simple_listener");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("chatter", 10, chatterCallback);
ros::spin();
return 0;
}
ros::Subscriber sub = n.subscribe("chatter", 10, chatterCallback);
の2番目の引数の整数値は受信バッファーサイズです。リアルタイム性の高いトピック(=常に最新の値が欲しいトピック)では小さい数字にします。また、取りこぼしがあってほしくないトピックでは大きめの値を選びます。
公式のROSwikiのtutrialでは1000という非常に大きい値になっていますが、このように大きい数字にすると処理がバグることがあるので推奨しません。
CmakeListの設定
パッケージ直下にCmakeLists.txt
がありここにビルド用の情報を書き足します。今回の場合はCmakeLists.txt
に以下の4行を書き加えるだけです。
project(basic_lecture)
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
include_directories(
${catkin_INCLUDE_DIRS}
)
add_executable(basic_simple_talker src/basic_simple_talker.cpp)
add_executable(basic_simple_listener src/basic_simple_listener.cpp)
target_link_libraries(basic_simple_talker
${catkin_LIBRARIES}
)
target_link_libraries(basic_simple_listener
${catkin_LIBRARIES}
)
-
project()
はこのROSパッケージの名前を入れます。 -
find_package()
ではこのROSパッケージが依存するROSパッケージ名を入れます -
include_directories()
ではヘッダファイルのディレクトリの依存を記述します。基本的に${catkin_INCLUDE_DIRS}
だけで充分です。 -
add_executable()
では実行ファイルの生成の設定を書きます。1番目が実行ファイル名(自由に付けられる)で、2番目ではソースファイルを列挙します。 -
target_link_libraries()
ではライブラリの依存を書きます。基本的に${catkin_LIBRARIES}
だけで十分です。
ビルド
cd ~/catkin_ws
catkin build
catkinワークスペースでcatkin build
コマンドを実行するとワークスペース中のすべてのパッケージのビルドを始めます。コンパイルエラーが出た場合はここで表示されます。
実行
roscoreを実行するターミナル、simple_talkerを実行するターミナル、simple_listenerを実行するターミナルの3つのターミナルを使います。rosノードを実行するためにはあらかじめroscoreを実行する必要があります。各ターミナルごとに実行前にsource ~/catkin_ws/devel/setup.bash
を実行する必要があります。
roscore
rosrun basic_lecture basic_simple_talker
rosrun basic_lecture basic_simple_listener
#結果
3つ目のターミナルで以下のような表示が出てきて、/chatter
トピックが受信できていることが確認できました。