safety_limiter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2017, the neonavigation authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <ros/ros.h>
32 #include <sensor_msgs/PointCloud2.h>
33 #include <sensor_msgs/PointCloud.h>
34 #include <geometry_msgs/Twist.h>
35 #include <std_msgs/Bool.h>
36 #include <std_msgs/Empty.h>
39 
40 #include <Eigen/Core>
41 #include <Eigen/Geometry>
42 
43 #include <pcl/common/transforms.h>
44 #include <pcl/filters/voxel_grid.h>
45 #include <pcl/kdtree/kdtree_flann.h>
46 #include <pcl/point_cloud.h>
47 #include <pcl/point_types.h>
49 
50 #include <algorithm>
51 #include <cmath>
52 #include <random>
53 #include <string>
54 #include <iostream>
55 #include <sstream>
56 #include <vector>
57 
59 
60 pcl::PointXYZ operator-(const pcl::PointXYZ& a, const pcl::PointXYZ& b)
61 {
62  auto c = a;
63  c.x -= b.x;
64  c.y -= b.y;
65  c.z -= b.z;
66  return c;
67 }
68 pcl::PointXYZ operator+(const pcl::PointXYZ& a, const pcl::PointXYZ& b)
69 {
70  auto c = a;
71  c.x += b.x;
72  c.y += b.y;
73  c.z += b.z;
74  return c;
75 }
76 pcl::PointXYZ operator*(const pcl::PointXYZ& a, const float& b)
77 {
78  auto c = a;
79  c.x *= b;
80  c.y *= b;
81  c.z *= b;
82  return c;
83 }
85 {
86  return value.getType() == XmlRpc::XmlRpcValue::TypeInt ||
88 }
89 
91 {
92 protected:
99  std::vector<ros::Subscriber> sub_clouds_;
105 
106  geometry_msgs::Twist twist_;
108  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_;
110  double hz_;
111  double timeout_;
113  double vel_[2];
114  double acc_[2];
115  double tmax_;
116  double dt_;
117  double d_margin_;
118  double d_escape_;
119  double yaw_margin_;
120  double yaw_escape_;
121  double r_lim_;
122  double z_range_[2];
125  std::string frame_id_;
126 
132 
137 
138  constexpr static float EPSILON = 1e-6;
139 
141 
142 public:
144  : nh_()
145  , pnh_("~")
146  , tfl_(tfbuf_)
147  , cloud_(new pcl::PointCloud<pcl::PointXYZ>)
148  , cloud_clear_(false)
149  , last_disable_cmd_(0)
150  , watchdog_stop_(false)
151  , has_cloud_(false)
152  , has_twist_(true)
153  , has_collision_at_now_(false)
154  {
156  pub_twist_ = neonavigation_common::compat::advertise<geometry_msgs::Twist>(
157  nh_, "cmd_vel",
158  pnh_, "cmd_vel_out", 1, true);
159  pub_cloud_ = nh_.advertise<sensor_msgs::PointCloud>("collision", 1, true);
160  pub_debug_ = nh_.advertise<sensor_msgs::PointCloud>("debug", 1, true);
162  nh_, "cmd_vel_in",
163  pnh_, "cmd_vel_in", 1, &SafetyLimiterNode::cbTwist, this);
165  nh_, "disable_safety",
166  pnh_, "disable", 1, &SafetyLimiterNode::cbDisable, this);
168  nh_, "watchdog_reset",
169  pnh_, "watchdog_reset", 1, &SafetyLimiterNode::cbWatchdogReset, this);
170 
171  int num_input_clouds;
172  pnh_.param("num_input_clouds", num_input_clouds, 1);
173  if (num_input_clouds == 1)
174  {
175  sub_clouds_.push_back(neonavigation_common::compat::subscribe(
176  nh_, "cloud",
177  pnh_, "cloud", 1, &SafetyLimiterNode::cbCloud, this));
178  }
179  else
180  {
181  for (int i = 0; i < num_input_clouds; ++i)
182  {
183  sub_clouds_.push_back(nh_.subscribe(
184  "cloud" + std::to_string(i), 1, &SafetyLimiterNode::cbCloud, this));
185  }
186  }
187 
188  pnh_.param("freq", hz_, 6.0);
189  pnh_.param("cloud_timeout", timeout_, 0.8);
190  pnh_.param("disable_timeout", disable_timeout_, 0.1);
191  pnh_.param("lin_vel", vel_[0], 0.5);
192  pnh_.param("lin_acc", acc_[0], 1.0);
193  pnh_.param("ang_vel", vel_[1], 0.8);
194  pnh_.param("ang_acc", acc_[1], 1.6);
195  pnh_.param("z_range_min", z_range_[0], 0.0);
196  pnh_.param("z_range_max", z_range_[1], 0.5);
197  pnh_.param("dt", dt_, 0.1);
198  if (pnh_.hasParam("t_margin"))
199  ROS_WARN("safety_limiter: t_margin parameter is obsolated. Use d_margin and yaw_margin instead.");
200  pnh_.param("d_margin", d_margin_, 0.2);
201  pnh_.param("d_escape", d_escape_, 0.05);
202  pnh_.param("yaw_margin", yaw_margin_, 0.2);
203  pnh_.param("yaw_escape", yaw_escape_, 0.05);
204  pnh_.param("downsample_grid", downsample_grid_, 0.05);
205  pnh_.param("frame_id", frame_id_, std::string("base_link"));
206  double hold_d;
207  pnh_.param("hold", hold_d, 0.0);
208  hold_ = ros::Duration(std::max(hold_d, 1.0 / hz_));
209  double watchdog_interval_d;
210  pnh_.param("watchdog_interval", watchdog_interval_d, 0.0);
211  watchdog_interval_ = ros::Duration(watchdog_interval_d);
212  pnh_.param("allow_empty_cloud", allow_empty_cloud_, false);
213 
214  tmax_ = 0.0;
215  for (int i = 0; i < 2; i++)
216  {
217  auto t = vel_[i] / acc_[i];
218  if (tmax_ < t)
219  tmax_ = t;
220  }
221  tmax_ *= 1.5;
222  tmax_ += std::max(d_margin_ / vel_[0], yaw_margin_ / vel_[1]);
223  r_lim_ = 1.0;
224 
225  XmlRpc::XmlRpcValue footprint_xml;
226  if (!pnh_.hasParam("footprint"))
227  {
228  ROS_FATAL("Footprint doesn't specified");
229  throw std::runtime_error("Footprint doesn't specified");
230  }
231  pnh_.getParam("footprint", footprint_xml);
232  if (footprint_xml.getType() != XmlRpc::XmlRpcValue::TypeArray || footprint_xml.size() < 3)
233  {
234  ROS_FATAL("Invalid footprint");
235  throw std::runtime_error("Invalid footprint");
236  }
237  footprint_radius_ = 0;
238  for (int i = 0; i < footprint_xml.size(); i++)
239  {
240  if (!XmlRpc_isNumber(footprint_xml[i][0]) ||
241  !XmlRpc_isNumber(footprint_xml[i][1]))
242  {
243  ROS_FATAL("Invalid footprint value");
244  throw std::runtime_error("Invalid footprint value");
245  }
246 
247  vec v;
248  v[0] = static_cast<double>(footprint_xml[i][0]);
249  v[1] = static_cast<double>(footprint_xml[i][1]);
250  footprint_p.v.push_back(v);
251 
252  const float dist = hypotf(v[0], v[1]);
253  if (dist > footprint_radius_)
254  footprint_radius_ = dist;
255  }
256  footprint_p.v.push_back(footprint_p.v.front());
257  ROS_INFO("footprint radius: %0.3f", footprint_radius_);
258 
259  diag_updater_.setHardwareID("none");
260  diag_updater_.add("Collision", this, &SafetyLimiterNode::diagnoseCollision);
261  }
262  void spin()
263  {
264  ros::Timer predict_timer =
266 
267  if (watchdog_interval_ != ros::Duration(0.0))
268  {
269  watchdog_timer_ =
270  nh_.createTimer(watchdog_interval_, &SafetyLimiterNode::cbWatchdogTimer, this);
271  }
272 
273  ros::spin();
274  }
275 
276 protected:
277  void cbWatchdogReset(const std_msgs::Empty::ConstPtr& msg)
278  {
279  watchdog_timer_.setPeriod(watchdog_interval_, true);
280  watchdog_stop_ = false;
281  }
282  void cbWatchdogTimer(const ros::TimerEvent& event)
283  {
284  ROS_WARN_THROTTLE(1.0, "safety_limiter: Watchdog timed-out");
285  watchdog_stop_ = true;
286  geometry_msgs::Twist cmd_vel;
287  pub_twist_.publish(cmd_vel);
288  }
289  void cbPredictTimer(const ros::TimerEvent& event)
290  {
291  if (!has_twist_)
292  return;
293  if (!has_cloud_)
294  return;
295 
296  if (ros::Time::now() - last_cloud_stamp_ > ros::Duration(timeout_))
297  {
298  ROS_WARN_THROTTLE(1.0, "safety_limiter: PointCloud timed-out");
299  geometry_msgs::Twist cmd_vel;
300  pub_twist_.publish(cmd_vel);
301 
302  cloud_.reset(new pcl::PointCloud<pcl::PointXYZ>);
303  return;
304  }
305 
306  ros::Time now = ros::Time::now();
307  const double r_lim_current = predict(twist_);
308 
309  if (r_lim_current < r_lim_)
310  r_lim_ = r_lim_current;
311 
312  if (r_lim_current < 1.0)
313  hold_off_ = now + hold_;
314 
315  cloud_clear_ = true;
316 
317  diag_updater_.force_update();
318  }
319  double predict(const geometry_msgs::Twist& in)
320  {
321  pcl::PointCloud<pcl::PointXYZ>::Ptr pc(new pcl::PointCloud<pcl::PointXYZ>);
322  pcl::VoxelGrid<pcl::PointXYZ> ds;
323  ds.setInputCloud(cloud_);
324  ds.setLeafSize(downsample_grid_, downsample_grid_, downsample_grid_);
325  ds.filter(*pc);
326 
327  auto filter_z = [this](pcl::PointXYZ& p)
328  {
329  if (p.z < this->z_range_[0] || this->z_range_[1] < p.z)
330  return true;
331  p.z = 0.0;
332  return false;
333  };
334  pc->erase(std::remove_if(pc->points.begin(), pc->points.end(), filter_z),
335  pc->points.end());
336 
337  if (pc->size() == 0)
338  {
339  if (allow_empty_cloud_)
340  {
341  return 1.0;
342  }
343  ROS_WARN_THROTTLE(1.0, "safety_limiter: Empty pointcloud passed.");
344  return 0.0;
345  }
346 
347  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
348  kdtree.setInputCloud(pc);
349 
350  Eigen::Affine3f move;
351  Eigen::Affine3f move_inv;
352  Eigen::Affine3f motion =
353  Eigen::AngleAxisf(-twist_.angular.z * dt_, Eigen::Vector3f::UnitZ()) *
354  Eigen::Translation3f(Eigen::Vector3f(-twist_.linear.x * dt_, 0.0, 0.0));
355  Eigen::Affine3f motion_inv =
356  Eigen::Translation3f(Eigen::Vector3f(twist_.linear.x * dt_, 0.0, 0.0)) *
357  Eigen::AngleAxisf(twist_.angular.z * dt_, Eigen::Vector3f::UnitZ());
358  move.setIdentity();
359  move_inv.setIdentity();
360  sensor_msgs::PointCloud col_points;
361  sensor_msgs::PointCloud debug_points;
362  col_points.header.frame_id = frame_id_;
363  col_points.header.stamp = ros::Time::now();
364  debug_points.header = col_points.header;
365 
366  float d_col = 0;
367  float yaw_col = 0;
368  bool has_collision = false;
369  float d_escape_remain = 0;
370  float yaw_escape_remain = 0;
371  has_collision_at_now_ = false;
372 
373  for (float t = 0; t < tmax_; t += dt_)
374  {
375  if (t != 0)
376  {
377  d_col += twist_.linear.x * dt_;
378  d_escape_remain -= std::abs(twist_.linear.x) * dt_;
379  yaw_col += twist_.angular.z * dt_;
380  yaw_escape_remain -= std::abs(twist_.angular.z) * dt_;
381  move = move * motion;
382  move_inv = move_inv * motion_inv;
383  }
384 
385  pcl::PointXYZ center;
386  center = pcl::transformPoint(center, move_inv);
387  geometry_msgs::Point32 p;
388  p.x = center.x;
389  p.y = center.y;
390  p.z = 0.0;
391  debug_points.points.push_back(p);
392 
393  std::vector<int> indices;
394  std::vector<float> dist;
395  const int num = kdtree.radiusSearch(center, footprint_radius_, indices, dist);
396  if (num == 0)
397  continue;
398 
399  bool colliding = false;
400  for (auto& i : indices)
401  {
402  auto& p = pc->points[i];
403  auto point = pcl::transformPoint(p, move);
404  vec v(point.x, point.y);
405  if (footprint_p.inside(v))
406  {
407  geometry_msgs::Point32 pos;
408  pos.x = p.x;
409  pos.y = p.y;
410  pos.z = p.z;
411  col_points.points.push_back(pos);
412  colliding = true;
413  break;
414  }
415  }
416  if (colliding)
417  {
418  if (t == 0)
419  {
420  // The robot is already in collision.
421  // Allow movement under d_escape_ and yaw_escape_
422  d_escape_remain = d_escape_;
423  yaw_escape_remain = yaw_escape_;
424  has_collision_at_now_ = true;
425  }
426  if (d_escape_remain <= 0 || yaw_escape_remain <= 0)
427  {
428  if (has_collision_at_now_)
429  {
430  // It's not possible to escape from collision; stop completely.
431  d_col = yaw_col = 0;
432  }
433 
434  has_collision = true;
435  break;
436  }
437  }
438  }
439  pub_debug_.publish(debug_points);
440  pub_cloud_.publish(col_points);
441 
442  if (!has_collision)
443  return 1.0;
444 
445  // delay compensation:
446  // solve for d_compensated: d_compensated = d - delay * sqrt(2 * acc * d_compensated)
447  // d_compensated = d + acc * delay^2 - sqrt((acc * delay^2)^2 + 2 * d * acc * delay^2)
448 
449  const float delay = 1.0 * (1.0 / hz_) + dt_;
450  const float acc_dtsq[2] =
451  {
452  static_cast<float>(acc_[0] * std::pow(delay, 2)),
453  static_cast<float>(acc_[1] * std::pow(delay, 2)),
454  };
455 
456  d_col = std::max<float>(
457  0.0,
458  std::abs(d_col) - d_margin_ + acc_dtsq[0] -
459  std::sqrt(std::pow(acc_dtsq[0], 2) + 2 * acc_dtsq[0] * std::abs(d_col)));
460  yaw_col = std::max<float>(
461  0.0,
462  std::abs(yaw_col) - yaw_margin_ + acc_dtsq[1] -
463  std::sqrt(std::pow(acc_dtsq[1], 2) + 2 * acc_dtsq[1] * std::abs(yaw_col)));
464 
465  float d_r =
466  (std::sqrt(std::abs(2 * acc_[0] * d_col)) + EPSILON) / std::abs(twist_.linear.x);
467  float yaw_r =
468  (std::sqrt(std::abs(2 * acc_[1] * yaw_col)) + EPSILON) / std::abs(twist_.angular.z);
469  if (!std::isfinite(d_r))
470  d_r = 1.0;
471  if (!std::isfinite(yaw_r))
472  yaw_r = 1.0;
473 
474  return std::min(d_r, yaw_r);
475  }
476 
477  geometry_msgs::Twist
478  limit(const geometry_msgs::Twist& in)
479  {
480  auto out = in;
481  if (r_lim_ < 1.0 - EPSILON)
482  {
483  out.linear.x *= r_lim_;
484  out.angular.z *= r_lim_;
485  if (std::abs(in.linear.x - out.linear.x) > EPSILON ||
486  std::abs(in.angular.z - out.angular.z) > EPSILON)
487  {
489  1.0, "safety_limiter: (%0.2f, %0.2f)->(%0.2f, %0.2f)",
490  in.linear.x, in.angular.z,
491  out.linear.x, out.angular.z);
492  }
493  }
494  return out;
495  }
496 
497  class vec
498  {
499  public:
500  float c[2];
501  vec(const float x, const float y)
502  {
503  c[0] = x;
504  c[1] = y;
505  }
506  vec()
507  {
508  c[0] = c[1] = 0.0;
509  }
510  float& operator[](const int& i)
511  {
512  ROS_ASSERT(i < 2);
513  return c[i];
514  }
515  const float& operator[](const int& i) const
516  {
517  ROS_ASSERT(i < 2);
518  return c[i];
519  }
520  vec operator-(const vec& a) const
521  {
522  vec out = *this;
523  out[0] -= a[0];
524  out[1] -= a[1];
525  return out;
526  }
527  float cross(const vec& a) const
528  {
529  return (*this)[0] * a[1] - (*this)[1] * a[0];
530  }
531  float dot(const vec& a) const
532  {
533  return (*this)[0] * a[0] + (*this)[1] * a[1];
534  }
535  float dist(const vec& a) const
536  {
537  return hypotf((*this)[0] - a[0], (*this)[1] - a[1]);
538  }
539  float dist_line(const vec& a, const vec& b) const
540  {
541  return (b - a).cross((*this) - a) / b.dist(a);
542  }
543  float dist_linestrip(const vec& a, const vec& b) const
544  {
545  if ((b - a).dot((*this) - a) <= 0)
546  return this->dist(a);
547  if ((a - b).dot((*this) - b) <= 0)
548  return this->dist(b);
549  return std::abs(this->dist_line(a, b));
550  }
551  };
552  class polygon
553  {
554  public:
555  std::vector<vec> v;
556  void move(const float& x, const float& y, const float& yaw)
557  {
558  const float cos_v = cosf(yaw);
559  const float sin_v = sinf(yaw);
560  for (auto& p : v)
561  {
562  const auto tmp = p;
563  p[0] = cos_v * tmp[0] - sin_v * tmp[1] + x;
564  p[1] = sin_v * tmp[0] + cos_v * tmp[1] + y;
565  }
566  }
567  bool inside(const vec& a) const
568  {
569  int cn = 0;
570  for (size_t i = 0; i < v.size() - 1; i++)
571  {
572  auto& v1 = v[i];
573  auto& v2 = v[i + 1];
574  if ((v1[1] <= a[1] && a[1] < v2[1]) ||
575  (v2[1] <= a[1] && a[1] < v1[1]))
576  {
577  float lx;
578  lx = v1[0] + (v2[0] - v1[0]) * (a[1] - v1[1]) / (v2[1] - v1[1]);
579  if (a[0] < lx)
580  cn++;
581  }
582  }
583  return ((cn & 1) == 1);
584  }
585  float dist(const vec& a) const
586  {
587  float dist = FLT_MAX;
588  for (size_t i = 0; i < v.size() - 1; i++)
589  {
590  auto& v1 = v[i];
591  auto& v2 = v[i + 1];
592  auto d = a.dist_linestrip(v1, v2);
593  if (d < dist)
594  dist = d;
595  }
596  return dist;
597  }
598  };
599 
601 
602  void cbTwist(const geometry_msgs::Twist::ConstPtr& msg)
603  {
604  ros::Time now = ros::Time::now();
605 
606  twist_ = *msg;
607  has_twist_ = true;
608 
609  if (now - last_disable_cmd_ < ros::Duration(disable_timeout_))
610  {
611  pub_twist_.publish(twist_);
612  }
613  else if (ros::Time::now() - last_cloud_stamp_ > ros::Duration(timeout_) || watchdog_stop_)
614  {
615  geometry_msgs::Twist cmd_vel;
616  pub_twist_.publish(cmd_vel);
617  }
618  else
619  {
620  geometry_msgs::Twist cmd_vel = limit(twist_);
621  pub_twist_.publish(cmd_vel);
622 
623  if (now > hold_off_)
624  r_lim_ = 1.0;
625  }
626  }
627  void cbCloud(const sensor_msgs::PointCloud2::ConstPtr& msg)
628  {
629  pcl::PointCloud<pcl::PointXYZ>::Ptr pc(new pcl::PointCloud<pcl::PointXYZ>());
630 
631  try
632  {
633  sensor_msgs::PointCloud2 pc2_tmp;
634  geometry_msgs::TransformStamped trans = tfbuf_.lookupTransform(
635  frame_id_, msg->header.frame_id, msg->header.stamp, ros::Duration(0.1));
636  tf2::doTransform(*msg, pc2_tmp, trans);
637  pcl::fromROSMsg(pc2_tmp, *pc);
638  }
639  catch (tf2::TransformException& e)
640  {
641  ROS_WARN_THROTTLE(1.0, "safety_limiter: Transform failed: %s", e.what());
642  return;
643  }
644 
645  if (cloud_clear_)
646  {
647  cloud_clear_ = false;
648  cloud_.reset(new pcl::PointCloud<pcl::PointXYZ>);
649  }
650  *cloud_ += *pc;
651  last_cloud_stamp_ = msg->header.stamp;
652  has_cloud_ = true;
653  }
654  void cbDisable(const std_msgs::Bool::ConstPtr& msg)
655  {
656  if (msg->data)
657  {
658  last_disable_cmd_ = ros::Time::now();
659  }
660  }
661 
663  {
664  if (r_lim_ == 1.0)
665  {
666  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
667  }
668  else if (r_lim_ == 0.0)
669  {
670  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN,
671  (has_collision_at_now_) ?
672  "Cannot escape from collision." :
673  "Trying to avoid collision, but cannot move anymore.");
674  }
675  else
676  {
677  stat.summary(diagnostic_msgs::DiagnosticStatus::OK,
678  (has_collision_at_now_) ?
679  "Escaping from collision." :
680  "Reducing velocity to avoid collision.");
681  }
682  stat.addf("Velocity Limit Ratio", "%.2f", r_lim_);
683  }
684 };
685 
686 int main(int argc, char** argv)
687 {
688  ros::init(argc, argv, "safety_limiter");
689 
690  SafetyLimiterNode limiter;
691  limiter.spin();
692 
693  return 0;
694 }
d
std::vector< ros::Subscriber > sub_clouds_
double predict(const geometry_msgs::Twist &in)
static constexpr float EPSILON
pcl::PointCloud< pcl::PointXYZ >::Ptr cloud_
ros::NodeHandle nh_
int main(int argc, char **argv)
#define ROS_FATAL(...)
float cross(const vec &a) const
void publish(const boost::shared_ptr< M > &message) const
geometry_msgs::Twist twist_
float dist(const vec &a) const
void cbCloud(const sensor_msgs::PointCloud2::ConstPtr &msg)
void summary(unsigned char lvl, const std::string s)
diagnostic_updater::Updater diag_updater_
void cbWatchdogReset(const std_msgs::Empty::ConstPtr &msg)
int size() const
tf2_ros::Buffer tfbuf_
void setHardwareID(const std::string &hwid)
void cbDisable(const std_msgs::Bool::ConstPtr &msg)
bool inside(const vec &a) const
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
void setPeriod(const Duration &period, bool reset=true)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void add(const std::string &name, TaskFunction f)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
pcl::PointXYZ operator*(const pcl::PointXYZ &a, const float &b)
ros::Subscriber subscribe(ros::NodeHandle &nh_new, const std::string &topic_new, ros::NodeHandle &nh_old, const std::string &topic_old, uint32_t queue_size, void(*fp)(M), const ros::TransportHints &transport_hints=ros::TransportHints())
void cbWatchdogTimer(const ros::TimerEvent &event)
tf2_ros::TransformListener tfl_
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
Type const & getType() const
ros::Duration watchdog_interval_
#define ROS_WARN(...)
void addf(const std::string &key, const char *format,...)
float dist_line(const vec &a, const vec &b) const
void move(const float &x, const float &y, const float &yaw)
ROSCPP_DECL void spin(Spinner &spinner)
ros::Time last_cloud_stamp_
float dist_linestrip(const vec &a, const vec &b) const
#define ROS_WARN_THROTTLE(period,...)
ros::Publisher pub_debug_
ros::Duration hold_
#define ROS_INFO(...)
float dist(const vec &a) const
pcl::PointXYZ operator+(const pcl::PointXYZ &a, const pcl::PointXYZ &b)
void cbTwist(const geometry_msgs::Twist::ConstPtr &msg)
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
float dot(const vec &a) const
const float & operator[](const int &i) const
ros::Timer watchdog_timer_
ros::Publisher pub_cloud_
geometry_msgs::Twist limit(const geometry_msgs::Twist &in)
ros::Time last_disable_cmd_
void diagnoseCollision(diagnostic_updater::DiagnosticStatusWrapper &stat)
static Time now()
vec operator-(const vec &a) const
vec(const float x, const float y)
float & operator[](const int &i)
#define ROS_ASSERT(cond)
void cbPredictTimer(const ros::TimerEvent &event)
ros::Publisher pub_twist_
ros::Subscriber sub_disable_
bool XmlRpc_isNumber(XmlRpc::XmlRpcValue &value)
ros::NodeHandle pnh_
ros::Subscriber sub_watchdog_
ros::Subscriber sub_twist_
pcl::PointXYZ operator-(const pcl::PointXYZ &a, const pcl::PointXYZ &b)


safety_limiter
Author(s): Atsushi Watanabe
autogenerated on Tue Jul 9 2019 05:00:02