LoginSignup
11
5

More than 1 year has passed since last update.

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

Last updated at Posted at 2019-04-23

ROS2関係トップページへ
ROS2レクチャー:初級 -ROS1 style-
ROS2レクチャー:初級 -class style-

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

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

  • Rate系
    • 主にsleep関数に関係する.
    • WallRateとRateがある.とりあえずWallRate推奨する.
  • Timer系
    • 定期的な処理を行わせる.
    • nodeの機能として実現され,nodeの定期的な処理を主な対象としている.
  • 詳しくはrclcppのAPIのRateおよびTimerの項を参照.


時間管理について

以下はROSメインの話.

時間管理を考えると,実時間とシミュレーション時間は結構異なる.シミュレーションでは時間を早めたり遅くしたりすることができる.また時間が過去に戻ったり未来に飛ばしたりもできる.それらをうまく扱わなければ変な動作をしてしまう.
ROS2では時間管理のために SystemTimeSteadyTimeそしてROSTimeという時間の抽象化を行っており,基本的に ROSTimeの使用が推奨されている.これらは,std::chrono::system_clockstd::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に詳しい.

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

準備

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

Rate系およびTimer系プログラム

作成物:github.comの以下のファイル

  • src/main.cpp

プログラム

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

これまでと同様に関係部分の抜粋.

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}
)

コンパイル・実行

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-

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5