ridgeback_ros_force_based_move.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Stefan Kohlbrecher, TU Darmstadt
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 exert
20  * forces on a robot, resulting in motion. Based on the
21  * planar_move plugin by Piyush Khandelwal.
22  * Author: Stefan Kohlbrecher
23  * Date: 06 August 2015
24  */
25 
27 
28 namespace gazebo
29 {
30 
32 
34 
35  // Load the controller
36  void GazeboRosForceBasedMove::Load(physics::ModelPtr parent,
37  sdf::ElementPtr sdf)
38  {
39 
40  parent_ = parent;
41 
42  /* Parse parameters */
43 
44  robot_namespace_ = "";
45  if (!sdf->HasElement("robotNamespace"))
46  {
47  ROS_INFO("ForceBasedPlugin missing <robotNamespace>, "
48  "defaults to \"%s\"", robot_namespace_.c_str());
49  }
50  else
51  {
53  sdf->GetElement("robotNamespace")->Get<std::string>();
54  }
55 
56  command_topic_ = "cmd_vel";
57  if (!sdf->HasElement("commandTopic"))
58  {
59  ROS_WARN("ForceBasedPlugin (ns = %s) missing <commandTopic>, "
60  "defaults to \"%s\"",
61  robot_namespace_.c_str(), command_topic_.c_str());
62  }
63  else
64  {
65  command_topic_ = sdf->GetElement("commandTopic")->Get<std::string>();
66  }
67 
68  odometry_topic_ = "odom";
69  if (!sdf->HasElement("odometryTopic"))
70  {
71  ROS_WARN("ForceBasedPlugin (ns = %s) missing <odometryTopic>, "
72  "defaults to \"%s\"",
73  robot_namespace_.c_str(), odometry_topic_.c_str());
74  }
75  else
76  {
77  odometry_topic_ = sdf->GetElement("odometryTopic")->Get<std::string>();
78  }
79 
80  odometry_frame_ = "odom";
81  if (!sdf->HasElement("odometryFrame"))
82  {
83  ROS_WARN("ForceBasedPlugin (ns = %s) missing <odometryFrame>, "
84  "defaults to \"%s\"",
85  robot_namespace_.c_str(), odometry_frame_.c_str());
86  }
87  else
88  {
89  odometry_frame_ = sdf->GetElement("odometryFrame")->Get<std::string>();
90  }
91 
92 
94  force_x_velocity_p_gain_ = 10000.0;
95  force_y_velocity_p_gain_ = 10000.0;
96 
97  if (sdf->HasElement("yaw_velocity_p_gain"))
98  (sdf->GetElement("yaw_velocity_p_gain")->GetValue()->Get(torque_yaw_velocity_p_gain_));
99 
100  if (sdf->HasElement("x_velocity_p_gain"))
101  (sdf->GetElement("x_velocity_p_gain")->GetValue()->Get(force_x_velocity_p_gain_));
102 
103  if (sdf->HasElement("y_velocity_p_gain"))
104  (sdf->GetElement("y_velocity_p_gain")->GetValue()->Get(force_y_velocity_p_gain_));
105 
106  ROS_INFO_STREAM("ForceBasedMove using gains: yaw: " << torque_yaw_velocity_p_gain_ <<
107  " x: " << force_x_velocity_p_gain_ <<
108  " y: " << force_y_velocity_p_gain_ << "\n");
109 
110  robot_base_frame_ = "base_footprint";
111  if (!sdf->HasElement("robotBaseFrame"))
112  {
113  ROS_WARN("ForceBasedPlugin (ns = %s) missing <robotBaseFrame>, "
114  "defaults to \"%s\"",
115  robot_namespace_.c_str(), robot_base_frame_.c_str());
116  }
117  else
118  {
119  robot_base_frame_ = sdf->GetElement("robotBaseFrame")->Get<std::string>();
120  }
121 
122  ROS_INFO_STREAM("robotBaseFrame for force based move plugin: " << robot_base_frame_ << "\n");
123 
124  this->link_ = parent->GetLink(robot_base_frame_);
125 
126  odometry_rate_ = 20.0;
127  if (!sdf->HasElement("odometryRate"))
128  {
129  ROS_WARN("ForceBasedPlugin (ns = %s) missing <odometryRate>, "
130  "defaults to %f",
132  }
133  else
134  {
135  odometry_rate_ = sdf->GetElement("odometryRate")->Get<double>();
136  }
137 
138  cmd_vel_time_out_ = 0.25;
139  if (!sdf->HasElement("cmdVelTimeOut"))
140  {
141  ROS_WARN("ForceBasedPlugin (ns = %s) missing <cmdVelTimeOut>, "
142  "defaults to %f",
144  }
145  else
146  {
147  cmd_vel_time_out_ = sdf->GetElement("cmdVelTimeOut")->Get<double>();
148  }
149 
150  this->publish_odometry_tf_ = true;
151  if (!sdf->HasElement("publishOdometryTf")) {
152  ROS_WARN("ForceBasedPlugin Plugin (ns = %s) missing <publishOdometryTf>, defaults to %s",
153  this->robot_namespace_.c_str(), this->publish_odometry_tf_ ? "true" : "false");
154  } else {
155  this->publish_odometry_tf_ = sdf->GetElement("publishOdometryTf")->Get<bool>();
156  }
157 
158  last_odom_publish_time_ = parent_->GetWorld()->GetSimTime();
159  last_odom_pose_ = parent_->GetWorldPose();
160  x_ = 0.0;
161  y_ = 0.0;
162  rot_ = 0.0;
163  alive_ = true;
164 
166 
167  // Ensure that ROS has been initialized and subscribe to cmd_vel
168  if (!ros::isInitialized())
169  {
170  ROS_FATAL_STREAM("ForceBasedPlugin (ns = " << robot_namespace_
171  << "). A ROS node for Gazebo has not been initialized, "
172  << "unable to load plugin. Load the Gazebo system plugin "
173  << "'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
174  return;
175  }
177 
178  ROS_DEBUG("OCPlugin (%s) has started!",
179  robot_namespace_.c_str());
180 
182 
183  if (publish_odometry_tf_)
185 
186  // subscribe to the odometry topic
188  ros::SubscribeOptions::create<geometry_msgs::Twist>(command_topic_, 1,
189  boost::bind(&GazeboRosForceBasedMove::cmdVelCallback, this, _1),
190  ros::VoidPtr(), &queue_);
191 
192  vel_sub_ = rosnode_->subscribe(so);
193  odometry_pub_ = rosnode_->advertise<nav_msgs::Odometry>(odometry_topic_, 1);
194 
195  // start custom queue for diff drive
197  boost::thread(boost::bind(&GazeboRosForceBasedMove::QueueThread, this));
198 
199  // listen to the update event (broadcast every simulation iteration)
201  event::Events::ConnectWorldUpdateBegin(
202  boost::bind(&GazeboRosForceBasedMove::UpdateChild, this));
203 
204  }
205 
206  // Update the controller
208  {
209  boost::mutex::scoped_lock scoped_lock(lock);
210  math::Pose pose = parent_->GetWorldPose();
211 
212  if ((parent_->GetWorld()->GetSimTime() - last_cmd_vel_time_) > cmd_vel_time_out_) {
213  x_ = 0.0;
214  y_ = 0.0;
215  rot_ = 0.0;
216  }
217 
218  math::Vector3 angular_vel = parent_->GetWorldAngularVel();
219  link_->AddTorque(math::Vector3(0.0,
220  0.0,
221  (rot_ - angular_vel.z) * torque_yaw_velocity_p_gain_));
222 
223  // float yaw = pose.rot.GetYaw();
224 
225  math::Vector3 linear_vel = parent_->GetRelativeLinearVel();
226 
227  link_->AddRelativeForce(math::Vector3((x_ - linear_vel.x)* force_x_velocity_p_gain_,
228  (y_ - linear_vel.y)* force_y_velocity_p_gain_,
229  0.0));
230  //parent_->PlaceOnNearestEntityBelow();
231  //parent_->SetLinearVel(math::Vector3(
232  // x_ * cosf(yaw) - y_ * sinf(yaw),
233  // y_ * cosf(yaw) + x_ * sinf(yaw),
234  // 0));
235  //parent_->SetAngularVel(math::Vector3(0, 0, rot_));
236 
237  if (odometry_rate_ > 0.0) {
238  common::Time current_time = parent_->GetWorld()->GetSimTime();
239  double seconds_since_last_update =
240  (current_time - last_odom_publish_time_).Double();
241  if (seconds_since_last_update > (1.0 / odometry_rate_)) {
242  publishOdometry(seconds_since_last_update);
243  last_odom_publish_time_ = current_time;
244  }
245  }
246  }
247 
248  // Finalize the controller
250  alive_ = false;
251  queue_.clear();
252  queue_.disable();
253  rosnode_->shutdown();
254  callback_queue_thread_.join();
255  }
256 
258  const geometry_msgs::Twist::ConstPtr& cmd_msg)
259  {
260  boost::mutex::scoped_lock scoped_lock(lock);
261  x_ = cmd_msg->linear.x;
262  y_ = cmd_msg->linear.y;
263  rot_ = cmd_msg->angular.z;
264  last_cmd_vel_time_= parent_->GetWorld()->GetSimTime();
265  }
266 
268  {
269  static const double timeout = 0.01;
270  while (alive_ && rosnode_->ok())
271  {
273  }
274  }
275 
277  {
278 
279  ros::Time current_time = ros::Time::now();
280  std::string odom_frame = tf::resolve(tf_prefix_, odometry_frame_);
281  std::string base_footprint_frame =
283 
284  math::Vector3 angular_vel = parent_->GetRelativeAngularVel();
285  math::Vector3 linear_vel = parent_->GetRelativeLinearVel();
286 
287  odom_transform_= odom_transform_ * this->getTransformForMotion(linear_vel.x, angular_vel.z, step_time);
288 
290  odom_.twist.twist.angular.z = angular_vel.z;
291  odom_.twist.twist.linear.x = linear_vel.x;
292 
293  odom_.header.stamp = current_time;
294  odom_.header.frame_id = odom_frame;
295  odom_.child_frame_id = base_footprint_frame;
296 
297  if (transform_broadcaster_.get()){
298  transform_broadcaster_->sendTransform(
299  tf::StampedTransform(odom_transform_, current_time, odom_frame,
300  base_footprint_frame));
301  }
302 
303  odom_.pose.covariance[0] = 0.001;
304  odom_.pose.covariance[7] = 0.001;
305  odom_.pose.covariance[14] = 1000000000000.0;
306  odom_.pose.covariance[21] = 1000000000000.0;
307  odom_.pose.covariance[28] = 1000000000000.0;
308 
309  if (std::abs(angular_vel.z) < 0.0001) {
310  odom_.pose.covariance[35] = 0.01;
311  }else{
312  odom_.pose.covariance[35] = 100.0;
313  }
314 
315  odom_.twist.covariance[0] = 0.001;
316  odom_.twist.covariance[7] = 0.001;
317  odom_.twist.covariance[14] = 0.001;
318  odom_.twist.covariance[21] = 1000000000000.0;
319  odom_.twist.covariance[28] = 1000000000000.0;
320 
321  if (std::abs(angular_vel.z) < 0.0001) {
322  odom_.twist.covariance[35] = 0.01;
323  }else{
324  odom_.twist.covariance[35] = 100.0;
325  }
326 
327 
328 
330  }
331 
332 
333  tf::Transform GazeboRosForceBasedMove::getTransformForMotion(double linear_vel_x, double angular_vel, double timeSeconds) const
334  {
335  tf::Transform tmp;
336  tmp.setIdentity();
337 
338 
339  if (std::abs(angular_vel) < 0.0001) {
340  //Drive straight
341  tmp.setOrigin(tf::Vector3(static_cast<double>(linear_vel_x*timeSeconds), 0.0, 0.0));
342  } else {
343  //Follow circular arc
344  double distChange = linear_vel_x * timeSeconds;
345  double angleChange = angular_vel * timeSeconds;
346 
347  double arcRadius = distChange / angleChange;
348 
349  tmp.setOrigin(tf::Vector3(std::sin(angleChange) * arcRadius,
350  arcRadius - std::cos(angleChange) * arcRadius,
351  0.0));
352  tmp.setRotation(tf::createQuaternionFromYaw(angleChange));
353  }
354 
355  return tmp;
356  }
357 
358  GZ_REGISTER_MODEL_PLUGIN(GazeboRosForceBasedMove)
359 }
TFSIMD_FORCE_INLINE void setRotation(const Quaternion &q)
boost::shared_ptr< ros::NodeHandle > rosnode_
void publish(const boost::shared_ptr< M > &message) const
std::string getPrefixParam(ros::NodeHandle &nh)
physics::LinkPtr link_
A pointer to the Link, where force is applied.
ROSCPP_DECL bool isInitialized()
tf::Transform getTransformForMotion(double linear_vel_x, double angular_vel, double timeSeconds) const
#define ROS_WARN(...)
void setIdentity()
std::string resolve(const std::string &prefix, const std::string &frame_name)
static Quaternion createQuaternionFromYaw(double yaw)
#define ROS_FATAL_STREAM(args)
#define ROS_INFO(...)
void Load(physics::ModelPtr parent, sdf::ElementPtr sdf)
boost::shared_ptr< tf::TransformBroadcaster > transform_broadcaster_
static void poseTFToMsg(const Pose &bt, geometry_msgs::Pose &msg)
#define ROS_INFO_STREAM(args)
static Time now()
void cmdVelCallback(const geometry_msgs::Twist::ConstPtr &cmd_msg)
boost::shared_ptr< void > VoidPtr
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
#define ROS_DEBUG(...)


ridgeback_gazebo_plugins
Author(s): Stefan Kohlbrecher , Johannes Meyer
autogenerated on Thu Aug 27 2020 04:08:28