コンテンツへスキップ

これまで、ROSをラズパイにいれ、デバックしやすいようにエディタを用意し、Topicを軽く紹介しました。今回はその続きで、service,parameterに関しての記事です。

目次

  • はじめに
  • Service
  • Service のサンプルコード
  • service の動作
  • service の他の項目
  • Parameter
  • Parameter のサンプルコード
  • Parameter の動作
  • roslaunch
  • 雑記
  • 参考

はじめに

OSとは、ロボット開発を促進するミドルウェアで、特に取り上げる基本要素は以下の3つです。

  • Topic
  • Service
  • Parameter

これまでインストールやTopicについて書いてきましたので良ければ参考にしてください。ROSの詳細についても書いています。Ubuntuに入れた回でROSの理念の概要、Topicの回でROSの通信や構造について多少詳しく書いています。

また、この記事では参考本に沿ってやっていきます。サンプルコードとして記載したのは一部です。全文は本に載っているので参考にしてください。

参考本

Service

Topic回と同様に濃い青が実際に作るプログラム、薄い青がプログラムによって作られたもの、矢印がデータの流れを表しています。

serviceのイメージ図

serviceはNode間の1対1の双方向同期通信です。Topicは複数のNodeにmessageを送っていましたが、serviceは送ったデータを相手が受け取ったかどうかを知りたい場合などに使用します。

非連続的な通信であり、応答が終了すると通信の接続は切断されます。

serviceのサンプルコード

tutorial_serviceを作成します。依存パッケージはmessage_generation , roscpp, std_srvs です。

service_server.cpp

int main(int argc, char **argv){
  ros::init(argc, argv, "service_server");
  ros::NodeHandle nh;
  ros::ServiceServer srv = nh.advertiseService("say_hello", serviceSayHello);
  ros::spin();
  return 0;
}

service_serverノードは、"say_hello"サービスを提供し、コールバック関数serviceSayHelloを呼び出します。 serviceSayHelloはコンソールで"Hello World"と言うだけの関数ですので、カットしました。 ros::spin関数で永遠にコールバックを待機させています。

service_client.cpp

int main(int argc, char** argv)
{
  using std_srvs::Empty;
  ros::init(argc, argv, "service_client");
  ros::NodeHandle nh;
  ros::ServiceClient cli = nh.serviceClient<Empty>("say_hello");
  Empty args;
  bool ret = cli.call(args);
  if(ret) ROS_INFO("Sucess");
  else ROS_INFO("Failure");
  return 0;
}

service_clientノードは、"say_hello"サービスを利用するクライアントです。 ros::ServiceClient::callでサービスビスを呼び出し、戻り値をうけとり、呼び出しの成否をbool型retで受け取ります(ちょっと自信無いですが)。 成功した場合はコンソールで"Sucess"と表示します。"成功"は正しくは"Success"ですが、綴りを間違えました。

CMakeListでservice_server,service_clientノードを指定し、ビルドします。

serviceの動作

serviceの動作

以下のように表示されてますね(Sucess は Successです)。

  • Client ->Sucess
  • Server ->Hello World

ノードの様子を確認します。グラフを表示するときには以下のようにコマンド入力します。

$rosrun rqt_graph rqt_graph
tutorial_service動作中のノード

service_serverノードが起動されていることがわかります。serverしか表示されないみたいですね。

Serviceの他の項目

  • 独自型
  • 非同的な使用方法 actionlib

actionはサービスに似た双方向非同期通信です。目標(Goal)、結果(Result)、中間結果(Feedback)で構成されます。 要請から応答までの時間が長い場合や処理中に中間結果が必要な場合に利用されます。

parameter

parameterのイメージ図

ParameterはROSに用意されている設定ファイルに当たる機能です。変数とデフォルトが設定されます。 実機の設定値を決定するのは大変ですが、parameterを利用すると、毎回ソースファイルから変更する手間を省くことができます。

parameterのコード

