-
Notifications
You must be signed in to change notification settings - Fork 773
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
[ros2] Add sim_time to gazebo_ros_init #794
Conversation
/// Called by Gazebo to load plugin. | ||
/// \param[in] argc Argument count. | ||
/// \param[in] argv Argument values. | ||
void Load(int argc, char ** argv); |
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.
We could add override
gazebo_ros/src/gazebo_ros_clock.cpp
Outdated
static const gazebo::common::Time DEFAULT_PUBLISH_PERIOD; | ||
|
||
void OnWorldCreated(std::string _world_name); | ||
void PublishSimTime(); |
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.
Missing documentation
gazebo_ros/src/gazebo_ros_clock.cpp
Outdated
void GazeboRosClock::Load(int argc, char ** argv) | ||
{ | ||
(void) argc; | ||
(void) argv; |
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.
Should we try to pass these to rclcpp::init
in case it hasn't been initialized yet?
|
||
class GazeboRosClockPrivate; | ||
|
||
/// Initializes ROS with the system arguments passed to Gazebo (i.e. calls rclcpp::init). |
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.
Documentation from a different plugin
gazebo_ros/src/gazebo_ros_clock.cpp
Outdated
gazebo::common::Time publish_period_; | ||
static const gazebo::common::Time DEFAULT_PUBLISH_PERIOD; | ||
|
||
void OnWorldCreated(std::string _world_name); |
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.
Make input a const reference
gazebo_ros/src/gazebo_ros_clock.cpp
Outdated
|
||
clock_pub_ = rosnode_->create_publisher<rosgraph_msgs::msg::Clock>("/clock"); | ||
world_update_event_ = gazebo::event::Events::ConnectWorldUpdateBegin( | ||
std::bind(&GazeboRosClockPrivate::PublishSimTime, this)); |
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.
You could connect to a callback that receives gazebo::common::UpdateInfo
, so you can get the times from there and don't need to keep a pointer to the world. This should save the whole logic of waiting for a world to be created.
See an example here.
I don't know that it makes sense to have such a standalone plugin for a ROS clock, I would think that it goes well with I'd say it makes sense that |
2e03079
to
6baf251
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.
exciting we will have sim time in ROS 2 soon!
gazebo_ros/test/test_sim_time.cpp
Outdated
TEST_F(TestSimTime, TestClock) | ||
{ | ||
auto node = std::make_shared<rclcpp::Node>("my_node"); | ||
rclcpp::Clock clock; |
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.
don't think this is what you want here (an rclcpp::Clock
might not be using sim time). You'd be wanting to check node->now()
(which will use ROS time if the use_sim_time
parameter has been set). (When you do that, please set the use_sim_time
parameter explicitly on the node and don't rely on ros2/rclcpp#514)
gazebo_ros/test/test_sim_time.cpp
Outdated
auto second_msg = | ||
gazebo_ros::get_message_or_timeout<ClockMsg>(node, "/clock", rclcpp::Duration(5, 0)); | ||
ASSERT_NE(second_msg, nullptr); | ||
auto second_msg_time = clock.now(); |
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.
I imagine you also wanted to check that the time roughly matches what was published on the clock topic
gazebo_ros/src/gazebo_ros_init.cpp
Outdated
if (impl_->rosnode_->get_parameter("publish_rate", rate_param)) { | ||
if (rclcpp::ParameterType::PARAMETER_DOUBLE == rate_param.get_type()) { | ||
impl_->throttler_ = Throttler(gazebo::common::Time(1.0 / rate_param.as_double())); | ||
} else if (rclcpp::ParameterType::PARAMETER_INTEGER != rate_param.get_type()) { |
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.
should this be ==
?
gazebo_ros/src/gazebo_ros_init.cpp
Outdated
{ | ||
public: | ||
GazeboRosInitPrivate(); | ||
gazebo_ros::Node::SharedPtr rosnode_; |
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.
recommend ros_node_
to match e.g.
gazebo_ros::Node::SharedPtr ros_node_; |
gazebo_ros/src/utils.cpp
Outdated
@@ -60,4 +60,30 @@ std::string SensorFrameID(const gazebo::sensors::Sensor & _sensor, const sdf::El | |||
return gazebo_ros::ScopedNameBase(_sensor.ParentName()); | |||
} | |||
|
|||
Throttler::Throttler(const gazebo::common::Time & _period) |
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.
I don't think Times should be use to represent durations (at least in ROS we have different types; Time is meant for time stamps). Just the rate constructor seems like it'd be fine
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.
I agree the other constructor may be confusing. I'll continue to use time to store the period internally because Gazebo does not have a duration type
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.
I would suggest instead to store the period as a double and compare doubles with doubles e.g. https://github.com/ros-simulation/gazebo_ros_pkgs/pull/793/files#diff-b9fc9fd135967672730a2b1c536338b7L71
|
||
void GazeboRosInitPrivate::PublishSimTime(const gazebo::common::UpdateInfo & _info) | ||
{ | ||
if (!throttler_.IsReady(_info.realTime)) {return;} |
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.
@tfoote do you agree that specifying the rate of publishing to /clock
wrt to real time is appropriate here? seems reasonable since then even if RTF is really low the clock will still be published regularly
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.
There's not a real standard, but I believe that the publish rate wrt to realtime makes sense. It's mostly limited by the clock communication bandwidth requirments which are hardware based and thus connect to realtime.
gazebo_ros/test/test_utils.cpp
Outdated
{ | ||
// Test frequency | ||
Throttler t(2.0); | ||
EXPECT_FALSE(t.IsReady(Time(0, 4E8))); |
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.
for the usual usage (with time stamps as an input), the first call to IsReady
will be true because of the jump from 0. This isn't necessarily an issue, but want to check it's what we want since it's contrary to this specific test. If so would be good to document (and maybe make that behaviour consistent in all cases).
gazebo_ros/src/gazebo_ros_init.cpp
Outdated
RCLCPP_INFO(rclcpp::get_logger("gazebo_ros_init"), "ROS has been initialized."); | ||
|
||
impl_->rosnode_ = gazebo_ros::Node::Create("gazebo_ros_clock"); | ||
impl_->clock_pub_ = impl_->rosnode_->create_publisher<rosgraph_msgs::msg::Clock>("/clock"); |
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.
@tfoote I think setting durability on the /clock
publisher's QoS settings would be appropriate for late-subscribers when the simulation's paused. Would you agree?
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.
Yes, adding durability would make sense so that a late starting node would get their time initialized.
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.
added in 165cb30
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.
interestingly, in ROS 1 it isn't published as latched:
pub_clock_ = nh_->advertise<rosgraph_msgs::Clock>("/clock",10); |
gazebo_ros/src/gazebo_ros_init.cpp
Outdated
} | ||
|
||
// By default publish at 10 HZ (100 millisecond period) | ||
const gazebo::common::Time GazeboRosInitPrivate::DEFAULT_PUBLISH_PERIOD = gazebo::common::Time(0, |
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.
(genuine question): how come we don't just initialise this above?
/// Called by Gazebo to load plugin. | ||
/// \param[in] argc Argument count. | ||
/// \param[in] argv Argument values. | ||
// Documentation inherited | ||
void Load(int argc, char ** argv); |
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.
could add override
(attribution: think this might have been mentioned before)
Rewrote test to actually test a node's sim time and sanity check on the /clock output. |
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.
looks pretty good to me now!
// Time should go forward | ||
EXPECT_GT(second_msg, first_msg); | ||
// The message from the clock should be the node's time | ||
EXPECT_EQ(first_msg_time, rclcpp::Time(first_msg->clock)); |
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.
Seems like this is subject to a race condition (additional clock message may have been received by the node after first_msg_time
was stored), so we will likely benefit from a tolerance here and below
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.
I take back what I said, since spinning only happens in get_message_or_timeout
. It's not possible that additional messages are received between storing first_msg
and first_msg_time
.
@ros-pull-request-builder retest this please |
I added example usage and a wiki page to the original post |
Usage:
Wiki: https://github.com/ros-simulation/gazebo_ros_pkgs/wiki/ROS-2-Migration:-ROS-Clocks-and-sim-time