Help us understand the problem. What is going on with this article?

ROSの基本的な開発をしよう

More than 3 years have passed since last update.

はじめに

このチュートリアルはROSにおける一般的な開発フローを学べます。
また、独自のメッセージ型を定義して自分のソースコードに適用する仕方を学べます。
ROSのバージョンはgroovyを対象にしていますが基本的にバージョンは違っても大丈夫だと思います。

1. ROSのワークスペースを作る

ROSのワークスペースを作ります。以下のコマンドを入力してください。
また、ROSに関するツールを使えるようにするため、パスを通しておきます。

mkdir -p ros_ws/src
cd ros_ws
source /opt/ros/groovy/setup.bash

ここで一度makeしておきます。ROSではcatkin_makeというコマンドを使ってワークスペースのプロジェクトをビルドします。また、初回でこのコマンドを行えばワークスペースに必要なファイルやディレクトリが生成されます。

catkin_make

catkin_makeしたら以下のようなファイル階層になっていると思います。

ros_ws
|--build
|--devel
|--src
  • build
    • ビルドに関する設定やmakeのlogのファイルが入っています。
  • devel
    • 実行ファイルやmakeによって生成されたものが入っています。
  • src
    • ユーザがソースコードを保存する場所です。

これでワークスペースはできました。

2. ROSパッケージを作る

ROSでは任意の機能をつめたソフトウェアの集合をパッケージと呼びます。
パッケージの雛型はcatkin_create_pkgで作成することができます。またcatkin_create_pkgのコマンド引数は以下のとおりです。

catkin_create_pkg [package_name] [depend1] [depends2] ...

コンソールに以下のコマンドを入力してください。

cd src
catkin_create_pkg comp_tutorial roscpp std_msgs

この場合、パッケージの名前はcomp_tutorial、また依存関係を持たせるパッケージはroscpp、std_msgsということになります。
ワークスペースでもう一度catkin_makeしましょう。

cd ~/ros_ws/
catkin_make

3. ROSの通信モデル

ros_pubsub.png

ROSのコーディングに入る前にまず、ROSの通信モデルについて説明します。
ROSではPublish/Subscribeメッセージングと呼ばれる通信モデルでノード(ソフトウェア)同士が通信します。
各要素の役割は以下とおりです。

  • Message:ROSで使用するデータの呼び名。中身のデータ構造はROSにあらかじめ用意されているものか独自の定義が可能
  • Topic:メッセージを分類する系統ごとに作成される論理チャネル
  • Publisher:メッセージを特定のトピックへ配信するノード
  • Subscriber:特定のトピックを購読対象として登録しメッセージを受信するノード

ROSではこのようにPublisherとSubscriberがtopicを介してMessageをやり取りすることでデータ通信をします。
Publish/Subscribeの特徴として、P2Pな通信であることがあげられます。これは、お互いが通信相手の情報を知る必要はなく、ノード構成ネットワークへの脱退、参加が容易になります。
つまりこれはシステムへの機能の追加・変更がとても楽に行えることを意味します。また、1対1の通信専用の方法としてROS Serviceというものもあります。

4. ROSのコーディング

ここではROSの具体的なコーディングを行います。

ROS message

ROSでは処理に必要なデータは基本的にメッセージとして通信を行ないます。
そのメッセージのデータ構造はさまざまなデータ型から任意のものを選択して独自のデータ構造にすることができます。
たとえば、データ型には以下のものがあります。

  • int8, int16, int32, int64 (plus uint*)
  • float32, float64
  • string
  • time, duration
  • other msg files
  • variable-length array[] and fixed-length array[C]

簡単なメッセージファイルを作ってみましょう。

cd ~/ros_ws/src/comp_tutorial
mkdir msg; cd msg
touch adder.msg
emacs adder.msg

メッセージファイルadder.msgの中には以下の記述をしてください。
このmsgファイルでは8bitのunsigned int型の変数を2個保有していることになります。

adder.msg
uint16 a
uint16 b

このメッセージファイルを元にメッセージ型を定義するヘッダファイルが生成されます。
ヘッダファイル生成の設定を行うため以下のファイルを編集してください。

 cd ~/ros_ws/src/comp_tutorial
 emacs CMakeLists.txt

CMakeLists.txt
#該当意部分がはコメントアウトして適宜修正
#7行目あたり
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
  message_generation
)

#45行目あたり
## Generate messages in the 'msg' folder
add_message_files(
   FILES
   adder.msg
 )

#66行目あたり
generate_messages(
   DEPENDENCIES
   std_msgs
)

catkin_makeしましょう。

cd ~/ros_ws
catkin_make

catkin_makeに成功すると以下のディレクトリにメッセージを定義したヘッダファイルが生成されます。

less ~/ros_ws/devel/include/comp_tutorial/adder.h
…
namespace comp_tutorial
{
template <class ContainerAllocator>
struct adder_
{
  typedef adder_<ContainerAllocator> Type;

  adder_()
    : a(0)
    , b(0)  {
    }
  adder_(const ContainerAllocator& _alloc)
    : a(0)
    , b(0)  {
    }
…

ROSのノードを記述する

ROSのノードをC++言語で記述していきます。

cd ~/ros_ws/src/comp_tutorial/src
touch para_in.cpp adder.cpp
  • para_in.cpp:処理に必要なパラメータをPublishするPublisher
  • adder.cpp:para_inから受け取ったパラメータを元に足し算をして表示するSubscriber

Publisherを作る

以下に示すコードがPublisherとなります。
なお、コード中のAPIの説明などはコメントによって記しています。

para_in.cpp
// ros/ros.h ROSに関する基本的なAPIのためのヘッダ
#include "ros/ros.h"
// comp_tutrial/adder.h adder.msgから生成されたメッセージを定義しているヘッダ
#include "comp_tutorial/adder.h"

int main(int argc, char **argv)
{
  // 初期化のためのAPI
  // このノードは"para_in"という名前であるという意味
  ros::init(argc, argv, "para_in");

  // ノードハンドラの宣言
  ros::NodeHandle n;

  //Publisherとしての定義
  // n.advertise<comp_tutorial::adder>("para_input", 1000);
  // comp_tutorial::adder型のメッセージをpara_inputというトピックへ配信する
  //"1000"はトピックキューの最大値
  ros::Publisher para_pub = n.advertise<comp_tutorial::adder>("para_input", 1000);

  //1秒間に1つのメッセージをPublishする
  ros::Rate loop_rate(1);

  //comp_tutrial::adder型のオブジェクトを定義
  //adder.msgで定義したa,bはメンバ変数としてアクセスできる
  comp_tutorial::adder msg;

  int count = 0;
  while (ros::ok())//ノードが実行中は基本的にros::ok()=1
  {
    msg.a = count;
    msg.b = count;
    para_pub.publish(msg);//PublishのAPI
    printf("a = %d b = %d \n",msg.a , msg.b );
    ros::spinOnce();
    loop_rate.sleep();
    count++;
  }
  return 0;
}

Subscriberをつくる

以下に示すコードがSubscriberとなります。
なお、コード中のAPIの説明などはコメントによって記し、Publisherと同じ部分のコメントは省いています。

adder.cpp
#include "ros/ros.h"
#include "comp_tutorial/adder.h"

// Subscribeする対象のトピックが更新されたら呼び出されるコールバック関数
// 引数にはトピックにPublishされるメッセージの型と同じ型を定義する
void chatterCallback(const comp_tutorial::adder msg)
{
    int result;
    result = msg.a + msg.b;
    printf("a:%d + b:%d = %d\n",msg.a , msg.b, result );
}

int main(int argc, char **argv)
{

  ros::init(argc, argv, "adder");
  ros::NodeHandle n;

  // Subscriberとしてpara_inputというトピックがSubscribeし、トピックが更新されたときは
  // chatterCallbackという名前のコールバック関数を実行する
  ros::Subscriber sub = n.subscribe("para_input", 1000, chatterCallback);

  // トピック更新の待ちうけを行うAPI
  ros::spin();

  return 0;
}

2つのファイルの記述が終わったら、パッケージをビルドするために
CMakeLists.txtを編集します。
以下のコマンドでCMakeLists.txtを編集してください。

cd ~/ros_ws/src/comp_tutorial
emacs CMakeLists.txt
CMakeLists.txt
#ファイルの末尾に追加
add_executable(adder src/adder.cpp)
target_link_libraries(adder ${catkin_LIBRARIES})
add_executable(para_in src/para_in.cpp)
target_link_libraries(para_in ${catkin_LIBRARIES})

編集し終わったらビルドしましょう。

cd ~/ros_ws/
catkin_make

5. ROSで作ったノードを実行してみる

ビルドが成功したら、さっそく実行してみましょう。
現在開いているコンソールnほかにもう2つのコンソールを開き以下のコマンドを上からそれぞれ入力してください。

1つ目のコンソール
ROSではroscoreというコマンドを始めに起動することでさまざまなソフトウェアをスタートすることができます。
具体的にはroscoreはネームサービスなどを行います。

cd ~/ros_ws
source devel/setup.bash
roscore

2つ目のコンソール
ROSでは各ノードの実行はrosrunというコマンドによって実行されます。
”adder”を起動します。

cd ~/ros_ws
source devel/setup.bash
rosrun comp_tutorial adder

3つ目のコンソール
”para_in”を起動します。

cd ~/ros_ws
source devel/setup.bash
rosrun comp_tutorial para_in

起動に成功したら以下のような結果が得られます。

root@localhost:~/ros_ws# rosrun comp_tutorial para_in
a = 0 b = 0
a = 1 b = 1
a = 2 b = 2
a = 3 b = 3
a = 4 b = 4
a = 5 b = 5

root@localhost:~/ros_ws# rosrun comp_tutorial adder
a:1 + b:1 = 2
a:2 + b:2 = 4
a:3 + b:3 = 6
a:4 + b:4 = 8
a:5 + b:5 = 10

おわりに

いかがだったでしょうか。ROSのチュートリアルをもう少し簡単にわかりやすくまとめてみました。
もし何かご意見ありましたらコメントお願いします。

参考にしたサイト

ROSの公式Wiki http://wiki.ros.org/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away