AI Vehicles & TrafficLights

This commit is contained in:
Xisco Bosch 2017-05-18 11:22:03 +02:00
parent 0958ffbcbc
commit 906bc6bf09
11 changed files with 765 additions and 5 deletions

View File

@ -0,0 +1,361 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#include "Carla.h"
#include "AICarlaVehicleController.h"
#include "Components/BoxComponent.h"
#include "Components/SphereComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "WheeledVehicle.h"
#include "WheeledVehicleMovementComponent.h"
#include "EngineUtils.h"
#include "GameFramework/Pawn.h"
#include "CityMapGenerator.h"
#include "Tagger.h"
#include "TrafficLight.h"
#include "MapGen/RoadMap.h"
// Find first component of type road.
static bool RayTrace(
UWorld *World,
const FVector &Start,
const FVector &End,
bool &Stop)
{
FHitResult Hit;
TArray <FHitResult> OutHits;
static FName TraceTag = FName(TEXT("VehicleTrace"));
//World->DebugDrawTraceTag = TraceTag;
const bool Success = World->LineTraceMultiByObjectType(
OutHits,
Start,
End,
FCollisionObjectQueryParams(ECollisionChannel::ECC_Vehicle),
FCollisionQueryParams(TraceTag, true));
if (Success) {
for (FHitResult &Item : OutHits) {
if (ATagger::MatchComponent(*Item.Component, ECityObjectLabel::Vehicles)) {
Stop = true;
return true;
}
}
}
return false;
}
AAICarlaVehicleController::AAICarlaVehicleController() :
Super(),
MovementComponent(nullptr)
{
bAutoManageActiveCameraTarget = false;
}
AAICarlaVehicleController::~AAICarlaVehicleController() {}
// =============================================================================
// -- APlayerController --------------------------------------------------------
// =============================================================================
void AAICarlaVehicleController::SetupInputComponent(){ Super::SetupInputComponent(); }
void AAICarlaVehicleController::Possess(APawn *aPawn)
{
Super::Possess(aPawn);
if (IsPossessingAVehicle()) {
UE_LOG(LogCarla, Error, TEXT("Controller already possessing a pawn!"));
return;
}
auto *WheeledVehicle = Cast<AWheeledVehicle>(aPawn);
if (WheeledVehicle != nullptr) {
// Bind hit events.
// aPawn->OnActorHit.AddDynamic(this, &AAICarlaVehicleController::OnCollisionEvent);
// Get vehicle movement component.
MovementComponent = WheeledVehicle->GetVehicleMovementComponent();
check(MovementComponent != nullptr);
// Get vehicle box component.
TArray<UBoxComponent *> BoundingBoxes;
WheeledVehicle->GetComponents<UBoxComponent>(BoundingBoxes);
if (BoundingBoxes.Num() > 0) {
VehicleBounds = BoundingBoxes[0];
} else {
UE_LOG(LogCarla, Error, TEXT("Pawn is missing the bounding box!"));
}
TArray<USphereComponent *> ControlPoints;
WheeledVehicle->GetComponents<USphereComponent>(ControlPoints);
if (ControlPoints.Num() >= 0) {
if (ControlPoints[0]->GetName().Equals("Right")){
VehicleRightControl = ControlPoints[0];
VehicleLeftControl = ControlPoints[1];
}
else{
VehicleRightControl = ControlPoints[1];
VehicleLeftControl = ControlPoints[0];
}
}else{
UE_LOG(LogCarla, Error, TEXT("Vehicle control point not found!"));
}
}
}
void AAICarlaVehicleController::BeginPlay()
{
TActorIterator<ACityMapGenerator> It(GetWorld());
if (It) {
RoadMap = It->GetRoadMap();
}
}
void AAICarlaVehicleController::Tick(float DeltaTime){
Super::PlayerTick(DeltaTime);
check(MovementComponent != nullptr);
if (RoadMap == nullptr) {
UE_LOG(LogCarla, Error, TEXT("Controller doesn't have a road map"));
return;
}
FRoadMapPixelData roadData = RoadMap->GetDataAt(GetPawn()->GetActorLocation());
float steering = 2.0, throttle = 1.0f;
if (route.Num() > 0){
steering = GoTo(route[route_it]);
}
else{
steering = CalcStreeringValue();
}
const FVector Start = GetPawn()->GetActorLocation() + (GetPawn()->GetActorForwardVector().GetSafeNormal() * 250.0) + FVector(0.0, 0.0, 50.0);
const FVector End = Start + GetPawn()->GetActorForwardVector().GetSafeNormal() * 400.0;
auto speed = MovementComponent->GetForwardSpeed() * 0.036f;
//RayTrace to detect trafficLights or Vehicles
bool stop;
auto World = GetWorld();
if (TrafficLightStop) throttle = Stop(speed);
else {
if (RayTrace(World, Start, End, stop)) {
if (stop) throttle = Stop(speed);
else throttle = Move(speed);
}
else{
throttle = Move(speed);
}
}
MovementComponent->SetSteeringInput(steering);
MovementComponent->SetThrottleInput(throttle);
UE_LOG(LogCarla, Log,
TEXT("Throttle: %f Steering: %f "),
throttle,
steering
);
}
float AAICarlaVehicleController::GoTo(FVector objective){
float steering = 0;
if (objective.Equals(GetPawn()->GetActorLocation(), 40.0f)){
++route_it;
if (route_it == route.Num()){
route.Empty();
route_it = 0;
return CalcStreeringValue();
}
}
FVector direction = objective - GetPawn()->GetActorLocation();
direction = direction.GetSafeNormal();
FVector forward = GetPawn()->GetActorForwardVector();
float dirAngle = direction.UnitCartesianToSpherical().Y;
float actorAngle = forward.UnitCartesianToSpherical().Y;
dirAngle *= (180.0f/PI);
actorAngle *= (180.0/PI);
float angle = dirAngle - actorAngle;
if (angle > 180.0f) angle -= 360.0f;
else if (angle < -180.0f) angle += 360.0f;
if (angle < -70.0f) steering = -1.0f;
else if (angle > 70.0f) steering = 1.0f;
else steering += angle/70.0f;
return steering;
}
float AAICarlaVehicleController::CalcStreeringValue(){
float steering = 0;
FRoadMapPixelData rightRoadData = RoadMap->GetDataAt(VehicleRightControl->GetComponentLocation());
if (!rightRoadData.IsRoad()) steering -= 0.2f;
FRoadMapPixelData leftRoadData = RoadMap->GetDataAt(VehicleLeftControl->GetComponentLocation());
if (!leftRoadData.IsRoad()) steering += 0.2f;
FRoadMapPixelData roadData = RoadMap->GetDataAt(GetPawn()->GetActorLocation());
if (!roadData.IsRoad()){
steering = -1;
}
else if (roadData.HasDirection()){
FVector direction = roadData.GetDirection();
FVector right = rightRoadData.GetDirection();
FVector left = leftRoadData.GetDirection();
FVector forward = GetPawn()->GetActorForwardVector();
forward.Z = 0.0f;
float dirAngle = direction.UnitCartesianToSpherical().Y;
float actorAngle = forward.UnitCartesianToSpherical().Y;
float rightAngle = right.UnitCartesianToSpherical().Y;
float leftAngle = left.UnitCartesianToSpherical().Y;
dirAngle *= (180.0f/PI);
actorAngle *= (180.0/PI);
rightAngle *= (180.0/PI);
leftAngle *= (180.0/PI);
UE_LOG(LogCarla, Log,
TEXT("direction: X: %f Y: %f Z: %f --> %f"),
direction.X,
direction.Y,
direction.Z,
dirAngle
);
UE_LOG(LogCarla, Log,
TEXT("right: X: %f Y: %f Z: %f --> %f"),
right.X,
right.Y,
right.Z,
rightAngle
);
UE_LOG(LogCarla, Log,
TEXT("Left: X: %f Y: %f Z: %f --> %f"),
left.X,
left.Y,
left.Z,
leftAngle
);
float min = dirAngle - 90.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 (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) angle += 360.0f;
if (angle < -70.0f) steering = -1.0f;
else if (angle > 70.0f) steering = 1.0f;
else steering += angle/70.0f;
}
return steering;
}
float AAICarlaVehicleController::Stop(float &speed){
if (speed > 0.0f) return -1.0f;
else return 0;
}
float AAICarlaVehicleController::Move(float &speed){
return 1.0f - (speed/MAX_SPEED);
}
void AAICarlaVehicleController::RedTrafficLight(bool state){
if (state) TrafficLightStop = true;
else TrafficLightStop = false;
}
void AAICarlaVehicleController::NewSpeedLimit(float speed){
MAX_SPEED = speed;
}
void AAICarlaVehicleController::NewRoute(TArray<FVector> positions){
this->route = positions;
route_it = 0;
}
/*
bool AAICarlaVehicleController::DoTrace()
{
FHitResult RV_Hit(ForceInit);
FVector Start = GetPawn()->GetActorLocation() + (GetPawn()->GetActorForwardVector() * 250) + FVector(0.0, 0.0, 50.0);
// you need to add a uproperty to the header file for a float PlayerInteractionDistance
FVector End = Start + (GetPawn()->GetActorForwardVector() * 500);
//If Trace Hits anything
if( UMyStaticFunctionLibrary::Trace(GetWorld(),GetPawn(),Start,End,HitData) )
{
//Print out the name of the traced actor
if(HitData.GetActor())
{
ClientMessage(HitData.GetActor()->GetName());
//Print out distance from start of trace to impact point
ClientMessage("Trace Distance: " + FString::SanitizeFloat(HitData.Distance));
}
return true;
}
return false;
}
*/

