mujoco_ros_utils
SensorPublisher.cpp
Go to the documentation of this file.
1 #include "SensorPublisher.h"
2 
3 #include <mujoco/mujoco.h>
4 
5 #include <iostream>
6 
7 namespace MujocoRosUtils
8 {
9 
11 {
12  mjpPlugin plugin;
13  mjp_defaultPlugin(&plugin);
14 
15  plugin.name = "MujocoRosUtils::SensorPublisher";
16  plugin.capabilityflags |= mjPLUGIN_SENSOR;
17 
18  const char * attributes[] = {"sensor_name", "frame_id", "topic_name", "publish_rate"};
19 
20  plugin.nattribute = sizeof(attributes) / sizeof(attributes[0]);
21  plugin.attributes = attributes;
22 
23  plugin.nstate = +[](const mjModel *, // m
24  int // plugin_id
25  ) { return 0; };
26 
27  plugin.nsensordata = +[](const mjModel *, // m
28  int, // plugin_id
29  int // sensor_id
30  ) { return 0; };
31 
32  // Can only run after forces have been computed
33  plugin.needstage = mjSTAGE_ACC;
34 
35  plugin.init = +[](const mjModel * m, mjData * d, int plugin_id)
36  {
37  auto * plugin_instance = SensorPublisher::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<SensorPublisher *>(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 SensorPublisher *>(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 SensorPublisher *>(d->plugin_data[plugin_id]);
63  plugin_instance->compute(m, d, plugin_id);
64  };
65 
66  mjp_registerPlugin(&plugin);
67 }
68 
69 SensorPublisher * SensorPublisher::Create(const mjModel * m, mjData * d, int plugin_id)
70 {
71  // sensor_name
72  const char * sensor_name_char = mj_getPluginConfig(m, plugin_id, "sensor_name");
73  if(strlen(sensor_name_char) == 0)
74  {
75  mju_error("[SensorPublisher] `sensor_name` is missing.");
76  return nullptr;
77  }
78  int sensor_id = 0;
79  for(; sensor_id < m->nsensor; sensor_id++)
80  {
81  if(strcmp(sensor_name_char, mj_id2name(m, mjOBJ_SENSOR, sensor_id)) == 0)
82  {
83  break;
84  }
85  }
86  if(sensor_id == m->nsensor)
87  {
88  mju_error("[SensorCommand] The sensor with the specified name not found.");
89  return nullptr;
90  }
91 
92  // msg_type
93  MessageType msg_type;
94  int sensor_dim = m->sensor_dim[sensor_id];
95  if(sensor_dim == 1)
96  {
97  msg_type = MsgScalar;
98  }
99  else if(sensor_dim == 3)
100  {
101  if(m->sensor_type[sensor_id] == mjSENS_FRAMEPOS)
102  {
103  msg_type = MsgPoint;
104  }
105  else
106  {
107  msg_type = MsgVector3;
108  }
109  }
110  else if(sensor_dim == 4)
111  {
112  msg_type = MsgQuaternion;
113  }
114  else
115  {
116  mju_error("[SensorPublisher] Unsupported sensor data dimensions: %d.", sensor_dim);
117  return nullptr;
118  }
119 
120  // frame_id
121  const char * frame_id_char = mj_getPluginConfig(m, plugin_id, "frame_id");
122  std::string frame_id = "";
123  if(strlen(frame_id_char) > 0)
124  {
125  frame_id = std::string(frame_id_char);
126  }
127 
128  // topic_name
129  const char * topic_name_char = mj_getPluginConfig(m, plugin_id, "topic_name");
130  std::string topic_name = "";
131  if(strlen(topic_name_char) > 0)
132  {
133  topic_name = std::string(topic_name_char);
134  }
135 
136  // publish_rate
137  const char * publish_rate_char = mj_getPluginConfig(m, plugin_id, "publish_rate");
138  mjtNum publish_rate = 30.0;
139  if(strlen(publish_rate_char) > 0)
140  {
141  publish_rate = strtod(publish_rate_char, nullptr);
142  }
143  if(publish_rate <= 0)
144  {
145  mju_error("[SensorPublisher] `publish_rate` must be positive.");
146  return nullptr;
147  }
148 
149  std::cout << "[SensorPublisher] Create." << std::endl;
150 
151  return new SensorPublisher(m, d, sensor_id, msg_type, frame_id, topic_name, publish_rate);
152 }
153 
155  mjData *, // d
156  int sensor_id,
157  MessageType msg_type,
158  const std::string & frame_id,
159  const std::string & topic_name,
160  mjtNum publish_rate)
161 : sensor_id_(sensor_id), msg_type_(msg_type), frame_id_(frame_id), topic_name_(topic_name),
162  publish_skip_(std::max(static_cast<int>(1.0 / (publish_rate * m->opt.timestep)), 1))
163 {
164  if(frame_id_.empty())
165  {
166  frame_id_ = "map";
167  }
168  if(topic_name_.empty())
169  {
170  std::string sensor_name = std::string(mj_id2name(m, mjOBJ_SENSOR, sensor_id_));
171  topic_name_ = "mujoco/" + sensor_name;
172  }
173 
174  int argc = 0;
175  char ** argv = nullptr;
176  if(!rclcpp::ok())
177  {
178  rclcpp::init(argc, argv);
179  }
180  rclcpp::NodeOptions node_options;
181 
182  nh_ = rclcpp::Node::make_shared("mujoco_ros", node_options);
183  if(msg_type_ == MsgScalar)
184  {
185  pub_ = nh_->create_publisher<mujoco_ros_utils::msg::ScalarStamped>(topic_name_, 1);
186  }
187  else if(msg_type_ == MsgPoint)
188  {
189  pub_ = nh_->create_publisher<geometry_msgs::msg::PointStamped>(topic_name_, 1);
190  }
191  else if(msg_type_ == MsgVector3)
192  {
193  pub_ = nh_->create_publisher<geometry_msgs::msg::Vector3Stamped>(topic_name_, 1);
194  }
195  else // if(msg_type_ == MsgQuaternion)
196  {
197  pub_ = nh_->create_publisher<geometry_msgs::msg::QuaternionStamped>(topic_name_, 1);
198  }
199 }
200 
201 void SensorPublisher::reset(const mjModel *, // m
202  int // plugin_id
203 )
204 {
205 }
206 
207 void SensorPublisher::compute(const mjModel * m, mjData * d, int // plugin_id
208 )
209 {
210  sim_cnt_++;
211  if(sim_cnt_ % publish_skip_ != 0)
212  {
213  return;
214  }
215 
216  std_msgs::msg::Header header;
217  header.stamp = nh_->get_clock()->now();
218  header.frame_id = frame_id_;
219 
220  int sensor_adr = m->sensor_adr[sensor_id_];
221  if(msg_type_ == MsgScalar)
222  {
223  mujoco_ros_utils::msg::ScalarStamped msg;
224  msg.header = header;
225  msg.value.data = d->sensordata[sensor_adr];
226  std::dynamic_pointer_cast<rclcpp::Publisher<mujoco_ros_utils::msg::ScalarStamped>>(pub_)->publish(msg);
227  }
228  else if(msg_type_ == MsgPoint)
229  {
230  geometry_msgs::msg::PointStamped msg;
231  msg.header = header;
232  msg.point.x = d->sensordata[sensor_adr + 0];
233  msg.point.y = d->sensordata[sensor_adr + 1];
234  msg.point.z = d->sensordata[sensor_adr + 2];
235  std::dynamic_pointer_cast<rclcpp::Publisher<geometry_msgs::msg::PointStamped>>(pub_)->publish(msg);
236  }
237  else if(msg_type_ == MsgVector3)
238  {
239  geometry_msgs::msg::Vector3Stamped msg;
240  msg.header = header;
241  msg.vector.x = d->sensordata[sensor_adr + 0];
242  msg.vector.y = d->sensordata[sensor_adr + 1];
243  msg.vector.z = d->sensordata[sensor_adr + 2];
244  std::dynamic_pointer_cast<rclcpp::Publisher<geometry_msgs::msg::Vector3Stamped>>(pub_)->publish(msg);
245  }
246  else // if(msg_type_ == MsgQuaternion)
247  {
248  geometry_msgs::msg::QuaternionStamped msg;
249  msg.header = header;
250  msg.quaternion.w = d->sensordata[sensor_adr + 0];
251  msg.quaternion.x = d->sensordata[sensor_adr + 1];
252  msg.quaternion.y = d->sensordata[sensor_adr + 2];
253  msg.quaternion.z = d->sensordata[sensor_adr + 3];
254  std::dynamic_pointer_cast<rclcpp::Publisher<geometry_msgs::msg::QuaternionStamped>>(pub_)->publish(msg);
255  }
256 }
257 
258 } // namespace MujocoRosUtils
Plugin to publish sensor data.
std::string topic_name_
Topic name.
rclcpp::Node::SharedPtr nh_
ROS node handle.
SensorPublisher(SensorPublisher &&)=default
Copy constructor.
int publish_skip_
Iteration interval to skip ROS publish.
static void RegisterPlugin()
Register plugin.
static SensorPublisher * Create(const mjModel *m, mjData *d, int plugin_id)
Create an instance.
int sim_cnt_
Iteration count of simulation.
MessageType msg_type_
Type of ROS message.
std::string frame_id_
Frame ID of message header.
enum MujocoRosUtils::SensorPublisher::MessageType_ MessageType
Type of ROS message.
rclcpp::PublisherBase::SharedPtr pub_
ROS publisher.
void reset(const mjModel *m, int plugin_id)
Reset.
void compute(const mjModel *m, mjData *d, int plugin_id)
Compute.