首先,spawn_actor指令是在carla/PythonAPI/carla/source/libcarla/World.cpp——L281中传送给Python端的。
L202 的 “CityObjectLabel”是否要改?cr::CityObjectLabel 对应carla/Libcarla/source/carla/rpc中的ObjectLabel.h
spawn_actor放的blueprint是cc::ActorBlueprint
找到cc::World.h里的L109
SharedPtr<Actor> SpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent = nullptr,
rpc::AttachmentType attachment_type = rpc::AttachmentType::Rigid);
到cr::Actor.h 得知SpawnActor返回的是指向Actor类的指针
Actor更详细的信息到cr::ActorDescription.h
但发现cc::World中的SpawnActor不是其定义,还是调用了别的所以继续找
另一路径:从cc::World.h到cc::detail::EpisodeProxy.cpp到Simulator.h和cpp
Simulator.cpp的L315
SharedPtr<Actor> Simulator::SpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent,
rpc::AttachmentType attachment_type,
GarbageCollectionPolicy gc) {
rpc::Actor actor;
if (parent != nullptr) {
actor = _client.SpawnActorWithParent(
blueprint.MakeActorDescription(),
transform,
parent->GetId(),
attachment_type);
} else {
actor = _client.SpawnActor(
blueprint.MakeActorDescription(),
transform);
}
# DUBUG_ASSERT是一个调试断,如果后面为空指针,则会引发一个错误,追究报错是否是在这里产生?结合DEBUG_ASSERT源码及习惯,基本可排除
DEBUG_ASSERT(_episode != nullptr);
_episode->RegisterActor(actor);
const auto gca = (gc == GarbageCollectionPolicy::Inherit ? _gc_policy : gc);
auto result = ActorFactory::MakeActor(GetCurrentEpisode(), actor, gca);
log_debug(
result->GetDisplayId(),
"created",
gca == GarbageCollectionPolicy::Enabled ? "with" : "without",
"garbage collection");
return result;
}
可以看到有三个与spawn actor相关的代码,逐个排查:
①actor = _client.SpawnActor(
blueprint.MakeActorDescription(),
transform)②_episode->RegisterActor(actor);
③auto result = ActorFactory::MakeActor(GetCurrentEpisode(), actor, gca);
现排查①,找到cc::detail::Client.h和cpp,在Client.cpp文件中有:
rpc::Actor Client::SpawnActor(
const rpc::ActorDescription &description,
const geom::Transform &transform) {
return _pimpl->CallAndWait<rpc::Actor>("spawn_actor", description, transform);
}
使用CallAndWait方法远程调用"spawn_actor"方法,我要知道spawn_actor方法在哪,于是我需要知道CallAndWait方法在从哪里远程调用。
在同样的Client.cpp文件中找到CallAndWait方法的定义:
auto CallAndWait(const std::string &function, Args && ... args) {
auto object = RawCall(function, std::forward<Args>(args) ...);
using R = typename carla::rpc::Response<T>;
auto response = object.template as<R>();
if (response.HasError()) {
throw_exception(std::runtime_error(response.GetError().What()));
}
return Get(response);
}
其事实上使用RawCall实现远程调用,在同样的Client.cpp文件中找到RawCall方法的定义:
auto RawCall(const std::string &function, Args && ... args) {
try {
return rpc_client.call(function, std::forward<Args>(args) ...);
} catch (const ::rpc::timeout &) {
throw_exception(TimeoutException(endpoint, GetTimeout()));
}
}
在cr::Client.h找到call的定义:
template <typename... Args>
auto call(const std::string &function, Args &&... args) {
return _client.call(function, Metadata::MakeSync(), std::forward<Args>(args)...);
}
一开始没找到,后来在GitHub中搜索"spawn_actor"之后,在carla\Unreal\CarlaUE4\Plugins\Carla\Source\Carla\Server\CarlaServer.cpp的L553里找到:
BIND_SYNC(spawn_actor) << [this](
cr::ActorDescription Description,
const cr::Transform &Transform) -> R<cr::Actor>
{
REQUIRE_CARLA_EPISODE();
auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
if (Result.Key != EActorSpawnResultStatus::Success)
{
UE_LOG(LogCarla, Error, TEXT("Actor not Spawned"));
RESPOND_ERROR_FSTRING(FActorSpawnResult::StatusToString(Result.Key));
}
// 我暂时不涉及LargeMap,所以这4行用处不大
"""
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(Episode->GetWorld());
if(LargeMap)
{
LargeMap->OnActorSpawned(*Result.Value);
}
"""
return Episode->SerializeActor(Result.Value);
};
看到如果此处有Result.Key != EActorSpawnResultStatus::Success问题,则会在UE日志中打印“Actor not Spawned”。相关SpawnResult的东西在carla\Unreal\CarlaUE4\Plugins\Carla\Source\Carla\Actor\ActorSpawnResult.h和cpp中
在carla\Unreal\CarlaUE4\Saved\Logs中查看了3月12日晚22点的日志CarlaUE4-backup-2024.03.12-14.13.27,在10708行确实发现了该打印:
[2024.03.12-14.11.19:988][367]LogCarla: Spawning actor 'boat.motorboat.z03'
[2024.03.12-14.11.19:989][367]LogCarla: Warning: Failed to spawn actor 'boat.motorboat.z03'
[2024.03.12-14.11.19:989][367]LogCarla: Error: Actor not Spawned
[2024.03.12-14.11.19:989][367]LogCarlaServer: Responding error: Unknown error while trying to spawn actor
基本确定①或从①开始就出现了问题!
我需要知道为什么会有Result.Key != EActorSpawnResultStatus::Success?
先看Result是什么:找到SpawnActorWithInfo定义所在的carla\Unreal\CarlaUE4\Plugins\Carla\Source\Carla\Game\CarlaEpisode.cpp
TPair<EActorSpawnResultStatus, FCarlaActor*> UCarlaEpisode::SpawnActorWithInfo(
const FTransform &Transform,
FActorDescription thisActorDescription,
FCarlaActor::IdType DesiredId)
{
"""
手动注释,我不用LargeMap
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(GetWorld());
FTransform LocalTransform = Transform;
if(LargeMap)
{
LocalTransform = LargeMap->GlobalToLocalTransform(LocalTransform);
}
"""
// NewTransform.AddToTranslation(-1.0f * FVector(CurrentMapOrigin));
auto result = ActorDispatcher->SpawnActor(LocalTransform, thisActorDescription, DesiredId);
if (Recorder->IsEnabled())
{
if (result.Key == EActorSpawnResultStatus::Success)
{
Recorder->CreateRecorderEventAdd(
result.Value->GetActorId(),
static_cast<uint8_t>(result.Value->GetActorType()),
Transform,
std::move(thisActorDescription)
);
}
}
return result;
}
看到return result说明Result = 这里的result,进一步追溯result定义函数SpawnActor,由指针知在carla\Unreal\CarlaUE4\Plugins\Carla\Source\Carla\Actor\ActorDispatcher.cpp中,如下:
TPair<EActorSpawnResultStatus, FCarlaActor*> UActorDispatcher::SpawnActor(
const FTransform &Transform,
FActorDescription Description,
FCarlaActor::IdType DesiredId)
{
if ((Description.UId == 0u) || (Description.UId > static_cast<uint32>(SpawnFunctions.Num())))
{
UE_LOG(LogCarla, Error, TEXT("Invalid ActorDescription '%s' (UId=%d)"), *Description.Id, Description.UId);
return MakeTuple(EActorSpawnResultStatus::InvalidDescription, nullptr);
}
UE_LOG(LogCarla, Log, TEXT("Spawning actor '%s'"), *Description.Id);
Description.Class = Classes[Description.UId - 1];
FActorSpawnResult Result = SpawnFunctions[Description.UId - 1](Transform, Description);
if ((Result.Status == EActorSpawnResultStatus::Success) && (Result.Actor == nullptr))
{
UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Trying to spawn '%s'"), *Description.Id);
UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Reported success but did not return an actor"));
Result.Status = EActorSpawnResultStatus::UnknownError;
}
FCarlaActor* View = Result.IsValid() ?
RegisterActor(*Result.Actor, std::move(Description), DesiredId) : nullptr;
if (!View)
{
UE_LOG(LogCarla, Warning, TEXT("Failed to spawn actor '%s'"), *Description.Id);
check(Result.Status != EActorSpawnResultStatus::Success);
}
else
{
ATagger::TagActor(*View->GetActor(), true);
}
return MakeTuple(Result.Status, View);
}
结合日志可以看到,是在 ”if( ! view )“ 那里出现了问题!!!
! view为True,说明view是False,结合FCarlaActor* View = Result.IsValid() ?
稍微了改了一下ActorDispatcher.cpp里的printf内容,uid有问题(?)——感觉应该是GameMode自己排的序,没有问题。
Result.IsValid调用的是carla\Unreal\CarlaUE4\Plugins\Carla\Source\Carla\Actor\ActorSpawnResult.h里的IsValid函数,如下:
bool IsValid() const
{
return (Actor != nullptr) && (Status == EActorSpawnResultStatus::Success);
}
可以看到view返回false可能是(Actor != nullptr) = False 或者
(Status == EActorSpawnResultStatus::Success) = False。结合同文件中EActorSpawnResultStatus的定义,发现二者一样,即为Actor是空指针!
关于SpawnFunctions:在ActorDispatcher.h中的定义:
TArray<SpawnFunctionType> SpawnFunctions; 是一个SpawnFunctionType类型函数组成的数组
同样在ActorDispatcher.h中 SpawnFunctionType定义:
using SpawnFunctionType = TFunction<FActorSpawnResult(const FTransform &, const FActorDescription &)>;
接受FTransform和FActorDescription参量,返回FActorSpawnResult类型量
SpawnFunctions的扩充:在ActorDispatcher.cpp里面
void UActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Functor)
{
if (UActorBlueprintFunctionLibrary::CheckActorDefinition(Definition))
{
Definition.UId = static_cast<uint32>(SpawnFunctions.Num()) + 1u;
Definitions.Emplace(Definition);
SpawnFunctions.Emplace(Functor);
Classes.Emplace(Definition.Class);
}
else
{
UE_LOG(LogCarla, Warning, TEXT("Invalid definition '%s' ignored"), *Definition.Id);
}
}
添加Functor,这里ActorDispatcher.cpp里面有调用
void UActorDispatcher::Bind(ACarlaActorFactory &ActorFactory)
{
for (const auto &Definition : ActorFactory.GetDefinitions())
{
Bind(Definition, [&](const FTransform &Transform, const FActorDescription &Description) {
return ActorFactory.SpawnActor(Transform, Description);
});
}
}
这里的ActorFactory.SpawnActor函数似乎是ue4里的!!!
确实是ue4里蓝图类里的SpawnActor函数,更改之后成功,问题已解决!
注意Cast To是转换主语
这里是当时①碰壁后做的尝试……
转战②,找到cc::detail::Episode.h中
void RegisterActor(rpc::Actor actor) {
_actors.Insert(std::move(actor));
}
关于③,找到cc::detail::ActorFactory中
SharedPtr<Actor> ActorFactory::MakeActor(
EpisodeProxy episode,
rpc::Actor description,
GarbageCollectionPolicy gc) {
auto init = ActorInitializer{description, episode};
if (description.description.id == "sensor.other.lane_invasion") {
return MakeActorImpl<LaneInvasionSensor>(std::move(init), gc);
#ifdef RSS_ENABLED
} else if (description.description.id == "sensor.other.rss") {
return MakeActorImpl<RssSensor>(std::move(init), gc);
#endif
} else if (description.HasAStream()) {
return MakeActorImpl<ServerSideSensor>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "vehicle.")) {
return MakeActorImpl<Vehicle>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "boat.")) {
return MakeActorImpl<Boat>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "walker.")) {
return MakeActorImpl<Walker>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "traffic.traffic_light")) {
return MakeActorImpl<TrafficLight>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "traffic.")) {
return MakeActorImpl<TrafficSign>(std::move(init), gc);
} else if (description.description.id == "controller.ai.walker") {
return MakeActorImpl<WalkerAIController>(std::move(init), gc);
}
return MakeActorImpl<Actor>(std::move(init), gc);
}
其中ActorInitializer来自cc::Actor.h
explicit Actor(ActorInitializer init)
: LIBCARLA_INITIALIZE_LIFETIME_PROFILER(init.GetDisplayId()),
Super(std::move(init)) {}
歪个题:Carla.Actor中有add_force的代码!