View File

@ -0,0 +1,136 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#pragma once
#include "GameFramework/PlayerController.h"
#include "AICarlaVehicleController.generated.h"
//#include "TrafficLight.h"
class UBoxComponent;
class USphereComponent;
class URoadMap;
class UWheeledVehicleMovementComponent;
/**
*
*/
UCLASS()
class CARLA_API AAICarlaVehicleController : public APlayerController
{
GENERATED_BODY()
// ===========================================================================
/// @name Constructor and destructor
// ===========================================================================
/// @{
public:
AAICarlaVehicleController();
~AAICarlaVehicleController();
/// @}
// ===========================================================================
/// @name APlayerController overrides
// ===========================================================================
/// @{
public:
virtual void SetupInputComponent() override;
virtual void Possess(APawn *aPawn) override;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
/// @}
// ===========================================================================
/// @name Vehicle pawn info
// ===========================================================================
/// @{
public:
bool IsPossessingAVehicle() const
{
return MovementComponent != nullptr;
}
/// World location of the vehicle.
FVector GetVehicleLocation() const;
/// Speed forward in km/h. Might be negative if goes backwards.
float GetVehicleForwardSpeed() const;
/// Orientation vector of the vehicle, pointing forward.
FVector GetVehicleOrientation() const;
int32 GetVehicleCurrentGear() const;
/// @}
// ===========================================================================
/// @name Vehicle movement
// ===========================================================================
/// @{
public:
void SetThrottleInput(float Value);
void SetSteeringInput(float Value);
void SetHandbrakeInput(bool Value);
/// @}
// ===========================================================================
/// @name Blueprint functions
// ===========================================================================
/// @{
public:
UFUNCTION(BlueprintCallable, Category="Trigger")
void RedTrafficLight(bool state);
UFUNCTION(BlueprintCallable, Category="Trigger")
void NewSpeedLimit(float speed);
UFUNCTION(BlueprintCallable, Category="Trigger")
void NewRoute(TArray<FVector> positions);
private:
float CalcStreeringValue();
float GoTo(FVector objective);
float Stop(float &speed);
float Move(float &speed);
bool DoTrace();
private:
UPROPERTY()
UBoxComponent *VehicleBounds;
UPROPERTY()
USphereComponent* VehicleRightControl;
UPROPERTY()
USphereComponent* VehicleLeftControl;
UPROPERTY()
AActor *forwardTrigger;
UPROPERTY()
URoadMap *RoadMap;
UPROPERTY()
UWheeledVehicleMovementComponent *MovementComponent;
UPROPERTY(EditAnywhere)
float MAX_SPEED = 30.0f;
bool TrafficLightStop = false;
int route_it = 0;
TArray<FVector> route;
};

