diff --git a/Docs/python_api.md b/Docs/python_api.md index 381c42b9d..3fea6ea68 100644 --- a/Docs/python_api.md +++ b/Docs/python_api.md @@ -108,10 +108,25 @@ - `apply_control(vehicle_control)` - `get_control()` - `set_autopilot(enabled=True)` +- `get_speed_limit()` +- `get_traffic_light_state()` +- `is_at_traffic_light()` +- `get_traffic_light()` ## `carla.TrafficLight(carla.Actor)` - `state` +- `set_state(traffic_light_state)` +- `get_state()` +- `set_green_time(green_time)` +- `get_green_time()` +- `set_yellow_time(yellow_time)` +- `get_yellow_time()` +- `set_red_time(red_time)` +- `get_red_time()` +- `get_elapsed_time()` +- `freeze(True)` +- `is_frozen()` ## `carla.Sensor(carla.Actor)` @@ -303,10 +318,10 @@ Static presets ## `carla.TrafficLightState` -- `Off` - `Red` - `Yellow` - `Green` +- `Off` - `Unknown` ## `carla.LaneMarking` diff --git a/LibCarla/source/carla/client/TrafficLight.cpp b/LibCarla/source/carla/client/TrafficLight.cpp index 3ee88a418..eb8eefc52 100644 --- a/LibCarla/source/carla/client/TrafficLight.cpp +++ b/LibCarla/source/carla/client/TrafficLight.cpp @@ -11,9 +11,50 @@ namespace carla { namespace client { - rpc::TrafficLightState TrafficLight::GetState() { - return GetEpisode().Lock()->GetActorDynamicState(*this).state.traffic_light_state; + void TrafficLight::SetState(rpc::TrafficLightState state) { + GetEpisode().Lock()->SetTrafficLightState(*this, state); } + rpc::TrafficLightState TrafficLight::GetState() const { + return GetEpisode().Lock()->GetActorDynamicState(*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()->GetActorDynamicState(*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()->GetActorDynamicState(*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()->GetActorDynamicState(*this).state.traffic_light_data.red_time; + } + + float TrafficLight::GetElapsedTime() const { + return GetEpisode().Lock()->GetActorDynamicState(*this).state.traffic_light_data.elapsed_time; + } + + void TrafficLight::Freeze(bool freeze) { + GetEpisode().Lock()->FreezeTrafficLight(*this, freeze); + } + + bool TrafficLight::IsFrozen() const { + return GetEpisode().Lock()->GetActorDynamicState(*this).state.traffic_light_data.time_is_frozen; + } + + } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/client/TrafficLight.h b/LibCarla/source/carla/client/TrafficLight.h index 14deb6a00..0f34020a4 100644 --- a/LibCarla/source/carla/client/TrafficLight.h +++ b/LibCarla/source/carla/client/TrafficLight.h @@ -19,10 +19,20 @@ namespace client { /// Return the current state of the traffic light. /// - /// @note This function does not call the simulator, it returns the - /// traffic light state received in the last tick. - rpc::TrafficLightState GetState(); + /// @note These functions do not call the simulator, they return the + /// data received in the last tick. + void SetState(rpc::TrafficLightState state); + rpc::TrafficLightState GetState() const; + void SetGreenTime(float green_time); + float GetGreenTime() const; + void SetYellowTime(float yellow_time); + float GetYellowTime() const; + void SetRedTime(float red_time); + float GetRedTime() const; + float GetElapsedTime() const; + void Freeze(bool freeze); + bool IsFrozen() const; }; } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/client/Vehicle.cpp b/LibCarla/source/carla/client/Vehicle.cpp index bd4c98daf..ac3dc7d81 100644 --- a/LibCarla/source/carla/client/Vehicle.cpp +++ b/LibCarla/source/carla/client/Vehicle.cpp @@ -7,6 +7,9 @@ #include "carla/client/Vehicle.h" #include "carla/client/detail/Simulator.h" +#include "carla/client/ActorList.h" +#include "carla/client/TrafficLight.h" +#include "carla/rpc/TrafficLightState.h" namespace carla { namespace client { @@ -23,8 +26,30 @@ namespace client { } Vehicle::Control Vehicle::GetControl() const { - return GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_control; + return GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_data.control; + } + + float Vehicle::GetSpeedLimit() const + { + return GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_data.speed_limit; + } + + rpc::TrafficLightState Vehicle::GetTrafficLightState() const + { + return GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_data.traffic_light_state; + } + + bool Vehicle::IsAtTrafficLight() + { + return GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_data.has_traffic_light; + } + + SharedPtr Vehicle::GetTrafficLight() const + { + auto id = GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_data.traffic_light_id; + SharedPtr actor = GetWorld().GetActors()->Find(id); + return boost::static_pointer_cast(actor); } } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/client/Vehicle.h b/LibCarla/source/carla/client/Vehicle.h index fd0a2b03c..121cf1ea7 100644 --- a/LibCarla/source/carla/client/Vehicle.h +++ b/LibCarla/source/carla/client/Vehicle.h @@ -8,9 +8,11 @@ #include "carla/client/Actor.h" #include "carla/rpc/VehicleControl.h" +#include "carla/rpc/TrafficLightState.h" namespace carla { namespace client { + class TrafficLight; class Vehicle : public Actor { public: @@ -27,14 +29,22 @@ namespace client { /// Return the control last applied to this vehicle. /// - /// @note This function does not call the simulator, it returns the Control + /// @note The following functions do not call the simulator, they return the data /// received in the last tick. + ////////////////////////////////////////////////////////////////////////////////// Control GetControl() const; - private: + float GetSpeedLimit() const; + rpc::TrafficLightState GetTrafficLightState() const; + + bool IsAtTrafficLight(); + + SharedPtr GetTrafficLight() const; + + private: Control _control; }; } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/client/detail/Client.cpp b/LibCarla/source/carla/client/detail/Client.cpp index 954412711..bbed887d7 100644 --- a/LibCarla/source/carla/client/detail/Client.cpp +++ b/LibCarla/source/carla/client/detail/Client.cpp @@ -14,6 +14,7 @@ #include "carla/rpc/WalkerControl.h" #include "carla/streaming/Client.h" + #include namespace carla { @@ -148,15 +149,35 @@ namespace detail { _pimpl->AsyncCall("apply_control_to_walker", walker, control); } - void Client::SetActorVelocity(const rpc::Actor &actor, const geom::Vector3D &vector) { + void Client::SetTrafficLightState(const rpc::Actor &trafficLight, const rpc::TrafficLightState trafficLightState) { + _pimpl->AsyncCall("set_traffic_light_state", trafficLight, trafficLightState); + } + + void Client::SetTrafficLightGreenTime(const rpc::Actor &trafficLight, float greenTime) { + _pimpl->AsyncCall("set_traffic_light_green_time", trafficLight, greenTime); + } + + void Client::SetTrafficLightYellowTime(const rpc::Actor &trafficLight, float yellowTime) { + _pimpl->AsyncCall("set_traffic_light_yellow_time", trafficLight, yellowTime); + } + + void Client::SetTrafficLightRedTime(const rpc::Actor &trafficLight, float redTime) { + _pimpl->AsyncCall("set_traffic_light_red_time", trafficLight, redTime); + } + + void Client::FreezeTrafficLight(const rpc::Actor &trafficLight, bool freeze) { + _pimpl->AsyncCall("freeze_traffic_light", trafficLight, freeze); + } + + void Client::SetActorVelocity(const rpc::Actor &actor, const geom::Vector3D &vector) { _pimpl->AsyncCall("set_actor_velocity", actor, vector); } - void Client::SetActorAngularVelocity(const rpc::Actor &actor, const geom::Vector3D &vector) { + void Client::SetActorAngularVelocity(const rpc::Actor &actor, const geom::Vector3D &vector) { _pimpl->AsyncCall("set_actor_angular_velocity", actor, vector); } - void Client::AddActorImpulse(const rpc::Actor &actor, const geom::Vector3D &vector) { + void Client::AddActorImpulse(const rpc::Actor &actor, const geom::Vector3D &vector) { _pimpl->AsyncCall("add_actor_impulse", actor, vector); } @@ -176,4 +197,4 @@ namespace detail { } // namespace detail } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/client/detail/Client.h b/LibCarla/source/carla/client/detail/Client.h index 3d891126a..d51c8f904 100644 --- a/LibCarla/source/carla/client/detail/Client.h +++ b/LibCarla/source/carla/client/detail/Client.h @@ -15,6 +15,8 @@ #include "carla/rpc/EpisodeInfo.h" #include "carla/rpc/MapInfo.h" #include "carla/rpc/WeatherParameters.h" +#include "carla/rpc/TrafficLightState.h" + #include #include @@ -107,6 +109,26 @@ namespace detail { const rpc::Actor &walker, const rpc::WalkerControl &control); + void SetTrafficLightState( + const rpc::Actor &trafficLight, + const rpc::TrafficLightState trafficLightState); + + void SetTrafficLightGreenTime( + const rpc::Actor &trafficLight, + float greenTime); + + void SetTrafficLightYellowTime( + const rpc::Actor &trafficLight, + float yellowTime); + + void SetTrafficLightRedTime( + const rpc::Actor &trafficLight, + float redTime); + + void FreezeTrafficLight( + const rpc::Actor &trafficLight, + bool freeze); + void SetActorVelocity( const rpc::Actor &actor, const geom::Vector3D &vector); @@ -135,4 +157,4 @@ namespace detail { } // namespace detail } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/client/detail/Simulator.h b/LibCarla/source/carla/client/detail/Simulator.h index 76aab1c45..1c2596908 100644 --- a/LibCarla/source/carla/client/detail/Simulator.h +++ b/LibCarla/source/carla/client/detail/Simulator.h @@ -18,6 +18,8 @@ #include "carla/client/detail/Episode.h" #include "carla/client/detail/EpisodeProxy.h" #include "carla/profiler/LifetimeProfiled.h" +#include "carla/client/TrafficLight.h" +#include "carla/rpc/TrafficLightState.h" #include @@ -235,6 +237,31 @@ namespace detail { void UnSubscribeFromSensor(const Sensor &sensor); + /// @} + // ========================================================================= + /// @name Operations with traffic lights + // ========================================================================= + /// @{ + void SetTrafficLightState(TrafficLight &trafficLight, const rpc::TrafficLightState trafficLightState) { + _client.SetTrafficLightState(trafficLight.Serialize(), trafficLightState); + } + + void SetTrafficLightGreenTime(TrafficLight &trafficLight, float greenTime) { + _client.SetTrafficLightGreenTime(trafficLight.Serialize(), greenTime); + } + + void SetTrafficLightYellowTime(TrafficLight &trafficLight, float yellowTime) { + _client.SetTrafficLightYellowTime(trafficLight.Serialize(), yellowTime); + } + + void SetTrafficLightRedTime(TrafficLight &trafficLight, float redTime) { + _client.SetTrafficLightRedTime(trafficLight.Serialize(), redTime); + } + + void FreezeTrafficLight(TrafficLight &trafficLight, bool freeze) { + _client.FreezeTrafficLight(trafficLight.Serialize(), freeze); + } + /// @} // ========================================================================= /// @name Debug @@ -258,4 +285,4 @@ namespace detail { } // namespace detail } // namespace client -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/LibCarla/source/carla/rpc/TrafficLightState.h b/LibCarla/source/carla/rpc/TrafficLightState.h index 317c0a1d6..c4c924505 100644 --- a/LibCarla/source/carla/rpc/TrafficLightState.h +++ b/LibCarla/source/carla/rpc/TrafficLightState.h @@ -14,11 +14,10 @@ namespace carla { namespace rpc { enum class TrafficLightState : uint8_t { - Off, Red, Yellow, Green, - + Off, Unknown, SIZE }; @@ -26,4 +25,4 @@ namespace rpc { } // namespace rpc } // namespace carla -MSGPACK_ADD_ENUM(carla::rpc::TrafficLightState); +MSGPACK_ADD_ENUM(carla::rpc::TrafficLightState); \ No newline at end of file diff --git a/LibCarla/source/carla/sensor/data/ActorDynamicState.h b/LibCarla/source/carla/sensor/data/ActorDynamicState.h index 0c209931d..a32df5e6c 100644 --- a/LibCarla/source/carla/sensor/data/ActorDynamicState.h +++ b/LibCarla/source/carla/sensor/data/ActorDynamicState.h @@ -52,6 +52,18 @@ namespace detail { }; #pragma pack(pop) +#pragma pack(push, 1) + struct VehicleData { + VehicleData() = default; + + PackedVehicleControl control; + float speed_limit; + rpc::TrafficLightState traffic_light_state; + bool has_traffic_light; + rpc::actor_id_type traffic_light_id; + }; +#pragma pack(pop) + #pragma pack(push, 1) class PackedWalkerControl { public: @@ -75,6 +87,18 @@ namespace detail { }; #pragma pack(pop) +#pragma pack(push, 1) + struct TrafficLightData { + TrafficLightData() = default; + + rpc::TrafficLightState state; + float green_time; + float yellow_time; + float red_time; + float elapsed_time; + bool time_is_frozen; + }; +#pragma pack(pop) } // namespace detail #pragma pack(push, 1) @@ -91,8 +115,8 @@ namespace detail { geom::Vector3D angular_velocity; union TypeDependentState { - rpc::TrafficLightState traffic_light_state; - detail::PackedVehicleControl vehicle_control; + detail::TrafficLightData traffic_light_data; + detail::VehicleData vehicle_data; detail::PackedWalkerControl walker_control; } state; }; @@ -100,9 +124,9 @@ namespace detail { #pragma pack(pop) static_assert( - sizeof(ActorDynamicState) == 13u * sizeof(uint32_t) + sizeof(detail::PackedVehicleControl), + sizeof(ActorDynamicState) == 13u * sizeof(uint32_t) + sizeof(detail::VehicleData), "Invalid ActorDynamicState size!"); } // namespace data } // namespace sensor -} // namespace carla +} // namespace carla \ No newline at end of file diff --git a/PythonAPI/source/libcarla/Actor.cpp b/PythonAPI/source/libcarla/Actor.cpp index 182045e69..cf441c919 100644 --- a/PythonAPI/source/libcarla/Actor.cpp +++ b/PythonAPI/source/libcarla/Actor.cpp @@ -76,6 +76,10 @@ void export_actor() { .def("apply_control", &cc::Vehicle::ApplyControl, (arg("control"))) .def("get_control", &cc::Vehicle::GetControl) .def("set_autopilot", &cc::Vehicle::SetAutopilot, (arg("enabled")=true)) + .def("get_speed_limit", &cc::Vehicle::GetSpeedLimit) + .def("get_traffic_light_state", &cc::Vehicle::GetTrafficLightState) + .def("is_at_traffic_light", &cc::Vehicle::IsAtTrafficLight) + .def("get_traffic_light", &cc::Vehicle::GetTrafficLight) .def(self_ns::str(self_ns::self)) ; @@ -87,15 +91,26 @@ void export_actor() { ; enum_("TrafficLightState") - .value("Off", cr::TrafficLightState::Off) .value("Red", cr::TrafficLightState::Red) .value("Yellow", cr::TrafficLightState::Yellow) .value("Green", cr::TrafficLightState::Green) + .value("Off", cr::TrafficLightState::Off) .value("Unknown", cr::TrafficLightState::Unknown) ; class_, boost::noncopyable, boost::shared_ptr>("TrafficLight", no_init) .add_property("state", &cc::TrafficLight::GetState) + .def("set_state", &cc::TrafficLight::SetState, (arg("state"))) + .def("get_state", &cc::TrafficLight::GetState) + .def("set_green_time", &cc::TrafficLight::SetGreenTime, (arg("green_time"))) + .def("get_green_time", &cc::TrafficLight::GetGreenTime) + .def("set_yellow_time", &cc::TrafficLight::SetYellowTime, (arg("yellow_time"))) + .def("get_yellow_time", &cc::TrafficLight::GetYellowTime) + .def("set_red_time", &cc::TrafficLight::SetRedTime, (arg("red_time"))) + .def("get_red_time", &cc::TrafficLight::GetRedTime) + .def("get_elapsed_time", &cc::TrafficLight::GetElapsedTime) + .def("freeze", &cc::TrafficLight::Freeze, (arg("freeze"))) + .def("is_frozen", &cc::TrafficLight::IsFrozen) .def(self_ns::str(self_ns::self)) ; -} +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp index e5b0706d0..bf01c4e88 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp @@ -17,7 +17,7 @@ #include #include -static auto AWorldObserver_GetActorState(const FActorView &View) +static auto AWorldObserver_GetActorState(const FActorView &View, const FActorRegistry &Registry) { using AType = FActorView::ActorType; @@ -28,9 +28,28 @@ static auto AWorldObserver_GetActorState(const FActorView &View) auto Vehicle = Cast(View.GetActor()); if (Vehicle != nullptr) { - state.vehicle_control = carla::rpc::VehicleControl{Vehicle->GetVehicleControl()}; + state.vehicle_data.control = carla::rpc::VehicleControl{Vehicle->GetVehicleControl()}; + auto Controller = Cast(Vehicle->GetController()); + if (Controller != nullptr) + { + using TLS = carla::rpc::TrafficLightState; + state.vehicle_data.traffic_light_state = static_cast(Controller->GetTrafficLightState()); + state.vehicle_data.speed_limit = Controller->GetSpeedLimit(); + auto TrafficLight = Controller->GetTrafficLight(); + if (TrafficLight != nullptr) + { + state.vehicle_data.has_traffic_light = true; + auto TrafficLightView = Registry.Find(TrafficLight); + state.vehicle_data.traffic_light_id = TrafficLightView.GetActorId(); + } + else + { + state.vehicle_data.has_traffic_light = false; + } + } } } + else if (AType::Walker == View.GetActorType()) { auto Walker = Cast(View.GetActor()); @@ -46,7 +65,12 @@ static auto AWorldObserver_GetActorState(const FActorView &View) if (TrafficLight != nullptr) { using TLS = carla::rpc::TrafficLightState; - state.traffic_light_state = static_cast(TrafficLight->GetTrafficSignState()); + state.traffic_light_data.state = static_cast(TrafficLight->GetTrafficLightState()); + state.traffic_light_data.green_time = TrafficLight->GetGreenTime(); + state.traffic_light_data.yellow_time = TrafficLight->GetYellowTime(); + state.traffic_light_data.red_time = TrafficLight->GetRedTime(); + state.traffic_light_data.elapsed_time = TrafficLight->GetElapsedTime(); + state.traffic_light_data.time_is_frozen = TrafficLight->GetTimeIsFrozen(); } } @@ -90,7 +114,7 @@ static carla::Buffer AWorldObserver_Serialize( actor_view.GetActor()->GetActorTransform(), carla::geom::Vector3D{velocity.X, velocity.Y, velocity.Z}, carla::geom::Vector3D{angularVelocity.X, angularVelocity.Y, angularVelocity.Z}, - AWorldObserver_GetActorState(actor_view) + AWorldObserver_GetActorState(actor_view, Registry) }; write_data(info); } @@ -120,4 +144,4 @@ void AWorldObserver::Tick(float DeltaSeconds) Episode->GetActorRegistry()); Stream.Send_GameThread(*this, std::move(buffer)); -} +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp index ba2df7292..fcc6a6ba4 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp @@ -470,6 +470,71 @@ void FTheNewCarlaServer::FPimpl::BindActions() Controller->SetAutopilot(bEnabled); }); + Server.BindSync("set_traffic_light_state", [this](cr::Actor Actor, cr::TrafficLightState trafficLightState) { + RequireEpisode(); + auto ActorView = Episode->GetActorRegistry().Find(Actor.id); + if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) { + RespondErrorStr("unable to set state: actor not found"); + } + auto TrafficLight = Cast(ActorView.GetActor()); + if (TrafficLight == nullptr) { + RespondErrorStr("unable to set state: actor is not a traffic light"); + } + TrafficLight->SetTrafficLightState(static_cast(trafficLightState)); + }); + + Server.BindSync("set_traffic_light_green_time", [this](cr::Actor Actor, float GreenTime) { + RequireEpisode(); + auto ActorView = Episode->GetActorRegistry().Find(Actor.id); + if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) { + RespondErrorStr("unable to set green time: actor not found"); + } + auto TrafficLight = Cast(ActorView.GetActor()); + if (TrafficLight == nullptr) { + RespondErrorStr("unable to set green time: actor is not a traffic light"); + } + TrafficLight->SetGreenTime(GreenTime); + }); + + Server.BindSync("set_traffic_light_yellow_time", [this](cr::Actor Actor, float YellowTime) { + RequireEpisode(); + auto ActorView = Episode->GetActorRegistry().Find(Actor.id); + if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) { + RespondErrorStr("unable to set yellow time: actor not found"); + } + auto TrafficLight = Cast(ActorView.GetActor()); + if (TrafficLight == nullptr) { + RespondErrorStr("unable to set yellow time: actor is not a traffic light"); + } + TrafficLight->SetYellowTime(YellowTime); + }); + + Server.BindSync("set_traffic_light_red_time", [this](cr::Actor Actor, float RedTime) { + RequireEpisode(); + auto ActorView = Episode->GetActorRegistry().Find(Actor.id); + if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) { + RespondErrorStr("unable to set red time: actor not found"); + } + auto TrafficLight = Cast(ActorView.GetActor()); + if (TrafficLight == nullptr) { + RespondErrorStr("unable to set red time: actor is not a traffic light"); + } + TrafficLight->SetRedTime(RedTime); + }); + + Server.BindSync("freeze_traffic_light", [this](cr::Actor Actor, bool Freeze) { + RequireEpisode(); + auto ActorView = Episode->GetActorRegistry().Find(Actor.id); + if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) { + RespondErrorStr("unable to alter frozen state: actor not found"); + } + auto TrafficLight = Cast(ActorView.GetActor()); + if (TrafficLight == nullptr) { + RespondErrorStr("unable to alter frozen state: actor is not a traffic light"); + } + TrafficLight->SetTimeIsFrozen(Freeze); + }); + Server.BindSync("draw_debug_shape", [this](const cr::DebugShape &shape) { RequireEpisode(); auto *World = Episode->GetWorld(); @@ -526,4 +591,4 @@ void FTheNewCarlaServer::Stop() carla::rpc::Actor FTheNewCarlaServer::SerializeActor(FActorView View) const { return Pimpl->SerializeActor(View); -} +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.cpp index 557828ebd..3a53ff801 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.cpp @@ -38,7 +38,7 @@ static ETrafficSignState ToTrafficSignState(ETrafficLightState State) { ATrafficLightBase::ATrafficLightBase(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer) { - PrimaryActorTick.bCanEverTick = false; + PrimaryActorTick.bCanEverTick = true; } void ATrafficLightBase::OnConstruction(const FTransform &Transform) @@ -47,6 +47,38 @@ void ATrafficLightBase::OnConstruction(const FTransform &Transform) SetTrafficLightState(State); } +void ATrafficLightBase::Tick(float DeltaSeconds) +{ + if (TimeIsFrozen) + { + return; + } + + ElapsedTime += DeltaSeconds; + + float ChangeTime; + + switch (State) { + case ETrafficLightState::Red: + ChangeTime = RedTime; + break; + case ETrafficLightState::Yellow: + ChangeTime = YellowTime; + break; + case ETrafficLightState::Green: + ChangeTime = GreenTime; + break; + default: + UE_LOG(LogCarla, Error, TEXT("Invalid traffic light state!")); + SetTrafficLightState(ETrafficLightState::Red); + return; + } + + if (ElapsedTime > ChangeTime) { + SwitchTrafficLightState(); + } +} + #if WITH_EDITOR void ATrafficLightBase::PostEditChangeProperty(FPropertyChangedEvent &Event) { @@ -61,11 +93,16 @@ void ATrafficLightBase::PostEditChangeProperty(FPropertyChangedEvent &Event) void ATrafficLightBase::SetTrafficLightState(const ETrafficLightState InState) { + NumChanges++; + ElapsedTime = 0.0f; State = InState; SetTrafficSignState(ToTrafficSignState(State)); for (auto Controller : Vehicles) { if (Controller != nullptr) { Controller->SetTrafficLightState(State); + if (State == ETrafficLightState::Green) { + Controller->SetTrafficLight(nullptr); + } } } if (State == ETrafficLightState::Green) { @@ -101,7 +138,63 @@ void ATrafficLightBase::NotifyWheeledVehicle(ACarlaWheeledVehicle *Vehicle) Controller->SetTrafficLightState(State); if (State != ETrafficLightState::Green) { Vehicles.Add(Controller); + Controller->SetTrafficLight(this); } } } } + +void ATrafficLightBase::SetGreenTime(float InGreenTime) +{ + GreenTime = InGreenTime; +} + +float ATrafficLightBase::GetGreenTime() const +{ + return GreenTime; +} + +void ATrafficLightBase::SetYellowTime(float InYellowTime) +{ + YellowTime = InYellowTime; +} + +float ATrafficLightBase::GetYellowTime() const +{ + return YellowTime; +} + +void ATrafficLightBase::SetRedTime(float InRedTime) +{ + RedTime = InRedTime; +} + +float ATrafficLightBase::GetRedTime() const +{ + return RedTime; +} + +float ATrafficLightBase::GetElapsedTime() const +{ + return ElapsedTime; +} + +void ATrafficLightBase::SetTimeIsFrozen(bool InTimeIsFrozen) +{ + TimeIsFrozen = InTimeIsFrozen; + if (!TimeIsFrozen) + { + NumChanges = 0; + ElapsedTime = 0.0f; + } +} + +bool ATrafficLightBase::GetTimeIsFrozen() const +{ + return TimeIsFrozen; +} + +int ATrafficLightBase::GetNumChanges() const +{ + return NumChanges; +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.h index 762da424b..89cad918d 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Traffic/TrafficLightBase.h @@ -12,6 +12,7 @@ #include "TrafficLightBase.generated.h" + class ACarlaWheeledVehicle; class AWheeledVehicleAIController; @@ -24,10 +25,14 @@ public: ATrafficLightBase(const FObjectInitializer &ObjectInitializer); + virtual void Tick(float DeltaSeconds) override; + protected: virtual void OnConstruction(const FTransform &Transform) override; + + #if WITH_EDITOR virtual void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override; #endif // WITH_EDITOR @@ -50,6 +55,36 @@ public: UFUNCTION(Category = "Traffic Light", BlueprintCallable) void NotifyWheeledVehicle(ACarlaWheeledVehicle *Vehicle); + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + void SetGreenTime(float InGreenTime); + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + float GetGreenTime() const; + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + void SetYellowTime(float InYellowTime); + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + float GetYellowTime() const; + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + void SetRedTime(float InRedTime); + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + float GetRedTime() const; + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + float GetElapsedTime() const; + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + void SetTimeIsFrozen(bool InTimeIsFrozen); + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + bool GetTimeIsFrozen() const; + + UFUNCTION(Category = "Traffic Light", BlueprintCallable) + int GetNumChanges() const; + protected: UFUNCTION(Category = "Traffic Light", BlueprintImplementableEvent) @@ -62,4 +97,22 @@ private: UPROPERTY(Category = "Traffic Light", VisibleAnywhere) TArray Vehicles; -}; + + UPROPERTY(Category = "Traffic Light", EditAnywhere) + float GreenTime = 10.0f; + + UPROPERTY(Category = "Traffic Light", EditAnywhere) + float YellowTime = 2.0f; + + UPROPERTY(Category = "Traffic Light", EditAnywhere) + float RedTime = 7.0f; + + UPROPERTY(Category = "Traffic Light", VisibleAnywhere) + float ElapsedTime = 0.0f; + + UPROPERTY(Category = "Traffic Light", EditAnywhere) + bool TimeIsFrozen = false; + + UPROPERTY(Category = "Traffic Light", VisibleAnywhere) + int NumChanges = 0; +}; \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleAIController.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleAIController.h index d03969b00..b1d789dce 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleAIController.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleAIController.h @@ -176,6 +176,20 @@ public: TrafficLightState = InTrafficLightState; } + /// Get traffic light currently affecting this vehicle. + UFUNCTION(Category = "Wheeled Vehicle Controller", BlueprintCallable) + ATrafficLightBase* GetTrafficLight() const + { + return TrafficLight; + } + + /// Set traffic light currently affecting this vehicle. + UFUNCTION(Category = "Wheeled Vehicle Controller", BlueprintCallable) + void SetTrafficLight(ATrafficLightBase* InTrafficLight) + { + TrafficLight = InTrafficLight; + } + /// Set a fixed route to follow if autopilot is enabled. UFUNCTION(Category = "Wheeled Vehicle Controller", BlueprintCallable) void SetFixedRoute(const TArray &Locations, bool bOverwriteCurrent=true); @@ -192,6 +206,7 @@ public: return AutopilotControl; } + private: void TickAutopilotController(); @@ -235,7 +250,10 @@ private: UPROPERTY(VisibleAnywhere) float MaximumSteerAngle = -1.0f; + UPROPERTY() + ATrafficLightBase* TrafficLight; + FVehicleControl AutopilotControl; std::queue TargetLocations; -}; +}; \ No newline at end of file