-
Notifications
You must be signed in to change notification settings - Fork 255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Progress-bar for ros2 bag play #1836
base: rolling
Are you sure you want to change the base?
Progress-bar for ros2 bag play #1836
Conversation
Signed-off-by: Nicola Loi <[email protected]>
video-example.mp4(at 2.6-2.7 seconds of bag duration, the progress bar is slightly updating while in paused state because I was clicking the left arrow for the play next keyboard control) Since [INFO] [1729028986.845909253] [rosbag2_player]: Pausing play.
Bag Time 1718553782.525239 Duration 1.272325/6.974378 [P] while this longer version of the progress bar doesn't work properly without extra line clearing (in this case, it's easy to clear the line since the logs come from rosbag2_player., but for "external" logs, this becomes more difficult): [INFO] [1729028986.845909253] [rosbag2_player]: Pausing play.us:Running]
Bag Time 1718553782.525239 Duration 1.272325/6.974378 [status:Paused] @MichaelOrlov looking forward to your feedback, for now I have made a test MVP code to check the feasibility of the feature. |
Signed-off-by: Nicola Loi <[email protected]>
d503e5f
to
2cb732d
Compare
Signed-off-by: Nicola Loi <[email protected]>
b815f9e
to
4ba1a8c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolaloi Thank you for your contribution.
I have a few concerns about the design and implementation.
First, we need to limit the frequency with which we will print in std::cout
. The best way to do this is to create a local variable, aka size_t progress_bar_update_freq_
(in Hz).
e.g. 1 Hz = once per/sec, 2 Hz = twice per second, 3 = three times per second etc..
Then, check the delay between the last call in the print_status(..)
. If the delay is more than the threshold, print; otherwise, skip.
We also need to move the check for the if (disable_progress_bar_)
inside print_status(..)
to make the logic cleaner and in one place.
Calling double current_time_secs = RCUTILS_NS_TO_S(static_cast<double>(clock_->now()));
each time in the print_status(..)
is very inefficient and expensive since we are locking mutex inside and transorming current time to the ROS time. We actually know the current ROS time at which we are playing. This is a timestamp from the message. I would suggest passing it to the print function as a parameter.
i.e., add tiemstamp parameter to the print_status(..)
function and use message_ptr->recv_timestamp
as a source of timestamp.
I found the implementation of the print_status(..)
function a bit messy.
That is a quintessence of the modern C++17 with templates and old style plain C code.
Need to avoid using C code. Please use C++ alternatives. I am not sure if we really need to flush buffer each time. Flush is an expensive operation since this is a blocking system call. Need to avoid it if possible.
IMO templating print_status(..)
function is overengineering and make code less readable and less understandable. The cleaner solution would be if using enum class values for different modes. In this case all extra wrappers like check_and_print_status()
will not be needed. We will be able to call print_status(PrintStatus::Paused)
directly from where we needed it.
@MichaelOrlov thanks for the comments.
Should the progress bar be disabled by default, or enabled by default with a default low update frequency? |
253256a
to
44fa94a
Compare
Signed-off-by: Nicola Loi <[email protected]>
Signed-off-by: Nicola Loi <[email protected]>
44fa94a
to
43fa0f8
Compare
I have made changes as discussed. Linked modifications: I have modified the
|
@nicolaloi I have not had a chance yet to look deeply into the code after your latest changes. However, I have a few comments.
|
Ok, I'll set the default rate to 3 Hz. For 2nd and 3rd points, there is no longer the |
Signed-off-by: Nicola Loi <[email protected]>
eb9ea35
to
9cdf5ad
Compare
I have realized the newly added variables |
Signed-off-by: Nicola Loi <[email protected]>
Signed-off-by: Nicola Loi <[email protected]>
@MichaelOrlov So, to avoid synchronization issues without using mutexes, etc to not increase overhead, the variable Regarding how to print the current timestamp: when a message is published, the Extras:
|
Signed-off-by: Nicola Loi <[email protected]>
Signed-off-by: Nicola Loi <[email protected]>
Signed-off-by: Nicola Loi <[email protected]>
@nicolaloi I have not had a chance yet to make a new full round of review. However, I have a comment about reducing the precision for output bag duration. rosbag2/rosbag2_storage/include/rosbag2_storage/yaml.hpp Lines 70 to 86 in c8feaea
The possible use case is that the user may stop playback at the point of interest and then copy past the current timestamp, for instance, to the Foxglove Studio to be able to open the same bag at the current location for further introspection. |
I wasn't using nanoseconds because the problem with them is that the progress bar message will be longer than other log messages, and artifacts will appear:
Using nanoseconds for example:
Some digits and the final [P] will stay at the end of previous log messages. But if nanoseconds for both bag time and bag duration are a must, then I can make space for their nanosecond digits by
So something like (printing an explanation for t: and d: at the beginning, together with the ending time info):
I will push this now. |
Signed-off-by: Nicola Loi <[email protected]>
@nicolaloi But why ??
Why not have a longer length, whatever we need, and whatever will be readable? |
Can we print a separator line in between? Like
|
I am using short strings to try to avoid as much as possible 'poisoning' the log messages of other nodes that could print on stdout on the same terminal, given that at the end of the progress bar there is a carriage return '\r'. For example, a long string like:
will be overwritten (due to `\r') by this external log message from the user in the same terminal:
into
And now you cannot know if the inliers were 2, 25, 254, 2541, or 25413.
Then, there can always be shorter strings than any possible progress bar, especially if the user just prints using std::cout and not RCLCPP_INFO_STREAM. So this problem could happen whatever the progress bar length is, but using a shorter one makes it less likely. Especially, I was trying to have a progress bar at least shorter than any log message that could be printed by rosbag2_player, so the various "Set rate to 1.2", "Pausing play", etc.. printed by the rosbag2_player would not become something like This was my reason for using short progress bar strings, but if these are not issues or anyway something that the progress bar should not take care of, then yes I can push a progress bar with the long version. Regarding the separator line, I can try to think about it, maybe it is feasible using only raw ANSI escape codes, maybe it is difficult to implement without side-effects or without using a terminal control library like curses. Especially considering that you don't have control or knowledge of all the messages that could be printed in the terminal. |
@nicolaloi As far as I understand you are warring about output std::cout output mashup due to the calling it from the multiple threads. //Thread 1
std::cout << "the quick brown fox " << "jumped over the lazy dog " << std::endl;
//Thread 2
std::cout << "my mother washes" << " seashells by the sea shore" << std::endl;
//Could just as easily print like this or any other crazy order.
my mother washes the quick brown fox seashells by the sea shore \n
jumped over the lazy dog \n The proposed solution is simply compose your string before you pass it to cout For example. //There are other ways, but stringstream uses << just like cout..
std::stringstream msg;
msg << "Error:" << Err_num << ", " << ErrorString( Err_num ) << "\n";
std::cout << msg.str(); This way your stings can't be garbled because they are already fully formed, plus its also a better practice to fully form your strings anyway before dispatching them. |
I am already composing the string with an ostringstream before printing it.
|
@nicolaloi Ideally it would be nice to have something similar to the https://github.com/xqms/rosbag_fancy @xqms Since you are the author of `rosbag_fancy´, your help with this PR and/or ideas on how to output the status bar without smashing other log messages will be very appreciated. |
@nicolaloi In a short term I agree to shorten the status string to something like
i.e. put the current timestamp into the square brackets |
@nicolaloi General comment: Could you please rename the term |
Ok based on the comments, I will change the progress bar string to |
Signed-off-by: Nicola Loi <[email protected]>
Signed-off-by: Nicola Loi <[email protected]>
6a3cbc3
to
fb464b0
Compare
force pushed since I forgot DCO in a previous commit |
Hey, here's how rosbag_fancy does it:
This also ensures that the progress bar is always at the bottom. Note that this approach assumes that you update the UI more often than log messages appear. Here's a link to the last step in the code: https://github.com/xqms/rosbag_fancy/blob/1f5ec4d172418a44ee206749182d0bec7cc553f0/rosbag_fancy/src/ui.cpp#L334 However, rosbag_fancy does not have to worry about multi-threading. |
@nicolaloi Could you please rebase your branch and address conflicts one more time? |
Signed-off-by: Nicola Loi <[email protected]>
Signed-off-by: Nicola Loi <[email protected]>
@xqms thanks for the suggestions. Adding extra lines is indeed a good idea to mitigate the problem. External user's log messages shorter than the progress bar string can still be smashed, but the extra lines give more safety margin.
Due to this, I have added an extra option, video_example.mp4From the video, you can see that with 3 external log messages (with one being a short message), you could encounter some issues with 2,1, and 0 separation lines. General rule: if between two progress bar updates you are expecting N external log messages and at least one is shorter than the progress bar strings, then you should set at least N However, if the external log messages are longer than the progress bar strings, or there will be less than "default separation lines" (2) external log messages between two progress bar updates, then everything is ok by default. Moreover, this is an issue only if the user has his own log messages on the same output of the playback player and the progress bar is enabled. @MichaelOrlov I have also added the separator line ( |
Signed-off-by: Nicola Loi <[email protected]>
Closes #1762: Adds a progress bar for
ros2 bag play
, showing the bag time and duration, similar to what is seen in ROS1.In ROS1, the progress bar was easy to handle because the
rosbag play
command didn't print additional output during playback. However, in ROS2, many logs can be printed during playback (e.g., keyboard control logs).The progress bar is printed and continuously updated on the last line of the playback output. I have tested this initial implementation with keyboard controls (play, pause, play next, set rate), Ctrl+C, throwing an exception, and the flags
--log-level debug
,--delay X
, and--start-offset X
.To try it, use the new
--progress-bar
flag when playing a bag.