View File

@ -0,0 +1,8 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#include "Carla.h"
#include "AIVehicleController.h"

View File

@ -0,0 +1,19 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#pragma once
#include "AIController.h"
#include "AIVehicleController.generated.h"
/**
*
*/
UCLASS()
class CARLA_API AAIVehicleController : public AAIController
{
GENERATED_BODY()
};

View File

@ -0,0 +1,20 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#include "Carla.h"
#include "TrafficLight.h"
// Sets default values
ATrafficLight::ATrafficLight()
{
// 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;
}
// Called when the game starts or when spawned
void ATrafficLight::BeginPlay()
{
Super::BeginPlay();
}

View File

@ -0,0 +1,37 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#pragma once
#include "GameFramework/Actor.h"
#include "TrafficLight.generated.h"
UENUM(BlueprintType)
enum class ETrafficLightState : uint8{
RED UMETA(DisplayName = "Red"),
YELLOW UMETA(DisplayName = "Yellow"),
GEEN UMETA(DisplayName = "Green")
};
UCLASS()
class CARLA_API ATrafficLight : public AActor
{
GENERATED_BODY()
public:
ATrafficLight();
~ATrafficLight(){};
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
UPROPERTY(BlueprintReadWrite, Category=TrafficLightValues, EditAnywhere)
ETrafficLightState state;
};

View File

@ -0,0 +1,28 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#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;
}
// Called when the game starts or when spawned
void ATrafficLightGroup::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ATrafficLightGroup::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}

