Merge branch 'master' into NoRenderingMode

This commit is contained in:
Manish 2019-01-30 19:14:40 +01:00
commit 2f49b7ab6e
32 changed files with 1452 additions and 265 deletions

View File

@ -1,5 +1,7 @@
## Latest changes
* Updated the Python API to enable the retrieval of a vehicle's speed limit and impacting traffic light
* Added functionality to the Python API to the allow control over traffic lights
* Upgraded to Unreal Engine 4.21
* Upgraded Boost to 1.69.0
* Added point transformation functionality for LibCarla and PythonAPI
@ -10,12 +12,14 @@
* Added support for spawning and controlling walkers (pedestrians)
* Renamed vehicle.get_vehicle_control() to vehicle.get_control() to be consistent with walkers
* Remove crash reporter from packaged build
* Added sensor for detecting obstacles
* Added a few methods to manage an actor:
- set_velocity: for setting the linear velocity
- set_angular_velocity: for setting the angular velocity
- get_angular_velocity: for getting the angular velocity
- add_impulse: for applying an impulse (in world axis)
* Added support for gnss_sensor
* Fixed autopilot direction not properly initialized that interfered with the initial raycast direction
* Fixed TCP accept error, too many open files while creating and destroying a lot of sensors
* Fixed lost error messages in client-side, now when a request fails it reports the reason
* Improved simulator fatal error handling, now uses UE4 fatal error system

View File

