####################################
##FILL ME IN
####################################
## for a custom note with links:
## note =This tutorial assumes you have completed the writing a tf listener tutorial [[tf/Tutorials/Writing a tf listener (Python)|(Python)]] [[tf/Tutorials/Writing a tf listener (C++)|(C++)]]
## for the canned note of "This tutorial assumes that you have completed the previous tutorials:" just add the links
## note.0=
## descriptive title for the tutorial
## title =フレームを加える (C++)
## multi-line description to be displayed in search
## description = このチュートリアルではどのようにして特別な固定のフレームをtfに加えるかを学びます
## the next tutorial description (optional)
## next = tf and time
## links to next tutorial (optional)
## next.0.link=[[ja/tf/Tutorials/tf and Time (C++)|(C++)]]
## next.1.link=
## what level user is this tutorial for
## level= BeginnerCategory
## keywords =
####################################
<<IncludeCSTemplate(TutorialCSHeaderTemplate)>>

<<TableOfContents(4)>>
<<Buildsystem()>>

##introstart
前回のチュートリアルの中で、tf broadcasterとtf listenerを加えることでturtle のデモを再現しました。今回のチュートリアルでは、どのようにtfツリーに特別なフレームを加えるかについて学んでいきましょう。この過程はtf broadcasterを作ることにとても似ていて、tfの利便さの一端を実感できるでしょう。


== なぜフレームを追加するのか ==
ほとんどのタスクにおいて、ローカルフレームの中について考えるのは簡単です、例えば、レーザスキャナの中心でのフレームでレーザスキャンを推論するのは簡単です。tfは、それぞれのセンサにローカルフレームを定義し、リンクし、そのほかのこともできるようにしてくれています。そして、tfは導入された特別なフレームのtransformもすべて管理してくれます。


== どこにフレームを追加すべきか ==
tfはフレームの'''木構造(tree structure)'''を作ります(フレーム構造の中に閉ループができることが許されません)。つまり、フレームは一つの親のみを持つが、子は複数もっているということです。現在、今までのチュートリアルでできたtfツリーは3つのフレームをもっています。ワールド、turtle1、turtle2です。二つのturtleは、worldの子にあたります。もし、新しいtfを加えたいなら、3つのすでにあるフレームが親のフレームになる必要があり、新しいフレームは子フレームになるでしょう。


 {{attachment:tree.png||height="282px",width="315px"}}


== どのようにフレームを加えるか ==
turtleの例を用いて、1匹目のturtleに新しいフレームを加えましょう。このフレームは2匹目のturtleにとって、"carrot"になるでしょう。

ソースファイルから作っていきましょう。まずは一つ前のチュートリアルで作ったパッケージのディレクトリに移動してください。:
{{{
 $ roscd learning_tf
}}}
##introend
=== コード ===
エディタを立ち上げ、以下のソースコードを`src/frame_tf_broadcaster.cpp`として、コピー&ペーストして保存してください。

{{{
#!cplusplus block=broadcaster
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>

int main(int argc, char** argv){
  ros::init(argc, argv, "my_tf_broadcaster");
  ros::NodeHandle node;

  tf::TransformBroadcaster br;
  tf::Transform transform;

  ros::Rate rate(10.0);
  while (node.ok()){
    transform.setOrigin( tf::Vector3(0.0, 2.0, 0.0) );
    transform.setRotation( tf::Quaternion(0, 0, 0) );
    br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "turtle1", "carrot1"));
    rate.sleep();
  }
  return 0;
};
}}}
コードは[[ja/tf/Tutorials/Writing a tf broadcaster (C++)|tf broadcaster チュートリアル]]の例にとても似ています。 

=== コード解説 ===
このコードの中のキーとなる行を部分的に見ていきましょう。:

<<CodeRef(broadcaster,13,15)>>

ここで新しい親の`turtle1`から新しい子の`carrot1`へのtransformを作成しています。
`carrot1`フレームは、`turtle1`から左にオフセット2メートルのところです。

== frame broadcasterを実行する ==
コードがこれでできたので、まずコンパイルしてみましょう。CMakeLists.txtを開いて、以下の行をファイルの最後に追加してください。:

