【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では時間管理のために 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に詳しい.
以上を踏まえて,ROS2では未実装のものもあり鋭意構築中なのかな?
例えば,sleepに関してはWallRate,Rate系のsleep()があった.これに加えてrclcpp::sleep_forやDurationクラスが追加されている(Eloquentまではなかった.foxyから.).
とりあえず少しずつ気が付いたところ・勉強したところを還元しアップデートしていくしかない.
Githubのissueやその中にあるリンクにて議論が行われている.
準備
$ cd ~/ros2_studies_ws/
$ ros2 pkg create minimal_timer --dependencies rclcpp
Rate系およびTimer系プログラム
作成物:github.comの以下のファイル
- 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 format="3">
<depend>rclcpp</depend>
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}
)
コンパイル・実行
$ 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-】