@ -46,6 +46,7 @@ This is the list of sensors currently available
* [sensor.lidar.ray_cast](#sensorlidarray_cast)
* [sensor.other.collision](#sensorothercollision)
* [sensor.other.lane_detector](#sensorotherlane_detector)
* [sensor.other.obstacle](#sensorotherobstacle)
sensor.camera.rgb
-----------------
@ -305,3 +306,26 @@ objects.
| `longitude` | double | Longitude position of the actor |
| `altitude` | double | Altitude of the actor |
sensor.other.obstacle
---------------------
This sensor, when attached to an actor, reports if there is obstacles ahead.
| Blueprint attribute | Type | Default | Description |
| -------------------- | ---- | ------- | ----------- |
| `distance` | float | 5 | Distance to throw the trace to |
| `hit_radius` | float | 0.5 | Radius of the trace |
| `only_dynamics` | bool | false | If true, the trace will only look for dynamic objects |
| `debug_linetrace` | bool | false | If true, the trace will be visible |
| `sensor_tick` | float | 0.0 | Seconds between sensor captures (ticks) |
This sensor produces
[`carla.ObstacleDetectionSensorEvent`](python_api.md#carlaobstacledetectionsensoreventdata)
objects.
| Sensor data attribute | Type | Description |
| ---------------------- | ----------- | ----------- |
| `actor` | carla.Actor | Actor that detected the obstacle ("self" actor) |
| `other_actor` | carla.Actor | Actor detected as obstacle |
| `distance ` | float | Distance from actor to other_actor |

View File

@ -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)`
@ -166,6 +181,12 @@
- `longitude`
- `altitude`
## `carla.ObstacleDetectionSensorEvent(carla.SensorData)`
- `actor`
- `other_actor`
- `distance`
## `carla.VehicleControl`
- `throttle`
@ -303,10 +324,10 @@ Static presets
## `carla.TrafficLightState`
- `Off`
- `Red`
- `Yellow`
- `Green`
- `Off`
- `Unknown`
## `carla.LaneMarking`

View File

@ -11,8 +11,48 @@
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

View File

@ -19,9 +19,30 @@ 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

View File

@ -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,7 +26,25 @@ 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<TrafficLight> Vehicle::GetTrafficLight() const {
auto id = GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_data.traffic_light_id;
SharedPtr<Actor> actor = GetWorld().GetActors()->Find(id);
return boost::static_pointer_cast<TrafficLight>(actor);
}
} // namespace client

View File

@ -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,10 +29,20 @@ 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;
float GetSpeedLimit() const;
rpc::TrafficLightState GetTrafficLightState() const;
bool IsAtTrafficLight();
SharedPtr<TrafficLight> GetTrafficLight() const;
private:
Control _control;

View File

@ -170,6 +170,28 @@ namespace detail {
_pimpl->AsyncCall("apply_control_to_walker", walker, control);
}
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);
}

View File

@ -15,6 +15,7 @@
#include "carla/rpc/EpisodeInfo.h"
#include "carla/rpc/MapInfo.h"
#include "carla/rpc/WeatherParameters.h"
#include "carla/rpc/TrafficLightState.h"
#include <functional>
#include <memory>
@ -30,8 +31,12 @@ namespace rpc {
class VehicleControl;
class WalkerControl;
}
namespace sensor { class SensorData; }
namespace streaming { class Token; }
namespace sensor {
class SensorData;
}
namespace streaming {
class Token;
}
}
namespace carla {
@ -107,6 +112,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);

View File

@ -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 <memory>
@ -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

View File

@ -14,11 +14,10 @@ namespace carla {
namespace rpc {
enum class TrafficLightState : uint8_t {
Off,
Red,
Yellow,
Green,
Off,
Unknown,
SIZE
};

View File

@ -18,6 +18,7 @@
#include "carla/sensor/s11n/EpisodeStateSerializer.h"
#include "carla/sensor/s11n/ImageSerializer.h"
#include "carla/sensor/s11n/LidarSerializer.h"
#include "carla/sensor/s11n/ObstacleDetectionEventSerializer.h"
// 2. Add a forward-declaration of the sensor here.
class ACollisionSensor;
@ -27,6 +28,7 @@ class ASceneCaptureCamera;
class ASemanticSegmentationCamera;
class AWorldObserver;
class AGnssSensor;
class AObstacleDetectionSensor;
namespace carla {
namespace sensor {
@ -42,7 +44,8 @@ namespace sensor {
std::pair<ASemanticSegmentationCamera *, s11n::ImageSerializer>,
std::pair<ARayCastLidar *, s11n::LidarSerializer>,
std::pair<ACollisionSensor *, s11n::CollisionEventSerializer>,
std::pair<AGnssSensor *, s11n::ImageSerializer>
std::pair<AGnssSensor *, s11n::ImageSerializer>,
std::pair<AObstacleDetectionSensor *, s11n::ObstacleDetectionEventSerializer>
>;
} // namespace sensor
@ -60,5 +63,6 @@ namespace sensor {
#include "Carla/Sensor/SemanticSegmentationCamera.h"
#include "Carla/Sensor/WorldObserver.h"
#include "Carla/Sensor/GnssSensor.h"
#include "Carla/Sensor/ObstacleDetectionSensor.h"
#endif // LIBCARLA_SENSOR_REGISTRY_WITH_SENSOR_INCLUDES

View File

@ -50,6 +50,19 @@ namespace detail {
bool manual_gear_shift;
int32_t gear;
};
#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)
@ -73,8 +86,21 @@ namespace detail {
float speed;
bool jump;
};
#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 +117,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,7 +126,7 @@ 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

View File

@ -0,0 +1,68 @@
// 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 <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Debug.h"
#include "carla/client/detail/ActorVariant.h"
#include "carla/sensor/SensorData.h"
#include "carla/sensor/s11n/ObstacleDetectionEventSerializer.h"
namespace carla {
namespace sensor {
namespace data {
/// A registered detection.
class ObstacleDetectionEvent : public SensorData {
using Super = SensorData;
protected:
using Serializer = s11n::ObstacleDetectionEventSerializer;
friend Serializer;
explicit ObstacleDetectionEvent(const RawData &data)
: Super(data),
//_deserialized_data(),
_self_actor(nullptr),
_other_actor(nullptr) {
auto ddata = Serializer::DeserializeRawData(data);
_self_actor = std::move(ddata.self_actor);
_other_actor = std::move(ddata.other_actor);
_distance = ddata.distance;
}
public:
/// Get "self" actor. Actor that measured the collision.
SharedPtr<client::Actor> GetActor() const {
return _self_actor.Get(GetEpisode());
}
/// Get the actor to which we collided.
SharedPtr<client::Actor> GetOtherActor() const {
return _other_actor.Get(GetEpisode());
}
/// Normal impulse result of the collision.
float GetDistance() const {
return _distance;
}
private:
client::detail::ActorVariant _self_actor;
client::detail::ActorVariant _other_actor;
float _distance;
};
} // namespace data
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,20 @@
// 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 <https://opensource.org/licenses/MIT>.
#include "carla/sensor/data/ObstacleDetectionEvent.h"
#include "carla/sensor/s11n/ObstacleDetectionEventSerializer.h"
namespace carla {
namespace sensor {
namespace s11n {
SharedPtr<SensorData> ObstacleDetectionEventSerializer::Deserialize(RawData data) {
return SharedPtr<SensorData>(new data::ObstacleDetectionEvent(std::move(data)));
}
} // namespace s11n
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,57 @@
// 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 <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Buffer.h"
#include "carla/Debug.h"
#include "carla/Memory.h"
#include "carla/rpc/Actor.h"
#include "carla/sensor/RawData.h"
namespace carla {
namespace sensor {
class SensorData;
namespace s11n {
/// Serializes the current state of the whole episode.
class ObstacleDetectionEventSerializer {
public:
struct Data {
rpc::Actor self_actor;
rpc::Actor other_actor;
float distance;
MSGPACK_DEFINE_ARRAY(self_actor, other_actor, distance)
};
constexpr static auto header_offset = 0u;
static Data DeserializeRawData(const RawData &message) {
return MsgPack::UnPack<Data>(message.begin(), message.size());
}
template <typename SensorT>
static Buffer Serialize(
const SensorT &,
rpc::Actor self_actor,
rpc::Actor other_actor,
float distance) {
return MsgPack::Pack(Data{self_actor, other_actor, distance});
}
static SharedPtr<SensorData> Deserialize(RawData data);
};
} // namespace s11n
} // namespace sensor
} // namespace carla

View File

@ -71,11 +71,16 @@ void export_actor() {
.def(self_ns::str(self_ns::self))
;
class_<cc::Vehicle, bases<cc::Actor>, boost::noncopyable, boost::shared_ptr<cc::Vehicle>>("Vehicle", no_init)
class_<cc::Vehicle, bases<cc::Actor>, boost::noncopyable, boost::shared_ptr<cc::Vehicle>>("Vehicle",
no_init)
.add_property("bounding_box", CALL_RETURNING_COPY(cc::Vehicle, GetBoundingBox))
.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 +92,28 @@ void export_actor() {
;
enum_<cr::TrafficLightState>("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_<cc::TrafficLight, bases<cc::Actor>, boost::noncopyable, boost::shared_ptr<cc::TrafficLight>>("TrafficLight", no_init)
class_<cc::TrafficLight, bases<cc::Actor>, boost::noncopyable, boost::shared_ptr<cc::TrafficLight>>(
"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))
;
}

View File

@ -11,6 +11,7 @@
#include <carla/pointcloud/PointCloudIO.h>
#include <carla/sensor/SensorData.h>
#include <carla/sensor/data/CollisionEvent.h>
#include <carla/sensor/data/ObstacleDetectionEvent.h>
#include <carla/sensor/data/Image.h>
#include <carla/sensor/data/LaneInvasionEvent.h>
#include <carla/sensor/data/LidarMeasurement.h>
@ -46,6 +47,13 @@ namespace data {
return out;
}
std::ostream &operator<<(std::ostream &out, const ObstacleDetectionEvent &meas) {
out << "ObstacleDetectionEvent(frame=" << meas.GetFrameNumber()
<< ", other_actor=" << meas.GetOtherActor()
<< ')';
return out;
}
std::ostream &operator<<(std::ostream &out, const LaneInvasionEvent &meas) {
out << "LaneInvasionEvent(frame=" << meas.GetFrameNumber() << ')';
return out;
@ -200,6 +208,13 @@ void export_sensor_data() {
.def(self_ns::str(self_ns::self))
;
class_<csd::ObstacleDetectionEvent, bases<cs::SensorData>, boost::noncopyable, boost::shared_ptr<csd::ObstacleDetectionEvent>>("ObstacleDetectionEvent", no_init)
.add_property("actor", &csd::ObstacleDetectionEvent::GetActor)
.add_property("other_actor", &csd::ObstacleDetectionEvent::GetOtherActor)
.add_property("distance", CALL_RETURNING_COPY(csd::ObstacleDetectionEvent, GetDistance))
.def(self_ns::str(self_ns::self))
;
enum_<cre::LaneMarking>("LaneMarking")
.value("Other", cre::LaneMarking::Other)
.value("Broken", cre::LaneMarking::Broken)

View File

@ -441,6 +441,82 @@ void UActorBlueprintFunctionLibrary::MakePedestrianDefinitions(
FillActorDefinitionArray(ParameterArray, Definitions, &MakePedestrianDefinition);
}
void UActorBlueprintFunctionLibrary::MakePropDefinition(
const FPropParameters &Parameters,
bool &Success,
FActorDefinition &Definition)
{
/// @todo We need to validate here the params.
FillIdAndTags(Definition, TEXT("static"), TEXT("prop"), Parameters.Name);
AddRecommendedValuesForActorRoleName(Definition, {TEXT("prop")});
auto GetSize = [](EPropSize Value) {
switch (Value)
{
case EPropSize::Tiny: return TEXT("tiny");
case EPropSize::Small: return TEXT("small");
case EPropSize::Medium: return TEXT("medium");
case EPropSize::Big: return TEXT("big");
case EPropSize::Huge: return TEXT("huge");
default: return TEXT("unknown");
}
};
Definition.Attributes.Emplace(FActorAttribute{
TEXT("size"),
EActorAttributeType::String,
GetSize(Parameters.Size)});
Success = CheckActorDefinition(Definition);
}
void UActorBlueprintFunctionLibrary::MakePropDefinitions(
const TArray<FPropParameters> &ParameterArray,
TArray<FActorDefinition> &Definitions)
{
FillActorDefinitionArray(ParameterArray, Definitions, &MakePropDefinition);
}
void UActorBlueprintFunctionLibrary::MakeObstacleDetectorDefinitions(
const FString &Type,
const FString &Id,
FActorDefinition &Definition)
{
Definition = MakeGenericSensorDefinition(TEXT("other"), TEXT("obstacle"));
AddVariationsForSensor(Definition);
// Distance.
FActorVariation distance;
distance.Id = TEXT("distance");
distance.Type = EActorAttributeType::Float;
distance.RecommendedValues = { TEXT("5.0") };
distance.bRestrictToRecommended = false;
// HitRadius.
FActorVariation hitradius;
hitradius.Id = TEXT("hit_radius");
hitradius.Type = EActorAttributeType::Float;
hitradius.RecommendedValues = { TEXT("0.5") };
hitradius.bRestrictToRecommended = false;
// Only Dynamics
FActorVariation onlydynamics;
onlydynamics.Id = TEXT("only_dynamics");
onlydynamics.Type = EActorAttributeType::Bool;
onlydynamics.RecommendedValues = { TEXT("false") };
onlydynamics.bRestrictToRecommended = false;
// Debug Line Trace
FActorVariation debuglinetrace;
debuglinetrace.Id = TEXT("debug_linetrace");
debuglinetrace.Type = EActorAttributeType::Bool;
debuglinetrace.RecommendedValues = { TEXT("false") };
debuglinetrace.bRestrictToRecommended = false;
Definition.Variations.Append({
distance,
hitradius,
onlydynamics,
debuglinetrace
});
}
/// ============================================================================
/// -- Helpers to retrieve attribute values ------------------------------------
/// ============================================================================

View File

@ -9,6 +9,7 @@
#include "Carla/Actor/ActorDefinition.h"
#include "Carla/Actor/ActorDescription.h"
#include "Carla/Actor/PedestrianParameters.h"
#include "Carla/Actor/PropParameters.h"
#include "Carla/Actor/VehicleParameters.h"
#include "Kismet/BlueprintFunctionLibrary.h"
@ -91,6 +92,23 @@ public:
const TArray<FPedestrianParameters> &ParameterArray,
TArray<FActorDefinition> &Definitions);
UFUNCTION(Category = "Carla Actor", BlueprintCallable)
static void MakePropDefinition(
const FPropParameters &Parameters,
bool &Success,
FActorDefinition &Definition);
UFUNCTION(Category = "Carla Actor", BlueprintCallable)
static void MakePropDefinitions(
const TArray<FPropParameters> &ParameterArray,
TArray<FActorDefinition> &Definitions);
UFUNCTION()
static void MakeObstacleDetectorDefinitions(
const FString &Type,
const FString &Id,
FActorDefinition &Definition);
/// @}
/// ==========================================================================
/// @name Helpers to retrieve attribute values

View File

@ -0,0 +1,40 @@
// 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 <https://opensource.org/licenses/MIT>.
#pragma once
#include "Engine/StaticMesh.h"
#include "PropParameters.generated.h"
UENUM(BlueprintType)
enum class EPropSize : uint8
{
Tiny UMETA(DisplayName = "Tiny", ToolTip = "Smaller than a mailbox"),
Small UMETA(DisplayName = "Small", ToolTip = "Size of a mailbox"),
Medium UMETA(DisplayName = "Medium", ToolTip = "Size of a human"),
Big UMETA(DisplayName = "Big", ToolTip = "Size of a bus stop"),
Huge UMETA(DisplayName = "Huge", ToolTip = "Size of a house or bigger"),
SIZE UMETA(Hidden),
INVALID UMETA(DisplayName = "INVALID")
};
USTRUCT(BlueprintType)
struct CARLA_API FPropParameters
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UStaticMesh *Mesh;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EPropSize Size = EPropSize::INVALID;
};

View File

@ -169,28 +169,39 @@ void AOpenDriveActor::BuildRoutes()
const std::vector<Waypoint> MapLaneBeginWaypoint =
WaypointGen::GenerateLaneEnd(*map_ptr);
// Since we are going to iterate all the successors of all the lanes, we need
// a vector to store the already visited lanes. Lanes can be successors of
// multiple other lanes
std::vector<std::pair<IdType, int>> AlreadyVisited;
for (auto &&EndLaneWaypoint : MapLaneBeginWaypoint)
{
std::vector<Waypoint> Successors = WaypointGen::GetSuccessors(EndLaneWaypoint);
// generate the RoutePlanner
ARoutePlanner *RoutePlanner = GetWorld()->SpawnActor<ARoutePlanner>();
RoutePlanner->bIsIntersection = std::any_of(Successors.begin(), Successors.end(), [](auto w) {
return w.IsIntersection();
});
RoutePlanner->SetBoxExtent(FVector(70.f, 70.f, 50.f));
RoutePlanner->SetActorRotation(EndLaneWaypoint.ComputeTransform().rotation);
RoutePlanner->SetActorLocation(EndLaneWaypoint.ComputeTransform().location +
FVector(0.f, 0.f, TriggersHeight));
// The RoutePlanner will be created only if some route must be added to it
// so no one will be created unnecessarily
ARoutePlanner *RoutePlanner = nullptr;
// fill the RoutePlanner with all the needed roads
// Fill the RoutePlanner with all the needed roads
for (auto &&Successor : Successors)
{
const IdType RoadId = Successor.GetRoadId();
const int LaneId = Successor.GetLaneId();
// Create an identifier of the current lane
const auto Identifier = std::make_pair(RoadId, LaneId);
// If Identifier does not exist in AlreadyVisited we haven't visited the lane
if (!std::any_of(AlreadyVisited.begin(), AlreadyVisited.end(), [&Identifier](auto i) {
return (i.first == Identifier.first && i.second == Identifier.second);
}))
{
// Add the identifier as visited
AlreadyVisited.emplace_back(Identifier);
const float MaxDist = map.GetRoad(RoadId)->GetLength();
std::vector<Waypoint> Waypoints;
Waypoints.emplace_back(Successor);
for (float Dist = RoadAccuracy; Dist < MaxDist; Dist += RoadAccuracy)
@ -203,7 +214,7 @@ void AOpenDriveActor::BuildRoutes()
Waypoints.emplace_back(NewWaypoint[0]);
}
// merge with the first waypoint of the next lane if needed
// Merge with the first waypoint of the next lane if needed
Waypoints.emplace_back(WaypointGen::GetNext(
Successor, CarlaMath::clamp(MaxDist - 0.1f, 0.f, MaxDist))[0]);
@ -211,11 +222,25 @@ void AOpenDriveActor::BuildRoutes()
TArray<FVector> Positions = WaypointVector2FVectorArray(Waypoints, TriggersHeight);
// If the route planner does not exist, create it
if (RoutePlanner == nullptr)
{
RoutePlanner = GetWorld()->SpawnActor<ARoutePlanner>();
RoutePlanner->bIsIntersection = std::any_of(Successors.begin(), Successors.end(), [](auto w) {
return w.IsIntersection();
});
RoutePlanner->SetBoxExtent(FVector(70.f, 70.f, 50.f));
RoutePlanner->SetActorRotation(EndLaneWaypoint.ComputeTransform().rotation);
RoutePlanner->SetActorLocation(EndLaneWaypoint.ComputeTransform().location +
FVector(0.f, 0.f, TriggersHeight));
}
RoutePlanner->AddRoute(1.f, Positions);
RoutePlanners.Add(RoutePlanner);
}
}
}
}
void AOpenDriveActor::RemoveRoutes()
{

View File

@ -0,0 +1,154 @@
// 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 <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "Carla/Sensor/ObstacleDetectionSensor.h"
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
#include "Carla/Actor/ActorRegistry.h"
#include "Carla/Game/CarlaEpisode.h"
#include "Carla/Game/CarlaGameInstance.h"
#include "Carla/Game/TheNewCarlaGameModeBase.h"
AObstacleDetectionSensor::AObstacleDetectionSensor(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
}
FActorDefinition AObstacleDetectionSensor::GetSensorDefinition()
{
FActorDefinition SensorDefinition = FActorDefinition();
UActorBlueprintFunctionLibrary::MakeObstacleDetectorDefinitions(TEXT("other"), TEXT("obstacle"), SensorDefinition);
return SensorDefinition;
}
void AObstacleDetectionSensor::Set(const FActorDescription &Description)
{
//Multiplying numbers for 100 in order to convert from meters to centimeters
Super::Set(Description);
Distance = UActorBlueprintFunctionLibrary::RetrieveActorAttributeToFloat(
"distance",
Description.Variations,
Distance) * 100.0f;
HitRadius = UActorBlueprintFunctionLibrary::RetrieveActorAttributeToFloat(
"hit_radius",
Description.Variations,
HitRadius) * 100.0f;
bOnlyDynamics = UActorBlueprintFunctionLibrary::RetrieveActorAttributeToBool(
"only_dynamics",
Description.Variations,
bOnlyDynamics);
bDebugLineTrace = UActorBlueprintFunctionLibrary::RetrieveActorAttributeToBool(
"debug_linetrace",
Description.Variations,
bDebugLineTrace);
}
void AObstacleDetectionSensor::BeginPlay()
{
Super::BeginPlay();
auto *GameMode = Cast<ATheNewCarlaGameModeBase>(GetWorld()->GetAuthGameMode());
if (GameMode == nullptr)
{
UE_LOG(LogCarla, Error, TEXT("AObstacleDetectionSensor: Game mode not compatible with this sensor"));
return;
}
Episode = &GameMode->GetCarlaEpisode();
}
void AObstacleDetectionSensor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
const FVector &Start = GetActorLocation();
const FVector &End = Start + (GetActorForwardVector() * Distance);
UWorld* currentWorld = GetWorld();
// Struct in which the result of the scan will be saved
FHitResult HitOut = FHitResult();
// Initialization of Query Parameters
FCollisionQueryParams TraceParams(FName(TEXT("ObstacleDetection Trace")), true, this);
// If debug mode enabled, we create a tag that will make the sweep be
// displayed.
if (bDebugLineTrace)
{
const FName TraceTag("ObstacleDebugTrace");
currentWorld->DebugDrawTraceTag = TraceTag;
TraceParams.TraceTag = TraceTag;
}
// Hit against complex meshes
TraceParams.bTraceComplex = true;
// Ignore trigger boxes
TraceParams.bIgnoreTouches = true;
// Limit the returned information
TraceParams.bReturnPhysicalMaterial = false;
// Ignore ourselves
TraceParams.AddIgnoredActor(this);
if(Super::GetOwner()!=nullptr)
TraceParams.AddIgnoredActor(Super::GetOwner());
bool isHitReturned;
// Choosing a type of sweep is a workaround until everything get properly
// organized under correct collision channels and object types.
if (bOnlyDynamics)
{
// If we go only for dynamics, we check the object type AllDynamicObjects
FCollisionObjectQueryParams TraceChannel = FCollisionObjectQueryParams(
FCollisionObjectQueryParams::AllDynamicObjects);
isHitReturned = currentWorld->SweepSingleByObjectType(
HitOut,
Start,
End,
FQuat(),
TraceChannel,
FCollisionShape::MakeSphere(HitRadius),
TraceParams);
}
else
{
// Else, if we go for everything, we get everything that interacts with a
// Pawn
ECollisionChannel TraceChannel = ECC_WorldStatic;
isHitReturned = currentWorld->SweepSingleByChannel(
HitOut,
Start,
End,
FQuat(),
TraceChannel,
FCollisionShape::MakeSphere(HitRadius),
TraceParams);
}
if (isHitReturned)
{
OnObstacleDetectionEvent(this, HitOut.Actor.Get(), HitOut.Distance, HitOut);
}
}
void AObstacleDetectionSensor::OnObstacleDetectionEvent(
AActor *Actor,
AActor *OtherActor,
float HitDistance,
const FHitResult &Hit)
{
if ((Episode != nullptr) && (Actor != nullptr) && (OtherActor != nullptr))
{
GetDataStream(*this).Send(*this,
Episode->SerializeActor(Episode->FindOrFakeActor(Actor)),
Episode->SerializeActor(Episode->FindOrFakeActor(OtherActor)),
HitRadius);
}
}

View File

@ -0,0 +1,56 @@
// 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 <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla/Sensor/Sensor.h"
#include "Carla/Actor/ActorDefinition.h"
#include "Carla/Actor/ActorDescription.h"
#include "ObstacleDetectionSensor.generated.h"
class UCarlaEpisode;
/// A sensor to register collisions.
UCLASS()
class CARLA_API AObstacleDetectionSensor : public ASensor
{
GENERATED_BODY()
public:
static FActorDefinition GetSensorDefinition();
AObstacleDetectionSensor(const FObjectInitializer &ObjectInitializer);
void Set(const FActorDescription &Description) override;
void BeginPlay() override;
void Tick(float DeltaSeconds) override;
private:
UFUNCTION()
void OnObstacleDetectionEvent(
AActor *Actor,
AActor *OtherActor,
float Distance,
const FHitResult &Hit);
UPROPERTY()
const UCarlaEpisode *Episode = nullptr;
private:
float Distance;
float HitRadius;
bool bOnlyDynamics = false;
bool bDebugLineTrace = false;
};

View File

@ -17,7 +17,7 @@
#include <carla/sensor/data/ActorDynamicState.h>
#include <compiler/enable-ue4-macros.h>
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<ACarlaWheeledVehicle>(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<AWheeledVehicleAIController>(Vehicle->GetController());
if (Controller != nullptr)
{
using TLS = carla::rpc::TrafficLightState;
state.vehicle_data.traffic_light_state = static_cast<TLS>(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<APawn>(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<TLS>(TrafficLight->GetTrafficSignState());
state.traffic_light_data.state = static_cast<TLS>(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();
}
}
@ -75,7 +99,8 @@ static carla::Buffer AWorldObserver_Serialize(
write_data(header);
// Write every actor.
for (auto &&View : Registry) {
for (auto &&View : Registry)
{
check(View.IsValid());
constexpr float TO_METERS = 1e-2;
const auto velocity = TO_METERS * View.GetActor()->GetVelocity();
@ -83,13 +108,15 @@ static carla::Buffer AWorldObserver_Serialize(
const auto RootComponent = Cast<UPrimitiveComponent>(View.GetActor()->GetRootComponent());
FVector angularVelocity { 0.0f, 0.0f, 0.0f };
if (RootComponent != nullptr)
{
angularVelocity = RootComponent->GetPhysicsAngularVelocityInDegrees();
}
ActorDynamicState info = {
View.GetActorId(),
View.GetActor()->GetActorTransform(),
carla::geom::Vector3D{velocity.X, velocity.Y, velocity.Z},
carla::geom::Vector3D{angularVelocity.X, angularVelocity.Y, angularVelocity.Z},
AWorldObserver_GetActorState(View)
AWorldObserver_GetActorState(View, Registry)
};
write_data(info);
}
@ -119,6 +146,5 @@ void AWorldObserver::Tick(float DeltaSeconds)
GameTimeStamp,
FPlatformTime::Seconds(),
Episode->GetActorRegistry());
AsyncStream.Send(*this, std::move(buffer));
}

View File

@ -55,7 +55,8 @@ public:
FPimpl(uint16_t port)
: Server(port),
StreamingServer(port + 1u) {
StreamingServer(port + 1u)
{
BindActions();
}
@ -68,6 +69,7 @@ public:
private:
void BindActions();
};
// =============================================================================
@ -110,7 +112,8 @@ void FTheNewCarlaServer::FPimpl::BindActions()
{
REQUIRE_CARLA_EPISODE();
auto WorldObserver = Episode->GetWorldObserver();
if (WorldObserver == nullptr) {
if (WorldObserver == nullptr)
{
RESPOND_ERROR("internal error: missing world observer");
}
return cr::EpisodeInfo{
@ -450,6 +453,101 @@ void FTheNewCarlaServer::FPimpl::BindActions()
return R<void>::Success();
});
Server.BindSync("set_traffic_light_state", [this](
cr::Actor Actor,
cr::TrafficLightState trafficLightState) -> R<void>
{
REQUIRE_CARLA_EPISODE();
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
RESPOND_ERROR("unable to set state: actor not found");
}
auto TrafficLight = Cast<ATrafficLightBase>(ActorView.GetActor());
if (TrafficLight == nullptr)
{
RESPOND_ERROR("unable to set state: actor is not a traffic light");
}
TrafficLight->SetTrafficLightState(static_cast<ETrafficLightState>(trafficLightState));
return R<void>::Success();
});
Server.BindSync("set_traffic_light_green_time", [this](
cr::Actor Actor,
float GreenTime) -> R<void>
{
REQUIRE_CARLA_EPISODE();
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
RESPOND_ERROR("unable to set green time: actor not found");
}
auto TrafficLight = Cast<ATrafficLightBase>(ActorView.GetActor());
if (TrafficLight == nullptr)
{
RESPOND_ERROR("unable to set green time: actor is not a traffic light");
}
TrafficLight->SetGreenTime(GreenTime);
return R<void>::Success();
});
Server.BindSync("set_traffic_light_yellow_time", [this](
cr::Actor Actor,
float YellowTime) -> R<void>
{
REQUIRE_CARLA_EPISODE();
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
RESPOND_ERROR("unable to set yellow time: actor not found");
}
auto TrafficLight = Cast<ATrafficLightBase>(ActorView.GetActor());
if (TrafficLight == nullptr)
{
RESPOND_ERROR("unable to set yellow time: actor is not a traffic light");
}
TrafficLight->SetYellowTime(YellowTime);
return R<void>::Success();
});
Server.BindSync("set_traffic_light_red_time", [this](
cr::Actor Actor,
float RedTime) -> R<void>
{
REQUIRE_CARLA_EPISODE();
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
RESPOND_ERROR("unable to set red time: actor not found");
}
auto TrafficLight = Cast<ATrafficLightBase>(ActorView.GetActor());
if (TrafficLight == nullptr)
{
RESPOND_ERROR("unable to set red time: actor is not a traffic light");
}
TrafficLight->SetRedTime(RedTime);
return R<void>::Success();
});
Server.BindSync("freeze_traffic_light", [this](
cr::Actor Actor,
bool Freeze) -> R<void>
{
REQUIRE_CARLA_EPISODE();
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
RESPOND_ERROR("unable to alter frozen state: actor not found");
}
auto TrafficLight = Cast<ATrafficLightBase>(ActorView.GetActor());
if (TrafficLight == nullptr)
{
RESPOND_ERROR("unable to alter frozen state: actor is not a traffic light");
}
TrafficLight->SetTimeIsFrozen(Freeze);
return R<void>::Success();
});
Server.BindSync("draw_debug_shape", [this](const cr::DebugShape &shape) -> R<void>
{
REQUIRE_CARLA_EPISODE();

View File

@ -19,8 +19,10 @@ static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
return ((Vehicle != nullptr) && !Vehicle->IsPendingKill());
}
static ETrafficSignState ToTrafficSignState(ETrafficLightState State) {
switch (State) {
static ETrafficSignState ToTrafficSignState(ETrafficLightState State)
{
switch (State)
{
case ETrafficLightState::Green:
return ETrafficSignState::TrafficLightGreen;
case ETrafficLightState::Yellow:
@ -38,7 +40,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,13 +49,48 @@ 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)
{
Super::PostEditChangeProperty(Event);
const FName PropertyName = (Event.Property != nullptr ? Event.Property->GetFName() : NAME_None);
if (PropertyName == GET_MEMBER_NAME_CHECKED(ATrafficLightBase, State)) {
if (PropertyName == GET_MEMBER_NAME_CHECKED(ATrafficLightBase, State))
{
SetTrafficLightState(State);
}
}
@ -61,14 +98,23 @@ 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) {
for (auto Controller : Vehicles)
{
if (Controller != nullptr)
{
Controller->SetTrafficLightState(State);
if (State == ETrafficLightState::Green)
{
Controller->SetTrafficLight(nullptr);
}
}
if (State == ETrafficLightState::Green) {
}
if (State == ETrafficLightState::Green)
{
Vehicles.Empty();
}
OnTrafficLightStateChanged(State);
@ -76,7 +122,8 @@ void ATrafficLightBase::SetTrafficLightState(const ETrafficLightState InState)
void ATrafficLightBase::SwitchTrafficLightState()
{
switch (State) {
switch (State)
{
case ETrafficLightState::Red:
SetTrafficLightState(ETrafficLightState::Green);
break;
@ -95,13 +142,72 @@ void ATrafficLightBase::SwitchTrafficLightState()
void ATrafficLightBase::NotifyWheeledVehicle(ACarlaWheeledVehicle *Vehicle)
{
if (IsValid(Vehicle)) {
if (IsValid(Vehicle))
{
auto Controller = Cast<AWheeledVehicleAIController>(Vehicle->GetController());
if (Controller != nullptr) {
if (Controller != nullptr)
{
Controller->SetTrafficLightState(State);
if (State != ETrafficLightState::Green) {
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;
}

View File

@ -16,7 +16,8 @@ class ACarlaWheeledVehicle;
class AWheeledVehicleAIController;
UCLASS()
class CARLA_API ATrafficLightBase : public ATrafficSignBase {
class CARLA_API ATrafficLightBase : public ATrafficSignBase
{
GENERATED_BODY()
@ -24,12 +25,15 @@ 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
public:
@ -50,6 +54,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 +96,22 @@ private:
UPROPERTY(Category = "Traffic Light", VisibleAnywhere)
TArray<AWheeledVehicleAIController *> 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;
};

View File

@ -11,7 +11,8 @@
/// State of a ACarlaWheeledVehicle, to be displayed in editor for debugging
/// purposes.
UENUM(BlueprintType)
enum class ECarlaWheeledVehicleState : uint8 {
enum class ECarlaWheeledVehicleState : uint8
{
AutopilotOff UMETA(DisplayName = "Autopilot Off"),
FreeDriving UMETA(DisplayName = "Free driving"),
FollowingFixedRoute UMETA(DisplayName = "Following fixed route"),

View File

@ -18,7 +18,8 @@
// -- Static local methods -----------------------------------------------------
// =============================================================================
static bool RayTrace(const AActor &Actor, const FVector &Start, const FVector &End) {
static bool RayCast(const AActor &Actor, const FVector &Start, const FVector &End)
{
FHitResult OutHit;
static FName TraceTag = FName(TEXT("VehicleTrace"));
FCollisionQueryParams CollisionParams(TraceTag, true);
@ -31,6 +32,9 @@ static bool RayTrace(const AActor &Actor, const FVector &Start, const FVector &E
FCollisionObjectQueryParams(FCollisionObjectQueryParams::AllDynamicObjects),
CollisionParams);
// DrawDebugLine(Actor.GetWorld(), Start, End,
// Success ? FColor(255, 0, 0) : FColor(0, 255, 0), false);
return Success && OutHit.bBlockingHit;
}
@ -42,21 +46,26 @@ static bool IsThereAnObstacleAhead(
const auto ForwardVector = Vehicle.GetVehicleOrientation();
const auto VehicleBounds = Vehicle.GetVehicleBoundingBoxExtent();
FVector NormDirection = Direction.GetSafeNormal();
const float Distance = std::max(50.0f, Speed * Speed); // why?
const FVector StartCenter = Vehicle.GetActorLocation() + (ForwardVector * (250.0f + VehicleBounds.X / 2.0f)) + FVector(0.0f, 0.0f, 50.0f);
const FVector EndCenter = StartCenter + Direction * (Distance + VehicleBounds.X / 2.0f);
const FVector StartCenter = Vehicle.GetActorLocation() +
(ForwardVector * (250.0f + VehicleBounds.X / 2.0f)) + FVector(0.0f, 0.0f, 50.0f);
const FVector EndCenter = StartCenter + NormDirection * (Distance + VehicleBounds.X / 2.0f);
const FVector StartRight = StartCenter + (FVector(ForwardVector.Y, -ForwardVector.X, ForwardVector.Z) * 100.0f);
const FVector EndRight = StartRight + Direction * (Distance + VehicleBounds.X / 2.0f);
const FVector StartRight = StartCenter +
(FVector(ForwardVector.Y, -ForwardVector.X, ForwardVector.Z) * 100.0f);
const FVector EndRight = StartRight + NormDirection * (Distance + VehicleBounds.X / 2.0f);
const FVector StartLeft = StartCenter + (FVector(-ForwardVector.Y, ForwardVector.X, ForwardVector.Z) * 100.0f);
const FVector EndLeft = StartLeft + Direction * (Distance + VehicleBounds.X / 2.0f);
const FVector StartLeft = StartCenter +
(FVector(-ForwardVector.Y, ForwardVector.X, ForwardVector.Z) * 100.0f);
const FVector EndLeft = StartLeft + NormDirection * (Distance + VehicleBounds.X / 2.0f);
return
RayTrace(Vehicle, StartCenter, EndCenter) ||
RayTrace(Vehicle, StartRight, EndRight) ||
RayTrace(Vehicle, StartLeft, EndLeft);
RayCast(Vehicle, StartCenter, EndCenter) ||
RayCast(Vehicle, StartRight, EndRight) ||
RayCast(Vehicle, StartLeft, EndLeft);
}
template <typename T>
@ -70,8 +79,8 @@ static void ClearQueue(std::queue<T> &Queue)
// -- Constructor and destructor -----------------------------------------------
// =============================================================================
AWheeledVehicleAIController::AWheeledVehicleAIController(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer)
AWheeledVehicleAIController::AWheeledVehicleAIController(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
{
RandomEngine = CreateDefaultSubobject<URandomEngine>(TEXT("RandomEngine"));
@ -162,10 +171,12 @@ void AWheeledVehicleAIController::SetFixedRoute(
const TArray<FVector> &Locations,
const bool bOverwriteCurrent)
{
if (bOverwriteCurrent) {
if (bOverwriteCurrent)
{
ClearQueue(TargetLocations);
}
for (auto &Location : Locations) {
for (auto &Location : Locations)
{
TargetLocations.emplace(Location);
}
}
@ -176,8 +187,9 @@ void AWheeledVehicleAIController::SetFixedRoute(
void AWheeledVehicleAIController::TickAutopilotController()
{
#if WITH_EDITOR
if (Vehicle == nullptr) { // This happens in simulation mode in editor.
#if WITH_EDITOR // This happens in simulation mode in editor.
if (Vehicle == nullptr)
{
bAutopilotEnabled = false;
return;
}
@ -185,37 +197,45 @@ void AWheeledVehicleAIController::TickAutopilotController()
check(Vehicle != nullptr);
if (RoadMap == nullptr) {
return;
}
FVector Direction;
float Steering;
if (!TargetLocations.empty()) {
if (!TargetLocations.empty())
{
Steering = GoToNextTargetLocation(Direction);
} else {
Steering = CalcStreeringValue(Direction);
}
else
{
Steering = RoadMap != nullptr ? CalcStreeringValue(Direction) : 0.0f;
Direction = Vehicle->GetVehicleTransform().GetRotation().Rotator().Vector();
}
// Speed in km/h.
const auto Speed = Vehicle->GetVehicleForwardSpeed() * 0.036f;
float Throttle;
if (TrafficLightState != ETrafficLightState::Green) {
if (TrafficLightState != ETrafficLightState::Green)
{
Vehicle->SetAIVehicleState(ECarlaWheeledVehicleState::WaitingForRedLight);
Throttle = Stop(Speed);
} else if (IsThereAnObstacleAhead(*Vehicle, Speed, Direction)) {
}
else if (IsThereAnObstacleAhead(*Vehicle, Speed, Direction))
{
Vehicle->SetAIVehicleState(ECarlaWheeledVehicleState::ObstacleAhead);
Throttle = Stop(Speed);
} else {
}
else
{
Throttle = Move(Speed);
}
if (Throttle < 0.001f) {
if (Throttle < 0.001f)
{
AutopilotControl.Brake = 1.0f;
AutopilotControl.Throttle = 0.0f;
} else {
}
else
{
AutopilotControl.Brake = 0.0f;
AutopilotControl.Throttle = Throttle;
}
@ -236,12 +256,16 @@ float AWheeledVehicleAIController::GoToNextTargetLocation(FVector &Direction)
return FVector{Result.X, Result.Y, CurrentLocation.Z};
} ();
if (Target.Equals(CurrentLocation, 200.0f)) {
if (Target.Equals(CurrentLocation, 200.0f))
{
TargetLocations.pop();
if (!TargetLocations.empty()) {
if (!TargetLocations.empty())
{
return GoToNextTargetLocation(Direction);
} else {
return CalcStreeringValue(Direction);
}
else
{
return RoadMap != nullptr ? CalcStreeringValue(Direction) : 0.0f;
}
}
@ -257,16 +281,26 @@ float AWheeledVehicleAIController::GoToNextTargetLocation(FVector &Direction)
float angle = dirAngle - actorAngle;
if (angle > 180.0f) { angle -= 360.0f;} else if (angle < -180.0f) {
if (angle > 180.0f)
{
angle -= 360.0f;
}
else if (angle < -180.0f)
{
angle += 360.0f;
}
float Steering = 0.0f;
if (angle < -MaximumSteerAngle) {
if (angle < -MaximumSteerAngle)
{
Steering = -1.0f;
} else if (angle > MaximumSteerAngle) {
}
else if (angle > MaximumSteerAngle)
{
Steering = 1.0f;
} else {
}
else
{
Steering += angle / MaximumSteerAngle;
}
@ -285,7 +319,8 @@ float AWheeledVehicleAIController::CalcStreeringValue(FVector &direction)
float forwardMagnitude = BoxExtent.X / 2.0f;
float Magnitude = (float) sqrt(pow((double) leftSensorPosition.X, 2.0) + pow((double) leftSensorPosition.Y, 2.0));
float Magnitude =
(float) sqrt(pow((double) leftSensorPosition.X, 2.0) + pow((double) leftSensorPosition.Y, 2.0));
// same for the right and left
float offset = FGenericPlatformMath::Acos(forwardMagnitude / Magnitude);
@ -304,19 +339,32 @@ float AWheeledVehicleAIController::CalcStreeringValue(FVector &direction)
leftSensorPosition.Y = sinL * Magnitude;
leftSensorPosition.X = cosL * Magnitude;
FVector rightPositon = GetPawn()->GetActorLocation() + FVector(rightSensorPosition.X, rightSensorPosition.Y, 0.0f);
FVector leftPosition = GetPawn()->GetActorLocation() + FVector(leftSensorPosition.X, leftSensorPosition.Y, 0.0f);
FVector rightPositon = GetPawn()->GetActorLocation() + FVector(rightSensorPosition.X,
rightSensorPosition.Y,
0.0f);
FVector leftPosition = GetPawn()->GetActorLocation() + FVector(leftSensorPosition.X,
leftSensorPosition.Y,
0.0f);
FRoadMapPixelData rightRoadData = RoadMap->GetDataAt(rightPositon);
if (!rightRoadData.IsRoad()) { steering -= 0.2f;}
if (!rightRoadData.IsRoad())
{
steering -= 0.2f;
}
FRoadMapPixelData leftRoadData = RoadMap->GetDataAt(leftPosition);
if (!leftRoadData.IsRoad()) { steering += 0.2f;}
if (!leftRoadData.IsRoad())
{
steering += 0.2f;
}
FRoadMapPixelData roadData = RoadMap->GetDataAt(GetPawn()->GetActorLocation());
if (!roadData.IsRoad()) {
if (!roadData.IsRoad())
{
steering = 0.0f;
} else if (roadData.HasDirection()) {
}
else if (roadData.HasDirection())
{
direction = roadData.GetDirection();
FVector right = rightRoadData.GetDirection();
@ -334,30 +382,61 @@ float AWheeledVehicleAIController::CalcStreeringValue(FVector &direction)
actorAngle *= (180.0 / PI);
float min = dirAngle - 90.0f;
if (min < -180.0f) { min = 180.0f + (min + 180.0f);}
if (min < -180.0f)
{
min = 180.0f + (min + 180.0f);
}
float max = dirAngle + 90.0f;
if (max > 180.0f) { max = -180.0f + (max - 180.0f);}
if (max > 180.0f)
{
max = -180.0f + (max - 180.0f);
}
if (dirAngle < -90.0 || dirAngle > 90.0) {
if (rightAngle < min && rightAngle > max) { steering -= 0.2f;}
if (leftAngle < min && leftAngle > max) { steering += 0.2f;}
} else {
if (rightAngle < min || rightAngle > max) { steering -= 0.2f;}
if (leftAngle < min || leftAngle > max) { steering += 0.2f;}
if (dirAngle < -90.0 || dirAngle > 90.0)
{
if (rightAngle < min && rightAngle > max)
{
steering -= 0.2f;
}
if (leftAngle < min && leftAngle > max)
{
steering += 0.2f;
}
}
else
{
if (rightAngle < min || rightAngle > max)
{
steering -= 0.2f;
}
if (leftAngle < min || leftAngle > max)
{
steering += 0.2f;
}
}
float angle = dirAngle - actorAngle;
if (angle > 180.0f) { angle -= 360.0f;} else if (angle < -180.0f) {
if (angle > 180.0f)
{
angle -= 360.0f;
}
else if (angle < -180.0f)
{
angle += 360.0f;
}
if (angle < -MaximumSteerAngle) {
if (angle < -MaximumSteerAngle)
{
steering = -1.0f;
} else if (angle > MaximumSteerAngle) {
}
else if (angle > MaximumSteerAngle)
{
steering = 1.0f;
} else {
}
else
{
steering += angle / MaximumSteerAngle;
}
}
@ -366,16 +445,23 @@ float AWheeledVehicleAIController::CalcStreeringValue(FVector &direction)
return steering;
}
float AWheeledVehicleAIController::Stop(const float Speed) {
float AWheeledVehicleAIController::Stop(const float Speed)
{
return (Speed >= 1.0f ? -Speed / SpeedLimit : 0.0f);
}
float AWheeledVehicleAIController::Move(const float Speed) {
if (Speed >= SpeedLimit) {
float AWheeledVehicleAIController::Move(const float Speed)
{
if (Speed >= SpeedLimit)
{
return Stop(Speed);
} else if (Speed >= SpeedLimit - 10.0f) {
}
else if (Speed >= SpeedLimit - 10.0f)
{
return 0.5f;
} else {
}
else
{
return 1.0f;
}
}

View File

@ -29,6 +29,7 @@ class CARLA_API AWheeledVehicleAIController : public APlayerController
/// @name Constructor and destructor
// ===========================================================================
/// @{
public:
AWheeledVehicleAIController(const FObjectInitializer &ObjectInitializer);
@ -40,6 +41,7 @@ public:
/// @name APlayerController overrides
// ===========================================================================
/// @{
public:
void Possess(APawn *aPawn) override;
@ -53,6 +55,7 @@ public:
/// @name Possessed vehicle
// ===========================================================================
/// @{
public:
UFUNCTION(Category = "Wheeled Vehicle Controller", BlueprintCallable)
@ -83,6 +86,7 @@ public:
/// @name Road map
// ===========================================================================
/// @{
public:
void SetRoadMap(URoadMap *InRoadMap)
@ -101,6 +105,7 @@ public:
/// @name Random engine
// ===========================================================================
/// @{
public:
UFUNCTION(Category = "Random Engine", BlueprintCallable)
@ -115,6 +120,7 @@ public:
/// @name Autopilot
// ===========================================================================
/// @{
public:
UFUNCTION(Category = "Wheeled Vehicle Controller", BlueprintCallable)
@ -126,7 +132,8 @@ public:
UFUNCTION(Category = "Wheeled Vehicle Controller", BlueprintCallable)
void SetAutopilot(bool Enable)
{
if (IsAutopilotEnabled() != Enable) {
if (IsAutopilotEnabled() != Enable)
{
ConfigureAutopilot(Enable);
}
}
@ -146,6 +153,7 @@ private:
/// @name Traffic
// ===========================================================================
/// @{
public:
/// Get current speed limit in km/h.
@ -176,6 +184,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<FVector> &Locations, bool bOverwriteCurrent = true);
@ -212,6 +234,8 @@ private:
// ===========================================================================
// -- Member variables -------------------------------------------------------
// ===========================================================================
/// @{
private:
UPROPERTY()
@ -235,6 +259,9 @@ private:
UPROPERTY(VisibleAnywhere)
float MaximumSteerAngle = -1.0f;
UPROPERTY()
ATrafficLightBase *TrafficLight;
FVehicleControl AutopilotControl;
std::queue<FVector> TargetLocations;

View File

@ -153,7 +153,8 @@ unset BOOST_BASENAME
# -- Get rpclib and compile it with libc++ and libstdc++ -----------------------
# ==============================================================================
RPCLIB_BASENAME=rpclib-d1146b7-ex
RPCLIB_PATCH=v2.2.1_c1
RPCLIB_BASENAME=rpclib-${RPCLIB_PATCH}
RPCLIB_LIBCXX_INCLUDE=${PWD}/${RPCLIB_BASENAME}-libcxx-install/include
RPCLIB_LIBCXX_LIBPATH=${PWD}/${RPCLIB_BASENAME}-libcxx-install/lib
@ -170,10 +171,7 @@ else
log "Retrieving rpclib."
git clone https://github.com/rpclib/rpclib.git ${RPCLIB_BASENAME}-source
pushd ${RPCLIB_BASENAME}-source >/dev/null
git reset --hard d1146b7
popd >/dev/null
git clone -b ${RPCLIB_PATCH} https://github.com/carla-simulator/rpclib.git ${RPCLIB_BASENAME}-source
log "Building rpclib with libc++."