View File

@ -0,0 +1,30 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#pragma once
#include "GameFramework/Actor.h"
#include "TrafficLightGroup.generated.h"
UCLASS()
class CARLA_API ATrafficLightGroup : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ATrafficLightGroup();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UPROPERTY (BlueprintReadOnly, Category=TrafficLights, EditAnywhere)
TArray<AActor*> LightComponents;
};

View File

@ -0,0 +1,68 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#include "Carla.h"
#include "IntersectionEntrance.h"
// Sets default values
AIntersectionEntrance::AIntersectionEntrance(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
// 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;
}
// Called when the game starts or when spawned
void AIntersectionEntrance::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AIntersectionEntrance::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
TArray<FVector> AIntersectionEntrance::GetRoute(int it)
{
TArray<AActor*> points = Routes[it].points;
TArray<FVector> route;
for (int i = 0; i < points.Num(); ++i){
route.Add(points[i]->GetActorLocation());
}
return route;
}
/*
#if WITH_EDITOR
void AIntersectionEntrance::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.Property) {
if (bCreateRoutes && (GetWorld() != nullptr)) {
//ClearRoutes();
for (int i = 0; i < Routes.Num(); ++i){
for(int e = 0; e < Routes[i].points.Num(); ++e){
AActor* actor= GetWorld()->SpawnActor<AActor>();//USphereComponent* createdComp = NewObject<USphereComponent>(this);//CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
USceneComponent* SphereMesh = NewObject<USceneComponent>(actor);
SphereMesh->AttachToComponent(RootComponent,FAttachmentTransformRules::KeepWorldTransform);
if(actor)
{
actor->RegisterAllComponents();
Routes[i].points[e] = actor;
//Routes[i].points[e].position = createdComp->GetRelativeTransform().GetLocation();
}
}
}
}
}
bCreateRoutes = false;
}
#endif // WITH_EDITOR
*/

View File

@ -0,0 +1,53 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#pragma once
#include "GameFramework/Actor.h"
#include "IntersectionEntrance.generated.h"
USTRUCT(BlueprintType)
struct FRoute {
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category=TrafficRoutes, EditAnywhere)
TArray < AActor *> points;
};
UCLASS(BlueprintType)
class CARLA_API AIntersectionEntrance : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AIntersectionEntrance(const FObjectInitializer& ObjectInitializer);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
protected:
UFUNCTION(BlueprintCallable, Category="Trigger")
TArray<FVector> GetRoute(int route);
/*
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif // WITH_EDITOR
*/
public:
UPROPERTY(Category = "Routes", EditAnywhere)
bool bCreateRoutes = false;
UPROPERTY(BlueprintReadWrite, Category=TrafficRoutes, EditAnywhere)
TArray< FRoute > Routes;
};

View File

@ -135,7 +135,7 @@ void URoadMap::SetPixelAt(
case ECityMapMeshTag::Road90DegTurn_Lane7:
bIsRoad = true;
bHasDirection = true;
Rotator.Yaw += 90.0f + 22.5f;
Rotator.Yaw += 90.0f; //+ 15.5f;
break;
case ECityMapMeshTag::Road90DegTurn_Lane5:
bIsRoad = true;
@ -145,7 +145,7 @@ void URoadMap::SetPixelAt(
case ECityMapMeshTag::Road90DegTurn_Lane3:
bIsRoad = true;
bHasDirection = true;
Rotator.Yaw += 90.0f + 45.0f + 22.5f;
Rotator.Yaw += 90.0f + 45.0f + 20.5f;
break;
case ECityMapMeshTag::Road90DegTurn_Lane8:
case ECityMapMeshTag::RoadTIntersection_Lane4:
@ -158,17 +158,17 @@ void URoadMap::SetPixelAt(
case ECityMapMeshTag::Road90DegTurn_Lane6:
bIsRoad = true;
bHasDirection = true;
Rotator.Yaw += 270.0f + 22.5f;
Rotator.Yaw += 270.0f + 30.0f;
break;
case ECityMapMeshTag::Road90DegTurn_Lane4:
bIsRoad = true;
bHasDirection = true;
Rotator.Yaw += 270.0f + 45.0f;
Rotator.Yaw += 270.0f + 50.0f;
break;
case ECityMapMeshTag::Road90DegTurn_Lane2:
bIsRoad = true;
bHasDirection = true;
Rotator.Yaw += 270.0f + 45.0f + 22.5f;
Rotator.Yaw += 270.0f + 70.0f;
break;
case ECityMapMeshTag::RoadTIntersection_Lane3:
case ECityMapMeshTag::RoadTIntersection_Lane6: