CARLA
LibCarla/source/carla/rss/RssSensor.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2020 Intel Corporation
2 //
3 // This work is licensed under the terms of the MIT license.
4 // For a copy, see <https://opensource.org/licenses/MIT>.
5 
6 #include "carla/rss/RssSensor.h"
7 
8 #include <ad/map/access/Operation.hpp>
9 #include <ad/rss/state/ProperResponse.hpp>
10 #include <ad/rss/world/Velocity.hpp>
11 #include <exception>
12 #include <fstream>
13 
14 #include "carla/Logging.h"
15 #include "carla/client/Map.h"
16 #include "carla/client/Sensor.h"
17 #include "carla/client/Vehicle.h"
19 #include "carla/rss/RssCheck.h"
21 
22 namespace carla {
23 namespace client {
24 
26 
27 RssSensor::RssSensor(ActorInitializer init) : Sensor(std::move(init)), _on_tick_register_id(0u), _drop_route(false) {}
28 
30  // ensure there is no processing anymore
31  if (IsListening()) {
32  Stop();
33  }
34 }
35 
37  if (IsListening()) {
39  ": registering of the actor constellation callback has to be done before start listening. Register has "
40  "no effect.");
41  return;
42  }
44 }
45 
47  if (IsListening()) {
48  log_error(GetDisplayId(), ": already listening");
49  return;
50  }
51 
52  if (GetParent() == nullptr) {
53  throw_exception(std::runtime_error(GetDisplayId() + ": not attached to actor"));
54  return;
55  }
56 
57  auto vehicle = boost::dynamic_pointer_cast<carla::client::Vehicle>(GetParent());
58  if (vehicle == nullptr) {
59  throw_exception(std::runtime_error(GetDisplayId() + ": parent is not a vehicle"));
60  return;
61  }
62 
63  // get maximum steering angle
64  float max_steer_angle_deg = 0.f;
65  for (auto const &wheel : vehicle->GetPhysicsControl().GetWheels()) {
66  max_steer_angle_deg = std::max(max_steer_angle_deg, wheel.max_steer_angle);
67  }
68  auto max_steering_angle = max_steer_angle_deg * static_cast<float>(M_PI) / 180.0f;
69 
70  auto map = GetWorld().GetMap();
71  DEBUG_ASSERT(map != nullptr);
72  std::string const open_drive_content = map->GetOpenDrive();
73 
74  auto mapInitializationResult = ::ad::map::access::initFromOpenDriveContent(
76  ::ad::map::landmark::TrafficLightType::LEFT_STRAIGHT_RED_YELLOW_GREEN);
77 
78  if (!mapInitializationResult) {
79  log_error(GetDisplayId(), ": Initialization of map failed");
80  return;
81  }
82 
84 
85  if (_rss_actor_constellation_callback == nullptr) {
86  _rss_check = std::make_shared<::carla::rss::RssCheck>(max_steering_angle);
87  } else {
88  _rss_check =
89  std::make_shared<::carla::rss::RssCheck>(max_steering_angle, _rss_actor_constellation_callback, GetParent());
90  }
91 
92  auto self = boost::static_pointer_cast<RssSensor>(shared_from_this());
93 
95  log_debug(GetDisplayId(), ": subscribing to tick event");
96  _on_tick_register_id = GetEpisode().Lock()->RegisterOnTickEvent(
97  [ cb = std::move(callback), weak_self = WeakPtr<RssSensor>(self) ](const auto &snapshot) {
98  auto self = weak_self.lock();
99  if (self != nullptr) {
100  self->TickRssSensor(snapshot.GetTimestamp(), cb);
101  }
102  });
103 }
104 
106  if (!IsListening()) {
107  log_error(GetDisplayId(), ": not listening at all");
108  return;
109  }
110 
111  log_debug(GetDisplayId(), ": unsubscribing from tick event");
112  GetEpisode().Lock()->RemoveOnTickEvent(_on_tick_register_id);
114 
115  if ( bool(_rss_check) ) {
116  _rss_check->GetLogger()->info("RssSensor stopping");
117  }
118  // don't remove the braces since they protect the lock_guard
119  {
120  // ensure there is no processing anymore when deleting rss_check object
121  const std::lock_guard<std::mutex> lock(_processing_lock);
122 
123  if ( bool(_rss_check) ) {
124  _rss_check->GetLogger()->info("RssSensor delete checker");
125  }
126  _rss_check.reset();
127  auto const map_initialization_counter_value = _global_map_initialization_counter_--;
128  if (map_initialization_counter_value == 0u) {
129  // last one stop listening is cleaning up the map
130  ::ad::map::access::cleanup();
131  }
132  }
133 }
134 
135 void RssSensor::SetLogLevel(const uint8_t &log_level) {
136  if (!bool(_rss_check)) {
137  log_error(GetDisplayId(), ": not yet listening. SetLogLevel has no effect.");
138  return;
139  }
140 
141  if (log_level < spdlog::level::n_levels) {
142  _rss_check->SetLogLevel(spdlog::level::level_enum(log_level));
143  }
144 }
145 
146 void RssSensor::SetMapLogLevel(const uint8_t &map_log_level) {
147  if (!bool(_rss_check)) {
148  log_error(GetDisplayId(), ": not yet listening. SetMapLogLevel has no effect.");
149  return;
150  }
151 
152  if (map_log_level < spdlog::level::n_levels) {
153  _rss_check->SetMapLogLevel(spdlog::level::level_enum(map_log_level));
154  }
155 }
156 
157 const ::ad::rss::world::RssDynamics &RssSensor::GetEgoVehicleDynamics() const {
158  static auto default_vehicle_dynamics = rss::RssCheck::GetDefaultVehicleDynamics();
159  if (!bool(_rss_check)) {
160  log_error(GetDisplayId(), ": not yet listening. GetEgoVehicleDynamics has no effect.");
161  return default_vehicle_dynamics;
162  }
163 
165  log_error(GetDisplayId(), ": Actor constellation callback registered. GetEgoVehicleDynamics has no effect.");
166  return default_vehicle_dynamics;
167  }
168 
169  return _rss_check->GetDefaultActorConstellationCallbackEgoVehicleDynamics();
170 }
171 
172 void RssSensor::SetEgoVehicleDynamics(const ::ad::rss::world::RssDynamics &ego_dynamics) {
173  if (!bool(_rss_check)) {
174  log_error(GetDisplayId(), ": not yet listening. SetEgoVehicleDynamics has no effect.");
175  return;
176  }
177 
179  log_error(GetDisplayId(), ": Actor constellation callback registered. SetEgoVehicleDynamics has no effect.");
180  return;
181  }
182 
183  _rss_check->SetDefaultActorConstellationCallbackEgoVehicleDynamics(ego_dynamics);
184 }
185 
186 const ::ad::rss::world::RssDynamics &RssSensor::GetOtherVehicleDynamics() const {
187  static auto default_vehicle_dynamics = rss::RssCheck::GetDefaultVehicleDynamics();
188  if (!bool(_rss_check)) {
189  log_error(GetDisplayId(), ": not yet listening. GetOtherVehicleDynamics has no effect.");
190  return default_vehicle_dynamics;
191  }
192 
194  log_error(GetDisplayId(), ": Actor constellation callback registered. GetOtherVehicleDynamics has no effect.");
195  return default_vehicle_dynamics;
196  }
197 
198  return _rss_check->GetDefaultActorConstellationCallbackOtherVehicleDynamics();
199 }
200 
201 void RssSensor::SetOtherVehicleDynamics(const ::ad::rss::world::RssDynamics &other_vehicle_dynamics) {
202  if (!bool(_rss_check)) {
203  log_error(GetDisplayId(), ": not yet listening. SetOtherVehicleDynamics has no effect.");
204  return;
205  }
206 
208  log_error(GetDisplayId(), ": Actor constellation callback registered. SetOtherVehicleDynamics has no effect.");
209  return;
210  }
211 
212  _rss_check->SetDefaultActorConstellationCallbackOtherVehicleDynamics(other_vehicle_dynamics);
213 }
214 
215 const ::ad::rss::world::RssDynamics &RssSensor::GetPedestrianDynamics() const {
216  static auto default_pedestrian_dynamics = rss::RssCheck::GetDefaultPedestrianDynamics();
217  if (!bool(_rss_check)) {
218  log_error(GetDisplayId(), ": not yet listening. GetPedestrianDynamics has no effect.");
219  return default_pedestrian_dynamics;
220  }
221 
223  log_error(GetDisplayId(), ": Actor constellation callback registered. GetPedestrianDynamics has no effect.");
224  return default_pedestrian_dynamics;
225  }
226 
227  return _rss_check->GetDefaultActorConstellationCallbackPedestrianDynamics();
228 }
229 
230 void RssSensor::SetPedestrianDynamics(const ::ad::rss::world::RssDynamics &pedestrian_dynamics) {
231  if (!bool(_rss_check)) {
232  log_error(GetDisplayId(), ": not yet listening. SetPedestrianDynamics has no effect.");
233  return;
234  }
235 
237  log_error(GetDisplayId(), ": Actor constellation callback registered. SetPedestrianDynamics has no effect.");
238  return;
239  }
240 
241  _rss_check->SetDefaultActorConstellationCallbackPedestrianDynamics(pedestrian_dynamics);
242 }
243 
245  if (!bool(_rss_check)) {
246  log_error(GetDisplayId(), ": not yet listening. GetRoadBoundariesMode has no effect.");
247  static auto default_road_boundaries_mode = rss::RssCheck::GetDefaultRoadBoundariesMode();
248  return default_road_boundaries_mode;
249  }
250 
251  return _rss_check->GetRoadBoundariesMode();
252 }
253 
255  if (!bool(_rss_check)) {
256  log_error(GetDisplayId(), ": not yet listening. SetRoadBoundariesMode has no effect.");
257  return;
258  }
259 
260  _rss_check->SetRoadBoundariesMode(road_boundaries_mode);
261 }
262 
264  if (!bool(_rss_check)) {
265  log_error(GetDisplayId(), ": not yet listening. AppendRoutingTarget has no effect.");
266  return;
267  }
268 
269  _rss_check->AppendRoutingTarget(routing_target);
270 }
271 
272 const std::vector<::carla::geom::Transform> RssSensor::GetRoutingTargets() const {
273  if (!bool(_rss_check)) {
274  log_error(GetDisplayId(), ": not yet listening. GetRoutingTargets has no effect.");
275  return std::vector<::carla::geom::Transform>();
276  }
277 
278  return _rss_check->GetRoutingTargets();
279 }
280 
282  if (!bool(_rss_check)) {
283  log_error(GetDisplayId(), ": not yet listening. ResetRoutingTargets has no effect.");
284  return;
285  }
286 
287  _rss_check->ResetRoutingTargets();
288 }
289 
291  // don't execute this immediately as it might break calculations completely
292  // postpone to next sensor tick
293  _drop_route = true;
294 }
295 
297  if (_processing_lock.try_lock()) {
298  if (!bool(_rss_check)){
299  _processing_lock.unlock();
300  return;
301  }
302  if ((timestamp.frame < _last_processed_frame) && ((_last_processed_frame - timestamp.frame) < 0xffffffffu)) {
303  _processing_lock.unlock();
304  _rss_check->GetLogger()->warn("RssSensor[{}] outdated tick dropped, LastProcessed={}", timestamp.frame, _last_processed_frame);
305  return;
306  }
307  _last_processed_frame = timestamp.frame;
309 
310  auto const settings = GetWorld().GetSettings();
311  if ( settings.synchronous_mode ) {
312  _rss_check->GetLogger()->trace("RssSensor[{}] sync-tick", timestamp.frame);
313  TickRssSensorThreadLocked(timestamp, actors, callback);
314  }
315  else {
316  // store the future to prevent the destructor of the future from blocked waiting
317  _rss_check->GetLogger()->trace("RssSensor[{}] async-tick", timestamp.frame);
318  _tick_future = std::async(&RssSensor::TickRssSensorThreadLocked, this, timestamp, actors, callback);
319  }
320  } else {
321  if (bool(_rss_check)){
322  _rss_check->GetLogger()->debug("RssSensor[{}] tick dropped", timestamp.frame);
323  }
324  }
325 }
326 
329  try {
330  double const time_since_epoch_check_start_ms =
331  std::chrono::duration<double, std::milli>(std::chrono::system_clock::now().time_since_epoch()).count();
332 
333  if (_drop_route) {
334  _drop_route = false;
335  _rss_check->DropRoute();
336  }
337 
338  // check all object<->ego pairs with RSS and calculate proper response
339  ::ad::rss::state::ProperResponse response;
340  ::ad::rss::state::RssStateSnapshot rss_state_snapshot;
341  ::ad::rss::situation::SituationSnapshot situation_snapshot;
342  ::ad::rss::world::WorldModel world_model;
343  carla::rss::EgoDynamicsOnRoute ego_dynamics_on_route;
344  auto const result = _rss_check->CheckObjects(timestamp, actors, GetParent(), response, rss_state_snapshot,
345  situation_snapshot, world_model, ego_dynamics_on_route);
346 
347  double const time_since_epoch_check_end_ms =
348  std::chrono::duration<double, std::milli>(std::chrono::system_clock::now().time_since_epoch()).count();
349  auto const delta_time_ms = time_since_epoch_check_end_ms - time_since_epoch_check_start_ms;
350  _rss_check->GetLogger()->debug("RssSensor[{}] response: S:{}->E:{} DeltaT:{}", timestamp.frame,
351  time_since_epoch_check_start_ms, time_since_epoch_check_end_ms,
352  delta_time_ms);
353  _rss_check_timings.push_back(delta_time_ms);
354  while (_rss_check_timings.size() > 10u) {
355  _rss_check_timings.pop_front();
356  }
357  double agv_time=0.;
358  for (auto run_time: _rss_check_timings) {
359  agv_time += run_time;
360  }
361  agv_time /= _rss_check_timings.size();
362  _rss_check->GetLogger()->info("RssSensor[{}] runtime {} avg {}", timestamp.frame, delta_time_ms, agv_time);
363  _processing_lock.unlock();
364 
365  callback(MakeShared<sensor::data::RssResponse>(timestamp.frame, timestamp.elapsed_seconds, GetTransform(), result,
366  response, rss_state_snapshot, situation_snapshot, world_model,
367  ego_dynamics_on_route));
368  } catch (const std::exception &e) {
369  _rss_check->GetLogger()->error("RssSensor[{}] tick exception", timestamp.frame);
370  _processing_lock.unlock();
371  } catch (...) {
372  _rss_check->GetLogger()->error("RssSensor[{}] tick exception", timestamp.frame);
373  _processing_lock.unlock();
374  }
375 }
376 
377 } // namespace client
378 } // namespace carla
std::list< double > _rss_check_timings
some debug timings
std::function<::carla::rss::ActorConstellationResult(carla::SharedPtr<::carla::rss::ActorConstellationData >)> ActorConstellationCallbackFunctionType
void TickRssSensorThreadLocked(const client::Timestamp &timestamp, SharedPtr< carla::client::ActorList > actors, CallbackFunctionType callback)
std::shared_ptr<::carla::rss::RssCheck > _rss_check
struct defining the ego vehicles current dynamics in respect to the current route ...
Definition: RssCheck.h:40
void SetEgoVehicleDynamics(const ::ad::rss::world::RssDynamics &ego_dynamics)
sets the ego vehicle dynamics to be used by the ego vehicle (
void Listen(CallbackFunctionType callback) override
Register a callback to be executed each time a new measurement is received.
void SetMapLogLevel(const uint8_t &map_log_level)
sets the current map log level
SharedPtr< ActorList > GetActors() const
Return a list with all the actors currently present in the world.
Definition: World.cpp:106
void DropRoute()
drop the current route (
void throw_exception(const std::exception &e)
Definition: Carla.cpp:135
void SetLogLevel(const uint8_t &log_level)
sets the current log level
std::mutex _processing_lock
the mutex to protect the actual RSS processing and in case it takes too long to process ever frame ...
static void log_error(Args &&... args)
Definition: Logging.h:110
const ::ad::rss::world::RssDynamics & GetPedestrianDynamics() const
boost::shared_ptr< T > SharedPtr
Use this SharedPtr (boost::shared_ptr) to keep compatibility with boost::python, but it would be nice...
Definition: Memory.h:20
This file contains definitions of common data structures used in traffic manager. ...
Definition: Carla.cpp:133
std::size_t frame
Number of frames elapsed since the simulator was launched.
Definition: Timestamp.h:30
SharedPtr< Map > GetMap() const
Return the map that describes this world.
Definition: World.cpp:24
std::size_t _on_tick_register_id
the id got when registering for the on tick event
The RSS Sensor class implementing the carla::client::Sensor interface This class is a proxy to the Rs...
void SetRoadBoundariesMode(const ::carla::rss::RoadBoundariesMode &road_boundaries_mode)
sets the current mode for respecting the road boundaries (
static void log_debug(Args &&...)
Definition: Logging.h:75
const std::string & GetDisplayId() const
static RoadBoundariesMode GetDefaultRoadBoundariesMode()
Definition: RssCheck.h:217
Used to initialize Actor classes.
#define DEBUG_ASSERT(predicate)
Definition: Debug.h:66
::ad::rss::world::RssDynamics GetDefaultPedestrianDynamics()
Definition: RssCheck.cpp:107
void SetOtherVehicleDynamics(const ::ad::rss::world::RssDynamics &other_vehicle_dynamics)
sets the ego vehicle dynamics to be used by other vehicles (
void AppendRoutingTarget(const ::carla::geom::Transform &routing_target)
appends a routing target to the current routing target list (
void ResetRoutingTargets()
resets the current routing target (
RoadBoundariesMode
struct defining the different supported handling of road boundaries
Definition: RssCheck.h:28
const ::ad::rss::world::RssDynamics & GetEgoVehicleDynamics() const
geom::Transform GetTransform() const
Return the current transform of the actor.
Definition: Actor.cpp:19
void TickRssSensor(const client::Timestamp &timestamp, CallbackFunctionType callback)
the acutal sensor tick callback function
const ::ad::rss::world::RssDynamics & GetOtherVehicleDynamics() const
void RegisterActorConstellationCallback(ActorConstellationCallbackFunctionType callback)
Register a callback to be executed for each actor within each measurement to be processed to decide o...
static std::atomic_uint _global_map_initialization_counter_
SharedPtr< Actor > GetParent() const
Definition: ActorState.cpp:31
std::function< void(SharedPtr< sensor::SensorData >)> CallbackFunctionType
std::size_t _last_processed_frame
last processed frame
bool IsListening() const override
Return whether this Sensor instance is currently listening to the associated sensor in the simulator...
bool _drop_route
reqired to store DropRoute() requests until next sensor tick
std::future< void > _tick_future
the future for the async ticking thread
ActorConstellationCallbackFunctionType _rss_actor_constellation_callback
SharedPtrType Lock() const
Same as TryLock but never return nullptr.
boost::weak_ptr< T > WeakPtr
Definition: Memory.h:23
const ::carla::rss::RoadBoundariesMode & GetRoadBoundariesMode() const
rpc::EpisodeSettings GetSettings() const
Definition: World.cpp:52
void Stop() override
Stop listening for new measurements.
void SetPedestrianDynamics(const ::ad::rss::world::RssDynamics &pedestrian_dynamics)
sets the ego vehicle dynamics to be used by pedestrians (
::ad::rss::world::RssDynamics GetDefaultVehicleDynamics()
Definition: RssCheck.cpp:88
double elapsed_seconds
Simulated seconds elapsed since the beginning of the current episode.
Definition: Timestamp.h:33
geom::Transform Transform
Definition: rpc/Transform.h:16
const std::vector<::carla::geom::Transform > GetRoutingTargets() const
RssSensor(ActorInitializer init)
constructor