Boat导入问题——UnknownError while spawning the actor(已解决√)

文章详细描述了在使用CarlaUE4时,跟踪和解决spawn_actor指令引发的问题,包括代码追踪、错误日志分析和函数调用链,最终定位到ActorDispatcher中的Actor创建失败原因。
摘要由CSDN通过智能技术生成

首先,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的代码!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值