diff --git a/LibCarla/source/carla/client/TrafficLight.cpp b/LibCarla/source/carla/client/TrafficLight.cpp index 3b7057c8c..1f2536386 100644 --- a/LibCarla/source/carla/client/TrafficLight.cpp +++ b/LibCarla/source/carla/client/TrafficLight.cpp @@ -11,64 +11,64 @@ namespace carla { namespace client { -void TrafficLight::SetState(rpc::TrafficLightState state) { - GetEpisode().Lock()->SetTrafficLightState(*this, state); -} - -rpc::TrafficLightState TrafficLight::GetState() const { - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.state; -} - -void TrafficLight::SetGreenTime(float green_time) { - GetEpisode().Lock()->SetTrafficLightGreenTime(*this, green_time); -} - -float TrafficLight::GetGreenTime() const { - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.green_time; -} - -void TrafficLight::SetYellowTime(float yellow_time) { - GetEpisode().Lock()->SetTrafficLightYellowTime(*this, yellow_time); -} - -float TrafficLight::GetYellowTime() const { - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.yellow_time; -} - -void TrafficLight::SetRedTime(float red_time) { - GetEpisode().Lock()->SetTrafficLightRedTime(*this, red_time); -} - -float TrafficLight::GetRedTime() const { - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.red_time; -} - -float TrafficLight::GetElapsedTime() const { - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.elapsed_time; -} - -void TrafficLight::Freeze(bool freeze) { - GetEpisode().Lock()->FreezeTrafficLight(*this, freeze); -} - -bool TrafficLight::IsFrozen() const { - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.time_is_frozen; -} - -uint32_t TrafficLight::GetPoleIndex() -{ - return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.pole_index; -} - -std::vector> TrafficLight::GetGroupTrafficLights() { - std::vector> result; - auto ids = GetEpisode().Lock()->GetGroupTrafficLights(*this); - for (auto id : ids) { - SharedPtr actor = GetWorld().GetActors()->Find(id); - result.push_back(boost::static_pointer_cast(actor)); + void TrafficLight::SetState(rpc::TrafficLightState state) { + GetEpisode().Lock()->SetTrafficLightState(*this, state); + } + + rpc::TrafficLightState TrafficLight::GetState() const { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.state; + } + + void TrafficLight::SetGreenTime(float green_time) { + GetEpisode().Lock()->SetTrafficLightGreenTime(*this, green_time); + } + + float TrafficLight::GetGreenTime() const { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.green_time; + } + + void TrafficLight::SetYellowTime(float yellow_time) { + GetEpisode().Lock()->SetTrafficLightYellowTime(*this, yellow_time); + } + + float TrafficLight::GetYellowTime() const { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.yellow_time; + } + + void TrafficLight::SetRedTime(float red_time) { + GetEpisode().Lock()->SetTrafficLightRedTime(*this, red_time); + } + + float TrafficLight::GetRedTime() const { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.red_time; + } + + float TrafficLight::GetElapsedTime() const { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.elapsed_time; + } + + void TrafficLight::Freeze(bool freeze) { + GetEpisode().Lock()->FreezeTrafficLight(*this, freeze); + } + + bool TrafficLight::IsFrozen() const { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.time_is_frozen; + } + + uint32_t TrafficLight::GetPoleIndex() + { + return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.pole_index; + } + + std::vector> TrafficLight::GetGroupTrafficLights() { + std::vector> result; + auto ids = GetEpisode().Lock()->GetGroupTrafficLights(*this); + for (auto id : ids) { + SharedPtr actor = GetWorld().GetActors()->Find(id); + result.push_back(boost::static_pointer_cast(actor)); + } + return result; } - return result; -} } // namespace client } // namespace carla diff --git a/LibCarla/source/carla/client/TrafficLight.h b/LibCarla/source/carla/client/TrafficLight.h index 87f9b2790..803a52166 100644 --- a/LibCarla/source/carla/client/TrafficLight.h +++ b/LibCarla/source/carla/client/TrafficLight.h @@ -12,57 +12,57 @@ namespace carla { namespace client { -class TrafficLight : public Actor { + class TrafficLight : public Actor { -public: + public: - explicit TrafficLight(ActorInitializer init) : Actor(std::move(init)) {} + explicit TrafficLight(ActorInitializer init) : Actor(std::move(init)) {} - void SetState(rpc::TrafficLightState state); + void SetState(rpc::TrafficLightState state); - /// Return the current state of the traffic light. - /// - /// @note This function does not call the simulator, it returns the data - /// received in the last tick. - rpc::TrafficLightState GetState() const; + /// Return the current state of the traffic light. + /// + /// @note This function does not call the simulator, it returns the data + /// received in the last tick. + rpc::TrafficLightState GetState() const; - void SetGreenTime(float green_time); + void SetGreenTime(float green_time); - /// @note This function does not call the simulator, it returns the data - /// received in the last tick. - float GetGreenTime() const; + /// @note This function does not call the simulator, it returns the data + /// received in the last tick. + float GetGreenTime() const; - void SetYellowTime(float yellow_time); + void SetYellowTime(float yellow_time); - /// @note This function does not call the simulator, it returns the data - /// received in the last tick. - float GetYellowTime() const; + /// @note This function does not call the simulator, it returns the data + /// received in the last tick. + float GetYellowTime() const; - void SetRedTime(float red_time); + void SetRedTime(float red_time); - /// @note This function does not call the simulator, it returns the data - /// received in the last tick. - float GetRedTime() const; + /// @note This function does not call the simulator, it returns the data + /// received in the last tick. + float GetRedTime() const; - /// @note This function does not call the simulator, it returns the data - /// received in the last tick. - float GetElapsedTime() const; + /// @note This function does not call the simulator, it returns the data + /// received in the last tick. + float GetElapsedTime() const; - void Freeze(bool freeze); + void Freeze(bool freeze); - /// @note This function does not call the simulator, it returns the data - /// received in the last tick. - bool IsFrozen() const; + /// @note This function does not call the simulator, it returns the data + /// received in the last tick. + bool IsFrozen() const; - /// Returns the index of the pole in the traffic light group - uint32_t GetPoleIndex(); + /// Returns the index of the pole in the traffic light group + uint32_t GetPoleIndex(); - /// Return all traffic lights in the group this one belongs to. - /// - /// @note This function calls the simulator - std::vector> GetGroupTrafficLights(); + /// Return all traffic lights in the group this one belongs to. + /// + /// @note This function calls the simulator + std::vector> GetGroupTrafficLights(); -}; + }; } // namespace client } // namespace carla diff --git a/LibCarla/source/carla/opendrive/parser/ControllerParser.cpp b/LibCarla/source/carla/opendrive/parser/ControllerParser.cpp index cb002da21..955531ae6 100644 --- a/LibCarla/source/carla/opendrive/parser/ControllerParser.cpp +++ b/LibCarla/source/carla/opendrive/parser/ControllerParser.cpp @@ -14,44 +14,44 @@ namespace carla { namespace opendrive { namespace parser { -void ControllerParser::Parse( + void ControllerParser::Parse( const pugi::xml_document &xml, carla::road::MapBuilder &map_builder) { - // Extracting the OpenDRIVE - const pugi::xml_node opendrive_node = xml.child("OpenDRIVE"); - for (pugi::xml_node controller_node = opendrive_node.child("controller"); - controller_node; - controller_node = controller_node.next_sibling("controller")) { + // Extracting the OpenDRIVE + const pugi::xml_node opendrive_node = xml.child("OpenDRIVE"); + for (pugi::xml_node controller_node = opendrive_node.child("controller"); + controller_node; + controller_node = controller_node.next_sibling("controller")) { - const road::ContId controller_id = controller_node.attribute("id").value(); - const std::string controller_name = controller_node.attribute("name").value(); - const uint32_t controller_sequence = controller_node.attribute("sequence").as_uint(); + const road::ContId controller_id = controller_node.attribute("id").value(); + const std::string controller_name = controller_node.attribute("name").value(); + const uint32_t controller_sequence = controller_node.attribute("sequence").as_uint(); - log_debug("Controller: ", - controller_id, - controller_name, - controller_sequence); + log_debug("Controller: ", + controller_id, + controller_name, + controller_sequence); - std::set signals; + std::set signals; - for (pugi::xml_node control_node : controller_node.children("control")) { - const road::SignId signal_id = control_node.attribute("signalId").value(); - // The controller_type is included in the OpenDrive format but not used yet - // const std::string controller_type = control_node.attribute("type").value(); - signals.insert(signal_id); + for (pugi::xml_node control_node : controller_node.children("control")) { + const road::SignId signal_id = control_node.attribute("signalId").value(); + // The controller_type is included in the OpenDrive format but not used yet + // const std::string controller_type = control_node.attribute("type").value(); + signals.insert(signal_id); + } + + map_builder.CreateController( + controller_id, + controller_name, + controller_sequence, + std::move(signals) + ); } - map_builder.CreateController( - controller_id, - controller_name, - controller_sequence, - std::move(signals) - ); } -} - } // namespace parser } // namespace opendrive } // namespace carla diff --git a/LibCarla/source/carla/road/Controller.h b/LibCarla/source/carla/road/Controller.h index c97b2ea60..464c86c16 100644 --- a/LibCarla/source/carla/road/Controller.h +++ b/LibCarla/source/carla/road/Controller.h @@ -14,51 +14,51 @@ namespace carla { namespace road { -class MapBuilder; + class MapBuilder; -class Controller : private MovableNonCopyable { + class Controller : private MovableNonCopyable { -public: + public: - Controller( - ContId id, - std::string name, - uint32_t sequence) - : _id(id), - _name(name), - _sequence(sequence){} + Controller( + ContId id, + std::string name, + uint32_t sequence) + : _id(id), + _name(name), + _sequence(sequence){} - const ContId& GetControllerId() const{ - return _id; - } + const ContId& GetControllerId() const{ + return _id; + } - const std::string& GetName() const { - return _name; - } + const std::string& GetName() const { + return _name; + } - const uint32_t &GetSequence() const { - return _sequence; - } + const uint32_t &GetSequence() const { + return _sequence; + } - const std::set& GetSignals() const { - return _signals; - } + const std::set& GetSignals() const { + return _signals; + } - const std::set& GetJunctions() const { - return _junctions; - } + const std::set& GetJunctions() const { + return _junctions; + } -private: + private: - friend MapBuilder; + friend MapBuilder; - ContId _id; - std::string _name; - uint32_t _sequence; + ContId _id; + std::string _name; + uint32_t _sequence; - std::set _junctions; - std::set _signals; -}; + std::set _junctions; + std::set _signals; + }; } // namespace road } // namespace carla diff --git a/LibCarla/source/carla/road/MapBuilder.cpp b/LibCarla/source/carla/road/MapBuilder.cpp index df47df6d7..c41d497cd 100644 --- a/LibCarla/source/carla/road/MapBuilder.cpp +++ b/LibCarla/source/carla/road/MapBuilder.cpp @@ -769,6 +769,10 @@ namespace road { auto it = _map_data._controllers.find(controller); DEBUG_ASSERT(it != _map_data._controllers.end()); it->second->_junctions.insert(junction.first); + for(const auto & signal : it->second->_signals) { + auto signal_it = _map_data._signals.find(signal); + signal_it->second->_controllers.insert(controller); + } } } } diff --git a/LibCarla/source/carla/road/Signal.h b/LibCarla/source/carla/road/Signal.h index 229f9b679..4e78a79e2 100644 --- a/LibCarla/source/carla/road/Signal.h +++ b/LibCarla/source/carla/road/Signal.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma // de Barcelona (UAB). // // This work is licensed under the terms of the MIT license. @@ -173,6 +173,10 @@ namespace road { return _transform; } + const std::set& GetControllers() const { + return _controllers; + } + private: friend MapBuilder; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.cpp index 08912591a..c57d5e3eb 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.cpp @@ -1,16 +1,15 @@ -// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see . +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . #include "SignComponent.h" - -// Sets default values for this component's properties USignComponent::USignComponent() { - // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features - // off to improve performance if you don't need them. PrimaryComponentTick.bCanEverTick = false; - } // Called when the game starts @@ -27,3 +26,12 @@ void USignComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC Super::TickComponent(DeltaTime, TickType, ThisTickFunction); } + +const FString& USignComponent::GetSignId() const +{ + return SignId; +} + +void USignComponent::SetSignId(const FString &Id) { + SignId = Id; +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.h index f968bc880..82efc29fa 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/SignComponent.h @@ -1,40 +1,41 @@ -// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see . +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . #pragma once #include "CoreMinimal.h" -#include "Components/ActorComponent.h" +#include "Components/SceneComponent.h" #include "Carla/OpenDrive/OpenDrive.h" #include "SignComponent.generated.h" UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) -class CARLA_API USignComponent : public UActorComponent +class CARLA_API USignComponent : public USceneComponent { GENERATED_BODY() public: - // Sets default values for this component's properties USignComponent(); - void SetSignId(carla::road::SignId SignId) - { - Id = SignId; - } + UFUNCTION(BlueprintPure) + const FString &GetSignId() const; + + UFUNCTION(BlueprintCallable) + void SetSignId(const FString &Id); protected: // Called when the game starts virtual void BeginPlay() override; -public: // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; - private: - carla::road::SignId Id; - - FTransform Transform; + UPROPERTY(Category = "Traffic Sign", EditAnywhere) + FString SignId; }; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.cpp index e26a3ecb0..a35197c49 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.cpp @@ -1,34 +1,71 @@ -// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see . +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . #include "TrafficLightComponent.h" +#include "Kismet/GameplayStatics.h" +#include "TrafficLightGroup.h" +#include "TrafficLightManager.h" - -// Sets default values for this component's properties UTrafficLightComponent::UTrafficLightComponent() + : Super() { - // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features - // off to improve performance if you don't need them. - PrimaryComponentTick.bCanEverTick = true; - - // ... } - // Called when the game starts void UTrafficLightComponent::BeginPlay() { Super::BeginPlay(); - // ... + // Search the Traffic Light Manager + TArray TrafficLightManagerArray; + UGameplayStatics::GetAllActorsOfClass( + GetWorld(), + ATrafficLightManager::StaticClass(), + TrafficLightManagerArray); + // Create it if missing + if (!TrafficLightManagerArray.Num()) + { + TrafficLightManagerArray.Add( + GetWorld()->SpawnActor()); + } + + // Register this component + ATrafficLightManager *TrafficLightManager = Cast(TrafficLightManagerArray.Top()); + TrafficLightManager->RegisterLightComponent(this); } - // Called every frame void UTrafficLightComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - // ... } + +void UTrafficLightComponent::SetLightState(ETrafficLightState NewState) +{ + LightState = NewState; + LightChangeDispatcher.Broadcast(); +} + +ETrafficLightState UTrafficLightComponent::GetLightState() const +{ + return LightState; +} + +void UTrafficLightComponent::SetFrozenGroup(bool InFreeze) +{ + if (TrafficLightGroup) + { + TrafficLightGroup->SetFrozenGroup(InFreeze); + } +} + +ATrafficLightGroup* UTrafficLightComponent::GetGroup() +{ + return TrafficLightGroup; +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.h index 1a3ccdf05..c7d105081 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightComponent.h @@ -1,14 +1,25 @@ -// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see . +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . #pragma once #include "CoreMinimal.h" -#include "Components/ActorComponent.h" +#include "SignComponent.h" +#include "TrafficLightState.h" #include "TrafficLightComponent.generated.h" +class ATrafficLightManager; +class ATrafficLightGroup; -UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) -class CARLA_API UTrafficLightComponent : public UActorComponent +// Delegate to define dispatcher +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FLightChangeDispatcher); +//DECLARE_DYNAMIC_MULTICAST_DELEGATE_RetVal(ETrafficLightState, FLightChangeDispatcher); + +UCLASS(Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) +class CARLA_API UTrafficLightComponent : public USignComponent { GENERATED_BODY() @@ -16,12 +27,34 @@ public: // Sets default values for this component's properties UTrafficLightComponent(); + UFUNCTION(BlueprintCallable) + void SetLightState(ETrafficLightState NewState); + + UFUNCTION(BlueprintCallable) + ETrafficLightState GetLightState() const; + + UFUNCTION(BlueprintCallable) + void SetFrozenGroup(bool InFreeze); + + UFUNCTION(BlueprintPure) + ATrafficLightGroup* GetGroup(); + protected: // Called when the game starts virtual void BeginPlay() override; -public: // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; +private: + + friend ATrafficLightManager; + UPROPERTY(Category = "Traffic Light", EditAnywhere) + ETrafficLightState LightState; + + UPROPERTY(BlueprintAssignable, Category = "Traffic Light") + FLightChangeDispatcher LightChangeDispatcher; + + UPROPERTY() + ATrafficLightGroup *TrafficLightGroup = nullptr; }; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightController.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightController.cpp new file mode 100644 index 000000000..3d0fbf634 --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightController.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#include "TrafficLightController.h" + +UTrafficLightController::UTrafficLightController() +{ + +} + +void UTrafficLightController::SetState(TArray States) +{ + LightStates = States; + CurrentState = 0; +} + +const FTrafficLightStage &UTrafficLightController::GetCurrentState() const +{ + return LightStates[CurrentState]; +} + +float UTrafficLightController::NextState() +{ + CurrentState = (CurrentState + 1) % LightStates.Num(); + SetTrafficLightsState(GetCurrentState().State); + return GetCurrentState().Time; +} + +const TArray &UTrafficLightController::GetTrafficLights() +{ + return TrafficLights; +} + +void UTrafficLightController::AddTrafficLight(UTrafficLightComponent * TrafficLight) +{ + TrafficLights.Add(TrafficLight); +} + +const FString &UTrafficLightController::GetControllerId() const +{ + return ControllerId; +} + +void UTrafficLightController::SetControllerId(const FString &Id) +{ + ControllerId = Id; +} + +bool UTrafficLightController::IsCycleFinished() const +{ + return CurrentState == (LightStates.Num() - 1); +} + +void UTrafficLightController::SetTrafficLightsState(ETrafficLightState NewState) +{ + for(auto *Light : TrafficLights) + { + Light->SetLightState(NewState); + } +} + +int UTrafficLightController::GetSequence() const +{ + return Sequence; +} + +void UTrafficLightController::SetSequence(int InSequence) +{ + Sequence = InSequence; +} + +void UTrafficLightController::ResetState() +{ + CurrentState = (LightStates.Num() - 1); + SetTrafficLightsState(GetCurrentState().State); +} diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightController.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightController.h new file mode 100644 index 000000000..2158daafa --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightController.h @@ -0,0 +1,96 @@ +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#pragma once + +#include "CoreMinimal.h" +#include "Object.h" +#include "TrafficLightState.h" +#include "TrafficLightComponent.h" +#include "Containers/Map.h" +#include "TrafficLightController.generated.h" + +// Defines a stage of a semaphor with a State and +// the time this state lasts +USTRUCT(BlueprintType) +struct FTrafficLightStage +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float Time; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + ETrafficLightState State; +}; + +// Maps a controller from OpenDrive. +// Controls the asociated traffic lights and its cycles +UCLASS(BlueprintType) +class CARLA_API UTrafficLightController : public UObject +{ + GENERATED_BODY() + +public: + + UTrafficLightController(); + + UFUNCTION(BlueprintCallable) + void SetState(TArray States); + + UFUNCTION(BlueprintPure) + const FTrafficLightStage &GetCurrentState() const; + + // Updates traffic light components to the next state + UFUNCTION(BlueprintCallable) + float NextState(); + + UFUNCTION(BlueprintPure) + const TArray &GetTrafficLights(); + + UFUNCTION(BlueprintPure) + const FString &GetControllerId() const; + + UFUNCTION(BlueprintCallable) + void SetControllerId(const FString &Id); + + UFUNCTION(BlueprintCallable) + void AddTrafficLight(UTrafficLightComponent * TrafficLight); + + UFUNCTION(BlueprintCallable) + bool IsCycleFinished() const; + + UFUNCTION(BlueprintCallable) + void SetTrafficLightsState(ETrafficLightState NewState); + + UFUNCTION(BlueprintCallable) + int GetSequence() const; + + UFUNCTION(BlueprintCallable) + void SetSequence(int InSequence); + + UFUNCTION(BlueprintCallable) + void ResetState(); +private: + + UPROPERTY(EditAnywhere) + FString ControllerId; + + UPROPERTY(EditAnywhere) + int CurrentState = 0; + + // Pairs with the state of the semaphors (time - state) e.g. 10s in green + UPROPERTY(EditAnywhere) + TArray LightStates = { + {10, ETrafficLightState::Green}, {3, ETrafficLightState::Yellow}, {2, ETrafficLightState::Red}}; + + UPROPERTY(EditAnywhere) + TArray TrafficLights; + + // Sequence within junction (unused for now) + UPROPERTY(EditAnywhere) + int Sequence = 0; +}; \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightGroup.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightGroup.cpp new file mode 100644 index 000000000..be9f3b242 --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightGroup.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#include "Carla.h" +#include "TrafficLightGroup.h" + + +// Sets default values +ATrafficLightGroup::ATrafficLightGroup() +{ + // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + SceneComponent = CreateDefaultSubobject(TEXT("RootComponent")); + RootComponent = SceneComponent; +} + +// Called when the game starts or when spawned +void ATrafficLightGroup::BeginPlay() +{ + Super::BeginPlay(); + +} + +void ATrafficLightGroup::SetFrozenGroup(bool InFreeze) +{ + bIsFrozen = InFreeze; +} + +// Called every frame +void ATrafficLightGroup::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + if (bIsFrozen) + { + return; + } + + Timer -= DeltaTime; + + if(Timer <= 0 && Controllers.Num()) + { + NextCycleStep(); + } +} + +void ATrafficLightGroup::NextCycleStep() +{ + UTrafficLightController* controller = Controllers[CurrentController]; + if (controller->IsCycleFinished()) + { + NextController(); + } + else + { + Timer = controller->NextState(); + } +} + +void ATrafficLightGroup::NextController() +{ + CurrentController = (CurrentController + 1) % Controllers.Num(); + UTrafficLightController* controller = Controllers[CurrentController]; + Timer = controller->NextState(); +} + +int ATrafficLightGroup::GetJunctionId() const +{ + return JunctionId; +} diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightGroup.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightGroup.h new file mode 100644 index 000000000..56ee208bd --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightGroup.h @@ -0,0 +1,72 @@ +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "Components/SceneComponent.h" +#include "TrafficLightComponent.h" +#include "TrafficLightController.h" +#include "TrafficLightGroup.generated.h" + +class ATrafficLightManager; + +// Class with the logic of semaphors +UCLASS() +class CARLA_API ATrafficLightGroup : public AActor +{ + GENERATED_BODY() + +public: + // Sets default values for this actor's properties + ATrafficLightGroup(); + + UFUNCTION(BlueprintPure) + TArray& GetControllers() { + return Controllers; + } + + UFUNCTION(BlueprintCallable) + void SetFrozenGroup(bool InFreeze); + + UFUNCTION(BlueprintPure) + int GetJunctionId() const; + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + + // Called every frame + virtual void Tick(float DeltaTime) override; + +private: + + friend ATrafficLightManager; + UPROPERTY(Category = "Traffic Group", VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) + USceneComponent *SceneComponent; + + UPROPERTY(Category = "Traffic Group", EditAnywhere) + TArray Controllers; + + UPROPERTY() + float Timer = 0; + + UPROPERTY() + int CurrentController = 0; + + UFUNCTION() + void NextCycleStep(); + + UFUNCTION() + void NextController(); + + UPROPERTY(Category = "Traffic Group", EditAnywhere) + bool bIsFrozen = false; + + UPROPERTY(Category = "Traffic Group", EditAnywhere) + int JunctionId = -1; +}; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightManager.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightManager.cpp new file mode 100644 index 000000000..cd5132708 --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightManager.cpp @@ -0,0 +1,116 @@ +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#include "TrafficLightManager.h" +#include "Game/CarlaStatics.h" +#include + +ATrafficLightManager::ATrafficLightManager() { + PrimaryActorTick.bCanEverTick = false; +} + +void ATrafficLightManager::RegisterLightComponent(UTrafficLightComponent * TrafficLight) { + // Cast to std::string + carla::road::SignId SignId(TCHAR_TO_UTF8(*(TrafficLight->GetSignId()))); + + // Get OpenDRIVE signal + if (GetMap()->GetSignals().count(SignId) == 0) + { + carla::log_warning("Error: missing signal with id:", SignId); + return; + } + const auto &Signal = GetMap()->GetSignals().at(SignId); + if(Signal->GetControllers().empty()) + { + carla::log_warning("Error: no controllers in signal", SignId); + return; + } + // Only one controller per signal + auto ControllerId = *(Signal->GetControllers().begin()); + + // Get controller + const auto &Controller = GetMap()->GetControllers().at(ControllerId); + if(Controller->GetJunctions().empty()) + { + carla::log_warning("Error: no junctions in controller", ControllerId); + return; + } + // Get junction of the controller + auto JunctionId = *(Controller->GetJunctions().begin()); + + // Search/create TrafficGroup (junction traffic light manager) + if(!TrafficGroups.Contains(JunctionId)) + { + auto * TrafficLightGroup = + GetWorld()->SpawnActor(); + TrafficLightGroup->JunctionId = JunctionId; + TrafficGroups.Add(JunctionId, TrafficLightGroup); + carla::log_warning("Spawn TrafficLight Group"); + } + auto * TrafficLightGroup = TrafficGroups[JunctionId]; + + // Search/create controller in the junction + if(!TrafficControllers.Contains(ControllerId.c_str())) + { + auto *TrafficLightController = NewObject(); + TrafficLightController->SetControllerId(ControllerId.c_str()); + TrafficLightGroup->GetControllers().Add(TrafficLightController); + TrafficControllers.Add(ControllerId.c_str(), TrafficLightController); + carla::log_warning("Created Controller"); + } + auto *TrafficLightController = TrafficControllers[ControllerId.c_str()]; + + TrafficLight->TrafficLightGroup = TrafficLightGroup; + + // Add signal to controller + TrafficLightController->AddTrafficLight(TrafficLight); + TrafficLightController->ResetState(); + + // Add signal to map + TrafficLights.Add(TrafficLight->GetSignId(), TrafficLight); +} + +const boost::optional& ATrafficLightManager::GetMap() { + if(!GameMode) { + GameMode = UCarlaStatics::GetGameMode(this); + } + return GameMode->GetMap(); +} + +// Called when the game starts +void ATrafficLightManager::BeginPlay() +{ + Super::BeginPlay(); + +} + +ATrafficLightGroup* ATrafficLightManager::GetTrafficGroup(carla::road::JuncId JunctionId) +{ + if (TrafficGroups.Contains(JunctionId)) + { + return TrafficGroups[JunctionId]; + } + return nullptr; +} + + +UTrafficLightController* ATrafficLightManager::GetController(FString ControllerId) +{ + if (TrafficControllers.Contains(ControllerId)) + { + return TrafficControllers[ControllerId]; + } + return nullptr; +} + +UTrafficLightComponent* ATrafficLightManager::GetTrafficLight(FString SignId) +{ + if (!TrafficLights.Contains(SignId)) + { + return nullptr; + } + return TrafficLights[SignId]; +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightManager.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightManager.h new file mode 100644 index 000000000..b19b2aada --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightManager.h @@ -0,0 +1,60 @@ +// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#pragma once + +#include "TrafficLightComponent.h" +#include "TrafficLightGroup.h" +#include "Game/CarlaGameModeBase.h" +#include "TrafficLightManager.generated.h" + +// Class In charge of creating and assigning traffic +// light groups, controllers and components. +UCLASS() +class CARLA_API ATrafficLightManager : public AActor +{ + GENERATED_BODY() + +public: + + ATrafficLightManager(); + + UFUNCTION(BlueprintCallable) + void RegisterLightComponent(UTrafficLightComponent * TrafficLight); + + const boost::optional &GetMap(); + + UFUNCTION(BlueprintCallable) + ATrafficLightGroup* GetTrafficGroup(int JunctionId); + + UFUNCTION(BlueprintCallable) + UTrafficLightController* GetController(FString ControllerId); + + UFUNCTION(BlueprintCallable) + UTrafficLightComponent* GetTrafficLight(FString SignId); + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + +private: + + // Cached Carla Game Mode + UPROPERTY() + ACarlaGameModeBase *GameMode = 0; + + // Mapped references to ATrafficLightGroup (junction) + UPROPERTY() + TMap TrafficGroups; + + // Mapped references to UTrafficLightController (controllers) + UPROPERTY() + TMap TrafficControllers; + + // Mapped references to individual TrafficLightComponents + UPROPERTY() + TMap TrafficLights; +};