CARLA
ActorDispatcher.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017 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 "Carla.h"
9 
13 
14 #include "Carla/Game/Tagger.h"
16 
17 #include "GameFramework/Controller.h"
18 
20 #include "carla/ros2/ROS2.h"
22 
24 {
26  {
27  Definition.UId = static_cast<uint32>(SpawnFunctions.Num()) + 1u;
28  Definitions.Emplace(Definition);
29  SpawnFunctions.Emplace(Functor);
30  Classes.Emplace(Definition.Class);
31  }
32  else
33  {
34  UE_LOG(LogCarla, Warning, TEXT("Invalid definition '%s' ignored"), *Definition.Id);
35  }
36 }
37 
39 {
40  for (const auto &Definition : ActorFactory.GetDefinitions())
41  {
42  Bind(Definition, [&](const FTransform &Transform, const FActorDescription &Description) {
43  return ActorFactory.SpawnActor(Transform, Description);
44  });
45  }
46 }
47 
48 TPair<EActorSpawnResultStatus, FCarlaActor*> UActorDispatcher::SpawnActor(
49  const FTransform &Transform,
50  FActorDescription Description,
51  FCarlaActor::IdType DesiredId)
52 {
53  if ((Description.UId == 0u) || (Description.UId > static_cast<uint32>(SpawnFunctions.Num())))
54  {
55  UE_LOG(LogCarla, Error, TEXT("Invalid ActorDescription '%s' (UId=%d)"), *Description.Id, Description.UId);
56  return MakeTuple(EActorSpawnResultStatus::InvalidDescription, nullptr);
57  }
58 
59  UE_LOG(LogCarla, Log, TEXT("Spawning actor '%s'"), *Description.Id);
60 
61  Description.Class = Classes[Description.UId - 1];
62  FActorSpawnResult Result = SpawnFunctions[Description.UId - 1](Transform, Description);
63 
64  if ((Result.Status == EActorSpawnResultStatus::Success) && (Result.Actor == nullptr))
65  {
66  UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Trying to spawn '%s'"), *Description.Id);
67  UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Reported success but did not return an actor"));
68  Result.Status = EActorSpawnResultStatus::UnknownError;
69  }
70 
71  FCarlaActor* View = Result.IsValid() ?
72  RegisterActor(*Result.Actor, std::move(Description), DesiredId) : nullptr;
73  if (!View)
74  {
75  UE_LOG(LogCarla, Warning, TEXT("Failed to spawn actor '%s'"), *Description.Id);
76  check(Result.Status != EActorSpawnResultStatus::Success);
77  }
78  else
79  {
80  ATagger::TagActor(*View->GetActor(), true);
81  }
82 
83  return MakeTuple(Result.Status, View);
84 }
85 
87  const FTransform &Transform,
88  FActorDescription Description)
89 {
90  if ((Description.UId == 0u) || (Description.UId > static_cast<uint32>(SpawnFunctions.Num())))
91  {
92  UE_LOG(LogCarla, Error, TEXT("Invalid ActorDescription '%s' (UId=%d)"), *Description.Id, Description.UId);
93  return nullptr;
94  }
95 
96  UE_LOG(LogCarla, Log, TEXT("Spawning actor '%s'"), *Description.Id);
97 
98  Description.Class = Classes[Description.UId - 1];
99  FActorSpawnResult Result = SpawnFunctions[Description.UId - 1](Transform, Description);
100 
101  if ((Result.Status == EActorSpawnResultStatus::Success) && (Result.Actor == nullptr))
102  {
103  UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Trying to spawn '%s'"), *Description.Id);
104  UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Reported success but did not return an actor"));
105  Result.Status = EActorSpawnResultStatus::UnknownError;
106  return nullptr;
107  }
108 
109  if (Result.Status == EActorSpawnResultStatus::Success)
110  {
111  return Result.Actor;
112  }
113 
114  return nullptr;
115 }
116 
118 {
119  // Check if the actor is in the registry.
120  FCarlaActor* View = Registry.FindCarlaActor(ActorId);
121 
122  // Invalid destruction if is not marked to PendingKill (except is dormant, dormant actors can be destroyed)
123  if (!View)
124  {
125  UE_LOG(LogCarla, Warning, TEXT("Trying to destroy actor that is not in the registry"));
126  return false;
127  }
128 
129  const FString &Id = View->GetActorInfo()->Description.Id;
130 
131  // Destroy its controller if present.
132  AActor* Actor = View->GetActor();
133  if(Actor)
134  {
135  APawn* Pawn = Cast<APawn>(Actor);
136  AController* Controller = (Pawn != nullptr ? Pawn->GetController() : nullptr);
137  if (Controller != nullptr)
138  {
139  UE_LOG(LogCarla, Log, TEXT("Destroying actor's controller: '%s'"), *Id);
140  bool Success = Controller->Destroy();
141  if (!Success)
142  {
143  UE_LOG(LogCarla, Error, TEXT("Failed to destroy actor's controller: '%s'"), *Id);
144  }
145  }
146 
147  // Destroy the actor.
148  UE_LOG(LogCarla, Log, TEXT("UActorDispatcher::Destroying actor: '%s' %x"), *Id, Actor);
149  UE_LOG(LogCarla, Log, TEXT(" %s"), Actor?*Actor->GetName():*FString("None"));
150  if (!Actor || !Actor->Destroy())
151  {
152  UE_LOG(LogCarla, Error, TEXT("Failed to destroy actor: '%s'"), *Id);
153  return false;
154  }
155  }
156 
157  Registry.Deregister(ActorId);
158 
159  return true;
160 }
161 
163  AActor &Actor, FActorDescription Description,
164  FActorRegistry::IdType DesiredId)
165 {
166  FCarlaActor* View = Registry.Register(Actor, Description, DesiredId);
167  if (View)
168  {
169  // TODO: support external actor destruction
170  Actor.OnDestroyed.AddDynamic(this, &UActorDispatcher::OnActorDestroyed);
171 
172  // ROS2 mapping of actor->ros_name
173  #if defined(WITH_ROS2)
174  auto ROS2 = carla::ros2::ROS2::GetInstance();
175  if (ROS2->IsEnabled())
176  {
177  // actor ros_name
178  std::string RosName;
179  for (auto &&Attr : Description.Variations)
180  {
181  if (Attr.Key == "ros_name")
182  {
183  RosName = std::string(TCHAR_TO_UTF8(*Attr.Value.Value));
184  }
185  }
186  const std::string id = std::string(TCHAR_TO_UTF8(*Description.Id));
187  if (RosName == id) {
188  if(RosName.find("vehicle") != std::string::npos)
189  {
190  std::string VehicleName = "vehicle" + std::to_string(View->GetActorId());
191  ROS2->AddActorRosName(static_cast<void*>(&Actor), VehicleName);
192  }
193  else
194  {
195  size_t pos = RosName.find_last_of('.');
196  if (pos != std::string::npos) {
197  std::string lastToken = RosName.substr(pos + 1) + "__";
198  ROS2->AddActorRosName(static_cast<void*>(&Actor), lastToken);
199  }
200  }
201  } else {
202  ROS2->AddActorRosName(static_cast<void*>(&Actor), RosName);
203  }
204 
205  // vehicle controller for hero
206  for (auto &&Attr : Description.Variations)
207  {
208  if (Attr.Key == "role_name" && (Attr.Value.Value == "hero" || Attr.Value.Value == "ego"))
209  {
210  ROS2->AddActorCallback(static_cast<void*>(&Actor), RosName, [RosName](void *Actor, carla::ros2::ROS2CallbackData Data) -> void
211  {
212  AActor *UEActor = reinterpret_cast<AActor *>(Actor);
213  ActorROS2Handler Handler(UEActor, RosName);
214  boost::variant2::visit(Handler, Data);
215  });
216  }
217  }
218  }
219  #endif
220  }
221  return View;
222 }
223 
225 {
226  Registry.PutActorToSleep(Id, CarlaEpisode);
227 }
228 
230 {
231  Registry.WakeActorUp(Id, CarlaEpisode);
232 }
233 
235 {
236  FCarlaActor* CarlaActor = Registry.FindCarlaActor(Actor);
237  if (CarlaActor)
238  {
239  if (CarlaActor->IsActive())
240  {
241  Registry.Deregister(CarlaActor->GetActorId());
242  }
243  }
244 
245  #if defined(WITH_ROS2)
246  auto ROS2 = carla::ros2::ROS2::GetInstance();
247  if (ROS2->IsEnabled())
248  {
249  ROS2->RemoveActorRosName(reinterpret_cast<void *>(Actor));
250  }
251  #endif
252 }
Base class for Carla actor factories.
void Deregister(IdType Id)
void Bind(FActorDefinition Definition, SpawnFunctionType SpawnFunction)
Bind a definition to a spawn function.
TArray< TSubclassOf< AActor > > Classes
TPair< EActorSpawnResultStatus, FCarlaActor * > SpawnActor(const FTransform &Transform, FActorDescription ActorDescription, FCarlaActor::IdType DesiredId=0)
Spawns an actor based on ActorDescription at Transform.
void PutActorToSleep(IdType Id, UCarlaEpisode *CarlaEpisode)
AActor * ReSpawnActor(const FTransform &Transform, FActorDescription ActorDescription)
ReSpawns an actor based on ActorDescription at Transform.
void OnActorDestroyed(AActor *Actor)
bool DestroyActor(FCarlaActor::IdType ActorId)
Destroys an actor, properly removing it from the registry.
visitor class
FCarlaActor * RegisterActor(AActor &Actor, FActorDescription ActorDescription, FActorRegistry::IdType DesiredId=0)
Register an actor that was not created using "SpawnActor" function but that should be kept in the reg...
AActor * GetActor()
Definition: CarlaActor.h:90
uint32 UId
Uniquely identifies the definition (no need to fill it).
uint32 IdType
Definition: CarlaActor.h:27
TFunction< FActorSpawnResult(const FTransform &, const FActorDescription &)> SpawnFunctionType
A definition of a Carla Actor with all the variation and attributes.
void WakeActorUp(IdType Id, UCarlaEpisode *CarlaEpisode)
static bool CheckActorDefinition(const FActorDefinition &ActorDefinitions)
Return whether the actor definition is valid. Prints all the errors found.
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
TArray< FActorDefinition > Definitions
carla::SharedPtr< cc::Actor > Actor
A simulation episode.
Definition: CarlaEpisode.h:38
bool IsValid() const
FActorRegistry Registry
bool IsActive() const
Definition: CarlaActor.h:65
TSubclassOf< AActor > Class
Class of the actor to be spawned.
A description of a Carla Actor with all its variation.
boost::variant2::variant< VehicleControl > ROS2CallbackData
FActorDescription Description
Definition: ActorInfo.h:26
uint32_t ActorId
Definition: ActorId.h:14
const FActorInfo * GetActorInfo() const
Definition: CarlaActor.h:100
virtual TArray< FActorDefinition > GetDefinitions()
Retrieve the list of actor definitions that this class is able to spawn.
virtual FActorSpawnResult SpawnActor(const FTransform &SpawnAtTransform, const FActorDescription &ActorDescription)
Spawn an actor based on ActorDescription and Transform.
FCarlaActor::IdType IdType
Definition: ActorRegistry.h:24
TArray< SpawnFunctionType > SpawnFunctions
FString Id
Display ID that identifies the actor.
uint32 UId
UId of the definition in which this description was based.
void WakeActorUp(FCarlaActor::IdType Id, UCarlaEpisode *CarlaEpisode)
FCarlaActor * Register(AActor &Actor, FActorDescription Description, IdType DesiredId=0)
Register the Actor in the database.
static std::shared_ptr< ROS2 > GetInstance()
Definition: ROS2.h:51
static void TagActor(const AActor &Actor, bool bTagForSemanticSegmentation)
Set the tag of an actor.
Definition: Tagger.cpp:103
IdType GetActorId() const
Definition: CarlaActor.h:80
TSubclassOf< AActor > Class
Class of the actor to be spawned (Optional).
FCarlaActor * FindCarlaActor(IdType Id)
Definition: ActorRegistry.h:69
EActorSpawnResultStatus Status
Result of an actor spawn function.
geom::Transform Transform
Definition: rpc/Transform.h:16
A view over an actor and its properties.
Definition: CarlaActor.h:23
void PutActorToSleep(FCarlaActor::IdType Id, UCarlaEpisode *CarlaEpisode)