gazebo_bag_plugin.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Fadri Furrer, ASL, ETH Zurich, Switzerland
3  * Copyright 2015 Michael Burri, ASL, ETH Zurich, Switzerland
4  * Copyright 2015 Mina Kamel, ASL, ETH Zurich, Switzerland
5  * Copyright 2015 Janosch Nikolic, ASL, ETH Zurich, Switzerland
6  * Copyright 2015 Markus Achtelik, ASL, ETH Zurich, Switzerland
7  * Copyright 2016 Geoffrey Hunter <gbmhunter@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
23 
24 #include <ctime>
25 
26 #include <mav_msgs/Actuators.h>
27 
28 namespace gazebo {
29 
31 
32  if (node_handle_) {
34  delete node_handle_;
35  }
36  bag_.close();
37 }
38 
39 void GazeboBagPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf) {
40  if (kPrintOnPluginLoad) {
41  gzdbg << __FUNCTION__ << "() called." << std::endl;
42  }
43 
44  // Store the pointer to the model
45  model_ = _model;
46  // world_ = physics::get_world(model_->world.name);
47  world_ = model_->GetWorld();
48 
49  if (_sdf->HasElement("robotNamespace")) {
50  namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>();
51  } else {
52  gzerr << "[gazebo_bag_plugin] Please specify a robotNamespace.\n";
53  }
55 
56  if (_sdf->HasElement("bagFileName")) {
57  bag_filename_ = _sdf->GetElement("bagFileName")->Get<std::string>();
58  } else {
59  gzerr << "[gazebo_bag_plugin] Please specify a bagFileName.\n";
60  }
61 
62  if (_sdf->HasElement("linkName")) {
63  link_name_ = _sdf->GetElement("linkName")->Get<std::string>();
64  } else {
65  gzwarn << "[gazebo_bag_plugin] No linkName specified, using default "
66  << link_name_ << ".\n";
67  }
68 
69  // Get the pointer to the link
70  link_ = model_->GetLink(link_name_);
71  if (link_ == NULL) {
72  gzthrow("[gazebo_bag_plugin] Couldn't find specified link \"" << link_name_
73  << "\".");
74  }
75 
76  getSdfParam<std::string>(_sdf, "frameId", frame_id_, frame_id_);
77  getSdfParam<std::string>(_sdf, "imuTopic", imu_topic_, imu_topic_);
78  getSdfParam<std::string>(_sdf, "commandAttitudeThrustTopic",
81  getSdfParam<std::string>(_sdf, "commandMotorSpeedTopic",
84  getSdfParam<std::string>(_sdf, "commandRateThrustTopic",
87  getSdfParam<std::string>(_sdf, "windSpeedTopic",
89  getSdfParam<std::string>(_sdf, "motorTopic", motor_topic_, motor_topic_);
90  getSdfParam<std::string>(_sdf, "poseTopic", ground_truth_pose_topic_,
92  getSdfParam<std::string>(_sdf, "twistTopic", ground_truth_twist_topic_,
94  getSdfParam<std::string>(_sdf, "wrenchesTopic", wrench_topic_,
96  getSdfParam<std::string>(_sdf, "externalForceTopic", external_force_topic_,
98  getSdfParam<std::string>(_sdf, "waypointTopic", waypoint_topic_,
100  getSdfParam<std::string>(_sdf, "commandPoseTopic", command_pose_topic_,
102  getSdfParam<std::string>(_sdf, "recordingServiceName",
104 
105  getSdfParam<double>(_sdf, "rotorVelocitySlowdownSim",
108 
109  getSdfParam<bool>(_sdf, "waitToRecordBag", wait_to_record_, wait_to_record_);
110 
112  recording_service_name_, &GazeboBagPlugin::RecordingServiceCallback,
113  this);
114 
115  // Get the motor joints.
116  child_links_ = link_->GetChildJointsLinks();
117  for (unsigned int i = 0; i < child_links_.size(); i++) {
118  std::string link_name = child_links_[i]->GetScopedName();
119 
120  // Check if the link contains rotor_ in its name.
121  int pos = link_name.find("rotor_");
122  if (pos != link_name.npos) {
123  std::string motor_number_str = link_name.substr(pos + 6);
124  unsigned int motor_number = std::stoi(motor_number_str);
125  std::string joint_name = child_links_[i]->GetName() + "_joint";
126  physics::JointPtr joint = model_->GetJoint(joint_name);
127  motor_joints_.insert(MotorNumberToJointPair(motor_number, joint));
128  }
129  }
130 
131  // Get the contact manager.
132  std::vector<std::string> collisions;
133  contact_mgr_ = world_->Physics()->GetContactManager();
134  for (unsigned int i = 0; i < link_->GetCollisions().size(); ++i) {
135  physics::CollisionPtr collision = link_->GetCollision(i);
136  collisions.push_back(collision->GetScopedName());
137  }
138  for (unsigned int j = 0; j < child_links_.size(); ++j) {
139  unsigned int zero = 0;
140  for (unsigned int i = 0; i < child_links_[j]->GetCollisions().size(); ++i) {
141  collisions.push_back(child_links_[j]->GetCollision(i)->GetScopedName());
142  }
143  }
144 
145  if (!collisions.empty()) {
146  contact_mgr_->CreateFilter(link_->GetName(), collisions);
147  }
148 
149  // If we do not need to wait for user command, we start recording right away
150  if (!wait_to_record_) StartRecording();
151 }
152 
153 // This gets called by the world update start event.
154 void GazeboBagPlugin::OnUpdate(const common::UpdateInfo& _info) {
155  if (kPrintOnUpdates) {
156  gzdbg << __FUNCTION__ << "() called." << std::endl;
157  }
158 
159  // Get the current simulation time.
160  common::Time now = world_->SimTime();
161  LogWrenches(now);
162  LogGroundTruth(now);
163  LogMotorVelocities(now);
164 }
165 
167  time_t rawtime;
168  struct tm* timeinfo;
169  char buffer[80];
170 
171  time(&rawtime);
172  timeinfo = localtime(&rawtime);
173 
174  strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S", timeinfo);
175  std::string date_time_str(buffer);
176 
177  std::string key(".bag");
178  size_t pos = bag_filename_.rfind(key);
179  if (pos != std::string::npos) {
180  bag_filename_.erase(pos, key.length());
181  }
182  std::string full_bag_filename = bag_filename_ + "_" + date_time_str + ".bag";
183 
184  // Open a bag file and store it in ~/.ros/<full_bag_filename>.
185  bag_.open(full_bag_filename, rosbag::bagmode::Write);
186 
187  // Subscriber to IMU sensor_msgs::Imu Message.
190 
191  // Subscriber to External Force WrenchStamped Message.
194 
195  // Subscriber to Waypoint MultiDOFJointTrajectory Message.
198 
199  // Subscriber to PoseStamped pose command message.
202 
203  // Subscriber to Control Attitude Thrust Message.
207 
208  // Subscriber to Control Motor Speed Message.
212 
213  // Subscriber to Control Rate Thrust Message.
217 
218  // Subscriber to Wind Speed Message.
222 
223  // Listen to the update event. This event is broadcast every
224  // simulation iteration.
225  update_connection_ = event::Events::ConnectWorldUpdateBegin(
226  boost::bind(&GazeboBagPlugin::OnUpdate, this, _1));
227 
228  // Set the flag that we are actively recording.
229  is_recording_ = true;
230 
231  ROS_INFO("GazeboBagPlugin START recording bagfile %s",
232  full_bag_filename.c_str());
233 }
234 
236  // Shutdown all the subscribers.
237  imu_sub_.shutdown();
245 
246  // Disconnect the update event.
247 
248 
249  // Close the bag.
250  bag_.close();
251 
252  // Clear the flag to show that we are not actively recording
253  is_recording_ = false;
254 
255  ROS_INFO("GazeboBagPlugin STOP recording bagfile");
256 }
257 
258 void GazeboBagPlugin::ImuCallback(const sensor_msgs::ImuConstPtr& imu_msg) {
259  common::Time now = world_->SimTime();
260  ros::Time ros_now = ros::Time(now.sec, now.nsec);
261  writeBag(namespace_ + "/" + imu_topic_, ros_now, imu_msg);
262 }
263 
265  const geometry_msgs::WrenchStampedConstPtr& force_msg) {
266  common::Time now = world_->SimTime();
267  ros::Time ros_now = ros::Time(now.sec, now.nsec);
268  writeBag(namespace_ + "/" + external_force_topic_, ros_now, force_msg);
269 }
270 
272  const trajectory_msgs::MultiDOFJointTrajectoryConstPtr& trajectory_msg) {
273  common::Time now = world_->SimTime();
274  ros::Time ros_now = ros::Time(now.sec, now.nsec);
275  writeBag(namespace_ + "/" + waypoint_topic_, ros_now, trajectory_msg);
276 }
277 
279  const geometry_msgs::PoseStampedConstPtr& pose_msg) {
280  common::Time now = world_->SimTime();
281  ros::Time ros_now = ros::Time(now.sec, now.nsec);
282  writeBag(namespace_ + "/" + command_pose_topic_, ros_now, pose_msg);
283 }
284 
286  const mav_msgs::AttitudeThrustConstPtr& control_msg) {
287  common::Time now = world_->SimTime();
288  ros::Time ros_now = ros::Time(now.sec, now.nsec);
290  control_msg);
291 }
292 
294  const mav_msgs::ActuatorsConstPtr& control_msg) {
295  common::Time now = world_->SimTime();
296  ros::Time ros_now = ros::Time(now.sec, now.nsec);
297  writeBag(namespace_ + "/" + control_motor_speed_topic_, ros_now, control_msg);
298 }
299 
301  const mav_msgs::RateThrustConstPtr& control_msg) {
302  common::Time now = world_->SimTime();
303  ros::Time ros_now = ros::Time(now.sec, now.nsec);
304  writeBag(namespace_ + "/" + control_rate_thrust_topic_, ros_now, control_msg);
305 }
306 
308  const rotors_comm::WindSpeedConstPtr& wind_speed_msg) {
309  common::Time now = world_->SimTime();
310  ros::Time ros_now = ros::Time(now.sec, now.nsec);
311  writeBag(namespace_ + "/" + wind_speed_topic_, ros_now, wind_speed_msg);
312 }
313 
314 void GazeboBagPlugin::LogMotorVelocities(const common::Time now) {
315  ros::Time ros_now = ros::Time(now.sec, now.nsec);
316 
317  mav_msgs::Actuators rot_velocities_msg;
318  rot_velocities_msg.angular_velocities.resize(motor_joints_.size());
319 
320  MotorNumberToJointMap::iterator m;
321  for (m = motor_joints_.begin(); m != motor_joints_.end(); ++m) {
322  double motor_rot_vel =
323  m->second->GetVelocity(0) * rotor_velocity_slowdown_sim_;
324  rot_velocities_msg.angular_velocities[m->first] = motor_rot_vel;
325  }
326  rot_velocities_msg.header.stamp.sec = now.sec;
327  rot_velocities_msg.header.stamp.nsec = now.nsec;
328 
329  writeBag(namespace_ + "/" + motor_topic_, ros_now, rot_velocities_msg);
330 }
331 
332 void GazeboBagPlugin::LogGroundTruth(const common::Time now) {
333  ros::Time ros_now = ros::Time(now.sec, now.nsec);
334 
335  geometry_msgs::PoseStamped pose_msg;
336  geometry_msgs::TwistStamped twist_msg;
337 
338  // Get pose and update the message.
339  ignition::math::Pose3d pose = link_->WorldPose();
340  pose_msg.header.frame_id = frame_id_;
341  pose_msg.header.stamp.sec = now.sec;
342  pose_msg.header.stamp.nsec = now.nsec;
343  pose_msg.pose.position.x = pose.Pos().X();
344  pose_msg.pose.position.y = pose.Pos().Y();
345  pose_msg.pose.position.z = pose.Pos().Z();
346  pose_msg.pose.orientation.w = pose.Rot().W();
347  pose_msg.pose.orientation.x = pose.Rot().X();
348  pose_msg.pose.orientation.y = pose.Rot().Y();
349  pose_msg.pose.orientation.z = pose.Rot().Z();
350 
351  writeBag(namespace_ + "/" + ground_truth_pose_topic_, ros_now, pose_msg);
352 
353  // Get twist and update the message.
354  ignition::math::Vector3d linear_veloctiy = link_->WorldLinearVel();
355  ignition::math::Vector3d angular_veloctiy = link_->WorldAngularVel();
356  twist_msg.header.frame_id = frame_id_;
357  twist_msg.header.stamp.sec = now.sec;
358  twist_msg.header.stamp.nsec = now.nsec;
359  twist_msg.twist.linear.x = linear_veloctiy.X();
360  twist_msg.twist.linear.y = linear_veloctiy.Y();
361  twist_msg.twist.linear.z = linear_veloctiy.Z();
362  twist_msg.twist.angular.x = angular_veloctiy.X();
363  twist_msg.twist.angular.y = angular_veloctiy.Y();
364  twist_msg.twist.angular.z = angular_veloctiy.Z();
365 
366  writeBag(namespace_ + "/" + ground_truth_twist_topic_, ros_now, twist_msg);
367 }
368 
369 void GazeboBagPlugin::LogWrenches(const common::Time now) {
370  geometry_msgs::WrenchStamped wrench_msg;
371  std::vector<physics::Contact*> contacts = contact_mgr_->GetContacts();
372  for (int i = 0; i < contact_mgr_->GetContactCount(); ++i) {
373  std::string collision2_name =
374  contacts[i]->collision2->GetLink()->GetScopedName();
375  double body1_force = contacts[i]->wrench->body1Force.Length();
376 
377  // Exclude extremely small forces.
378  if (body1_force < 1e-10) continue;
379  // Do this, such that all the contacts are logged.
380  // (publishing on the same topic with the same time stamp is impossible)
381  ros::Time ros_now = ros::Time(now.sec, now.nsec + i * 1000);
382  std::string collision1_name =
383  contacts[i]->collision1->GetLink()->GetScopedName();
384  wrench_msg.header.frame_id = collision1_name + "--" + collision2_name;
385  wrench_msg.header.stamp.sec = now.sec;
386  wrench_msg.header.stamp.nsec = now.nsec;
387  wrench_msg.wrench.force.x = contacts[i]->wrench->body1Force.X();
388  wrench_msg.wrench.force.y = contacts[i]->wrench->body1Force.Y();
389  wrench_msg.wrench.force.z = contacts[i]->wrench->body1Force.Z();
390  wrench_msg.wrench.torque.x = contacts[i]->wrench->body1Torque.X();
391  wrench_msg.wrench.torque.y = contacts[i]->wrench->body1Torque.Y();
392  wrench_msg.wrench.torque.z = contacts[i]->wrench->body1Torque.Z();
393 
394  writeBag(namespace_ + "/" + wrench_topic_, ros_now, wrench_msg);
395  }
396 }
397 
399  rotors_comm::RecordRosbag::Request& req,
400  rotors_comm::RecordRosbag::Response& res) {
401  if (req.record && !is_recording_) {
402  StartRecording();
403  res.success = true;
404  } else if (req.record && is_recording_) {
405  gzwarn << "[gazebo_bag_plugin] Already recording rosbag, ignoring start "
406  "command.\n";
407  res.success = false;
408  } else if (!req.record && is_recording_) {
409  StopRecording();
410  res.success = true;
411  } else if (!req.record && !is_recording_) {
412  gzwarn << "[gazebo_bag_plugin] Already not recording rosbag, ignoring stop "
413  "command.\n";
414  res.success = false;
415  }
416 
417  return res.success;
418 }
419 
421 
422 } // namespace gazebo
void ExternalForceCallback(const geometry_msgs::WrenchStampedConstPtr &force_msg)
Called when an WrenchStamped message is received.
void WindSpeedCallback(const rotors_comm::WindSpeedConstPtr &wind_speed_msg)
Called when a WindSpeed message is received.
void CommandPoseCallback(const geometry_msgs::PoseStampedConstPtr &pose_msg)
Called when a PoseStamped message is received.
void LogMotorVelocities(const common::Time now)
Log all the motor velocities.
ros::NodeHandle * node_handle_
ssize_t pos
std::string ground_truth_pose_topic_
void open(std::string const &filename, uint32_t mode=bagmode::Read)
void WaypointCallback(const trajectory_msgs::MultiDOFJointTrajectoryConstPtr &trajectory_msg)
Called when a MultiDOFJointTrajectoryPoint message is received.
std::pair< const unsigned int, const physics::JointPtr > MotorNumberToJointPair
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ros::Subscriber control_rate_thrust_sub_
void ActuatorsCallback(const mav_msgs::ActuatorsConstPtr &control_msg)
Called when a Actuators message is received.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
Load the plugin.
void close()
void LogGroundTruth(const common::Time now)
Log the ground truth pose and twist.
ros::Subscriber control_attitude_thrust_sub_
ros::Subscriber waypoint_sub_
physics::ContactManager * contact_mgr_
Pointer to the ContactManager to get all collisions of this link and its children.
#define ROS_INFO(...)
std::string control_rate_thrust_topic_
ros::Subscriber wind_speed_sub_
physics::ModelPtr model_
static const bool kPrintOnPluginLoad
Definition: common.h:41
void AttitudeThrustCallback(const mav_msgs::AttitudeThrustConstPtr &control_msg)
Called when a AttitudeThrust message is received.
ros::Subscriber command_pose_sub_
void StopRecording()
Stop recording the rosbag.
This plugin is used to create rosbag files from within gazebo.
void StartRecording()
Starting recording the rosbag.
ros::Subscriber external_force_sub_
std::string control_motor_speed_topic_
void writeBag(const std::string &topic, const ros::Time &time, const T &msg)
physics::WorldPtr world_
MotorNumberToJointMap motor_joints_
ros::ServiceServer recording_service_
void RateThrustCallback(const mav_msgs::RateThrustConstPtr &control_msg)
Called when a RateThrust message is received.
std::string control_attitude_thrust_topic_
event::ConnectionPtr update_connection_
Pointer to the update event connection.
static const bool kPrintOnUpdates
Definition: common.h:42
void OnUpdate(const common::UpdateInfo &)
Called when the world is updated.
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
std::string ground_truth_twist_topic_
ros::Subscriber control_motor_speed_sub_
void ImuCallback(const sensor_msgs::ImuConstPtr &imu_msg)
Called when an IMU message is received.
bool is_recording_
Whether the plugin is currenly recording a rosbag.
bool RecordingServiceCallback(rotors_comm::RecordRosbag::Request &req, rotors_comm::RecordRosbag::Response &res)
Called when a request to start or stop recording is received.
void LogWrenches(const common::Time now)
Log all the wrenches.
bool wait_to_record_
Whether the plugin should wait for user command to start recording.
physics::Link_V child_links_


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Mon Feb 28 2022 23:39:03