Autonomous Racing  1
f1tenth Project Group of Technical University Dortmund, Germany
emergency_stop.cpp
Go to the documentation of this file.
1 #include "emergency_stop.h"
2 #include <std_msgs/Time.h>
3 
5  : m_emergency_status(EmergencyStatus::UNUSED)
6  , m_debug_geometry(this->m_node_handle, TOPIC_VISUALIZATION, LIDAR_FRAME)
7 {
8  m_lidar_subscriber =
9  m_node_handle.subscribe<sensor_msgs::LaserScan>(TOPIC_LASER_SCAN, 1, &EmergencyStop::lidarCallback, this);
10  m_emergency_stop_publisher = m_node_handle.advertise<std_msgs::Time>(TOPIC_EMERGENCY_STOP, 1);
11 
12  this->updateDynamicConfig();
13 
14  m_dyn_cfg_server.setCallback([&](emergency_stop::emergency_stopConfig& cfg, uint32_t) {
15  m_range_threshold = cfg.range_threshold;
16  m_car_bumper_length = cfg.car_bumper_length;
17  m_max_range = cfg.max_range;
18  });
19 }
20 
21 bool EmergencyStop::emergencyStop(const sensor_msgs::LaserScan::ConstPtr& lidar)
22 {
23  ROS_ASSERT_MSG(m_range_threshold <= m_max_range,
24  "Threshold is bigger then max range. Function will always return false.");
25  ROS_ASSERT_MSG(m_max_range > 0, "Max range is zero or below. Function will mostly return true.");
26  ROS_ASSERT_MSG(m_range_threshold > 0, "Threshold is zero or below. Function will mostly return false.");
27 
28  int available_samples = (lidar->angle_max - lidar->angle_min) / lidar->angle_increment;
29 
30  // calculate the sample_angle of the lidar to be used to check if there is
31  // an obstacle in front of the car, with respect to the m_range_threshold
32  // We want to check every lidar sample that is located in front of the car at a distance of m_range_threshold.
33  float sample_angle = std::atan(m_car_bumper_length / 2 / m_range_threshold);
34 
35  int index_start = available_samples / 2 - sample_angle / lidar->angle_increment / 2;
36  int index_end = available_samples / 2 + sample_angle / lidar->angle_increment / 2;
37  ROS_ASSERT_MSG(index_start >= 0 && index_end < available_samples,
38  "sample_angle is too big. Trying to access lidar samples out of bounds.");
39 
40  // determine the minimum distance between the car and a potetial obstacle
41  // Instead of calculating the range average, we are more cautious because we would
42  // rather have false positives instead of false negatives.
43  // i.e. we would rather stop too much than crash into an obstacle.
44  auto min_range = std::min(m_max_range, *std::min_element(lidar->ranges.begin() + index_start,
45  lidar->ranges.begin() + index_end));
46  ROS_ASSERT_MSG(min_range >= 0, "The minimal distance between the car and a potential obstacle is below zero.");
47 
48  const float car_bumper_length_half = m_car_bumper_length / 2;
49  // Min range to obstacle
50  this->m_debug_geometry.drawLine(1, createPoint(min_range, -car_bumper_length_half, 0),
51  createPoint(min_range, car_bumper_length_half, 0), createColor(1., 1., 0, 1.),
52  0.03);
53 
54  // Range threshold
55  if (!(min_range < m_range_threshold))
56  {
57  m_debug_geometry.drawLine(0, createPoint(m_range_threshold, -car_bumper_length_half, 0),
58  createPoint(m_range_threshold, car_bumper_length_half, 0), createColor(0, 1., 0, 1.),
59  0.03);
60  }
61  else
62  {
63  this->m_debug_geometry.drawLine(0, createPoint(m_range_threshold, -car_bumper_length_half, 0),
64  createPoint(m_range_threshold, car_bumper_length_half, 0),
65  createColor(1., 0, 0, 1.), 0.03);
66  }
67 
68  return min_range < m_range_threshold;
69 }
70 
71 void EmergencyStop::lidarCallback(const sensor_msgs::LaserScan::ConstPtr& lidar)
72 {
73  bool emergency_stop_active = emergencyStop(lidar);
74 
75  this->m_emergency_status = (this->m_emergency_status == EmergencyStatus::UNUSED)
76  ? emergency_stop_active ? EmergencyStatus::ACTIVATED : EmergencyStatus::CLEARED
77  : this->m_emergency_status;
78 
79  if (emergency_stop_active)
80  {
81  if (this->m_emergency_status == EmergencyStatus::ACTIVATED)
82  {
83  ROS_WARN_STREAM("Wall detected. Emergency stop is active.");
84  this->m_emergency_status = EmergencyStatus::CLEARED;
85  }
86 
87  std_msgs::Time message;
88  message.data = ros::Time::now();
89 
90  m_emergency_stop_publisher.publish(message);
91  }
92  else
93  {
94  if (this->m_emergency_status == EmergencyStatus::CLEARED)
95  {
96  ROS_WARN_STREAM("Emergency stop is inactive.");
97  this->m_emergency_status = EmergencyStatus::ACTIVATED;
98  }
99  }
100 }
101 
102 void EmergencyStop::updateDynamicConfig()
103 {
104  emergency_stop::emergency_stopConfig cfg;
105  {
106  cfg.range_threshold = m_range_threshold;
107  cfg.car_bumper_length = m_car_bumper_length;
108  cfg.max_range = m_max_range;
109  }
110  m_dyn_cfg_server.updateConfig(cfg);
111 }
112 
113 int main(int argc, char** argv)
114 {
115  ros::init(argc, argv, "emergency_stop");
116  EmergencyStop emergency_stop;
117  ros::spin();
118  return EXIT_SUCCESS;
119 }
constexpr const char * TOPIC_LASER_SCAN
int main(int argc, char **argv)
constexpr const char * LIDAR_FRAME
std_msgs::ColorRGBA createColor(double r, double g, double b, double a)
constexpr const char * TOPIC_VISUALIZATION
EmergencyStatus
void drawLine(int id, geometry_msgs::Point point1, geometry_msgs::Point point2, std_msgs::ColorRGBA color, float width)
geometry_msgs::Point createPoint(float x, float y, float z)
constexpr const char * TOPIC_EMERGENCY_STOP