CARLA
StopSignComponent.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #include "StopSignComponent.h"
8 #include "TrafficLightState.h"
10 
11 #include <queue>
12 
19 
20 void UStopSignComponent::InitializeSign(const carla::road::Map &Map)
21 {
22 
23  const double epsilon = 0.00001;
24 
25  auto References = GetAllReferencesToThisSignal(Map);
26 
27  for (auto& Reference : References)
28  {
29  auto RoadId = Reference.first;
30  const auto* SignalReference = Reference.second;
31  TSet<carla::road::RoadId> SignalPredecessors;
32  // Stop box
33  for(auto &validity : SignalReference->GetValidities())
34  {
35  for(auto lane : carla::geom::Math::GenerateRange(validity._from_lane, validity._to_lane))
36  {
37  if(lane == 0)
38  continue;
39 
40  auto signal_waypoint = Map.GetWaypoint(
41  RoadId, lane, SignalReference->GetS()).get();
42 
43  if(Map.GetLane(signal_waypoint).GetType() != cr::Lane::LaneType::Driving)
44  continue;
45 
46  auto box_waypoint = signal_waypoint;
47  // Prevent adding the bounding box inside the intersection
48  if (Map.IsJunction(RoadId)) {
49  auto predecessors = Map.GetPredecessors(box_waypoint);
50  if (predecessors.size() == 1) {
51  auto predecessor = predecessors.front();
52  if (!Map.IsJunction(predecessor.road_id)) {
53  box_waypoint = predecessor;
54  }
55  }
56  }
57 
58  // Get 50% of the half size of the width of the lane
59  float BoxWidth = static_cast<float>(
60  0.5f*Map.GetLaneWidth(box_waypoint)*0.5);
61  float BoxLength = 1.5f;
62  float BoxHeight = 1.0f;
63  // Prevent a situation where the road width is 0,
64  // this could happen in a lane that is just appearing
65  BoxWidth = std::max(0.01f, BoxWidth);
66  // Get min and max
67  double LaneLength = Map.GetLane(box_waypoint).GetLength();
68  double LaneDistance = Map.GetLane(box_waypoint).GetDistance();
69  // Safe distance to avoid overlapping the bounding box with the intersection
70  float AdditionalDistance = 1.5f;
71  if(lane < 0)
72  {
73  box_waypoint.s = FMath::Clamp(box_waypoint.s - (BoxLength + AdditionalDistance),
74  LaneDistance + epsilon, LaneDistance + LaneLength - epsilon);
75  }
76  else
77  {
78  box_waypoint.s = FMath::Clamp(box_waypoint.s + (BoxLength + AdditionalDistance),
79  LaneDistance + epsilon, LaneDistance + LaneLength - epsilon);
80  }
81  FTransform BoxTransform = Map.ComputeTransform(box_waypoint);
82  ALargeMapManager* LargeMapManager = UCarlaStatics::GetLargeMapManager(GetWorld());
83  if (LargeMapManager)
84  {
85  BoxTransform = LargeMapManager->GlobalToLocalTransform(BoxTransform);
86  }
87  GenerateStopBox(BoxTransform, FVector(100*BoxLength, 100*BoxWidth, 100*BoxHeight));
88 
89  auto Predecessors = Map.GetPredecessors(signal_waypoint);
90  for(auto &Prev : Predecessors)
91  {
92  if(!SignalPredecessors.Contains(Prev.road_id))
93  {
94  SignalPredecessors.Add(Prev.road_id);
95  }
96  }
97  }
98  }
99 
100  //Check boxes
101  if(Map.IsJunction(RoadId))
102  {
103  auto JuncId = Map.GetJunctionId(RoadId);
104  const auto * Junction = Map.GetJunction(JuncId);
105  if(Junction->RoadHasConflicts(RoadId))
106  {
107  const auto &ConflictingRoads = Junction->GetConflictsOfRoad(RoadId);
108  for(const auto &Conflict : ConflictingRoads)
109  {
110  auto Waypoints = Map.GenerateWaypointsInRoad(Conflict);
111  for(auto& Waypoint : Waypoints)
112  {
113  // Skip roads that share the same previous road
114  bool bHasSamePredecessor = false;
115  auto Predecessors = Map.GetPredecessors(Waypoint);
116  for(auto &Prev : Predecessors)
117  {
118  if(SignalPredecessors.Contains(Prev.road_id))
119  {
120  bHasSamePredecessor = true;
121  }
122  }
123  if(bHasSamePredecessor)
124  {
125  continue;
126  }
127  if(Map.GetLane(Waypoint).GetType() != cr::Lane::LaneType::Driving)
128  continue;
129 
130  // Cover the road within the junction
131  auto CurrentWaypoint = Waypoint;
132  auto NextWaypoint = CurrentWaypoint;
133  float BoxSize = static_cast<float>(
134  0.9*Map.GetLaneWidth(NextWaypoint)*0.5);
135  // Prevent a situation where the road width is 0
136  // This could happen in a lane that is just appearing
137  BoxSize = std::max(0.01f, BoxSize);
138  float UEBoxSize = 100*BoxSize;
139 
140  FTransform BoxTransform = Map.ComputeTransform(NextWaypoint);
141  ALargeMapManager* LargeMapManager = UCarlaStatics::GetLargeMapManager(GetWorld());
142  if (LargeMapManager)
143  {
144  BoxTransform = LargeMapManager->GlobalToLocalTransform(BoxTransform);
145  }
146  GenerateCheckBox(BoxTransform, UEBoxSize);
147  while (true)
148  {
149  auto Next = Map.GetNext(NextWaypoint, 2*BoxSize);
150  if (Next.size() != 1)
151  {
152  break;
153  }
154  NextWaypoint = Next.front();
155  if(NextWaypoint.road_id != Waypoint.road_id)
156  {
157  break;
158  }
159  BoxTransform = Map.ComputeTransform(NextWaypoint);
160  if (LargeMapManager)
161  {
162  BoxTransform = LargeMapManager->GlobalToLocalTransform(BoxTransform);
163  }
164  GenerateCheckBox(BoxTransform, UEBoxSize);
165  }
166  // Cover the road before the junction
167  // Hard coded anticipation time (boxes placed prior to the junction)
168  double AnticipationTime = 0.1;
169  auto Previous = Map.GetPrevious(Waypoint, 2*BoxSize);
170  std::queue<std::pair<float, carla::road::element::Waypoint>>
171  WaypointQueue;
172  for (auto & Prev : Previous)
173  {
174  WaypointQueue.push({AnticipationTime, Prev});
175  }
176  while (!WaypointQueue.empty())
177  {
178  auto CurrentElement = WaypointQueue.front();
179  WaypointQueue.pop();
180  GenerateCheckBox(Map.ComputeTransform(CurrentElement.second), UEBoxSize);
181 
182  float Speed = 40;
183  auto* InfoSpeed = Map.GetLane(CurrentElement.second).GetRoad()->GetInfo<carla::road::element::RoadInfoSpeed>(CurrentElement.second.s);
184  if(InfoSpeed)
185  {
186  Speed = InfoSpeed->GetSpeed();
187  }
188  float RemainingTime = CurrentElement.first - BoxSize/Speed;
189  if(RemainingTime > 0)
190  {
191  Previous = Map.GetPrevious(CurrentElement.second, 2*BoxSize);
192  for (auto & Prev : Previous)
193  {
194  WaypointQueue.push({RemainingTime, Prev});
195  }
196  }
197  }
198  }
199  }
200  }
201  }
202  }
203 }
204 
205 void UStopSignComponent::GenerateStopBox(const FTransform BoxTransform,
206  const FVector BoxSize)
207 {
208  UBoxComponent* BoxComponent = GenerateTriggerBox(BoxTransform, BoxSize);
209  BoxComponent->OnComponentBeginOverlap.AddDynamic(this, &UStopSignComponent::OnOverlapBeginStopEffectBox);
210  BoxComponent->OnComponentEndOverlap.AddDynamic(this, &UStopSignComponent::OnOverlapEndStopEffectBox);
211  AddEffectTriggerVolume(BoxComponent);
212 }
213 
214 void UStopSignComponent::GenerateCheckBox(const FTransform BoxTransform,
215  float BoxSize)
216 {
217  UBoxComponent* BoxComponent = GenerateTriggerBox(BoxTransform, BoxSize);
218  BoxComponent->OnComponentBeginOverlap.AddDynamic(this, &UStopSignComponent::OnOverlapBeginStopCheckBox);
219  BoxComponent->OnComponentEndOverlap.AddDynamic(this, &UStopSignComponent::OnOverlapEndStopCheckBox);
220 }
221 
222 void UStopSignComponent::GiveWayIfPossible()
223 {
224  if (VehiclesToCheck.Num() == 0)
225  {
226  for (auto Vehicle : VehiclesInStop)
227  {
228  AWheeledVehicleAIController* VehicleController =
229  Cast<AWheeledVehicleAIController>(Vehicle->GetController());
230  VehicleController->SetTrafficLightState(ETrafficLightState::Green);
231  }
232  }
233  else
234  {
235  if(VehiclesInStop.Num())
236  {
237  for (auto Vehicle : VehiclesInStop)
238  {
239  AWheeledVehicleAIController* VehicleController =
240  Cast<AWheeledVehicleAIController>(Vehicle->GetController());
241  VehicleController->SetTrafficLightState(ETrafficLightState::Red);
242  }
243  // 1 second delay
244  DelayedGiveWay(1.0f);
245  }
246  }
247 }
248 
249 void UStopSignComponent::DelayedGiveWay(float Delay)
250 {
251  FTimerHandle TimerHandler;
252  GetWorld()->GetTimerManager().
253  SetTimer(TimerHandler, this, &UStopSignComponent::GiveWayIfPossible, Delay);
254 }
255 
256 void UStopSignComponent::OnOverlapBeginStopEffectBox(UPrimitiveComponent *OverlappedComp,
257  AActor *OtherActor,
258  UPrimitiveComponent *OtherComp,
259  int32 OtherBodyIndex,
260  bool bFromSweep,
261  const FHitResult &SweepResult)
262 {
263  ACarlaWheeledVehicle * Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
264  if (Vehicle)
265  {
266  AWheeledVehicleAIController* VehicleController =
267  Cast<AWheeledVehicleAIController>(Vehicle->GetController());
268  if (VehicleController)
269  {
270  VehicleController->SetTrafficLightState(ETrafficLightState::Red);
271  VehiclesInStop.Add(Vehicle);
272 
273  // 2 second delay for stop
274  DelayedGiveWay(2.0f);
275  }
276  }
277  RemoveSameVehicleInBothLists();
278 }
279 
280 void UStopSignComponent::OnOverlapEndStopEffectBox(UPrimitiveComponent *OverlappedComp,
281  AActor *OtherActor,
282  UPrimitiveComponent *OtherComp,
283  int32 OtherBodyIndex)
284 {
285  ACarlaWheeledVehicle * Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
286  if (Vehicle)
287  {
288  VehiclesInStop.Remove(Vehicle);
289  }
290 }
291 
292 void UStopSignComponent::OnOverlapBeginStopCheckBox(UPrimitiveComponent *OverlappedComp,
293  AActor *OtherActor,
294  UPrimitiveComponent *OtherComp,
295  int32 OtherBodyIndex,
296  bool bFromSweep,
297  const FHitResult &SweepResult)
298 {
299  ACarlaWheeledVehicle * Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
300  if (Vehicle)
301  {
302  if(!VehiclesInStop.Contains(Vehicle))
303  {
304  if (!VehiclesToCheck.Contains(Vehicle))
305  {
306  VehiclesToCheck.Add(Vehicle, 0);
307  }
308  VehiclesToCheck[Vehicle]++;
309  }
310  GiveWayIfPossible();
311  }
312 }
313 
314 void UStopSignComponent::OnOverlapEndStopCheckBox(UPrimitiveComponent *OverlappedComp,
315  AActor *OtherActor,
316  UPrimitiveComponent *OtherComp,
317  int32 OtherBodyIndex)
318 {
319  ACarlaWheeledVehicle * Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
320  if (Vehicle)
321  {
322  if(VehiclesToCheck.Contains(Vehicle))
323  {
324  VehiclesToCheck[Vehicle]--;
325  if(VehiclesToCheck[Vehicle] <= 0)
326  {
327  VehiclesToCheck.Remove(Vehicle);
328  }
329  }
330  // 0.5s delay
331  DelayedGiveWay(0.5f);
332  }
333 }
334 void UStopSignComponent::RemoveSameVehicleInBothLists()
335 {
336  for(auto* Vehicle : VehiclesInStop)
337  {
338  if(VehiclesToCheck.Contains(Vehicle))
339  {
340  VehiclesToCheck.Remove(Vehicle);
341  }
342  }
343 }
LaneType GetType() const
Definition: Lane.cpp:38
std::vector< Waypoint > GetPrevious(Waypoint waypoint, double distance) const
Return the list of waypoints at distance in the reversed direction that a vehicle at waypoint could d...
Definition: road/Map.cpp:590
boost::optional< element::Waypoint > GetWaypoint(const geom::Location &location, int32_t lane_type=static_cast< int32_t >(Lane::LaneType::Driving)) const
Definition: road/Map.cpp:212
Road * GetRoad() const
Definition: Lane.cpp:29
const Lane & GetLane(Waypoint waypoint) const
======================================================================== – Road information --------...
Definition: road/Map.cpp:834
double GetDistance() const
Definition: Lane.cpp:46
Junction * GetJunction(JuncId id)
Definition: road/Map.cpp:997
double GetLength() const
Definition: Lane.cpp:51
const T * GetInfo(const double s) const
Definition: Road.h:113
void SetTrafficLightState(ETrafficLightState InTrafficLightState)
Set traffic light state currently affecting this vehicle.
std::vector< Waypoint > GetNext(Waypoint waypoint, double distance) const
Return the list of waypoints at distance such that a vehicle at waypoint could drive to...
Definition: road/Map.cpp:554
Wheeled vehicle controller with optional AI.
geom::Transform ComputeTransform(Waypoint waypoint) const
Definition: road/Map.cpp:273
bool IsJunction(RoadId road_id) const
Definition: road/Map.cpp:302
std::vector< Waypoint > GetPredecessors(Waypoint waypoint) const
Definition: road/Map.cpp:536
static std::vector< int > GenerateRange(int a, int b)
Definition: Math.cpp:151
std::vector< Waypoint > GenerateWaypointsInRoad(RoadId road_id, Lane::LaneType lane_type=Lane::LaneType::Driving) const
Generate waypoints at the entry of each lane of the specified road.
Definition: road/Map.cpp:692
FTransform GlobalToLocalTransform(const FTransform &InTransform) const
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
Definition: CarlaStatics.h:100
JuncId GetJunctionId(RoadId road_id) const
Definition: road/Map.cpp:298
Base class for CARLA wheeled vehicles.
double GetLaneWidth(Waypoint waypoint) const
Definition: road/Map.cpp:285
carla::SharedPtr< carla::client::Junction > Junction