{{{{{#!wiki buildsystem catkin
{{{
add_executable(frame_tf_broadcaster src/frame_tf_broadcaster.cpp)
target_link_libraries(frame_tf_broadcaster ${catkin_LIBRARIES})
}}}
パッケージをビルドします;(catkinワークスペースのトップディレクトリにて):
{{{
 $ catkin_make
}}}
}}}}}

{{{{{#!wiki buildsystem rosbuild
{{{
  rosbuild_add_executable(frame_tf_broadcaster src/frame_tf_broadcaster.cpp)
}}}
パッケージをビルドします:
{{{
 $ make
}}}
ビルドが全て成功すると、binフォルダの中にturtle_tf_broadcasterと呼ばれるバイナリファイルが出来ているはずです。

}}}}}
このデモのためのlaunchファイル(start_demo.launch)を編集する段階に入りましょう。以下のものを<launch>タグのブロックの中にnodeブロックとしてマージします。:
{{{
  <launch>
    ...
    <node pkg="learning_tf" type="frame_tf_broadcaster"
          name="broadcaster_frame" />
  </launch>
}}}
##checkingstart
まず、前回のチュートリアルのlaunchファイルは止めていることを確認してください(ctrl-cを使ってください)。これで、turtleのデモを始める準備ができました。
{{{
 $ roslaunch learning_tf start_demo.launch
}}}

== 結果を確認する ==
もし一匹目のturtleを動かしたら、新しいフレームを加えたのにもかかわらず、以前のチュートリアルと動きが変わっていないことに気づくと思います。それは、特別なフレームを加えることは他のフレームになんら影響を与えないからで、listenerは今はまだ以前に定義されたフレームを使用しています。それでは、ここでlistenerの振る舞いを変えてみましょう。
##checkingend
`src/turtle_tf_listener.cpp`を開いて、`"/turtle1"`を`"/carrot1"`に26-27行あたりを置き換えてください:

{{{
#!cplusplus block=broadcaster
  listener.lookupTransform("/turtle2", "/carrot1",
                           ros::Time(0), transform);
}}}
心強いことに、ただリビルドをして再スタートするだけで、2匹目の亀がcarrotを1匹目の亀の代わりに追いかけているのが見えると思います。carrotは`turtle1`の左2メートルを常に動いていることを覚えていてください。そこには、キャロットに該当する視覚的な表示はそこにありませんが、それを追っかけて2匹目の亀が動いているのが見えると思います。

{{{{{#!wiki buildsystem catkin
{{{
 $ catkin_make
 $ roslaunch learning_tf start_demo.launch
}}}
}}}}}

{{{{{#!wiki buildsystem rosbuild
{{{
 $ make
 $ roslaunch learning_tf start_demo.launch
}}}
}}}}}

== 動いているフレームをブロードキャストする ==
このチュートリアルで配信するようにした余分なフレームは、親のフレームに対して時間がたっても位置が変わらないものとなっています。しかし、もし動いているフレームを配信したければ、時間で変化するようにbroadcasterを変えることができます。

`/carrot1`のフレームが`/turtle1`に呼応して、時間が経つにつれて位置が変わるようにframe_tf_broadcaster.cppを修正しましょう。

{{{
#!cplusplus 

    transform.setOrigin( tf::Vector3(2.0*sin(ros::Time::now().toSec()), 2.0*cos(ros::Time::now().toSec()), 0.0) );
    transform.setRotation( tf::Quaternion(0, 0, 0) );
}}}

再度turtle demoをリビルドして、再スタートしてください。
{{{{{#!wiki buildsystem catkin
{{{
 $ catkin_make
 $ roslaunch learning_tf start_demo.launch
}}}
}}}}}
{{{{{#!wiki buildsystem rosbuild
{{{
 $ make
 $ roslaunch learning_tf start_demo.launch
}}}
}}}}}

これで、次のtfと時間についてのチュートリアルに進む準備ができました。[[ja/tf/Tutorials/tf and Time (Python)|(Python)]] [[ja/tf/Tutorials/tf and Time (C++)|(C++)]]

## AUTOGENERATED DO NOT DELETE
## TutorialCategory
## TutorialTurtlesim
## C++Category
## LearningCategory