Skip to content

Commit bd665cb

Browse files
authored
Add delay option (ros2#789)
* Add delay option Signed-off-by: kosuke55 <[email protected]>
1 parent f4f4106 commit bd665cb

File tree

6 files changed

+98
-15
lines changed

6 files changed

+98
-15
lines changed

ros2bag/ros2bag/verb/play.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ def add_arguments(self, parser, cli_name): # noqa: D102
8282
'--clock', type=positive_float, nargs='?', const=40, default=0,
8383
help='Publish to /clock at a specific frequency in Hz, to act as a ROS Time Source. '
8484
'Value must be positive. Defaults to not publishing.')
85+
parser.add_argument(
86+
'-d', '--delay', type=float, default=0.0,
87+
help='Sleep SEC seconds before play. Valid range > 0.0')
8588

8689
def main(self, *, args): # noqa: D102
8790
qos_profile_overrides = {} # Specify a valid default
@@ -116,6 +119,7 @@ def main(self, *, args): # noqa: D102
116119
play_options.loop = args.loop
117120
play_options.topic_remapping_options = topic_remapping
118121
play_options.clock_publish_frequency = args.clock
122+
play_options.delay = args.delay
119123

120124
player = Player()
121125
player.play(storage_options, play_options)

rosbag2_py/src/rosbag2_py/_transport.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ PYBIND11_MODULE(_transport, m) {
225225
.def_readwrite("loop", &PlayOptions::loop)
226226
.def_readwrite("topic_remapping_options", &PlayOptions::topic_remapping_options)
227227
.def_readwrite("clock_publish_frequency", &PlayOptions::clock_publish_frequency)
228+
.def_readwrite("delay", &PlayOptions::delay)
228229
;
229230

230231
py::class_<RecordOptions>(m, "RecordOptions")

rosbag2_transport/include/rosbag2_transport/play_options.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ struct PlayOptions
4444
// Rate in Hz at which to publish to /clock.
4545
// 0 (or negative) means that no publisher will be created
4646
double clock_publish_frequency = 0.0;
47+
48+
// Sleep SEC seconds before play. Valid range > 0.0.
49+
float delay = 0.0;
4750
};
4851

4952
} // namespace rosbag2_transport

rosbag2_transport/src/rosbag2_transport/player.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,25 @@ bool Player::is_storage_completely_loaded() const
213213
void Player::play()
214214
{
215215
is_in_play_ = true;
216+
217+
float delay;
218+
if (play_options_.delay >= 0.0) {
219+
delay = play_options_.delay;
220+
} else {
221+
RCLCPP_WARN(
222+
this->get_logger(),
223+
"Invalid delay value: %f. Delay is disabled.",
224+
play_options_.delay);
225+
delay = 0.0;
226+
}
227+
216228
try {
217229
do {
230+
if (delay > 0.0) {
231+
RCLCPP_INFO_STREAM(this->get_logger(), "Sleep " << delay << " sec");
232+
std::chrono::duration<float> duration(delay);
233+
std::this_thread::sleep_for(duration);
234+
}
218235
reader_->open(storage_options_, {"", rmw_get_serialization_format()});
219236
const auto starting_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
220237
reader_->get_metadata().starting_time.time_since_epoch()).count();

rosbag2_transport/test/rosbag2_transport/test_play_loop.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ TEST_F(RosBag2PlayTestFixture, play_bag_file_twice) {
4343
const size_t read_ahead_queue_size = 1000;
4444
const float rate = 1.0;
4545
const bool loop_playback = false;
46+
double clock_publish_frequency = 0.0;
47+
const float delay = 1.0;
4648

4749
auto primitive_message1 = get_messages_basic_types()[0];
4850
primitive_message1->int32_value = test_value;
@@ -64,8 +66,9 @@ TEST_F(RosBag2PlayTestFixture, play_bag_file_twice) {
6466

6567
auto await_received_messages = sub_->spin_subscriptions();
6668

67-
rosbag2_transport::PlayOptions play_options =
68-
{read_ahead_queue_size, "", rate, {}, {}, loop_playback, {}};
69+
rosbag2_transport::PlayOptions play_options = {
70+
read_ahead_queue_size, "", rate, {}, {}, loop_playback, {},
71+
clock_publish_frequency, delay};
6972
auto player = std::make_shared<rosbag2_transport::Player>(
7073
std::move(
7174
reader), storage_options_, play_options);
@@ -100,6 +103,8 @@ TEST_F(RosBag2PlayTestFixture, messages_played_in_loop) {
100103
const size_t read_ahead_queue_size = 1000;
101104
const float rate = 1.0;
102105
const bool loop_playback = true;
106+
const double clock_publish_frequency = 0.0;
107+
const float delay = 1.0;
103108

104109
auto primitive_message1 = get_messages_basic_types()[0];
105110
primitive_message1->int32_value = test_value;
@@ -122,7 +127,7 @@ TEST_F(RosBag2PlayTestFixture, messages_played_in_loop) {
122127
auto await_received_messages = sub_->spin_subscriptions();
123128

124129
rosbag2_transport::PlayOptions play_options{read_ahead_queue_size, "", rate, {}, {},
125-
loop_playback, {}};
130+
loop_playback, {}, clock_publish_frequency, delay};
126131
auto player = std::make_shared<rosbag2_transport::Player>(
127132
std::move(
128133
reader), storage_options_, play_options);

rosbag2_transport/test/rosbag2_transport/test_play_timing.cpp

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ TEST_F(PlayerTestFixture, playing_respects_relative_timing_of_stored_messages)
7878
// messages
7979
auto start = std::chrono::steady_clock::now();
8080
auto player = std::make_shared<rosbag2_transport::Player>(
81-
std::move(
82-
reader), storage_options_, play_options_);
81+
std::move(reader), storage_options_, play_options_);
8382
player->play();
8483
auto replay_time = std::chrono::steady_clock::now() - start;
8584

@@ -113,8 +112,7 @@ TEST_F(PlayerTestFixture, playing_respects_rate)
113112
prepared_mock_reader->prepare(messages, topics_and_types);
114113
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
115114
auto player = std::make_shared<rosbag2_transport::Player>(
116-
std::move(
117-
reader), storage_options_, play_options_);
115+
std::move(reader), storage_options_, play_options_);
118116
auto start = std::chrono::steady_clock::now();
119117
player->play();
120118
auto replay_time = std::chrono::steady_clock::now() - start;
@@ -131,8 +129,7 @@ TEST_F(PlayerTestFixture, playing_respects_rate)
131129
prepared_mock_reader->prepare(messages, topics_and_types);
132130
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
133131
auto player = std::make_shared<rosbag2_transport::Player>(
134-
std::move(
135-
reader), storage_options_, play_options_);
132+
std::move(reader), storage_options_, play_options_);
136133
auto start = std::chrono::steady_clock::now();
137134
player->play();
138135
auto replay_time = std::chrono::steady_clock::now() - start;
@@ -148,8 +145,7 @@ TEST_F(PlayerTestFixture, playing_respects_rate)
148145
prepared_mock_reader->prepare(messages, topics_and_types);
149146
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
150147
auto player = std::make_shared<rosbag2_transport::Player>(
151-
std::move(
152-
reader), storage_options_, play_options_);
148+
std::move(reader), storage_options_, play_options_);
153149
auto start = std::chrono::steady_clock::now();
154150
player->play();
155151
auto replay_time = std::chrono::steady_clock::now() - start;
@@ -165,8 +161,7 @@ TEST_F(PlayerTestFixture, playing_respects_rate)
165161
prepared_mock_reader->prepare(messages, topics_and_types);
166162
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
167163
auto player = std::make_shared<rosbag2_transport::Player>(
168-
std::move(
169-
reader), storage_options_, play_options_);
164+
std::move(reader), storage_options_, play_options_);
170165
auto start = std::chrono::steady_clock::now();
171166
player->play();
172167
auto replay_time = std::chrono::steady_clock::now() - start;
@@ -182,12 +177,70 @@ TEST_F(PlayerTestFixture, playing_respects_rate)
182177
prepared_mock_reader->prepare(messages, topics_and_types);
183178
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
184179
auto player = std::make_shared<rosbag2_transport::Player>(
185-
std::move(
186-
reader), storage_options_, play_options_);
180+
std::move(reader), storage_options_, play_options_);
187181
auto start = std::chrono::steady_clock::now();
188182
player->play();
189183
auto replay_time = std::chrono::steady_clock::now() - start;
190184

