Skip to content
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

Merged
merged 10 commits into from
Aug 21, 2018
Merged

[ros2] Add sim_time to gazebo_ros_init #794

merged 10 commits into from
Aug 21, 2018

Conversation

kev-the-dev
Copy link
Collaborator

@kev-the-dev kev-the-dev commented Aug 7, 2018

  • Add a Throttler class to utils, something that can be reused in a few places
  • Add publishing sim time to /clock in gazebo_ros_init
    • The time of a simulation starts at 0.
    • Subscribers that have transient local durability specified in their QoS settings will be able to receive the previously-published time message(s) even if the simulation is paused (up to the queue depth of 10).

Usage:

$ ros2 launch gazebo_ros empty_world.launch.py
$ ros2 topic echo /clock
clock:
  sec: 7
  nanosec: 507000000

Wiki: https://github.com/ros-simulation/gazebo_ros_pkgs/wiki/ROS-2-Migration:-ROS-Clocks-and-sim-time

/// Called by Gazebo to load plugin.
/// \param[in] argc Argument count.
/// \param[in] argv Argument values.
void Load(int argc, char ** argv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add override

static const gazebo::common::Time DEFAULT_PUBLISH_PERIOD;

void OnWorldCreated(std::string _world_name);
void PublishSimTime();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing documentation

void GazeboRosClock::Load(int argc, char ** argv)
{
(void) argc;
(void) argv;
Copy link
Contributor

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).
Copy link
Contributor

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::common::Time publish_period_;
static const gazebo::common::Time DEFAULT_PUBLISH_PERIOD;

void OnWorldCreated(std::string _world_name);
Copy link
Contributor

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


clock_pub_ = rosnode_->create_publisher<rosgraph_msgs::msg::Clock>("/clock");
world_update_event_ = gazebo::event::Events::ConnectWorldUpdateBegin(
std::bind(&GazeboRosClockPrivate::PublishSimTime, this));
Copy link
Contributor

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.

@dhood dhood self-requested a review August 9, 2018 18:33
@dhood
Copy link
Collaborator

dhood commented Aug 9, 2018

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 gazebo_ros_init. I have seen that both approaches have been mentioned on #779 but not a discussion of pros/cons.

I'd say it makes sense that gazebo_ros_init sets up a reasonable amount of the default Gazebo-ROS integration, which includes clock publishing. No need to separate them if they will always be used together (I've never heard of anyone not wanting the clock to be published, and even if there's a use case for that, it might not warrant two separate plugins). What's the motivation for keeping them separate?

@kev-the-dev kev-the-dev changed the base branch from ros2-utils to ros2 August 10, 2018 01:04
@kev-the-dev kev-the-dev changed the title [ros2] Add gazebo_ros_clock [ros2] Add sim_time to gazebo_ros_init Aug 10, 2018
Copy link
Collaborator

@dhood dhood left a 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!

TEST_F(TestSimTime, TestClock)
{
auto node = std::make_shared<rclcpp::Node>("my_node");
rclcpp::Clock clock;
Copy link
Collaborator

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)

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();
Copy link
Collaborator

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

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()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be ==?

{
public:
GazeboRosInitPrivate();
gazebo_ros::Node::SharedPtr rosnode_;
Copy link
Collaborator

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_;

@@ -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)
Copy link
Collaborator

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

Copy link
Collaborator Author

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

Copy link
Collaborator

@dhood dhood Aug 10, 2018

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;}
Copy link
Collaborator

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

Copy link
Member

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.

{
// Test frequency
Throttler t(2.0);
EXPECT_FALSE(t.IsReady(Time(0, 4E8)));
Copy link
Collaborator

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

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");
Copy link
Collaborator

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?

Copy link
Member

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in 165cb30

Copy link
Collaborator

@dhood dhood Aug 21, 2018

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

}

// By default publish at 10 HZ (100 millisecond period)
const gazebo::common::Time GazeboRosInitPrivate::DEFAULT_PUBLISH_PERIOD = gazebo::common::Time(0,
Copy link
Collaborator

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);
Copy link
Collaborator

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)

@kev-the-dev
Copy link
Collaborator Author

Rewrote test to actually test a node's sim time and sanity check on the /clock output.

Copy link
Collaborator

@dhood dhood left a 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));
Copy link
Collaborator

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

Copy link
Collaborator

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.

@mikaelarguedas
Copy link

@ros-pull-request-builder retest this please

@dhood dhood added the ros2 label Aug 17, 2018
dhood
dhood previously approved these changes Aug 20, 2018
@dhood dhood dismissed their stale review August 20, 2018 22:02

noticed collapsed unresolved comments

@dhood
Copy link
Collaborator

dhood commented Aug 21, 2018

I added example usage and a wiki page to the original post

@dhood dhood merged commit fa8d749 into ros2 Aug 21, 2018
@dhood dhood deleted the ros2-clock branch August 21, 2018 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants