CARLA
Loading...
Searching...
No Matches
BehaviorAgent.cpp
Go to the documentation of this file.
1// Copyright (c) 2018-2020 CVC.
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
7
10#include "carla/client/Actor.h"
12#include "carla/client/Map.h"
15#include "carla/client/World.h"
17#include "carla/geom/Location.h"
19#include "carla/road/Lane.h"
22
23#include <algorithm>
24#include <cmath>
25#include <iostream>
26#include <type_traits>
27
28namespace carla {
29namespace agents {
30namespace navigation {
31
32namespace {
33
35
36 /// True if a `LaneChange` value contains the `flag` bit
37 /// (mirrors Python `==` checks like `right_turn == LaneChange.Right` /
38 /// `right_turn == LaneChange.Both`).
39 bool HasLaneChange(LaneChange value, LaneChange flag) {
40 using U = std::underlying_type_t<LaneChange>;
41 return (static_cast<U>(value) & static_cast<U>(flag)) == static_cast<U>(flag);
42 }
43
44 BehaviorParameters BehaviorParamsFor(BehaviorAgent::Behavior b) {
45 switch (b) {
49 default: return BehaviorParameters::Normal();
50 }
51 }
52
53} // anonymous namespace
54
55// ---------------------------------------------------------------------------
56// Construction
57// ---------------------------------------------------------------------------
58
60 Behavior behavior,
61 const Options &opts,
64 : BasicAgent(vehicle, /*target_speed_kmh=*/20.0f, opts, map, grp),
65 _behavior(BehaviorParamsFor(behavior)) {
66 // Match the Python BehaviorAgent override of the sampling resolution.
68}
69
70// ---------------------------------------------------------------------------
71// Information refresh
72// ---------------------------------------------------------------------------
73
76 _speed_limit = _vehicle->GetSpeedLimit();
77 // Even when follow_speed_limits is on this seed mirrors the Python reference.
79
80 _direction = _local_planner->TargetRoadOption();
83 }
84
85 _look_ahead_steps = static_cast<int>(_speed_limit / 10.0f);
86
87 auto incoming = _local_planner->GetIncomingWaypointAndDirection(_look_ahead_steps);
88 _incoming_waypoint = incoming.first;
89 _incoming_direction = incoming.second;
92 }
93}
94
95// ---------------------------------------------------------------------------
96// Traffic light handling
97// ---------------------------------------------------------------------------
98
100 auto actor_list = _world->GetActors();
101 auto lights_list = actor_list ? actor_list->Filter("*traffic_light*") : nullptr;
102 auto result = AffectedByTrafficLight(lights_list);
103 return result.first;
104}
105
106// ---------------------------------------------------------------------------
107// Tailgating
108// ---------------------------------------------------------------------------
109
111 // Python passes the prefiltered vehicle list around; the base helper
112 // `VehicleObstacleDetected` accepts a `SharedPtr<ActorList>` and applies
113 // its own proximity gating via `max_distance`, so we hand it the
114 // world-wide vehicle filter result here.
115 auto left_marking = waypoint->GetLeftLaneMarking();
116 auto right_marking = waypoint->GetRightLaneMarking();
117 auto left_wpt = waypoint->GetLeft();
118 auto right_wpt = waypoint->GetRight();
119
120 // Build the world-vehicle ActorList passthrough (matches Python's reuse of
121 // the filtered list).
122 auto vehicles_alist = _world->GetActors()
123 ? _world->GetActors()->Filter("*vehicle*")
124 : nullptr;
125
126 const float behind_max =
128
129 auto behind = VehicleObstacleDetected(vehicles_alist,
130 behind_max,
131 /*up_angle_th=*/180.0f,
132 /*low_angle_th=*/160.0f,
133 /*lane_offset=*/0);
134
135 if (!(behind.affected && behind.actor)) return;
136 if (_speed >= GetSpeed(behind.actor)) return;
137
138 const int wp_lane_id = waypoint->GetLaneId();
139
140 // Right-lane tailgate avoidance.
141 if (right_marking.has_value() && right_wpt &&
142 (HasLaneChange(right_marking->lane_change, LaneChange::Right) ||
143 HasLaneChange(right_marking->lane_change, LaneChange::Both)) &&
144 (wp_lane_id * right_wpt->GetLaneId() > 0) &&
145 right_wpt->GetType() == road::Lane::LaneType::Driving) {
146 auto check = VehicleObstacleDetected(vehicles_alist,
147 behind_max,
148 /*up_angle_th=*/180.0f,
149 /*low_angle_th=*/0.0f,
150 /*lane_offset=*/1);
151 if (!check.affected) {
152 std::cout << "Tailgating, moving to the right!" << std::endl;
153 auto end_waypoint = _local_planner->TargetWaypoint();
155 if (end_waypoint) {
156 SetDestination(end_waypoint->GetTransform().location,
157 right_wpt->GetTransform().location);
158 }
159 }
160 return;
161 }
162
163 // Left-lane tailgate avoidance.
164 if (left_marking.has_value() && left_wpt &&
165 HasLaneChange(left_marking->lane_change, LaneChange::Left) &&
166 (wp_lane_id * left_wpt->GetLaneId() > 0) &&
167 left_wpt->GetType() == road::Lane::LaneType::Driving) {
168 auto check = VehicleObstacleDetected(vehicles_alist,
169 behind_max,
170 /*up_angle_th=*/180.0f,
171 /*low_angle_th=*/0.0f,
172 /*lane_offset=*/-1);
173 if (!check.affected) {
174 std::cout << "Tailgating, moving to the left!" << std::endl;
175 auto end_waypoint = _local_planner->TargetWaypoint();
177 if (end_waypoint) {
178 SetDestination(end_waypoint->GetTransform().location,
179 left_wpt->GetTransform().location);
180 }
181 }
182 }
183}
184
185// ---------------------------------------------------------------------------
186// Vehicle / pedestrian managers
187// ---------------------------------------------------------------------------
188
191 auto vehicles_alist = _world->GetActors()
192 ? _world->GetActors()->Filter("*vehicle*")
193 : nullptr;
194
195 // Python applies a 45 m prefilter around the waypoint here (excluding the
196 // ego). The base helper `VehicleObstacleDetected` honors `max_distance`
197 // internally, so we just route the world-wide vehicle list to it.
198 VehicleObstacle obs;
201 vehicles_alist,
203 /*up_angle_th=*/180.0f,
204 /*low_angle_th=*/0.0f,
205 /*lane_offset=*/-1);
208 vehicles_alist,
210 /*up_angle_th=*/180.0f,
211 /*low_angle_th=*/0.0f,
212 /*lane_offset=*/1);
213 } else {
215 vehicles_alist,
217 /*up_angle_th=*/30.0f,
218 /*low_angle_th=*/0.0f,
219 /*lane_offset=*/0);
220
221 // Tailgating check.
222 if (!obs.affected &&
224 !waypoint->IsJunction() &&
225 _speed > 10.0f &&
227 Tailgating(waypoint);
228 }
229 }
230
231 return obs;
232}
233
236 auto walkers_alist = _world->GetActors()
237 ? _world->GetActors()->Filter("*walker.pedestrian*")
238 : nullptr;
239
240 // Python applies a 10 m prefilter around the waypoint here. The base
241 // `VehicleObstacleDetected` honors `max_distance` internally, so we let
242 // it do the proximity gating from the world-wide walker list.
243 (void)waypoint; // location consumed indirectly via VehicleObstacleDetected
244 VehicleObstacle obs;
247 walkers_alist,
249 /*up_angle_th=*/90.0f,
250 /*low_angle_th=*/0.0f,
251 /*lane_offset=*/-1);
254 walkers_alist,
256 /*up_angle_th=*/90.0f,
257 /*low_angle_th=*/0.0f,
258 /*lane_offset=*/1);
259 } else {
261 walkers_alist,
263 /*up_angle_th=*/60.0f,
264 /*low_angle_th=*/0.0f,
265 /*lane_offset=*/0);
266 }
267 return obs;
268}
269
270// ---------------------------------------------------------------------------
271// Car-following control law
272// ---------------------------------------------------------------------------
273
275 SharedPtr<client::Actor> vehicle, float distance, bool debug) {
276 const float vehicle_speed = GetSpeed(vehicle);
277 const float delta_v = std::max(1.0f, (_speed - vehicle_speed) / 3.6f);
278 const float ttc = (delta_v != 0.0f)
279 ? distance / delta_v
280 : distance / std::nextafter(0.0f, 1.0f);
281
282 float target_speed = 0.0f;
283 if (_behavior.safety_time > ttc && ttc > 0.0f) {
284 target_speed = std::min({
285 Positive(vehicle_speed - _behavior.speed_decrease),
288 } else if (2.0f * _behavior.safety_time > ttc && ttc >= _behavior.safety_time) {
289 target_speed = std::min({
290 std::max(_min_speed, vehicle_speed),
293 } else {
294 target_speed = std::min({
297 }
298 _local_planner->SetSpeed(target_speed);
299 return _local_planner->RunStep(debug);
300}
301
302// ---------------------------------------------------------------------------
303// Main run-step
304// ---------------------------------------------------------------------------
305
308
309 if (_behavior.tailgate_counter > 0) {
311 }
312
313 const auto ego_vehicle_loc = _vehicle->GetLocation();
314 auto ego_vehicle_wp = _map->GetWaypoint(ego_vehicle_loc);
315
316 // 1. Red lights / stops.
317 if (TrafficLightManager()) {
318 return EmergencyStop();
319 }
320
321 // 2.1: Pedestrian avoidance.
322 auto walker_obs = PedestrianAvoidManager(ego_vehicle_wp);
323 if (walker_obs.affected && walker_obs.actor) {
324 const auto &walker_extent = walker_obs.actor->GetBoundingBox().extent;
325 const auto &ego_extent = _vehicle->GetBoundingBox().extent;
326 const float distance = walker_obs.distance
327 - std::max(walker_extent.y, walker_extent.x)
328 - std::max(ego_extent.y, ego_extent.x);
330 return EmergencyStop();
331 }
332 }
333
334 // 2.2: Vehicle avoidance / car following.
335 auto vehicle_obs = CollisionAndCarAvoidManager(ego_vehicle_wp);
336 rpc::VehicleControl control{};
337 if (vehicle_obs.affected && vehicle_obs.actor) {
338 const auto &v_extent = vehicle_obs.actor->GetBoundingBox().extent;
339 const auto &ego_extent = _vehicle->GetBoundingBox().extent;
340 const float distance = vehicle_obs.distance
341 - std::max(v_extent.y, v_extent.x)
342 - std::max(ego_extent.y, ego_extent.x);
344 return EmergencyStop();
345 }
346 control = CarFollowingManager(vehicle_obs.actor, distance, debug);
347 }
348 // 3: Intersection behaviour (left/right turn).
349 else if (_incoming_waypoint && _incoming_waypoint->IsJunction() &&
352 const float target_speed = std::min(_behavior.max_speed,
353 _speed_limit - 5.0f);
354 _local_planner->SetSpeed(target_speed);
355 control = _local_planner->RunStep(debug);
356 }
357 // 4: Normal behaviour.
358 else {
359 const float target_speed = std::min(_behavior.max_speed,
361 _local_planner->SetSpeed(target_speed);
362 control = _local_planner->RunStep(debug);
363 }
364 return control;
365}
366
367// ---------------------------------------------------------------------------
368// Emergency stop
369// ---------------------------------------------------------------------------
370
372 rpc::VehicleControl control{};
373 control.throttle = 0.0f;
374 control.brake = _max_brake;
375 control.hand_brake = false;
376 return control;
377}
378
379} // namespace navigation
380} // namespace agents
381} // namespace carla
float distance
C++ port of agents.navigation.basic_agent.BasicAgent.
Definition BasicAgent.h:44
SharedPtr< client::Map > _map
Definition BasicAgent.h:151
std::pair< bool, SharedPtr< client::TrafficLight > > AffectedByTrafficLight(SharedPtr< client::ActorList > lights=nullptr, std::optional< float > max_distance=std::nullopt)
Returns (affected, light) similar to Python _affected_by_traffic_light.
VehicleObstacle VehicleObstacleDetected(SharedPtr< client::ActorList > vehicles=nullptr, std::optional< float > max_distance=std::nullopt, float up_angle_th=90.0f, float low_angle_th=0.0f, int lane_offset=0)
Mirrors Python _vehicle_obstacle_detected.
SharedPtr< client::World > _world
Definition BasicAgent.h:150
SharedPtr< client::Vehicle > _vehicle
Definition BasicAgent.h:149
std::unique_ptr< LocalPlanner > _local_planner
Definition BasicAgent.h:153
void SetDestination(const geom::Location &end, std::optional< geom::Location > start=std::nullopt)
Computes a route from start (or the current target waypoint) to end and forwards it to the local plan...
rpc::VehicleControl CarFollowingManager(SharedPtr< client::Actor > vehicle, float distance, bool debug=false)
Car-following control law applied when there is a vehicle in front.
rpc::VehicleControl EmergencyStop() const
Build an emergency-stop control: throttle=0, brake=_max_brake, hand_brake=false, steer left untouched...
VehicleObstacle PedestrianAvoidManager(SharedPtr< client::Waypoint > waypoint)
Detect pedestrians ahead.
rpc::VehicleControl RunStep() override
Polymorphic entry point: keeps dispatch through BasicAgent* correct.
VehicleObstacle CollisionAndCarAvoidManager(SharedPtr< client::Waypoint > waypoint)
Detect collision/car-avoidance opportunities ahead.
void Tailgating(SharedPtr< client::Waypoint > waypoint)
Tailgating-avoidance lane change, called from CollisionAndCarAvoidManager.
BehaviorAgent(SharedPtr< client::Vehicle > vehicle, Behavior behavior=Behavior::Normal, const Options &opts=BasicAgent::DefaultOptions(), SharedPtr< client::Map > map=nullptr, SharedPtr< GlobalRoutePlanner > grp=nullptr)
bool TrafficLightManager()
Returns true if the agent is affected by a traffic light.
SharedPtr< client::Waypoint > _incoming_waypoint
void UpdateInformation()
Refresh cached scene information consumed by RunStep.
float Positive(float v)
Clamp v at zero. Inline because it's tiny.
Definition Misc.h:74
float GetSpeed(SharedPtr< client::Actor > actor)
Compute speed of an actor in km/h.
Definition Misc.cpp:37
road::element::LaneMarking::LaneChange LaneChange
This file contains definitions of common data structures used in traffic manager.
std::shared_ptr< T > SharedPtr
Definition Memory.h:15
static constexpr BehaviorParameters Aggressive()
static constexpr BehaviorParameters Cautious()
static constexpr BehaviorParameters Normal()
LaneChange
Can be used as flags.
Definition LaneMarking.h:50