tutorial_paramパッケージを作成します。依存パッケージはroscppだけです。

param_test.cpp

int main(int argc, char **argv)
{
    ros::init(argc, argv, "param_test");
    ros::NodeHandle nh;
    std::string text = nh.param<std::string>("text", "Hello World");
    int repeat_times = nh.param<int>("repeat_times", 10);
    double frequency = nh.param<double>("frequency", 0.5);
    ros::Rate loop_rate(frequency);
    for(int i = 0; i < repeat_times; i++){
        ROS_INFO("%s", text.c_str() );
        loop_rate.sleep();
    }
    return 0;
}

パラメータの登録とコンソールへの表示を指示しています。

ros::NodeHandle::paramでパラメータを登録します。text,repeat_time,frequencyを指定し、第一引数の名前のParameterがParameter Server上にない場合、第2引数で与えた値を引数に返すように設定します。

param_testノードを作成してビルドします。

parameterの動作

Parameterの動作
  • text ->"Hello World"
  • repeat_times -> 10回
  • frequency -> 0.5Hz

Parameterを指定せずに実行すると、それぞれが指定されていないのでparam_test.cppで記述した通りの規定値(デフォルト)で実行されました。

tutorial_paramのノード

Parameterの登録

以下のようにコマンドを入力すると、Parameter test,5回,2Hzで実行されます。

$ rosparam set /text "Parameter test"
$ rosparam set /repeat_times 5
$ rosparam set /frequency 2.0
$ rosrun tutorial_param param_test

この設定ファイルを外部に保存する場合dump、書き込む場合load機能を実行します。

$rosparam dump ~/params.yaml

作成されたファイルは以下のようになっています。

frequency: 2.0 //記述した部分
repeat_times: 5 //記述した部分
rosdistro: 'melodic

  '
roslaunch:
  uris: {host_ubuntu__38799: 'http://ubuntu:38799/'}
rosversion: '1.14.3

  '
run_id: 74601454-52ee-11e9-94d4-000c2958b845
text: Parameter test //記述した部分

roscoreを再起動すると、これらのパラメータが起動していない状態になりますが、loadするとパラメータが復元できます。

$ rosparam load ~/params.yaml
inomata@ubuntu:~/catkin_ws/src/tutorial_param$ rosparam list
/frequency
/repeat_times
/text
~省略(重要部分のみ表記)~

roslaunch

rosrun以外でノードを起動する方法にroslaunchがあります。roslaunchは複数のノードを実行するときなどに使用される機能です。

tutorial_paramパッケージ内にlaunchディレクトリを作成し、launchファイルを作成し、node,parameterを記述します。

param_test.launch.txt

<?xml version="1.0"?>
<launch>
    <node pkg="tutrial_param" type="param.test" name="param.test" output="screen" />
    <param name="text" value="parameter test" type="string" />
    <param name="repeat_times" value="5" type="int" />
    <param name="frequency" value="2.0" type="double" />
</laaunch>

roslaunchを実行します。roscoreを事前に起動しておかなくてもlaunchと同時に起動します。以下のように使用します。

$roslaunch [パッケージ] [launchファイル]
$roslaunch tutorial_param param_test.launch 
... logging to /home/inomata/.ros/log/74601454-52ee-11e9-94d4-000c2958b845/roslaunch-ubuntu-14888.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://ubuntu:42297/

SUMMARY
========

PARAMETERS
 * /frequency: 2.0
 * /repeat_times: 5
 * /rosdistro: melodic
 * /rosversion: 1.14.3
 * /text: parameter test

NODES
  /
    param_test (tutorial_param/param_test)

ROS_MASTER_URI=http://localhost:11311

process[param_test-1]: started with pid [14912]
[ INFO] [1553954248.157679236]: parameter test
[ INFO] [1553954248.658104672]: parameter test
[ INFO] [1553954249.158001451]: parameter test
[ INFO] [1553954249.658660154]: parameter test
[ INFO] [1553954250.157878784]: parameter test
~省略~
shutting down processing monitor complete done 

このように、launchファイルの設定が読み込まれるので、パラメータの設定や動作のログの保存が簡単にできます。 以下のようにしてノードを複数作成することもできます。

<?xml version="1.0"?>
<launch>
    <node pkg="tutorial_param" type="param_test" name="param_test1" output="screen" >
        <remap from="text" to="param_test1/text" />
        <remap from="repeat_times" to="param_test1/repeat_times" />
        <remap from="frequency" to="param_test1/frequency" />
        <param name="text" value="parameter test1" type="string" />
        <param name="repeat_times" value="5" type="int" />
        <param name="frequency" value="2.0" type="double" />
    </node>
    <node pkg="tutorial_param" type="param_test" name="param_test2" output="screen" >
        <remap from="text" to="param_test2/text" />
        <remap from="repeat_times" to="param_test2/repeat_times" />
        <remap from="frequency" to="param_test2/frequency" />
        <param name="text" value="parameter test2" type="string" />
        <param name="repeat_times" value="10" type="int" />
        <param name="frequency" value="1.0" type="double" />
    </node>
</launch>

実行結果

$roslaunch tutorial_param param_test_multi.launch 
                  ~省略~
process[param_test1-2]: started with pid [16453]
process[param_test2-3]: started with pid [16461]
[ INFO] [1553955293.937496298]: parameter test2
[ INFO] [1553955293.950236042]: parameter test1
[ INFO] [1553955294.448465352]: parameter test1
[ INFO] [1553955294.922201847]: parameter test2
[ INFO] [1553955294.930736280]: parameter test1
[ INFO] [1553955295.430756405]: parameter test1
[ INFO] [1553955295.921917747]: parameter test2
[ INFO] [1553955295.930332254]: parameter test1
[param_test1-2] process has finished cleanly
log file: /home/inomata/.ros/log/2a93dc86-52f6-11e9-94d4-000c2958b845/param_test1-2*.log
[ INFO] [1553955296.921807747]: parameter test2
[ INFO] [1553955297.921376642]: parameter test2
[ INFO] [1553955298.922054324]: parameter test2
[ INFO] [1553955299.922576736]: parameter test2
[ INFO] [1553955300.921124094]: parameter test2
[ INFO] [1553955301.921790482]: parameter test2
[ INFO] [1553955302.921487235]: parameter test2
[param_test2-3] process has finished cleanly
~省略~
done

雑記

ROSシリーズはなんの独自性もない記事になってしまい、反省してます。ラズパイにモータを取り付けるか、Scamperを動かしてもう少し面白い記事にしていきます。

参考

以前、Raspberry Pi 3 B + に Ubuntu MATE(16.04) を入れ、ROSでhelloworldしました。 基本的な機能を確認します。
catkin_makeは重いかも。ラズパイちゃんが固まるので注意。

目次

  • ROSとは
  • Topic
  • Topicのサンプルコード
  • 動作
  • 雑記
  • 参考

ROSとは

ロボット開発を促進するミドルウェアです。ROSではすべてモジュールとモジュール間通信の形式で構成されています。誰かが作ったプログラムを、詳細を知らないままに使用できます。1つ1つのモジュールをノードと呼びます。

ROSではすべての処理が「ノード(Node)とノードがメッセージ(Message)をやりとりする」という構造になっています。それらの集合がパッケージ(Package)と呼ばれます。ノードとノードの通信を行うのがマスタ(Master)で、roscoreコマンドで起動します。

ビルドはすべてパッケージフォルダ内のCMakeLists.txtに記述され、catkinで行われます。(Hydroバージョン以降)

  • Topic
  • Service
  • Parameter

この投稿では参考の本のtopicついてさわりのみ扱います。

topic

濃い青が実際に作るプログラム、薄い青がプログラムによって作られたもの、矢印がデータの流れを表しています。

Topic はノード間でやり取りされるデータの入れ物(話題)です。データを送る動作をpublish、データを受け取る動作をSubscribeといいます。

