BTR課題 : fawkes の plugin を作ってみましょう(Interfaces編)

BTR課題 : fawkes の plugin を作ってみましょう.にてplugin作成の勉強をしましたが,今回はそこから一歩踏み込んで他のプラグインとのデータのやり取りをしてみましょう.
ROSで言うところのPublisherとSubscriberの作成みたいなもんです.
プラグイン間のデータのやりとりには,BlackBoardを介します.
そこにデータを書き込むには,データの型の宣言が必要です.
構造体みたいなモノ と思えば大丈夫です.

ここでは,LRFで取得したデータをファイルに書き込んでみましょうか.
プラグイン名は,単純にLRFLoggerとでもしましょう.

cd ~/fawkes-robotino/src/plugin/
cp -r plugin_template lrf_logger
cd lrf_logger/
mv plugin_template_plugin.cpp lrf_logger_plugin.cpp
mv plugin_template_thread.cpp lrf_logger_thread.cpp
mv plugin_template_thread.h lrf_logger_thread.h

中身のクラス名やヘッダファイル名を修正し,Makefile の中も更新しましょう.


さて,サンプルのプログラムは,Robotino のモーターの値を書き換えるプログラムになっています.
BlackBoard上での名前は,MotorInterfaceの「Robotino」です.
これを前提に読み進めていきましょう.

Makefile

まず,Makefileです.

LIBS_lrf_logger_plugin = m fawkescore fawkesutils fawkesaspects fawkesbaseapp \
                         fawkesblackboard fawkesinterface MotorInterface

ライブラリとして読み込む必要があるので,LIBS_<プラグイン名> にインターフェース名を追加します.

<プラグイン名>_plugin.cpp

<プラグイン名>_plugin.cpp は,プラグインを読み込む仕組みの部分ですので,BlackBoardに関係する部分はありません.

<プラグイン名>_thread.h

<プラグイン名>_thread.h では,MotorInterfaceを手軽に扱うためにnamespaceに入れています(これを入れないと,いちいちfawkes::MotoerInterface を書かないといけなくなる).

namespace fawkes {
  class MotorInterface;
}

あと,内部的に変数も必要になるので,privateとして変数を宣言(ポインタで扱っています).

 private:
  fawkes::MotorInterface     *motor_if_;
<プラグイン名>_thread.cpp

さて,プラグインの主たる部分である<プラグイン名>_thread.cppです.
まずは,MotorInterfaceを使うために,ヘッダファイルを読み込んでいます.

#include <interfaces/MotorInterface.h>

初期化のinit関数にて,読み込み用でオープンし,内部変数に代入します(ポインタです).
ここのBlackBoard名(Robotino)は,読み込みをしているプラグイン(MotorInterfaceの方)を参照して調べましょう.
※read/writeの定義が今ひとつ理解できていませんが,その変数の所有者(プラグイン)がwriteで,それ以外のプラグインはreadでオープンしている感じがします.

void LRFLoggerPluginThread::init() {
        motor_if_ = blackboard->open_for_reading<MotorInterface>("Robotino");
}

終了時の処理はこれと対になっていて,オープンしたから閉じるって感じです.

void LRFLoggerPluginThread::finalize() {
        blackboard->close(motor_if_);
}

で,実際に使う(書き込みをする)のは,msgs_enqueue(msg)の呼び出しです.

void LRFLoggerPluginThread::send_transrot(float vx, float vy, float omega) {
        MotorInterface::TransRotMessage *msg = new MotorInterface::TransRotMessage(
                        vx, vy, omega);
        motor_if_->msgq_enqueue(msg);
}

書き込み形式のmsgは,MotorInterface::TransRotMessage 型で用意していますが,これに関してもMotorInterface側を参照して調べる必要があります.
利用しているプラグイン側はこんな程度ですね.


では,大元のMotorInterface って何じゃラホイってことで,こちらを調べてみましょう.
まず,これを定義しているのは,fawkes/src/libs/interfaces/MotorInterface.xml です.
ちなみに,makeによって,ここからtoluaとhとcppのファイルを自動生成します.
※あと,fawkes/src/libs/の下にはinterfaceとinterfacesの2つのディレクトリがあるため,<タブ>キーでの補間がうまく効きません.気をつけましょう.

MotorInterface.xml

XML形式で書かれた変数の定義ファイルです(構造体的なモノ).

<interface name="MotorInterface" author="Martin Liebenberg, Tim Niemueller" year="2007">
  <constants>
    <constant type="uint32" name="MOTOR_ENABLED" value="0">
      Motor is enabled and sending drive commands will make the robot move.
    </constant>
...
  </constants>
  <data>
    <comment>This interface is currently prepared best for a holonomic robot.
      It will need modifications or a split to support differential drives.
    </comment>
    <field type="uint32" name="motor_state">
      The current state of the motor.
    </field>
...
  </data>
  <message name="SetMotorState">
    <comment>Sets the current motor state.</comment>
    <field type="uint32" name="motor_state">
      The new motor state to set. Use the MOTOR_* constants.
    </field>
  </message>
...
</interface>

となっており,定数部の記述,データ部の記述,メッセージ部の記述にわかれています.
定数部は,このインターフェースで使う定数を定義しており,以後,名前(name)を使ってこれらの定数を表現できるようになります(たぶん).
データ部とメッセージ部は,変数の名前とその型を定義しています.
データ部は,単発の変数の情報が並んでいますが,メッセージはそれらの集合(構造体)のようになっています.
また,メッセージ部は,相手にデータを送信するときにつかう部分になっています.
要は,書き込んだデータを「時系列順にちゃんと相手に届ける」必要がある場合がメッセージで,「新しいデータで上書きして最新情報がわかればよい」のがデータ部になっているのかなと勝手に解釈しております(間違っている可能性もあるので,要注意).


さてさて,LRFのデータを取ってくるにはどうしたらよいでしょうか.
まず,LRFのデータを受け取るプラグインは,fawkes/src/plugins/laser にあります.
fawkes-robotino-2016と2019は,sick_tim55xとurg(HOKUYO)が対応しています.
BTRの場合,a-stepに,rplidarとsweepのプラグインを用意しています(ただし,あまり動作確認していないので要注意).
※実際のシステムへの組み込みはtk-fawkesを参照して下さい.
LRFから読み取ったデータは,_distances[int_deg]に格納しています.
そして,解像度に応じてLaser360/720/1080としてBlackBoardに書き込んでいます.
インターフェース名は,それぞれ,Laser360Interface/Laser720Interface/Laser1080Interface です.
ちなみに,内部変数的には,以下の様になります.

fawkes::Laser360Interface  *laser360_if;
fawkes::Laser720Interface  *laser720_if;
fawkes::Laser1080Interface *laser1080_if;

これを受け取るプログラムを書けば良いわけです.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

*