ROS2における時間管理・Rate系とTimer系

【[ROS2関係トップページへ](https://qiita.com/NeK/items/7ac0f4ec10d51dbca084)】
【[ROS2レクチャー:初級 -ROS1 style-](https://qiita.com/NeK/items/74e4bb9d1530e22a63fc)】
【[ROS2レクチャー:初級 -class style-](https://qiita.com/NeK/items/14db31ff784a0bfafe3d)】

【前:[ROS2の最小構成subscriber:初級 -ROS1 style-]】
【前:[ROS2の最小構成subscriber:初級 -class style-]】
【次:[ROS2の最小構成publisher:初級 -ROS1 style-]】
【次:[ROS2の最小構成publisher:初級 -class style-]】

[ROS2の最小構成subscriber:初級 -ROS1 style-]:https://qiita.com/NeK/items/2e4e1f78e76594891fc7
[ROS2の最小構成subscriber:初級 -class style-]:https://qiita.com/NeK/items/224595987212067f41db
[ROS2の最小構成publisher:初級 -ROS1 style-]:https://qiita.com/NeK/items/12faa483de71eb55162f
[ROS2の最小構成publisher:初級 -class style-]:https://qiita.com/NeK/items/3a123fadd8a574b14162

ROS2では時間管理をROSシステムが行うことを推奨している．これは，sleepなどの時間処理をROS2が管理する，という意味から，定期的な処理をsleepではなくnodeがnodeの機能によって行う(つまりROS2システムが行う)，という意味まで含む．
ここではsleep関数に関わるRate系と定期的な処理に関わるTimer系について書く．

- Rate系
    - 主にsleep関数に関係する．
    - WallRateとRateがある．とりあえずWallRate推奨する．
- Timer系
    - 定期的な処理を行わせる．
    - nodeの機能として実現され，nodeの定期的な処理を主な対象としている．
- 詳しくは[rclcppのAPI](http://docs.ros2.org/foxy/api/rclcpp/index.html)のRateおよびTimerの項を参照．

<details>
<summary>時間管理について</summary><div>

以下はROSメインの話．

時間管理を考えると，実時間とシミュレーション時間は結構異なる．シミュレーションでは時間を早めたり遅くしたりすることができる．また時間が過去に戻ったり未来に飛ばしたりもできる．それらをうまく扱わなければ変な動作をしてしまう．
ROS2では時間管理のために `SystemTime`，`SteadyTime`そして`ROSTime`という時間の抽象化を行っており，基本的に `ROSTime`の使用が推奨されている．これらは，`std::chrono::system_clock`と`std::chrono::steady_clock`を使って設計されている．
`SystemTime`はシステムクロックに直接結びついていて，`SteadyTime`は．．．ROS2 Designでは例による説明でよく分からなかった．
そして利用が推奨されている`ROSTime`はノードパラメータ`use_sim_time`の値(すべてのノードがデフォルトで持ってるパラメータ)によって挙動が変わる．`use_sim_time: true`の場合，ROS Time Sourceがアクティブになり，そちらが用いられる．`use_sim_time: false`の場合，ROS Time Sourceがアクティブでなくなり，`SystemTime`と同等になるっぽい．
そのROS Time Sourceは何かというと，ROSシステム全体で一つだけの`/clock`のトピックとなる．で，これはシステムクロックのように定期的に時間をpublishするのだが，過去に戻ろうとするとブロックされる(そして希望するならcallback関数を割り当てられる)．つまり，本物の時間のように値が単調増加となることが保証されるっぽい．
詳しい情報は[ROS2 DesignのClock and Time](https://design.ros2.org/articles/clock_and_time.html)に詳しい．

以上を踏まえて，ROS2では未実装のものもあり鋭意構築中なのかな？
例えば，sleepに関してはWallRate,Rate系のsleep()があった．これに加えてrclcpp::sleep_forやDurationクラスが追加されている(Eloquentまではなかった．foxyから．)．
とりあえず少しずつ気が付いたところ・勉強したところを還元しアップデートしていくしかない．
[Githubのissue](https://github.com/ros2/rcl/issues/898)やその中にあるリンクにて議論が行われている．

</div></details>

# 準備

```Bash:terminal
$ cd ~/ros2_studies_ws/
$ ros2 pkg create minimal_timer --dependencies rclcpp
```

# Rate系およびTimer系プログラム
作成物:[github.com](https://github.com/nek009/minimal_timer)の以下のファイル

- src/main.cpp

## プログラム

```c++:src/main.cpp
#include <rclcpp/rclcpp.hpp>
#include <chrono>

rclcpp::Node::SharedPtr node = nullptr;

int main(int argc, char * argv[]){
  using namespace std::chrono_literals;

  rclcpp::init(argc,argv);
  node = rclcpp::Node::make_shared("minimal_node");

  rclcpp::WallRate loop_rate(500ms);
  for(int i=0 ; i<3 ; i++){
    RCLCPP_INFO(node->get_logger(), "loop:%d",i);
    loop_rate.sleep();
  }

  for(int i=0 ; i<3 ; i++){
    RCLCPP_INFO(node->get_logger(), "loop:%d",i);
    rclcpp::sleep_for(500ms);
  }

  auto timer1 = node->create_wall_timer(
    1s,
    [](){
      RCLCPP_INFO(node->get_logger(),"node_loop");
    }
  );
  rclcpp::spin(node);

  rclcpp::shutdown();
  return 0;
}
```

## 概要
12行目前後でRate系の，23行目前後でTimer系の処理をしている．クラス化したnodeでも使い方は基本同じ．
また，時間関係の便利道具chronoを使用して，"500ms"や"1s"(1秒)，"1min"(1分)，"1h"など単位付きの時間が指定できるようにしている．

## 説明
### chrono
c++の機能としてchronoを使用．
2行目でインクルード．
7行目で単位付きの時間を使用するための設定．
12行目のように"500ms"と使用．

### Rate系
Rate系は実行周期を制御するもので，具体的にはsleep関数の実行にかかわるもの．
12行目のように宣言し，15行目のように使用．
普通のsleepのようにsleep(10)とスリーブ時間を設定することはできない．

### Timer系
例えばセンサ値を定期的に取得してpublish(発信)したい，など定期的な処理を行うためにTimer系が存在．
nodeの機能なので23行目のようにnodeがcreate_wall_timer関数を使用してtimerを作成．
create_wall_timerの第一引数(24行目)が実行周期，第二引数(25行目～27行目のlambda関数)が定期的な処理．
29行目でnodeを実行することで定期的な処理が実行される．

# package.xmlとCMakeLists.txt
これまでと同様に関係部分の抜粋．

```xml:package.xml
<package format="3">
  <depend>rclcpp</depend>
```

```CMakeLists.txt
find_package(rclcpp REQUIRED)
add_executable(timer_test
  src/main.cpp
)
ament_target_dependencies(timer_test
  rclcpp
)
install(TARGETS
  timer_test
  DESTINATION lib/${PROJECT_NAME}
)
```

# コンパイル・実行

```Bash:terminal
$ colcon build --symlink-install --packages-up-to minimal_timer
$ . install/local_setup.bash
$ ros2 run minimal_timer timer_test
```

【前:[ROS2の最小構成subscriber:初級 -ROS1 style-]】
【前:[ROS2の最小構成subscriber:初級 -class style-]】
【次:[ROS2の最小構成publisher:初級 -ROS1 style-]】
【次:[ROS2の最小構成publisher:初級 -class style-]】