191185
ASSERT_THAT(replay_time, Gt(message_time_difference));
192186
}
193187
}
188+
189+
TEST_F(PlayerTestFixture, playing_respects_delay)
190+
{
191+
auto primitive_message1 = get_messages_strings()[0];
192+
primitive_message1->string_value = "Hello World 1";
193+
194+
auto primitive_message2 = get_messages_strings()[0];
195+
primitive_message2->string_value = "Hello World 2";
196+
197+
auto message_time_difference = std::chrono::seconds(1);
198+
auto topics_and_types =
199+
std::vector<rosbag2_storage::TopicMetadata>{{"topic1", "test_msgs/Strings", "", ""}};
200+
std::vector<std::shared_ptr<rosbag2_storage::SerializedBagMessage>> messages =
201+
{serialize_test_message("topic1", 0, primitive_message1),
202+
serialize_test_message("topic1", 0, primitive_message2)};
203+
204+
messages[0]->time_stamp = 100;
205+
messages[1]->time_stamp =
206+
messages[0]->time_stamp + std::chrono::nanoseconds(message_time_difference).count();
207+
208+
float delay_margin = 1.0;
209+
210+
// Sleep 5.0 seconds before play
211+
{
212+
play_options_.delay = 5.0;
213+
std::chrono::duration<float> delay(play_options_.delay);
214+
std::chrono::duration<float> delay_uppper(play_options_.delay + delay_margin);
215+
216+
auto prepared_mock_reader = std::make_unique<MockSequentialReader>();
217+
prepared_mock_reader->prepare(messages, topics_and_types);
218+
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
219+
auto player = std::make_shared<rosbag2_transport::Player>(
220+
std::move(reader), storage_options_, play_options_);
221+
auto start = std::chrono::steady_clock::now();
222+
player->play();
223+
auto replay_time = std::chrono::steady_clock::now() - start;
224+
225+
ASSERT_THAT(replay_time, Gt(message_time_difference + delay));
226+
ASSERT_THAT(replay_time, Lt(message_time_difference + delay_uppper));
227+
}
228+
229+
// Invalid value should result in playing at default delay 0.0
230+
{
231+
play_options_.delay = -5.0;
232+
std::chrono::duration<float> delay_uppper(delay_margin);
233+
234+
auto prepared_mock_reader = std::make_unique<MockSequentialReader>();
235+
prepared_mock_reader->prepare(messages, topics_and_types);
236+
auto reader = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
237+
auto player = std::make_shared<rosbag2_transport::Player>(
238+
std::move(reader), storage_options_, play_options_);
239+
auto start = std::chrono::steady_clock::now();
240+
player->play();
241+
auto replay_time = std::chrono::steady_clock::now() - start;
242+
243+
ASSERT_THAT(replay_time, Gt(message_time_difference));
244+
ASSERT_THAT(replay_time, Lt(message_time_difference + delay_uppper));
245+
}
246+
}

0 commit comments

Comments
 (0)