From bd710c339c07426378428bc27a65aa4c41f16e16 Mon Sep 17 00:00:00 2001 From: Bernd Gassmann Date: Fri, 30 Nov 2018 16:05:30 +0100 Subject: [PATCH] Provide parent/attribute content of Actors via python interface While creating the new carla ros bridge some extensions became necessary within CARLA: The parent property of an actor via python interface is not yet filled. Therefore, the parent_id of Actors has to be transferred from the CARLA server via rpc interface. In addition, actor attributes are published via python interface. Changes in detail: carla/rpc/Actor.h: - add parent_id field to the Actor class for rpc transport TheNewCarlaServer.cpp: - fill the parent_id field with the appropriate value client/ActorList: - added GetActor() function to get an actor by id client/ActorVariant: - added actor_list optional parameter to Get() and MakeActor() function which allows to query for the parent actor in case the actor_list is available client/ActorAttribute: - solved problem of independent rpc::ActorAttribute* classes by introduction of ActorAttributeValueAccess class, to be able to reuse most of the functions for both ActorAttribueValues and ActorAttributes ActorBlueprintFunctionLibrary: - extended actor attributes by attribute 'role_name' having {autopilot, scenario, ego_vehicle} as recommended values for vehicles or {front,back,...} for sensors to be able to distiguish the different actors in a meaningful way when transferring to ROS topic names - extended vehicle attributes by not-modifiable attribute 'object_type' to be defined at blueprint creation time to provide ground truth object classification type PythonAPI: - libcarla: provide the actor attributes within python as dictionary - make use of role_name attribute to provide information required for ROS bridge to distinguish ego vehicle from others --- Docs/python_api.md | 1 + .../source/carla/client/ActorAttribute.cpp | 33 +-- LibCarla/source/carla/client/ActorAttribute.h | 234 ++++++++++++------ .../source/carla/client/ActorBlueprint.cpp | 4 +- LibCarla/source/carla/client/ActorList.cpp | 12 + LibCarla/source/carla/client/ActorList.h | 8 +- .../source/carla/client/detail/ActorState.cpp | 5 +- .../source/carla/client/detail/ActorState.h | 8 + .../carla/client/detail/ActorVariant.cpp | 12 +- .../source/carla/client/detail/ActorVariant.h | 12 +- LibCarla/source/carla/rpc/Actor.h | 4 +- PythonAPI/manual_control.py | 3 + PythonAPI/source/libcarla/Actor.cpp | 7 + PythonAPI/spawn_npc.py | 1 + .../Actor/ActorBlueprintFunctionLibrary.cpp | 38 ++- .../Actor/ActorBlueprintFunctionLibrary.h | 3 + .../Source/Carla/Server/TheNewCarlaServer.cpp | 1 + 17 files changed, 276 insertions(+), 110 deletions(-) diff --git a/Docs/python_api.md b/Docs/python_api.md index 2fdd3449e..8e67ca2ae 100644 --- a/Docs/python_api.md +++ b/Docs/python_api.md @@ -90,6 +90,7 @@ - `parent` - `semantic_tags` - `is_alive` +- `attributes` - `get_world()` - `get_location()` - `get_transform()` diff --git a/LibCarla/source/carla/client/ActorAttribute.cpp b/LibCarla/source/carla/client/ActorAttribute.cpp index eaf23aca3..2159bd711 100644 --- a/LibCarla/source/carla/client/ActorAttribute.cpp +++ b/LibCarla/source/carla/client/ActorAttribute.cpp @@ -12,10 +12,10 @@ namespace carla { namespace client { -#define LIBCARLA_THROW_INVALID_VALUE(message) throw InvalidAttributeValue(_attribute.id + ": " + message); +#define LIBCARLA_THROW_INVALID_VALUE(message) throw InvalidAttributeValue(GetId() + ": " + message); #define LIBCARLA_THROW_BAD_VALUE_CAST(type) \ if (GetType() != rpc::ActorAttributeType:: type) { \ - throw BadAttributeCast(_attribute.id + ": bad attribute cast: cannot convert to " #type); \ + throw BadAttributeCast(GetId() + ": bad attribute cast: cannot convert to " #type); \ } void ActorAttribute::Set(std::string value) { @@ -29,28 +29,29 @@ namespace client { Validate(); } + template <> - bool ActorAttribute::As() const { + bool ActorAttributeValueAccess::As() const { LIBCARLA_THROW_BAD_VALUE_CAST(Bool); - auto value = StringUtil::ToLowerCopy(_attribute.value); + auto value = StringUtil::ToLowerCopy(GetValue()); if (value == "true") { return true; } else if (value == "false") { return false; } - LIBCARLA_THROW_INVALID_VALUE("invalid bool: " + _attribute.value); + LIBCARLA_THROW_INVALID_VALUE("invalid bool: " + GetValue()); } template<> - int ActorAttribute::As() const { + int ActorAttributeValueAccess::As() const { LIBCARLA_THROW_BAD_VALUE_CAST(Int); - return std::atoi(_attribute.value.c_str()); + return std::atoi(GetValue().c_str()); } template<> - float ActorAttribute::As() const { + float ActorAttributeValueAccess::As() const { LIBCARLA_THROW_BAD_VALUE_CAST(Float); - double x = std::atof(_attribute.value.c_str()); + double x = std::atof(GetValue().c_str()); if ((x > std::numeric_limits::max()) || (x < std::numeric_limits::lowest())) { LIBCARLA_THROW_INVALID_VALUE("float overflow"); @@ -59,19 +60,19 @@ namespace client { } template <> - std::string ActorAttribute::As() const { + std::string ActorAttributeValueAccess::As() const { LIBCARLA_THROW_BAD_VALUE_CAST(String); - return _attribute.value; + return GetValue(); } template <> - sensor::data::Color ActorAttribute::As() const { + sensor::data::Color ActorAttributeValueAccess::As() const { LIBCARLA_THROW_BAD_VALUE_CAST(RGBColor); std::vector channels; - StringUtil::Split(channels, _attribute.value, ","); + StringUtil::Split(channels, GetValue(), ","); if (channels.size() != 3u) { - log_error("invalid color", _attribute.value); + log_error("invalid color", GetValue()); LIBCARLA_THROW_INVALID_VALUE("colors must have 3 channels (R,G,B)"); } @@ -86,8 +87,8 @@ namespace client { return {to_int(channels[0u]), to_int(channels[1u]), to_int(channels[2u])}; } - void ActorAttribute::Validate() const { - switch (_attribute.type) { + void ActorAttributeValueAccess::Validate() const { + switch (GetType()) { case rpc::ActorAttributeType::Bool: As(); break; case rpc::ActorAttributeType::Int: As(); break; case rpc::ActorAttributeType::Float: As(); break; diff --git a/LibCarla/source/carla/client/ActorAttribute.h b/LibCarla/source/carla/client/ActorAttribute.h index f915a8903..5bcee8e9d 100644 --- a/LibCarla/source/carla/client/ActorAttribute.h +++ b/LibCarla/source/carla/client/ActorAttribute.h @@ -44,36 +44,20 @@ namespace client { // -- ActorAttribute --------------------------------------------------------- // =========================================================================== - /// An attribute of an ActorBlueprint. - class ActorAttribute { + class ActorAttributeValueAccess + { public: + ActorAttributeValueAccess() = default; + ActorAttributeValueAccess(ActorAttributeValueAccess const &) = default; + ActorAttributeValueAccess(ActorAttributeValueAccess &&) = default; + virtual ~ActorAttributeValueAccess() = default; - ActorAttribute(rpc::ActorAttribute attribute) - : _attribute(std::move(attribute)) { - Validate(); - } + ActorAttributeValueAccess & operator= (ActorAttributeValueAccess const & ) = default; + ActorAttributeValueAccess & operator= (ActorAttributeValueAccess && ) = default; - const std::string &GetId() const { - return _attribute.id; - } + virtual const std::string &GetId() const = 0; - rpc::ActorAttributeType GetType() const { - return _attribute.type; - } - - const std::vector &GetRecommendedValues() const { - return _attribute.recommended_values; - } - - bool IsModifiable() const { - return _attribute.is_modifiable; - } - - /// Set the value of this attribute. - /// - /// @throw InvalidAttributeValue if attribute is not modifiable. - /// @throw InvalidAttributeValue if format does not match this type. - void Set(std::string value); + virtual rpc::ActorAttributeType GetType() const = 0; /// Cast the value to the given type. /// @@ -96,68 +80,162 @@ namespace client { return !(*this == rhs); } + protected: + virtual const std::string &GetValue() const = 0; + + void Validate() const; + }; + + template <> + bool ActorAttributeValueAccess::As() const; + + template <> + int ActorAttributeValueAccess::As() const; + + template <> + float ActorAttributeValueAccess::As() const; + + template <> + std::string ActorAttributeValueAccess::As() const; + + template <> + sensor::data::Color ActorAttributeValueAccess::As() const; + + template <> + inline auto ActorAttributeValueAccess::As() const { + return As(); + } + + template <> + inline auto ActorAttributeValueAccess::As() const { + return As(); + } + + template <> + inline auto ActorAttributeValueAccess::As() const { + return As(); + } + + template <> + inline auto ActorAttributeValueAccess::As() const { + return As(); + } + + template <> + inline auto ActorAttributeValueAccess::As() const { + return As(); + } + + template + inline bool ActorAttributeValueAccess::operator==(const T &rhs) const { + return As() == rhs; + } + + template <> + inline bool ActorAttributeValueAccess::operator==(const ActorAttributeValueAccess &rhs) const { + return + (GetType() == rhs.GetType()) && + (GetValue() == rhs.GetValue()); + } + + class ActorAttributeValue: public ActorAttributeValueAccess { + + public: + ActorAttributeValue(rpc::ActorAttributeValue attribute): + _attribute(std::move(attribute)) + { + Validate(); + } + ActorAttributeValue(ActorAttributeValue const &) = default; + ActorAttributeValue(ActorAttributeValue &&) = default; + virtual ~ActorAttributeValue() = default; + + ActorAttributeValue & operator= (ActorAttributeValue const & ) = default; + ActorAttributeValue & operator= (ActorAttributeValue && ) = default; + + virtual const std::string &GetId() const override { + return _attribute.id; + } + + virtual rpc::ActorAttributeType GetType() const override { + return _attribute.type; + } + + /// Serialize this object as a carla::rpc::ActorAttributeValue. + operator rpc::ActorAttributeValue() const{ + return _attribute; + } + + virtual const std::string &GetValue() const override { + return _attribute.value; + } + + private: + + rpc::ActorAttributeValue _attribute; + }; + + template <> + inline bool ActorAttributeValueAccess::operator==(const ActorAttributeValue &rhs) const { + return rhs.operator==(*this); + } + + /// An attribute of an ActorBlueprint. + class ActorAttribute: public ActorAttributeValueAccess { + + public: + ActorAttribute(rpc::ActorAttribute attribute) + : ActorAttributeValueAccess(), + _attribute(std::move(attribute)) { + Validate(); + } + + ActorAttribute(ActorAttribute const &) = default; + ActorAttribute(ActorAttribute &&) = default; + virtual ~ActorAttribute() = default; + + ActorAttribute & operator= (ActorAttribute const & ) = default; + ActorAttribute & operator= (ActorAttribute && ) = default; + + virtual const std::string &GetId() const override { + return _attribute.id; + } + + virtual rpc::ActorAttributeType GetType() const override { + return _attribute.type; + } + + const std::vector &GetRecommendedValues() const { + return _attribute.recommended_values; + } + + bool IsModifiable() const { + return _attribute.is_modifiable; + } + + /// Set the value of this attribute. + /// + /// @throw InvalidAttributeValue if attribute is not modifiable. + /// @throw InvalidAttributeValue if format does not match this type. + void Set(std::string value); + /// Serialize this object as a carla::rpc::ActorAttributeValue. operator rpc::ActorAttributeValue() const { return _attribute; } + protected: + virtual const std::string &GetValue() const override { + return _attribute.value; + } + private: - - void Validate() const; - rpc::ActorAttribute _attribute; }; template <> - bool ActorAttribute::As() const; - - template <> - int ActorAttribute::As() const; - - template <> - float ActorAttribute::As() const; - - template <> - std::string ActorAttribute::As() const; - - template <> - sensor::data::Color ActorAttribute::As() const; - - template <> - inline auto ActorAttribute::As() const { - return As(); - } - - template <> - inline auto ActorAttribute::As() const { - return As(); - } - - template <> - inline auto ActorAttribute::As() const { - return As(); - } - - template <> - inline auto ActorAttribute::As() const { - return As(); - } - - template <> - inline auto ActorAttribute::As() const { - return As(); - } - - template - inline bool ActorAttribute::operator==(const T &rhs) const { - return As() == rhs; - } - - template <> - inline bool ActorAttribute::operator==(const ActorAttribute &rhs) const { - return - (_attribute.type == rhs._attribute.type) && - (_attribute.value == rhs._attribute.value); + inline bool ActorAttributeValueAccess::operator==(const ActorAttribute &rhs) const { + return rhs.operator==(*this); } } // namespace client diff --git a/LibCarla/source/carla/client/ActorBlueprint.cpp b/LibCarla/source/carla/client/ActorBlueprint.cpp index fa07962fa..5af50f571 100644 --- a/LibCarla/source/carla/client/ActorBlueprint.cpp +++ b/LibCarla/source/carla/client/ActorBlueprint.cpp @@ -56,9 +56,7 @@ namespace client { description.id = _id; description.attributes.reserve(_attributes.size()); for (const auto &attribute : *this) { - if (attribute.IsModifiable()) { - description.attributes.push_back(attribute); - } + description.attributes.push_back(attribute); } return description; } diff --git a/LibCarla/source/carla/client/ActorList.cpp b/LibCarla/source/carla/client/ActorList.cpp index f553ec9e4..98091b313 100644 --- a/LibCarla/source/carla/client/ActorList.cpp +++ b/LibCarla/source/carla/client/ActorList.cpp @@ -20,6 +20,18 @@ namespace client { : _episode(std::move(episode)), _actors(std::make_move_iterator(actors.begin()), std::make_move_iterator(actors.end())) {} + SharedPtr ActorList::GetActor(actor_id_type const actor_id) const + { + for (auto &actor: _actors) + { + if (actor_id == actor.GetId()) + { + return actor.Get(_episode, shared_from_this()); + } + } + return nullptr; + } + ActorList ActorList::Filter(const std::string &wildcard_pattern) const { ActorList filtered{_episode, {}}; for (auto &&actor : _actors) { diff --git a/LibCarla/source/carla/client/ActorList.h b/LibCarla/source/carla/client/ActorList.h index 0b08ff002..445823816 100644 --- a/LibCarla/source/carla/client/ActorList.h +++ b/LibCarla/source/carla/client/ActorList.h @@ -21,7 +21,7 @@ namespace client { template auto MakeIterator(It it) const { return boost::make_transform_iterator(it, [this](auto &v) { - return v.Get(_episode); + return v.Get(_episode, shared_from_this()); }); } @@ -31,11 +31,11 @@ namespace client { ActorList Filter(const std::string &wildcard_pattern) const; SharedPtr operator[](size_t pos) const { - return _actors[pos].Get(_episode); + return _actors[pos].Get(_episode, shared_from_this()); } SharedPtr at(size_t pos) const { - return _actors.at(pos).Get(_episode); + return _actors.at(pos).Get(_episode, shared_from_this()); } auto begin() const { @@ -54,6 +54,8 @@ namespace client { return _actors.size(); } + SharedPtr GetActor(actor_id_type const actor_id) const; + private: friend class World; diff --git a/LibCarla/source/carla/client/detail/ActorState.cpp b/LibCarla/source/carla/client/detail/ActorState.cpp index b019dbddb..170e63bc1 100644 --- a/LibCarla/source/carla/client/detail/ActorState.cpp +++ b/LibCarla/source/carla/client/detail/ActorState.cpp @@ -7,6 +7,7 @@ #include "carla/client/detail/ActorState.h" #include +#include namespace carla { namespace client { @@ -25,7 +26,9 @@ namespace detail { "Actor "s + std::to_string(desc.id) + " (" + desc.description.id + ')'; - }(_description)) {} + }(_description)), + _attributes(_description.description.attributes.begin(), _description.description.attributes.end()) + {} } // namespace detail } // namespace client diff --git a/LibCarla/source/carla/client/detail/ActorState.h b/LibCarla/source/carla/client/detail/ActorState.h index aaddb4e88..cde421d8c 100644 --- a/LibCarla/source/carla/client/detail/ActorState.h +++ b/LibCarla/source/carla/client/detail/ActorState.h @@ -8,6 +8,7 @@ #include "carla/NonCopyable.h" #include "carla/client/World.h" +#include "carla/client/ActorAttribute.h" #include "carla/client/detail/EpisodeProxy.h" #include "carla/rpc/Actor.h" @@ -49,6 +50,11 @@ namespace detail { return World{_episode}; } + const std::vector &GetAttributes() const + { + return _attributes; + } + protected: const rpc::Actor &GetActorDescription() const { @@ -79,6 +85,8 @@ namespace detail { SharedPtr _parent; std::string _display_id; + + std::vector _attributes; }; } // namespace detail diff --git a/LibCarla/source/carla/client/detail/ActorVariant.cpp b/LibCarla/source/carla/client/detail/ActorVariant.cpp index 766dcca94..ee1959ef1 100644 --- a/LibCarla/source/carla/client/detail/ActorVariant.cpp +++ b/LibCarla/source/carla/client/detail/ActorVariant.cpp @@ -7,16 +7,24 @@ #include "carla/client/detail/ActorVariant.h" #include "carla/client/detail/ActorFactory.h" +#include "carla/client/ActorList.h" namespace carla { namespace client { namespace detail { - void ActorVariant::MakeActor(EpisodeProxy episode) const { + void ActorVariant::MakeActor(EpisodeProxy episode, SharedPtr actor_list) const { + auto const parent_id = GetParentId(); + SharedPtr parent = nullptr; + if ( (actor_list != nullptr) && (parent_id != 0) ) + { + // in case we have an actor list as context, we are able to actually create the parent actor + parent = actor_list->GetActor(parent_id); + } _value = detail::ActorFactory::MakeActor( episode, boost::get(std::move(_value)), - nullptr, /// @todo We need to create the parent too. + parent, GarbageCollectionPolicy::Disabled); } diff --git a/LibCarla/source/carla/client/detail/ActorVariant.h b/LibCarla/source/carla/client/detail/ActorVariant.h index 94405141a..234f3d79a 100644 --- a/LibCarla/source/carla/client/detail/ActorVariant.h +++ b/LibCarla/source/carla/client/detail/ActorVariant.h @@ -38,9 +38,9 @@ namespace detail { return *this; } - SharedPtr Get(EpisodeProxy episode) const { + SharedPtr Get(EpisodeProxy episode, SharedPtr actor_list = nullptr) const { if (_value.which() == 0u) { - MakeActor(episode); + MakeActor(episode, actor_list); } DEBUG_ASSERT(_value.which() == 1u); return boost::get>(_value); @@ -54,6 +54,10 @@ namespace detail { return Serialize().id; } + actor_id_type GetParentId() const { + return Serialize().parent_id; + } + const std::string &GetTypeId() const { return Serialize().description.id; } @@ -72,12 +76,12 @@ namespace detail { const rpc::Actor &operator()(const rpc::Actor &actor) const { return actor; } - const rpc::Actor &operator()(const SharedPtr &actor) const { + const rpc::Actor &operator()(const SharedPtr &actor) const { return actor->Serialize(); } }; - void MakeActor(EpisodeProxy episode) const; + void MakeActor(EpisodeProxy episode, SharedPtr actor_list) const; mutable boost::variant> _value; }; diff --git a/LibCarla/source/carla/rpc/Actor.h b/LibCarla/source/carla/rpc/Actor.h index 1ff25f11a..389253067 100644 --- a/LibCarla/source/carla/rpc/Actor.h +++ b/LibCarla/source/carla/rpc/Actor.h @@ -24,6 +24,8 @@ namespace rpc { actor_id_type id = 0u; + actor_id_type parent_id; + ActorDescription description; geom::BoundingBox bounding_box; @@ -49,7 +51,7 @@ namespace rpc { /// @} - MSGPACK_DEFINE_ARRAY(id, description, bounding_box, semantic_tags, stream_token); + MSGPACK_DEFINE_ARRAY(id, parent_id, description, bounding_box, semantic_tags, stream_token); }; } // namespace rpc diff --git a/PythonAPI/manual_control.py b/PythonAPI/manual_control.py index ecb9190f6..c08b6a721 100755 --- a/PythonAPI/manual_control.py +++ b/PythonAPI/manual_control.py @@ -133,6 +133,7 @@ class World(object): blueprint = self._get_random_blueprint() spawn_points = self.world.get_map().get_spawn_points() spawn_point = random.choice(spawn_points) if spawn_points else carla.Transform() + blueprint.set_attribute('role_name', 'hero') self.vehicle = self.world.spawn_actor(blueprint, spawn_point) self.collision_sensor = CollisionSensor(self.vehicle, self.hud) self.lane_invasion_sensor = LaneInvasionSensor(self.vehicle, self.hud) @@ -150,6 +151,8 @@ class World(object): start_pose.rotation.roll = 0.0 start_pose.rotation.pitch = 0.0 blueprint = self._get_random_blueprint() + blueprint.set_attribute('role_name', 'hero') + self.destroy() self.vehicle = self.world.spawn_actor(blueprint, start_pose) self.collision_sensor = CollisionSensor(self.vehicle, self.hud) diff --git a/PythonAPI/source/libcarla/Actor.cpp b/PythonAPI/source/libcarla/Actor.cpp index 63ccb8638..56b4fc3dd 100644 --- a/PythonAPI/source/libcarla/Actor.cpp +++ b/PythonAPI/source/libcarla/Actor.cpp @@ -47,6 +47,13 @@ void export_actor() { .add_property("parent", CALL_RETURNING_COPY(cc::Actor, GetParent)) .add_property("semantic_tags", &GetSemanticTags) .add_property("is_alive", CALL_RETURNING_COPY(cc::Actor, IsAlive)) + .add_property("attributes", +[](const cc::Actor &self) { + boost::python::dict atttribute_dict; + for (auto &&attribute_value : self.GetAttributes()) { + atttribute_dict[attribute_value.GetId()] = attribute_value.GetValue(); + } + return atttribute_dict; + }) .def("get_world", CALL_RETURNING_COPY(cc::Actor, GetWorld)) .def("get_location", &cc::Actor::GetLocation) .def("get_transform", &cc::Actor::GetTransform) diff --git a/PythonAPI/spawn_npc.py b/PythonAPI/spawn_npc.py index 470a6f1b6..71491af1a 100755 --- a/PythonAPI/spawn_npc.py +++ b/PythonAPI/spawn_npc.py @@ -77,6 +77,7 @@ def main(): if blueprint.has_attribute('color'): color = random.choice(blueprint.get_attribute('color').recommended_values) blueprint.set_attribute('color', color) + blueprint.set_attribute('role_name', 'autopilot') vehicle = world.try_spawn_actor(blueprint, transform) if vehicle is not None: actor_list.append(vehicle) diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.cpp index afc45a420..4b2061828 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.cpp @@ -192,6 +192,30 @@ static void FillIdAndTags(FActorDefinition &Def, TStrs &&... Strings) { Def.Id = JoinStrings(TEXT("."), std::forward(Strings)...).ToLower(); Def.Tags = JoinStrings(TEXT(","), std::forward(Strings)...).ToLower(); + // each actor gets an actor role name attribute (empty by default) + FActorVariation ActorRole; + ActorRole.Id = TEXT("role_name"); + ActorRole.Type = EActorAttributeType::String; + ActorRole.RecommendedValues = { TEXT("default") }; + ActorRole.bRestrictToRecommended = false; + Def.Variations.Emplace(ActorRole); +} + +static void AddRecommendedValuesForActorRoleName(FActorDefinition &Definition, TArray &&RecommendedValues) +{ + for (auto &&ActorVariation: Definition.Variations) + { + if ( ActorVariation.Id == "role_name" ) + { + ActorVariation.RecommendedValues = RecommendedValues; + return; + } + } +} + +static void AddRecommendedValuesForSensorRoleNames(FActorDefinition &Definition) +{ + AddRecommendedValuesForActorRoleName(Definition, {TEXT("front"), TEXT("back"), TEXT("left"), TEXT("right"), TEXT("front_left"), TEXT("front_right"), TEXT("back_left"), TEXT("back_right")}); } FActorDefinition UActorBlueprintFunctionLibrary::MakeGenericSensorDefinition( @@ -200,6 +224,7 @@ FActorDefinition UActorBlueprintFunctionLibrary::MakeGenericSensorDefinition( { FActorDefinition Definition; FillIdAndTags(Definition, TEXT("sensor"), Type, Id); + AddRecommendedValuesForSensorRoleNames(Definition); return Definition; } @@ -221,6 +246,7 @@ void UActorBlueprintFunctionLibrary::MakeCameraDefinition( FActorDefinition &Definition) { FillIdAndTags(Definition, TEXT("sensor"), TEXT("camera"), Id); + AddRecommendedValuesForSensorRoleNames(Definition); // FOV. FActorVariation FOV; FOV.Id = TEXT("fov"); @@ -239,7 +265,7 @@ void UActorBlueprintFunctionLibrary::MakeCameraDefinition( ResY.RecommendedValues = { TEXT("600") }; ResY.bRestrictToRecommended = false; - Definition.Variations = {ResX, ResY, FOV}; + Definition.Variations.Append({ResX, ResY, FOV}); if (bEnableModifyingPostProcessEffects) { @@ -270,6 +296,7 @@ void UActorBlueprintFunctionLibrary::MakeLidarDefinition( FActorDefinition &Definition) { FillIdAndTags(Definition, TEXT("sensor"), TEXT("lidar"), Id); + AddRecommendedValuesForSensorRoleNames(Definition); // Number of channels. FActorVariation Channels; Channels.Id = TEXT("channels"); @@ -301,7 +328,7 @@ void UActorBlueprintFunctionLibrary::MakeLidarDefinition( LowerFOV.Type = EActorAttributeType::Float; LowerFOV.RecommendedValues = { TEXT("-30.0") }; - Definition.Variations = {Channels, Range, PointsPerSecond, Frequency, UpperFOV, LowerFOV}; + Definition.Variations.Append({Channels, Range, PointsPerSecond, Frequency, UpperFOV, LowerFOV}); Success = CheckActorDefinition(Definition); } @@ -313,6 +340,7 @@ void UActorBlueprintFunctionLibrary::MakeVehicleDefinition( { /// @todo We need to validate here the params. FillIdAndTags(Definition, TEXT("vehicle"), Parameters.Make, Parameters.Model); + AddRecommendedValuesForActorRoleName(Definition, {TEXT("autopilot"), TEXT("scenario"), TEXT("ego_vehicle")}); Definition.Class = Parameters.Class; if (Parameters.RecommendedColors.Num() > 0) { @@ -326,6 +354,12 @@ void UActorBlueprintFunctionLibrary::MakeVehicleDefinition( } Definition.Variations.Emplace(Colors); } + + Definition.Attributes.Emplace(FActorAttribute{ + TEXT("object_type"), + EActorAttributeType::String, + Parameters.ObjectType}); + Definition.Attributes.Emplace(FActorAttribute{ TEXT("number_of_wheels"), EActorAttributeType::Int, diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.h index 5f929e80b..96028c4a9 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/ActorBlueprintFunctionLibrary.h @@ -34,6 +34,9 @@ struct CARLA_API FVehicleParameters UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 NumberOfWheels = 4; + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FString ObjectType; + UPROPERTY(EditAnywhere, BlueprintReadWrite) TArray RecommendedColors; }; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp index 11b1d8fcb..3bb302190 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp @@ -133,6 +133,7 @@ public: Actor.id = ActorView.GetActorId(); if (ActorView.IsValid()) { + Actor.parent_id = Episode->GetActorRegistry().Find(ActorView.GetActor()->GetOwner()).GetActorId(); Actor.description = *ActorView.GetActorDescription(); Actor.bounding_box = GetActorBoundingBox(*ActorView.GetActor()); Actor.semantic_tags.reserve(ActorView.GetSemanticTags().Num());