mujoco_ros_utils
ClockPublisher.cpp
Go to the documentation of this file.
1 #include "ClockPublisher.h"
2 
3 #include <mujoco/mujoco.h>
4 
5 #include <builtin_interfaces/msg/time.hpp>
6 #include <iostream>
7 
8 namespace MujocoRosUtils
9 {
10 
12 {
13  mjpPlugin plugin;
14  mjp_defaultPlugin(&plugin);
15 
16  plugin.name = "MujocoRosUtils::ClockPublisher";
17  plugin.capabilityflags |= mjPLUGIN_PASSIVE;
18 
19  const char * attributes[] = {"topic_name", "publish_rate", "use_sim_time"};
20 
21  plugin.nattribute = sizeof(attributes) / sizeof(attributes[0]);
22  plugin.attributes = attributes;
23 
24  plugin.nstate = +[](const mjModel *, // m
25  int // plugin_id
26  ) { return 0; };
27 
28  plugin.nsensordata = +[](const mjModel *, // m
29  int, // plugin_id
30  int // sensor_id
31  ) { return 0; };
32 
33  plugin.needstage = mjSTAGE_POS;
34 
35  plugin.init = +[](const mjModel * m, mjData * d, int plugin_id)
36  {
37  auto * plugin_instance = ClockPublisher::Create(m, d, plugin_id);
38  if(!plugin_instance)
39  {
40  return -1;
41  }
42  d->plugin_data[plugin_id] = reinterpret_cast<uintptr_t>(plugin_instance);
43  return 0;
44  };
45 
46  plugin.destroy = +[](mjData * d, int plugin_id)
47  {
48  delete reinterpret_cast<ClockPublisher *>(d->plugin_data[plugin_id]);
49  d->plugin_data[plugin_id] = 0;
50  };
51 
52  plugin.reset = +[](const mjModel * m, double *, // plugin_state
53  void * plugin_data, int plugin_id)
54  {
55  auto * plugin_instance = reinterpret_cast<class ClockPublisher *>(plugin_data);
56  plugin_instance->reset(m, plugin_id);
57  };
58 
59  plugin.compute = +[](const mjModel * m, mjData * d, int plugin_id, int // capability_bit
60  )
61  {
62  auto * plugin_instance = reinterpret_cast<class ClockPublisher *>(d->plugin_data[plugin_id]);
63  plugin_instance->compute(m, d, plugin_id);
64  };
65 
66  mjp_registerPlugin(&plugin);
67 }
68 
69 ClockPublisher * ClockPublisher::Create(const mjModel * m, mjData * d, int plugin_id)
70 {
71  // topic_name
72  const char * topic_name_char = mj_getPluginConfig(m, plugin_id, "topic_name");
73  std::string topic_name = "";
74  if(strlen(topic_name_char) > 0)
75  {
76  topic_name = std::string(topic_name_char);
77  }
78 
79  // publish_rate
80  const char * publish_rate_char = mj_getPluginConfig(m, plugin_id, "publish_rate");
81  mjtNum publish_rate = 100.0;
82  if(strlen(publish_rate_char) > 0)
83  {
84  publish_rate = strtod(publish_rate_char, nullptr);
85  }
86  if(publish_rate <= 0)
87  {
88  mju_error("[ClockPublisher] `publish_rate` must be positive.");
89  return nullptr;
90  }
91 
92  // use_sim_time
93  const char * use_sim_time_char = mj_getPluginConfig(m, plugin_id, "use_sim_time");
94  bool use_sim_time = true;
95  if(strlen(use_sim_time_char) > 0)
96  {
97  if(!(strcmp(use_sim_time_char, "true") == 0 || strcmp(use_sim_time_char, "false") == 0))
98  {
99  mju_error("[ClockPublisher] `use_sim_time` must be `true` or `false`.");
100  return nullptr;
101  }
102  use_sim_time = (strcmp(use_sim_time_char, "true") == 0);
103  }
104 
105  if(m->body_plugin[0] != plugin_id)
106  {
107  mju_error("[ClockPublisher] This plugin must be registered in worldbody.");
108  return nullptr;
109  }
110 
111  std::cout << "[ClockPublisher] Create." << std::endl;
112 
113  return new ClockPublisher(m, d, topic_name, publish_rate, use_sim_time);
114 }
115 
117  mjData *, // d
118  const std::string & topic_name,
119  mjtNum publish_rate,
120  bool use_sim_time)
121 : topic_name_(topic_name), publish_skip_(std::max(static_cast<int>(1.0 / (publish_rate * m->opt.timestep)), 1)),
122  use_sim_time_(use_sim_time)
123 {
124  if(topic_name_.empty())
125  {
126  topic_name_ = "/clock";
127  }
128 
129  int argc = 0;
130  char ** argv = nullptr;
131  if(!rclcpp::ok())
132  {
133  rclcpp::init(argc, argv);
134  }
135  rclcpp::NodeOptions node_options;
136 
137  nh_ = rclcpp::Node::make_shared("mujoco_ros", node_options);
138  pub_ = nh_->create_publisher<rosgraph_msgs::msg::Clock>(topic_name, 1);
139  // nh_->setParam("/use_sim_time", use_sim_time_);
140 }
141 
142 void ClockPublisher::reset(const mjModel *, // m
143  int // plugin_id
144 )
145 {
146 }
147 
148 void ClockPublisher::compute(const mjModel *, // m
149  mjData * d,
150  int // plugin_id
151 )
152 {
153  sim_cnt_++;
154  if(sim_cnt_ % publish_skip_ != 0)
155  {
156  return;
157  }
158 
159  rosgraph_msgs::msg::Clock msg;
160  builtin_interfaces::msg::Time time;
161  time.sec = static_cast<int32_t>(d->time);
162  time.nanosec = static_cast<uint32_t>((d->time - time.sec) * 1e9);
163  msg.clock = time;
164  pub_->publish(msg);
165 }
166 
167 } // namespace MujocoRosUtils
Plugin to publish clock topic.
void reset(const mjModel *m, int plugin_id)
Reset.
std::string topic_name_
Topic name of clock.
rclcpp::Node::SharedPtr nh_
ROS node handle.
int publish_skip_
Iteration interval to skip ROS publish.
static void RegisterPlugin()
Register plugin.
ClockPublisher(ClockPublisher &&)=default
Copy constructor.
void compute(const mjModel *m, mjData *d, int plugin_id)
Compute.
rclcpp::Publisher< rosgraph_msgs::msg::Clock >::SharedPtr pub_
ROS publisher for clock.
static ClockPublisher * Create(const mjModel *m, mjData *d, int plugin_id)
Create an instance.
int sim_cnt_
Iteration count of simulation.