Merge branch 'master' into roads

This commit is contained in:
nsubiron 2018-11-12 14:48:44 +01:00
commit 503fedeb6b
18 changed files with 298 additions and 89 deletions

View File

@ -102,8 +102,8 @@
## `carla.Vehicle(carla.Actor)` ## `carla.Vehicle(carla.Actor)`
- `bounding_box` - `bounding_box`
- `control`
- `apply_control(vehicle_control)` - `apply_control(vehicle_control)`
- `get_vehicle_control()`
- `set_autopilot(enabled=True)` - `set_autopilot(enabled=True)`
## `carla.TrafficLight(carla.Actor)` ## `carla.TrafficLight(carla.Actor)`
@ -272,7 +272,8 @@ Static presets
## `carla.TrafficLightState` ## `carla.TrafficLightState`
- `Unknown` - `Off`
- `Red` - `Red`
- `Yellow` - `Yellow`
- `Green` - `Green`
- `Unknown`

View File

@ -11,14 +11,8 @@
namespace carla { namespace carla {
namespace client { namespace client {
TrafficLightState TrafficLight::GetState() { rpc::TrafficLightState TrafficLight::GetState() {
auto state = GetEpisode().Lock()->GetActorDynamicState(*this).state; return GetEpisode().Lock()->GetActorDynamicState(*this).state.traffic_light_state;
switch (state) {
case 1u: return TrafficLightState::Red;
case 2u: return TrafficLightState::Yellow;
case 3u: return TrafficLightState::Green;
default: return TrafficLightState::Unknown;
}
} }
} // namespace client } // namespace client

View File

@ -7,17 +7,11 @@
#pragma once #pragma once
#include "carla/client/Actor.h" #include "carla/client/Actor.h"
#include "carla/rpc/TrafficLightState.h"
namespace carla { namespace carla {
namespace client { namespace client {
enum class TrafficLightState {
Unknown,
Red,
Yellow,
Green
};
class TrafficLight : public Actor { class TrafficLight : public Actor {
public: public:
@ -27,7 +21,7 @@ namespace client {
/// ///
/// @note This function does not call the simulator, it returns the /// @note This function does not call the simulator, it returns the
/// traffic light state received in the last tick. /// traffic light state received in the last tick.
TrafficLightState GetState(); rpc::TrafficLightState GetState();
}; };
} // namespace client } // namespace client

View File

@ -11,6 +11,10 @@
namespace carla { namespace carla {
namespace client { namespace client {
void Vehicle::SetAutopilot(bool enabled) {
GetEpisode().Lock()->SetVehicleAutopilot(*this, enabled);
}
void Vehicle::ApplyControl(const Control &control) { void Vehicle::ApplyControl(const Control &control) {
if (control != _control) { if (control != _control) {
GetEpisode().Lock()->ApplyControlToVehicle(*this, control); GetEpisode().Lock()->ApplyControlToVehicle(*this, control);
@ -18,8 +22,8 @@ namespace client {
} }
} }
void Vehicle::SetAutopilot(bool enabled) { Vehicle::Control Vehicle::GetVehicleControl() const {
GetEpisode().Lock()->SetVehicleAutopilot(*this, enabled); return GetEpisode().Lock()->GetActorDynamicState(*this).state.vehicle_control;
} }
} // namespace client } // namespace client

View File

@ -27,12 +27,9 @@ namespace client {
/// Return the control last applied to this vehicle. /// Return the control last applied to this vehicle.
/// ///
/// @warning This function only takes into account the control applied to /// @note This function does not call the simulator, it returns the Control
/// this instance of Vehicle. Note that several instances of Vehicle (even /// received in the last tick.
/// in different processes) may point to the same vehicle in the simulator. Control GetVehicleControl() const;
const Control &GetControl() const {
return _control;
}
private: private:

View File

@ -30,7 +30,7 @@ namespace detail {
geom::Transform transform; geom::Transform transform;
geom::Vector3D velocity; geom::Vector3D velocity;
geom::Vector3D acceleration; geom::Vector3D acceleration;
uint8_t state = 0u; sensor::data::ActorDynamicState::TypeDependentState state;
}; };
const auto &GetTimestamp() const { const auto &GetTimestamp() const {

View File

@ -0,0 +1,29 @@
// 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/MsgPack.h"
#include <cstdint>
namespace carla {
namespace rpc {
enum class TrafficLightState : uint8_t {
Off,
Red,
Yellow,
Green,
Unknown,
SIZE
};
} // namespace rpc
} // namespace carla
MSGPACK_ADD_ENUM(carla::rpc::TrafficLightState);

View File

@ -12,14 +12,14 @@ namespace rpc {
using WP = WeatherParameters; using WP = WeatherParameters;
// cloudyness precip. prec.dep. wind azimuth altitude // cloudyness precip. prec.dep. wind azimuth altitude
WP WP::ClearNoon = { 0.0f, 0.0f, 00.0f, 0.35f, 0.0f, 75.0f}; WP WP::ClearNoon = { 15.0f, 0.0f, 00.0f, 0.35f, 0.0f, 75.0f};
WP WP::CloudyNoon = { 80.0f, 0.0f, 00.0f, 0.35f, 0.0f, 75.0f}; WP WP::CloudyNoon = { 80.0f, 0.0f, 00.0f, 0.35f, 0.0f, 75.0f};
WP WP::WetNoon = { 20.0f, 0.0f, 50.0f, 0.35f, 0.0f, 75.0f}; WP WP::WetNoon = { 20.0f, 0.0f, 50.0f, 0.35f, 0.0f, 75.0f};
WP WP::WetCloudyNoon = { 80.0f, 0.0f, 50.0f, 0.35f, 0.0f, 75.0f}; WP WP::WetCloudyNoon = { 80.0f, 0.0f, 50.0f, 0.35f, 0.0f, 75.0f};
WP WP::MidRainyNoon = { 80.0f, 30.0f, 50.0f, 0.40f, 0.0f, 75.0f}; WP WP::MidRainyNoon = { 80.0f, 30.0f, 50.0f, 0.40f, 0.0f, 75.0f};
WP WP::HardRainNoon = { 90.0f, 60.0f, 100.0f, 1.0f, 0.0f, 75.0f}; WP WP::HardRainNoon = { 90.0f, 60.0f, 100.0f, 1.0f, 0.0f, 75.0f};
WP WP::SoftRainNoon = { 70.0f, 15.0f, 50.0f, 0.35f, 0.0f, 75.0f}; WP WP::SoftRainNoon = { 70.0f, 15.0f, 50.0f, 0.35f, 0.0f, 75.0f};
WP WP::ClearSunset = { 0.0f, 0.0f, 00.0f, 0.35f, 0.0f, 15.0f}; WP WP::ClearSunset = { 15.0f, 0.0f, 00.0f, 0.35f, 0.0f, 15.0f};
WP WP::CloudySunset = { 80.0f, 0.0f, 00.0f, 0.35f, 0.0f, 15.0f}; WP WP::CloudySunset = { 80.0f, 0.0f, 00.0f, 0.35f, 0.0f, 15.0f};
WP WP::WetSunset = { 20.0f, 0.0f, 50.0f, 0.35f, 0.0f, 15.0f}; WP WP::WetSunset = { 20.0f, 0.0f, 50.0f, 0.35f, 0.0f, 15.0f};
WP WP::WetCloudySunset = { 90.0f, 0.0f, 50.0f, 0.35f, 0.0f, 15.0f}; WP WP::WetCloudySunset = { 90.0f, 0.0f, 50.0f, 0.35f, 0.0f, 15.0f};

View File

@ -9,6 +9,8 @@
#include "carla/geom/Transform.h" #include "carla/geom/Transform.h"
#include "carla/geom/Vector3D.h" #include "carla/geom/Vector3D.h"
#include "carla/rpc/ActorId.h" #include "carla/rpc/ActorId.h"
#include "carla/rpc/TrafficLightState.h"
#include "carla/rpc/VehicleControl.h"
#include <cstdint> #include <cstdint>
@ -16,6 +18,37 @@ namespace carla {
namespace sensor { namespace sensor {
namespace data { namespace data {
namespace detail {
#pragma pack(push, 1)
class PackedVehicleControl {
public:
PackedVehicleControl() = default;
PackedVehicleControl(const rpc::VehicleControl &control)
: throttle(control.throttle),
steer(control.steer),
brake(control.brake),
hand_brake(control.hand_brake),
reverse(control.reverse) {}
operator rpc::VehicleControl() const {
return {throttle, steer, brake, hand_brake, reverse};
}
private:
float throttle;
float steer;
float brake;
bool hand_brake;
bool reverse;
};
#pragma pack(pop)
} // namespace detail
#pragma pack(push, 1) #pragma pack(push, 1)
/// Dynamic state of an actor at a certain frame. /// Dynamic state of an actor at a certain frame.
@ -27,12 +60,17 @@ namespace data {
geom::Vector3D velocity; geom::Vector3D velocity;
uint8_t state; union TypeDependentState {
rpc::TrafficLightState traffic_light_state;
detail::PackedVehicleControl vehicle_control;
} state;
}; };
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(ActorDynamicState) == 1u + 10u * sizeof(uint32_t), "Invalid ActorDynamicState size!"); static_assert(
sizeof(ActorDynamicState) == 10u * sizeof(uint32_t) + sizeof(detail::PackedVehicleControl),
"Invalid ActorDynamicState size!");
} // namespace data } // namespace data
} // namespace sensor } // namespace sensor

View File

@ -29,6 +29,7 @@ Use ARROWS or WASD keys for control.
R : toggle recording images to disk R : toggle recording images to disk
F1 : toggle HUD
H/? : toggle help H/? : toggle help
ESC : quit ESC : quit
""" """
@ -64,7 +65,10 @@ import carla
from carla import ColorConverter as cc from carla import ColorConverter as cc
import argparse import argparse
import collections
import datetime
import logging import logging
import math
import random import random
import re import re
import weakref import weakref
@ -79,6 +83,7 @@ try:
from pygame.locals import K_BACKSPACE from pygame.locals import K_BACKSPACE
from pygame.locals import K_DOWN from pygame.locals import K_DOWN
from pygame.locals import K_ESCAPE from pygame.locals import K_ESCAPE
from pygame.locals import K_F1
from pygame.locals import K_LEFT from pygame.locals import K_LEFT
from pygame.locals import K_RIGHT from pygame.locals import K_RIGHT
from pygame.locals import K_SLASH from pygame.locals import K_SLASH
@ -115,10 +120,16 @@ def find_weather_presets():
return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets]
def get_actor_display_name(actor, truncate=250):
name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:])
return (name[:truncate-1] + u'\u2026') if len(name) > truncate else name
class World(object): class World(object):
def __init__(self, carla_world, hud): def __init__(self, carla_world, hud):
self.world = carla_world self.world = carla_world
self.hud = hud self.hud = hud
self.world.on_tick(hud.on_world_tick)
blueprint = self._get_random_blueprint() blueprint = self._get_random_blueprint()
spawn_points = self.world.get_map().get_spawn_points() spawn_points = self.world.get_map().get_spawn_points()
spawn_point = random.choice(spawn_points) if spawn_points else carla.Transform() spawn_point = random.choice(spawn_points) if spawn_points else carla.Transform()
@ -196,6 +207,8 @@ class KeyboardControl(object):
return True return True
elif event.key == K_BACKSPACE: elif event.key == K_BACKSPACE:
world.restart() world.restart()
elif event.key == K_F1:
world.hud.toggle_info()
elif event.key == K_h or (event.key == K_SLASH and pygame.key.get_mods() & KMOD_SHIFT): elif event.key == K_h or (event.key == K_SLASH and pygame.key.get_mods() & KMOD_SHIFT):
world.hud.help.toggle() world.hud.help.toggle()
elif event.key == K_TAB: elif event.key == K_TAB:
@ -253,13 +266,70 @@ class HUD(object):
self._font_mono = pygame.font.Font(mono, 14) self._font_mono = pygame.font.Font(mono, 14)
self._notifications = FadingText(font, (width, 40), (0, height - 40)) self._notifications = FadingText(font, (width, 40), (0, height - 40))
self.help = HelpText(pygame.font.Font(mono, 24), width, height) self.help = HelpText(pygame.font.Font(mono, 24), width, height)
self.client_fps = 0
self.server_fps = 0 self.server_fps = 0
self.frame_number = 0
self.simulation_time = 0
self._show_info = True
self._info_text = []
self._server_clock = pygame.time.Clock()
def on_world_tick(self, timestamp):
self._server_clock.tick()
self.server_fps = self._server_clock.get_fps()
self.frame_number = timestamp.frame_count
self.simulation_time = timestamp.elapsed_seconds
def tick(self, world, clock): def tick(self, world, clock):
self.client_fps = clock.get_fps() if not self._show_info:
return
t = world.vehicle.get_transform()
v = world.vehicle.get_velocity()
c = world.vehicle.get_vehicle_control()
heading = 'N' if abs(t.rotation.yaw) < 89.5 else ''
heading += 'S' if abs(t.rotation.yaw) > 90.5 else ''
heading += 'E' if 179.5 > t.rotation.yaw > 0.5 else ''
heading += 'W' if -0.5 > t.rotation.yaw > -179.5 else ''
colhist = world.collision_sensor.get_collision_history()
collision = [colhist[x + self.frame_number - 200] for x in range(0, 200)]
max_col = max(1.0, max(collision))
collision = [x / max_col for x in collision]
self._info_text = [
'server: % 16d FPS' % self.server_fps,
'client: % 16d FPS' % clock.get_fps(),
'',
'vehicle: % 20s' % get_actor_display_name(world.vehicle, truncate=20),
'map: % 20s' % world.world.map_name,
'simulation time: % 12s' % datetime.timedelta(seconds=int(self.simulation_time)),
'',
'speed: % 15.0f km/h' % (3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2)),
u'heading:% 16.0f\N{DEGREE SIGN} % 2s' % (t.rotation.yaw, heading),
'location:% 20s' % ('(% 5.1f, % 5.1f)' % (t.location.x, t.location.y)),
'height: % 18.0f m' % t.location.z,
'',
('throttle:', c.throttle, 0.0, 1.0),
('steer:', c.steer, -1.0, 1.0),
('brake:', c.brake, 0.0, 1.0),
('reverse:', c.reverse),
('hand brake:', c.hand_brake),
'',
'collision:',
collision
]
vehicles = world.world.get_actors().filter('vehicle.*')
if len(vehicles) > 1:
self._info_text += ['', 'nearby vehicles:']
distance = lambda l: math.sqrt((l.x - t.location.x)**2 + (l.y - t.location.y)**2 + (l.z - t.location.z)**2)
vehicles = [(distance(x.get_location()), x) for x in vehicles if x.id != world.vehicle.id]
for d, vehicle in sorted(vehicles):
if d > 200.0:
break
vehicle_type = get_actor_display_name(vehicle, truncate=22)
self._info_text.append('% 4dm %s' % (d, vehicle_type))
self._notifications.tick(world, clock) self._notifications.tick(world, clock)
def toggle_info(self):
self._show_info = not self._show_info
def notification(self, text, seconds=2.0): def notification(self, text, seconds=2.0):
self._notifications.set_text(text, seconds=seconds) self._notifications.set_text(text, seconds=seconds)
@ -267,11 +337,42 @@ class HUD(object):
self._notifications.set_text('Error: %s' % text, (255, 0, 0)) self._notifications.set_text('Error: %s' % text, (255, 0, 0))
def render(self, display): def render(self, display):
if self._show_info:
info_surface = pygame.Surface((220, self.dim[1]))
info_surface.set_alpha(100)
display.blit(info_surface, (0, 0))
v_offset = 4
bar_h_offset = 100
bar_width = 106
for item in self._info_text:
if v_offset + 18 > self.dim[1]:
break
if isinstance(item, list):
if len(item) > 1:
points = [(x + 8, v_offset + 8 + (1.0 - y) * 30) for x, y in enumerate(item)]
pygame.draw.lines(display, (255, 136, 0), False, points, 2)
item = None
v_offset += 18
elif isinstance(item, tuple):
if isinstance(item[1], bool):
rect = pygame.Rect((bar_h_offset, v_offset + 8), (6, 6))
pygame.draw.rect(display, (255, 255, 255), rect, 0 if item[1] else 1)
else:
rect_border = pygame.Rect((bar_h_offset, v_offset + 8), (bar_width, 6))
pygame.draw.rect(display, (255, 255, 255), rect_border, 1)
f = (item[1] - item[2]) / (item[3] - item[2])
if item[2] < 0.0:
rect = pygame.Rect((bar_h_offset + f * (bar_width - 6), v_offset + 8), (6, 6))
else:
rect = pygame.Rect((bar_h_offset, v_offset + 8), (f * bar_width, 6))
pygame.draw.rect(display, (255, 255, 255), rect)
item = item[0]
if item: # At this point has to be a str.
surface = self._font_mono.render(item, True, (255, 255, 255))
display.blit(surface, (8, v_offset))
v_offset += 18
self._notifications.render(display) self._notifications.render(display)
self.help.render(display) self.help.render(display)
fps_text = 'client: %02d FPS; server: %02d FPS' % (self.client_fps, self.server_fps)
fps = self._font_mono.render(fps_text, True, (60, 60, 60))
display.blit(fps, (6, 4))
# ============================================================================== # ==============================================================================
@ -339,6 +440,7 @@ class HelpText(object):
class CollisionSensor(object): class CollisionSensor(object):
def __init__(self, parent_actor, hud): def __init__(self, parent_actor, hud):
self.sensor = None self.sensor = None
self._history = []
self._parent = parent_actor self._parent = parent_actor
self._hud = hud self._hud = hud
world = self._parent.get_world() world = self._parent.get_world()
@ -349,6 +451,12 @@ class CollisionSensor(object):
weak_self = weakref.ref(self) weak_self = weakref.ref(self)
self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event)) self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event))
def get_collision_history(self):
history = collections.defaultdict(int)
for frame, intensity in self._history:
history[frame] += intensity
return history
@staticmethod @staticmethod
def _on_collision(weak_self, event): def _on_collision(weak_self, event):
self = weak_self() self = weak_self()
@ -356,6 +464,11 @@ class CollisionSensor(object):
return return
actor_type = ' '.join(event.other_actor.type_id.replace('_', '.').title().split('.')[1:]) actor_type = ' '.join(event.other_actor.type_id.replace('_', '.').title().split('.')[1:])
self._hud.notification('Collision with %r' % actor_type) self._hud.notification('Collision with %r' % actor_type)
impulse = event.normal_impulse
intensity = math.sqrt(impulse.x**2 + impulse.y**2 + impulse.z**2)
self._history.append((event.frame_number, intensity))
if len(self._history) > 2000:
self._history.pop(0)
# ============================================================================== # ==============================================================================
@ -391,7 +504,6 @@ class CameraManager(object):
bp.set_attribute('image_size_y', str(hud.dim[1])) bp.set_attribute('image_size_y', str(hud.dim[1]))
item.append(bp) item.append(bp)
self._index = None self._index = None
self._server_clock = pygame.time.Clock()
def toggle_camera(self): def toggle_camera(self):
self._transform_index = (self._transform_index + 1) % len(self._camera_transforms) self._transform_index = (self._transform_index + 1) % len(self._camera_transforms)
@ -433,8 +545,6 @@ class CameraManager(object):
self = weak_self() self = weak_self()
if not self: if not self:
return return
self._server_clock.tick()
self._hud.server_fps = self._server_clock.get_fps()
if self._sensors[self._index][0].startswith('sensor.lidar'): if self._sensors[self._index][0].startswith('sensor.lidar'):
points = np.frombuffer(image.raw_data, dtype=np.dtype('f4')) points = np.frombuffer(image.raw_data, dtype=np.dtype('f4'))
points = np.reshape(points, (int(points.shape[0]/3), 3)) points = np.reshape(points, (int(points.shape[0]/3), 3))

View File

@ -7,6 +7,7 @@
#include <carla/client/Actor.h> #include <carla/client/Actor.h>
#include <carla/client/TrafficLight.h> #include <carla/client/TrafficLight.h>
#include <carla/client/Vehicle.h> #include <carla/client/Vehicle.h>
#include <carla/rpc/TrafficLightState.h>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
@ -59,17 +60,18 @@ void export_actor() {
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)) .add_property("bounding_box", CALL_RETURNING_COPY(cc::Vehicle, GetBoundingBox))
.add_property("control", CALL_RETURNING_COPY(cc::Vehicle, GetControl))
.def("apply_control", &cc::Vehicle::ApplyControl, (arg("control"))) .def("apply_control", &cc::Vehicle::ApplyControl, (arg("control")))
.def("get_vehicle_control", &cc::Vehicle::GetVehicleControl)
.def("set_autopilot", &cc::Vehicle::SetAutopilot, (arg("enabled")=true)) .def("set_autopilot", &cc::Vehicle::SetAutopilot, (arg("enabled")=true))
.def(self_ns::str(self_ns::self)) .def(self_ns::str(self_ns::self))
; ;
enum_<cc::TrafficLightState>("TrafficLightState") enum_<cr::TrafficLightState>("TrafficLightState")
.value("Unknown", cc::TrafficLightState::Unknown) .value("Off", cr::TrafficLightState::Off)
.value("Red", cc::TrafficLightState::Red) .value("Red", cr::TrafficLightState::Red)
.value("Yellow", cc::TrafficLightState::Yellow) .value("Yellow", cr::TrafficLightState::Yellow)
.value("Green", cc::TrafficLightState::Green) .value("Green", cr::TrafficLightState::Green)
.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)

View File

@ -12,12 +12,20 @@
#include "Carla/Game/Tagger.h" #include "Carla/Game/Tagger.h"
#include "Carla/Traffic/TrafficLightBase.h" #include "Carla/Traffic/TrafficLightBase.h"
static bool FActorRegistry_IsTrafficLight(const FActorView &View) static FActorView::ActorType FActorRegistry_GetActorType(const FActorView &View)
{ {
return if (View.IsValid())
View.IsValid() && {
View.GetSemanticTags().Contains(ECityObjectLabel::TrafficSigns) && if (nullptr != Cast<ACarlaWheeledVehicle>(View.GetActor()))
(nullptr != Cast<ATrafficLightBase>(View.GetActor())); {
return FActorView::ActorType::Vehicle;
}
else if (nullptr != Cast<ATrafficLightBase>(View.GetActor()))
{
return FActorView::ActorType::TrafficLight;
}
}
return FActorView::ActorType::Other;
} }
static FString GetRelevantTagAsString(const FActorView &View) static FString GetRelevantTagAsString(const FActorView &View)
@ -51,7 +59,7 @@ FActorView FActorRegistry::Register(AActor &Actor, FActorDescription Description
auto View = FActorView(Id, Actor, std::move(Description)); auto View = FActorView(Id, Actor, std::move(Description));
ATagger::GetTagsOfTaggedActor(Actor, View.SemanticTags); ATagger::GetTagsOfTaggedActor(Actor, View.SemanticTags);
View.bIsTrafficLight = FActorRegistry_IsTrafficLight(View); View.Type = FActorRegistry_GetActorType(View);
auto Result = ActorDatabase.emplace(Id, View); auto Result = ActorDatabase.emplace(Id, View);
check(Result.second); check(Result.second);

View File

@ -18,6 +18,12 @@ public:
using IdType = uint32; using IdType = uint32;
enum class ActorType : uint8 {
Other,
Vehicle,
TrafficLight
};
FActorView() = default; FActorView() = default;
FActorView(const FActorView &) = default; FActorView(const FActorView &) = default;
@ -31,6 +37,11 @@ public:
return Id; return Id;
} }
ActorType GetActorType() const
{
return Type;
}
AActor *GetActor() AActor *GetActor()
{ {
return TheActor; return TheActor;
@ -51,11 +62,6 @@ public:
return SemanticTags; return SemanticTags;
} }
bool IsTrafficLight() const
{
return bIsTrafficLight;
}
private: private:
friend class FActorRegistry; friend class FActorRegistry;
@ -67,12 +73,11 @@ private:
IdType Id = 0u; IdType Id = 0u;
ActorType Type = ActorType::Other;
AActor *TheActor = nullptr; AActor *TheActor = nullptr;
TSharedPtr<const FActorDescription> Description = nullptr; TSharedPtr<const FActorDescription> Description = nullptr;
TSet<ECityObjectLabel> SemanticTags; TSet<ECityObjectLabel> SemanticTags;
/// @todo
bool bIsTrafficLight = false;
}; };

View File

@ -8,6 +8,8 @@
#include "Carla/Sensor/ShaderBasedSensor.h" #include "Carla/Sensor/ShaderBasedSensor.h"
#include "Carla/Actor/ActorDefinition.h"
#include "DepthCamera.generated.h" #include "DepthCamera.generated.h"
/// Sensor that produces "depth" images. /// Sensor that produces "depth" images.

View File

@ -13,19 +13,34 @@
#include <compiler/disable-ue4-macros.h> #include <compiler/disable-ue4-macros.h>
#include <carla/sensor/SensorRegistry.h> #include <carla/sensor/SensorRegistry.h>
#include <carla/sensor/data/ActorDynamicState.h>
#include <compiler/enable-ue4-macros.h> #include <compiler/enable-ue4-macros.h>
static uint8 AWorldObserver_GetActorState(const FActorView &View) static auto AWorldObserver_GetActorState(const FActorView &View)
{ {
if (View.IsTrafficLight()) using AType = FActorView::ActorType;
carla::sensor::data::ActorDynamicState::TypeDependentState state;
if (AType::Vehicle == View.GetActorType())
{
auto Vehicle = Cast<ACarlaWheeledVehicle>(View.GetActor());
if (Vehicle != nullptr)
{
state.vehicle_control = carla::rpc::VehicleControl{Vehicle->GetVehicleControl()};
}
}
else if (AType::TrafficLight == View.GetActorType())
{ {
auto TrafficLight = Cast<ATrafficLightBase>(View.GetActor()); auto TrafficLight = Cast<ATrafficLightBase>(View.GetActor());
if (TrafficLight != nullptr) if (TrafficLight != nullptr)
{ {
return static_cast<uint8>(TrafficLight->GetTrafficSignState()); using TLS = carla::rpc::TrafficLightState;
state.traffic_light_state = static_cast<TLS>(TrafficLight->GetTrafficSignState());
} }
} }
return 0u;
return state;
} }
static carla::Buffer AWorldObserver_Serialize( static carla::Buffer AWorldObserver_Serialize(
@ -53,7 +68,7 @@ static carla::Buffer AWorldObserver_Serialize(
for (auto &&pair : Registry) { for (auto &&pair : Registry) {
auto &&actor_view = pair.second; auto &&actor_view = pair.second;
check(actor_view.GetActor() != nullptr); check(actor_view.GetActor() != nullptr);
constexpr float TO_METERS = 1e-3; constexpr float TO_METERS = 1e-2;
const auto velocity = TO_METERS * actor_view.GetActor()->GetVelocity(); const auto velocity = TO_METERS * actor_view.GetActor()->GetVelocity();
ActorDynamicState info = { ActorDynamicState info = {
actor_view.GetActorId(), actor_view.GetActorId(),

View File

@ -14,18 +14,18 @@
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ETrafficSignState : uint8 { enum class ETrafficSignState : uint8 {
UNKNOWN UMETA(DisplayName = "UNKNOWN"), UNKNOWN = 0u UMETA(DisplayName = "UNKNOWN"),
TrafficLightRed UMETA(DisplayName = "Traffic Light - Red"), TrafficLightRed = 1u UMETA(DisplayName = "Traffic Light - Red"),
TrafficLightYellow UMETA(DisplayName = "Traffic Light - Yellow"), TrafficLightYellow = 2u UMETA(DisplayName = "Traffic Light - Yellow"),
TrafficLightGreen UMETA(DisplayName = "Traffic Light - Green"), TrafficLightGreen = 3u UMETA(DisplayName = "Traffic Light - Green"),
SpeedLimit_30 UMETA(DisplayName = "Speed Limit - 30"), SpeedLimit_30 UMETA(DisplayName = "Speed Limit - 30"),
SpeedLimit_40 UMETA(DisplayName = "Speed Limit - 40"), SpeedLimit_40 UMETA(DisplayName = "Speed Limit - 40"),
SpeedLimit_50 UMETA(DisplayName = "Speed Limit - 50"), SpeedLimit_50 UMETA(DisplayName = "Speed Limit - 50"),
SpeedLimit_60 UMETA(DisplayName = "Speed Limit - 60"), SpeedLimit_60 UMETA(DisplayName = "Speed Limit - 60"),
SpeedLimit_90 UMETA(DisplayName = "Speed Limit - 90"), SpeedLimit_90 UMETA(DisplayName = "Speed Limit - 90"),
SpeedLimit_100 UMETA(DisplayName = "Speed Limit - 100"), SpeedLimit_100 UMETA(DisplayName = "Speed Limit - 100"),
SpeedLimit_120 UMETA(DisplayName = "Speed Limit - 120"), SpeedLimit_120 UMETA(DisplayName = "Speed Limit - 120"),
SpeedLimit_130 UMETA(DisplayName = "Speed Limit - 130") SpeedLimit_130 UMETA(DisplayName = "Speed Limit - 130")
}; };
UCLASS() UCLASS()

View File

@ -86,29 +86,33 @@ void ACarlaWheeledVehicle::ApplyVehicleControl(const FVehicleControl &VehicleCon
void ACarlaWheeledVehicle::SetThrottleInput(const float Value) void ACarlaWheeledVehicle::SetThrottleInput(const float Value)
{ {
GetVehicleMovementComponent()->SetThrottleInput(Value); GetVehicleMovementComponent()->SetThrottleInput(Value);
Control.Throttle = Value;
} }
void ACarlaWheeledVehicle::SetSteeringInput(const float Value) void ACarlaWheeledVehicle::SetSteeringInput(const float Value)
{ {
GetVehicleMovementComponent()->SetSteeringInput(Value); GetVehicleMovementComponent()->SetSteeringInput(Value);
Control.Steer = Value;
} }
void ACarlaWheeledVehicle::SetBrakeInput(const float Value) void ACarlaWheeledVehicle::SetBrakeInput(const float Value)
{ {
GetVehicleMovementComponent()->SetBrakeInput(Value); GetVehicleMovementComponent()->SetBrakeInput(Value);
Control.Brake = Value;
} }
void ACarlaWheeledVehicle::SetReverse(const bool Value) void ACarlaWheeledVehicle::SetReverse(const bool Value)
{ {
if (Value != bIsInReverse) { if (Value != Control.bReverse) {
bIsInReverse = Value; Control.bReverse = Value;
auto MovementComponent = GetVehicleMovementComponent(); auto MovementComponent = GetVehicleMovementComponent();
MovementComponent->SetUseAutoGears(!bIsInReverse); MovementComponent->SetUseAutoGears(!Control.bReverse);
MovementComponent->SetTargetGear(bIsInReverse ? -1 : 1, true); MovementComponent->SetTargetGear(Control.bReverse ? -1 : 1, true);
} }
} }
void ACarlaWheeledVehicle::SetHandbrakeInput(const bool Value) void ACarlaWheeledVehicle::SetHandbrakeInput(const bool Value)
{ {
GetVehicleMovementComponent()->SetHandbrakeInput(Value); GetVehicleMovementComponent()->SetHandbrakeInput(Value);
Control.bHandBrake = Value;
} }

View File

@ -41,6 +41,13 @@ public:
/// @{ /// @{
public: public:
/// Vehicle control currently applied to this vehicle.
UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable)
const FVehicleControl &GetVehicleControl() const
{
return Control;
}
/// Transform of the vehicle. Location is shifted so it matches center of the /// Transform of the vehicle. Location is shifted so it matches center of the
/// vehicle bounds rather than the actor's location. /// vehicle bounds rather than the actor's location.
UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable) UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable)
@ -80,6 +87,12 @@ public:
UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable) UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable)
float GetMaximumSteerAngle() const; float GetMaximumSteerAngle() const;
UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable)
ECarlaWheeledVehicleState GetAIVehicleState() const
{
return State;
}
/// @} /// @}
// =========================================================================== // ===========================================================================
/// @name Set functions /// @name Set functions
@ -105,7 +118,7 @@ public:
UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable) UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable)
void ToggleReverse() void ToggleReverse()
{ {
SetReverse(!bIsInReverse); SetReverse(!Control.bReverse);
} }
UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable) UFUNCTION(Category = "CARLA Wheeled Vehicle", BlueprintCallable)
@ -128,12 +141,6 @@ public:
State = InState; State = InState;
} }
UFUNCTION(Category = "AI Controller", BlueprintCallable)
ECarlaWheeledVehicleState GetAIVehicleState() const
{
return State;
}
private: private:
/// Current state of the vehicle controller (for debugging purposes). /// Current state of the vehicle controller (for debugging purposes).
@ -146,6 +153,5 @@ private:
UPROPERTY(Category = "CARLA Wheeled Vehicle", VisibleAnywhere) UPROPERTY(Category = "CARLA Wheeled Vehicle", VisibleAnywhere)
UVehicleAgentComponent *VehicleAgentComponent; UVehicleAgentComponent *VehicleAgentComponent;
UPROPERTY() FVehicleControl Control;
bool bIsInReverse = false;
}; };