Publisherはノードの起動時にTopic名をMasterに登録し、Messageで定めた形式で他のノードに送信します。 Subscriverは指定されたTopicを発振しているPublisherを問い合わせます。

名前と型などが設定されていて、Topicの名前を指定すればどのノードからでもデータを読み取ることができます。また一度接続されればメッセージ送受信が継続されます (非同期通信)ので、高頻度の通信を行うセンサ信号の送受信などに使用されます。

topicのサンプルコード

$cw
$catkin_create_pkg tutorial_topic roscpp std_msgs

まず上のようにパッケージを作成します。catkin_create_pkg パッケージ名 依存パッケージ のように書きます。

publisher.cpp

#include <ros/ros.h>
#include <std_msgs/Int32.h>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "publisher");
  ros::NodeHandle nh;
  ros::Publisher pub = nh.advertise<std_msgs::Int32>("number", 10);
  
  ros::Rate loop_rate(1);
  std_msgs::Int32 cnt;
  cnt.data = 0;
  
  while(ros::ok())
  {
    ROS_INFO("Count : %d", cnt.data);
    pub.publish(cnt);
    cnt.data++;
    loop_rate.sleep();
  }
  return 0;
}
  • ros::init(argc, argv, ノード名)はノードの初期化を行う関数です。
  • ros::NodeHandle はROSシステムにアクセスし、他のノードと通信を行うクラスです。
  • ros::NodeHandle::.advertise(topicの名前,バッファ容量)でtopicの登録を行っています。
  • loop_rate(1)で1Hzのウェイトをかけてループしています。
  • std_msgs::Int32は32bit符号付整数のラッパークラスです。ラッパークラスとは、別のプログラム(群)を包んで隠蔽し、使いやすくしたクラスです。今はデータはcnt.dataに格納されています。
  • ros::ok()は基本的にtrue、CNTR+Cで停止したときにfalseを返します。

subscriber.cpp

#include <ros/ros.h>
#include <std_msgs/Int32.h>

void onNumberSubscribed(const std_msgs::Int32 &msg)
{
  ROS_INFO("I heard: [%d]", msg.data);
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "subscriber");
  ros::NodeHandle nh;
  ros::Subscriber sub = nh.subscribe("number", 10, onNumberSubscribed);
  ros::spin();
  return 0;
}
  • ros::NodeHandle::subscribe(topic名, バッファ容量, コールバック関数名)でSubscribeするTopicを設定しています。今は"number"というTopicを受信するたびにonNumberSubscribedが呼び出されます。
  • ros::spin()は無限ループで、CNTR+Cで中断されると、以降の処理は行われません。

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(tutorial_topic)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)

catkin_package()
include_directories(${catkin_INCLUDE_DIRS})

add_executable(publisher src/publisher.cpp)
target_link_libraries(publisher ${catkin_LIBRARIES})

add_executable(subscriber src/subscriber.cpp)
target_link_libraries(subscriber ${catkin_LIBRARIES})

CMakeLists.txtはファイルを作成する指示書みたいなものです。自動で作成されるものを編集します。

  • cmake_minimum_requiredにはバージョン、prjectにはproject名、find_packageには依存パッケージが入っていると思います。
  • catkin_packageはcatkinビルドのオプションを指定します。
  • include_directories()はインクルードフォルダを指定します。今は各パッケージのincludeフォルダのヘッダーファイルを指定しています。

add_executable(実行ファイル名 src/実行ファイル名.cpp)以下をそれぞれ書き足します。add_executableはビルド後に実行するファイルを、target_link_librariesには生成時に必要なファイルを指定します。以下で ビルドします。

$cd ~/catkin_ws
$caikin_make -DCATKIN_WHITELIST_PACKAGES="パッケージ名"
$roscore
$rosrun tutorial_topic subscriber
$rosrun tutorial_topic publisher

指定したパッケージのみビルドし、それぞれ実行します。rosrunなどは起動したままにするので、端末は複数開いてください。

topicの動作

出力はこんな感じ。下のコマンドでノードとデータの移動をグラフとして表示できます。

$rosrun rqt_graph rqt_graph

publisherノードとsubscriberノードがnumberというtopicを受け渡ししているのがわかります。

topicはプリミティブ型は使えないので、ラッパーされたメッセージ型を使わなければなりません。int型の代わりにstd_msgsパッケージのInt32というメッセージ型を使っています。

その他

参考にした本には以下についてのサンプルコードが載っています。

  • 独自型の定義
  • spinOnce
  • AsyncSpinner
  • 同期

ROSでは独自型を定義する事ができます。ただし、ROSの「他の人のコードも利用できる」という性質上、独自型を作成するのは最低限にすべきでしょう。 また、上のサンプルコードにはspin関数を使っているので複数のTopicをSubscribeする事はできません。ノンブロッキングなspinOnceなどを使う必要があります。

また、Lidarの情報を扱う際には同期が活躍します。

雑記

モーターとセンサを取り付けたい。こいつ単体で何かできるようにしてやりたい。

参考

私はC++でROSのコードを書いているんですが、補完機能が使えないとdebugが大変。以前ROSを入れたラズパイに入れようとしたもののROSが入ってないと補完出来ないため、ひとまず仮想マシン上でやることにしました。

目次

  • 目的とROSに関して
  • Ubuntu
  • VMware
  • ROSのインストール
  • VScode
  • 雑記
  • 参考

目的とROSに関して

ROSはロボットソフトウェアプラットホームで、ロボットのプログラムをやる場合にメリットがたくさん。ROSを利用するには別にOSを用意する必要があり、一般的にUbuntuやLinuxが利用されています。

=>過去記事[Raspberry Pi 3 B+ + Ubuntu MATE + ROSのセットアップ]

私はコードはwindows上のVScodeで書いていますが、これではTabで補完できないのですべてのコード自分で書かなくてはならず、タイプミスがかなり多くて困っています。そこでエディタをパワーアップしたいんですが、補完機能を使用するにはROSが必要であり、windowsと相性が悪いとよく言われます。

この記事の目的はROSのコードを補完してくれるエディタを用意することです。

windows10, intel CORE i5 2.3GHz 2.40GHz 実装RAM 4.00GBです。VScodeをインストールして以降、デュアルディスプレイで作業すると重いかも知れませんのでご注意ください。

Ubuntu

Ubuntu is 何 =>
過去記事[Raspberry Pi 3 B+ + Ubuntu MATE + ROSのセットアップ]

Ubuntu は、Linuxベースで無償で提供されており日本人コミュニティのサポートが厚いOSです。 本来はラズパイに合わせてubuntu 16シリーズを入れるべきでしたが、間違って ubuntu 18.04を入れてしまいました。 参考のQiitaによると、ROSのバージョンはubuntuのバージョンが対応していないと動かないらしいので、注意してください。

最新の長期保証版はUbuntu 18.04で、過去の記事で入れたUbuntu MATEは16.04という扱いです。 以下からIOSファイルをダウンロードしてください。

ROSUbuntu
Kinetic16.04
Melodic18.04

VMware

仮想環境を構築します。仮想技術とは、ソフトウェアを活用してハードウェアを再現することで、限りある計算資源がジ歳以上にあるように見せる技術です。

要するに、本当はない架空のPCを用意するようなものです。

VMwareさんの「VMware Workstation Player 15」を使用します。ダウンロード/無償製品のダウンロードからVMware Workstation Playerのfor windowsをインストールします。

Windows または Linux PC 上での仮想マシンの実行に最適な製品です。管理対象の企業デスクトップの配信、教育機関での学習やトレーニングなどの用途に使用できます。

VMware Workstation Player の試用 -VMware より引用

インストーラを起動し、さっきダウンロードしたubuntuをVMにインストールをして、今回私はメモリが残り少ないのでFドライブを指定しました。ここまで10分くらい。

この後結構かかります。途中キーボードを聞かれましたが、私はgeneric101でした。しばらくすると終了してホーム画面がでます。

この時、横でメモ用にwindowsのVScodeを開いていたらだいぶ遅かったです。仮想環境のコア数を設定します。VMware上でPlayer(P)/設定/フリプロセッサを4にすます。動きが多少スムーズになりました。

ROSのインストール

ROS merodicを入れました。Ubuntu18をVMにインストールしてしまったが故の過ち。以下は入れるバージョンによってmerodicの部分を適宜kineticに変換してください。 下記コードを実行します。詳細は過去記事へ。

$sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
$sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
$sudo apt update
$sudo apt install ros-melodic-desktop-full 
$sudo rosdep init
$rosdep update
$echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc //毎回sourceが読み込まれるように設定
$source ~/.bashrc
$roscore //テスト用に実行

このsourceでは、ROSをインストールしたディレクトリに自動で環境変数を登録してくれるスクリプトファイルを読み込んでいます。

以下のように表示されればOK。

作業ファイルの初期化をします。ROSでは専用ビルドシステムcatkinをcatkin_ws上でおこないます。 catkin_wsを作成、初期化

$mkdir -p catkin_ws/src
$cd catkin_ws/src 
$catkin_init_workspace  
$cd ~/catkin_ws 
$catkin_make

ROSでは今後catkin_ws上で作業することになります。ウィキペディアによれば「catkin」という名前は開発したウィローガレージ社のウィロー(Willow = ヤナギ)の木にみられる尾状花序に由来するそうです。

VScode

VScodeを入れます。ページからダウンロードして使用します。

Download Visual Studio Code

Ubuntu上でDebian、Ubuntu用の.debファイルをダウンロードしてインストールします。コマンドからやる場合は以下を入力します。

$cd ~/ダウンロード
$sudo dpkg -i code_*.deb

インストールができたら拡張機能をいじって行きます。まずは下記コマンドまたはVScodeアイコンをクリックして開きます。

$code

左上の縦に並んだアイコンのうち一番下の四角マーク「拡張機能」を選択して、検索バーを使ってインストールしたい拡張機能を入力していきます 。インストールしたのは「Japanese Language Pack for Visual Studio Code」「C/C++」「Python」「ROS」「CMake Tools」「CMake」です。 インストールしたらVScodeを再起動して、ファイル/フォルダーをワークスペースに追加 からcatkin_wsを追加します。

するとcatkin_ws/.vscodeディレクトリに設定ファイル c_cpp_properties が作成されているので、これを編集します。

c_cpp_properties.jsonの変更点

"includePath": [
        "/opt/ros/melodic/include",
        "$HOME/catkin_ws/devel/include",//ここ
        "/usr/include"
      ],

以降はこれで作成したコードを使用します。

ここでROSの設定に戻って、自動でソースを読み込むようにしつつ、コマンドを加えておきます。

$code ~/.bashrc 
# Set ROS melodic
source /opt/ros/melodic/setup.bash //ここはすでに書き込んであります。
source ~/catkin_ws/devel/setup.bash

# Set alias command
alias cw='cd ~/catkin_ws'
alias cs='cd ~/catkin_ws/src'
alias cm='cd ~/catkin_ws && catkin_make'
$source ~/.bashrc //読み込み

ここで試しに下記を実行してみます。

$cs

~/catkin_ws/srcに移動していたらOKです。 次回起動するときはVMwareで△マークでパワーオンします。

雑記

kineticのが場合はmelodicの部分を書きかえばOKのはずです。しばらく使ってみて、ROSのバージョンの違いでどんな違いが出るかわかったら追記しようと思います。 少なくとも今週やっていた参考本の Scamperによる ROS & Raspberry Pi製作入門 の「topic」「service」「param」の章では記法に変化は見つかりませんでした。

参考