gazebo_ros_planar_move.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 
18 /*
19  * Desc: Simple model controller that uses a twist message to move a robot on
20  * the xy plane.
21  * Author: Piyush Khandelwal
22  * Date: 29 July 2013
23  */
24 
25 /*
26  * temporary copied from gazebo_plugins
27  */
28 
29 #include "gazebo_ros_planar_move.h"
30 
31 namespace gazebo
32 {
33 
35 
37 
38  // Load the controller
39  void GazeboRosPlanarForceMove::Load(physics::ModelPtr parent,
40  sdf::ElementPtr sdf)
41  {
42 
43  parent_ = parent;
44 
45  /* Parse parameters */
46 
47  robot_namespace_ = "";
48  if (!sdf->HasElement("robotNamespace"))
49  {
50  ROS_INFO_NAMED("planar_move", "PlanarMovePlugin missing <robotNamespace>, "
51  "defaults to \"%s\"", robot_namespace_.c_str());
52  }
53  else
54  {
56  sdf->GetElement("robotNamespace")->Get<std::string>();
57  }
58 
59  enable_y_axis_ = true;
60  if (!sdf->HasElement ("enableYAxis"))
61  {
62  ROS_INFO_NAMED("planar_move", "PlanarMovePlugin missing <enableYAxis>, "
63  "defaults to \"%d\"", enable_y_axis_);
64  }
65  else
66  {
67  enable_y_axis_ = sdf->GetElement("enableYAxis")->Get<bool>();
68  }
69 
70  command_topic_ = "cmd_vel";
71  if (!sdf->HasElement("commandTopic"))
72  {
73  ROS_WARN_NAMED("planar_move", "PlanarMovePlugin (ns = %s) missing <commandTopic>, "
74  "defaults to \"%s\"",
75  robot_namespace_.c_str(), command_topic_.c_str());
76  }
77  else
78  {
79  command_topic_ = sdf->GetElement("commandTopic")->Get<std::string>();
80  }
81 
82  odometry_topic_ = "odom";
83  if (!sdf->HasElement("odometryTopic"))
84  {
85  ROS_WARN_NAMED("planar_move", "PlanarMovePlugin (ns = %s) missing <odometryTopic>, "
86  "defaults to \"%s\"",
87  robot_namespace_.c_str(), odometry_topic_.c_str());
88  }
89  else
90  {
91  odometry_topic_ = sdf->GetElement("odometryTopic")->Get<std::string>();
92  }
93 
94  odometry_frame_ = "odom";
95  if (!sdf->HasElement("odometryFrame"))
96  {
97  ROS_WARN_NAMED("planar_move", "PlanarMovePlugin (ns = %s) missing <odometryFrame>, "
98  "defaults to \"%s\"",
99  robot_namespace_.c_str(), odometry_frame_.c_str());
100  }
101  else
102  {
103  odometry_frame_ = sdf->GetElement("odometryFrame")->Get<std::string>();
104  }
105 
106  robot_base_frame_ = "base_footprint";
107  if (!sdf->HasElement("robotBaseFrame"))
108  {
109  ROS_WARN_NAMED("planar_move", "PlanarMovePlugin (ns = %s) missing <robotBaseFrame>, "
110  "defaults to \"%s\"",
111  robot_namespace_.c_str(), robot_base_frame_.c_str());
112  }
113  else
114  {
115  robot_base_frame_ = sdf->GetElement("robotBaseFrame")->Get<std::string>();
116  }
117 
118  odometry_rate_ = 20.0;
119  if (!sdf->HasElement("odometryRate"))
120  {
121  ROS_WARN_NAMED("planar_move", "PlanarMovePlugin (ns = %s) missing <odometryRate>, "
122  "defaults to %f",
124  }
125  else
126  {
127  odometry_rate_ = sdf->GetElement("odometryRate")->Get<double>();
128  }
129 
130  use_force_feedback_ = false;
131  if (!sdf->HasElement ("useForceFeedback"))
132  {
133  ROS_INFO_NAMED("planar_move", "PlanarMovePlugin missing <useForceFeedback>, "
134  "defaults to \"%d\"", use_force_feedback_);
135  }
136  else
137  {
138  use_force_feedback_ = sdf->GetElement("useForceFeedback")->Get<bool>();
139  }
140 
141  if (use_force_feedback_) {
142  std::string applied_force_link = "base_link";
143  if (!sdf->HasElement("appliedForceLink"))
144  {
145  ROS_WARN_NAMED("planar_move", "PlanarMovePlugin (ns = %s) missing <appliedForceLink>, "
146  "defaults to \"%s\"",
147  robot_namespace_.c_str(), applied_force_link.c_str());
148  }
149  else
150  {
151  applied_force_link = sdf->GetElement("appliedForceLink")->Get<std::string>();
152  }
153  physics::LinkPtr lnk = parent_->GetLink(applied_force_link);
154  if (!lnk) {
155  physics::Link_V ll = parent_->GetLinks();
156  std::string nm = ll[0]->GetName();
157  lnk = ll[0];
158  ROS_WARN_NAMED("planar_move", "robot model does not have the link named '%s'"
159  ", use '%s' instead of it",
160  applied_force_link.c_str(), nm.c_str());
161  }
162  robot_link_ = lnk;
163 
164  gain_x_ = 20000;
165  gain_y_ = 20000;
166  gain_rot_ = 5000;
167  if (sdf->HasElement ("forceGainX"))
168  {
169  gain_x_ = sdf->GetElement("forceGainX")->Get<double>();
170  }
171  if (sdf->HasElement ("forceGainY"))
172  {
173  gain_y_ = sdf->GetElement("forceGainY")->Get<double>();
174  }
175  if (sdf->HasElement ("forceGainRot"))
176  {
177  gain_rot_ = sdf->GetElement("forceGainRot")->Get<double>();
178  }
179 
180  v_dead_zone_ = 0.0001;
181  if (sdf->HasElement ("velocityDeadZone"))
182  {
183  v_dead_zone_ = sdf->GetElement("velocityDeadZone")->Get<double>();
184  }
185 
186  ROS_INFO_NAMED("planar_move", "PlanarMovePlugin (ns = %s) "
187  "use force feedback to %s with (gain_x, gain_y, gain_rot) = (%f, %f, %f)",
188  robot_namespace_.c_str(),
189  robot_link_->GetName().c_str(),
191  }
192 
193 #if GAZEBO_MAJOR_VERSION >= 8
194  last_odom_publish_time_ = parent_->GetWorld()->SimTime();
195 #else
196  last_odom_publish_time_ = parent_->GetWorld()->GetSimTime();
197 #endif
198 #if GAZEBO_MAJOR_VERSION >= 8
199  last_odom_pose_ = parent_->WorldPose();
200 #else
201  last_odom_pose_ = parent_->GetWorldPose().Ign();
202 #endif
203  x_ = 0;
204  y_ = 0;
205  rot_ = 0;
206  alive_ = true;
207 
208  base_cmd_vel_ = true;
209  fixed_x_ = last_odom_pose_.Pos().X();
210  fixed_y_ = last_odom_pose_.Pos().Y();
211  fixed_yaw_ = last_odom_pose_.Rot().Yaw();
212 
213  // Ensure that ROS has been initialized and subscribe to cmd_vel
214  if (!ros::isInitialized())
215  {
216  ROS_FATAL_STREAM_NAMED("planar_move", "PlanarMovePlugin (ns = " << robot_namespace_
217  << "). A ROS node for Gazebo has not been initialized, "
218  << "unable to load plugin. Load the Gazebo system plugin "
219  << "'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
220  return;
221  }
223 
224  ROS_DEBUG_NAMED("planar_move", "OCPlugin (%s) has started",
225  robot_namespace_.c_str());
226 
229 
230  // subscribe to the odometry topic
232  ros::SubscribeOptions::create<geometry_msgs::Twist>(command_topic_, 1,
233  boost::bind(&GazeboRosPlanarForceMove::cmdVelCallback, this, _1),
234  ros::VoidPtr(), &queue_);
235 
236  vel_sub_ = rosnode_->subscribe(so);
237  odometry_pub_ = rosnode_->advertise<nav_msgs::Odometry>(odometry_topic_, 1);
238 
239  // start custom queue for diff drive
241  boost::thread(boost::bind(&GazeboRosPlanarForceMove::QueueThread, this));
242 
243  // listen to the update event (broadcast every simulation iteration)
245  event::Events::ConnectWorldUpdateBegin(
246  boost::bind(&GazeboRosPlanarForceMove::UpdateChild, this));
247 
248  }
249 
250  // Update the controller
252  {
253  boost::mutex::scoped_lock scoped_lock(lock);
254 
255 #if GAZEBO_MAJOR_VERSION >= 8
256  ignition::math::Pose3d pose = parent_->WorldPose();
257 #else
258  ignition::math::Pose3d pose = parent_->GetWorldPose().Ign();
259 #endif
260 
261  if ( use_force_feedback_ ) {
262  // feedback velocity error to applied force
263 #if GAZEBO_MAJOR_VERSION >= 8
264  ignition::math::Vector3d rlin = robot_link_->RelativeLinearVel();
265  ignition::math::Vector3d rang = robot_link_->RelativeAngularVel();
266 #else
267  ignition::math::Vector3d rlin = robot_link_->GetRelativeLinearVel().Ign();
268  ignition::math::Vector3d rang = robot_link_->GetRelativeAngularVel().Ign();
269 #endif
270 
271  double f_x, f_y, t_rot;
272  if (((x_ * x_) + (y_ * y_) + (rot_ * rot_)) <= v_dead_zone_) {
273  // Do nothing for the zero input
274  if (base_cmd_vel_) {
275  base_cmd_vel_ = false;
276  // store stopped location
277  fixed_x_ = pose.Pos().X();
278  fixed_y_ = pose.Pos().Y();
279  fixed_yaw_ = pose.Rot().Yaw();
280  }
281  f_x = fixed_x_ - pose.Pos().X();
282  f_y = fixed_y_ - pose.Pos().Y();
283  t_rot = fixed_yaw_ - pose.Rot().Yaw();
284  if (t_rot > M_PI) t_rot -= 2*M_PI;
285  if (t_rot < -M_PI) t_rot += 2*M_PI;
286  // convert to local direction
287  ignition::math::Vector3d wfv(f_x, f_y, 0);
288  ignition::math::Vector3d lfv = pose.Rot().RotateVectorReverse(wfv);
289  f_x = lfv.X();
290  f_y = lfv.Y();
291 
292  f_x *= (gain_x_*4);
293  f_y *= (gain_y_*4);
294  t_rot *= (gain_rot_*4);
295 
296  f_x += (x_ - rlin.X()) * gain_x_ * 0.3;
297  f_y += (y_ - rlin.Y()) * gain_y_ * 0.3;
298  t_rot += (rot_ - rang.Z()) * gain_rot_ * 0.3;
299  } else {
300  base_cmd_vel_ = true;
301  //ROS_WARN_NAMED("planar_force_move", "vel: %f %f %f / %f %f %f",
302  // rlin.X(), rlin.Y(), rlin.Z(),
303  // rang.X(), rang.Y(), rang.Z());
304  f_x = (x_ - rlin.X()) * gain_x_;
305  f_y = (y_ - rlin.Y()) * gain_y_;
306  t_rot = (rot_ - rang.Z()) * gain_rot_;
307  }
308  ignition::math::Vector3d rfc(f_x, f_y, 0);
309  ignition::math::Vector3d rtq(0, 0, t_rot);
310  //ROS_WARN_NAMED("planar_force_move", "apply: %f %f - %f",
311  // f_x, f_y, t_rot);
312  robot_link_->AddRelativeForce(rfc);
313  robot_link_->AddRelativeTorque(rtq);
314  } else {
315  // directly set velocity
316  float yaw = pose.Rot().Yaw();
317  parent_->SetLinearVel(ignition::math::Vector3d(
318  x_ * cosf(yaw) - y_ * sinf(yaw),
319  y_ * cosf(yaw) + x_ * sinf(yaw),
320  0));
321  parent_->SetAngularVel(ignition::math::Vector3d(0, 0, rot_));
322  }
323 
324  if (odometry_rate_ > 0.0) {
325 #if GAZEBO_MAJOR_VERSION >= 8
326  common::Time current_time = parent_->GetWorld()->SimTime();
327 #else
328  common::Time current_time = parent_->GetWorld()->GetSimTime();
329 #endif
330  double seconds_since_last_update =
331  (current_time - last_odom_publish_time_).Double();
332  if (seconds_since_last_update > (1.0 / odometry_rate_)) {
333  publishOdometry(seconds_since_last_update);
334  last_odom_publish_time_ = current_time;
335  }
336  }
337  }
338 
339  // Finalize the controller
341  alive_ = false;
342  queue_.clear();
343  queue_.disable();
344  rosnode_->shutdown();
345  callback_queue_thread_.join();
346  }
347 
349  const geometry_msgs::Twist::ConstPtr& cmd_msg)
350  {
351  boost::mutex::scoped_lock scoped_lock(lock);
352  x_ = cmd_msg->linear.x;
353  if (enable_y_axis_)
354  {
355  y_ = cmd_msg->linear.y;
356  }
357  rot_ = cmd_msg->angular.z;
358  }
359 
361  {
362  static const double timeout = 0.01;
363  while (alive_ && rosnode_->ok())
364  {
366  }
367  }
368 
370  {
371 
372  ros::Time current_time = ros::Time::now();
373  std::string odom_frame = tf::resolve(tf_prefix_, odometry_frame_);
374  std::string base_footprint_frame =
376 
377  // getting data for base_footprint to odom transform
378 #if GAZEBO_MAJOR_VERSION >= 8
379  ignition::math::Pose3d pose = this->parent_->WorldPose();
380 #else
381  ignition::math::Pose3d pose = this->parent_->GetWorldPose().Ign();
382 #endif
383 
384  tf::Quaternion qt(pose.Rot().X(), pose.Rot().Y(), pose.Rot().Z(), pose.Rot().W());
385  tf::Vector3 vt(pose.Pos().X(), pose.Pos().Y(), pose.Pos().Z());
386 
387  tf::Transform base_footprint_to_odom(qt, vt);
388  transform_broadcaster_->sendTransform(
389  tf::StampedTransform(base_footprint_to_odom, current_time, odom_frame,
390  base_footprint_frame));
391 
392  // publish odom topic
393  odom_.pose.pose.position.x = pose.Pos().X();
394  odom_.pose.pose.position.y = pose.Pos().Y();
395 
396  odom_.pose.pose.orientation.x = pose.Rot().X();
397  odom_.pose.pose.orientation.y = pose.Rot().Y();
398  odom_.pose.pose.orientation.z = pose.Rot().Z();
399  odom_.pose.pose.orientation.w = pose.Rot().W();
400  odom_.pose.covariance[0] = 0.00001;
401  odom_.pose.covariance[7] = 0.00001;
402  odom_.pose.covariance[14] = 1000000000000.0;
403  odom_.pose.covariance[21] = 1000000000000.0;
404  odom_.pose.covariance[28] = 1000000000000.0;
405  odom_.pose.covariance[35] = 0.001;
406 
407  // get velocity in /odom frame
408  ignition::math::Vector3d linear;
409  linear.X() = (pose.Pos().X() - last_odom_pose_.Pos().X()) / step_time;
410  linear.Y() = (pose.Pos().Y() - last_odom_pose_.Pos().Y()) / step_time;
411  if (rot_ > M_PI / step_time)
412  {
413  // we cannot calculate the angular velocity correctly
414  odom_.twist.twist.angular.z = rot_;
415  }
416  else
417  {
418  float last_yaw = last_odom_pose_.Rot().Yaw();
419  float current_yaw = pose.Rot().Yaw();
420  while (current_yaw < last_yaw - M_PI) current_yaw += 2 * M_PI;
421  while (current_yaw > last_yaw + M_PI) current_yaw -= 2 * M_PI;
422  float angular_diff = current_yaw - last_yaw;
423  odom_.twist.twist.angular.z = angular_diff / step_time;
424  }
425  last_odom_pose_ = pose;
426 
427  // convert velocity to child_frame_id (aka base_footprint)
428  float yaw = pose.Rot().Yaw();
429  odom_.twist.twist.linear.x = cosf(yaw) * linear.X() + sinf(yaw) * linear.Y();
430  odom_.twist.twist.linear.y = cosf(yaw) * linear.Y() - sinf(yaw) * linear.X();
431 
432  odom_.header.stamp = current_time;
433  odom_.header.frame_id = odom_frame;
434  odom_.child_frame_id = base_footprint_frame;
435 
437  }
438 
439  //GZ_REGISTER_MODEL_PLUGIN(GazeboRosPlanarMove)
441 }
void cmdVelCallback(const geometry_msgs::Twist::ConstPtr &cmd_msg)
boost::shared_ptr< ros::NodeHandle > rosnode_
#define ROS_INFO_NAMED(name,...)
Gazebo.
void publish(const boost::shared_ptr< M > &message) const
nm
std::string getPrefixParam(ros::NodeHandle &nh)
#define ROS_WARN_NAMED(name,...)
void Load(physics::ModelPtr parent, sdf::ElementPtr sdf)
boost::shared_ptr< tf::TransformBroadcaster > transform_broadcaster_
ROSCPP_DECL bool isInitialized()
#define M_PI
std::string resolve(const std::string &prefix, const std::string &frame_name)
#define ROS_DEBUG_NAMED(name,...)
#define ROS_FATAL_STREAM_NAMED(name, args)
pose
static Time now()
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
boost::shared_ptr< void > VoidPtr
bool enable_y_axis_
Enable Y-axis movement.


seed_r7_gazebo
Author(s):
autogenerated on Sun Apr 18 2021 02:41:01