Moved GNSS sensor from client to server

This commit is contained in:
doterop 2019-10-30 11:22:53 +01:00 committed by Marc Garcia Puig
parent 6187bf4916
commit 4ec1338007
15 changed files with 201 additions and 188 deletions

View File

@ -1,9 +1,11 @@
## Latest
* Added new sensor: Inertial measurement unit (IMU)
* Moved GNSS sensor from client to server side
* Now all the camera-based sensors are provided with an additional parametrized lens distortion shader
* API changes:
- Lidar: `range` is now set in meters, not in centimeters
- Lidar: `horizontal_angle` is now received in radians, not in degrees
- GNSS: `carla.GnssEvent` renamed to `carla.GnssMeasurement`
* API extensions:
- Added `carla.IMUMeasurement`
* Updated manual_control.py with a lens disortion effect example

View File

@ -23,9 +23,8 @@ collision.
Although most sensors compute their measurements in the server side (UE4), it's
worth noticing that some sensors run in the client-side only. An example of such
sensor is the GNSS, it computes the simulated geo-location in the client-side
based on its 3D location. For further details see
[Appendix: Client-side sensors](#appendix-client-side-sensors).
sensor is the LaneInvasion, it notifies every time a lane mark has been crossed.
For further details see [Appendix: Client-side sensors](#appendix-client-side-sensors).
In this tutorial, we'll be focusing on server-side sensors.
@ -551,16 +550,14 @@ void MySensor::Tick(float DeltaSeconds)
Some sensors do not require the simulator to do their measurements, those
sensors may run completely in the client-side freeing the simulator from extra
computations. Examples of such sensors are the _GNSS_ and the _LaneInvasion_
sensors.
computations. Examples of such sensors is the _LaneInvasion_ sensors.
The usual approach is to create a "dummy" sensor in the server-side, just so the
simulator is aware that such actor exists. However, this dummy sensor doesn't tick
nor sends any sort of data. Its counterpart on the client-side however,
registers a "on tick" callback to execute some code on every new update. For
instance, the GNSS sensor registers a callback that converts the current 3D
location of the vehicle to a geo-location (latitude, longitude, altitude) every
tick.
instance, the LaneInvasion sensor registers a callback that notifies every time a
lane mark has been crossed.
It is very important to take into account that the "on tick" callback in the
client-side is executed concurrently, i.e., the same method may be executed

View File

@ -1,94 +0,0 @@
// Copyright (c) 2019 Intel Labs.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "carla/client/GnssSensor.h"
#include "carla/Logging.h"
#include "carla/client/Map.h"
#include "carla/client/detail/Simulator.h"
#include "carla/geom/GeoLocation.h"
#include "carla/sensor/data/GnssEvent.h"
#include <exception>
namespace carla {
namespace client {
// ===========================================================================
// -- GnssCallback -----------------------------------------------------------
// ===========================================================================
class GnssCallback {
public:
GnssCallback(
ActorId sensor_id,
geom::GeoLocation geo_reference,
Sensor::CallbackFunctionType &&user_callback)
: _sensor_id(sensor_id),
_geo_reference(geo_reference),
_callback(std::move(user_callback)) {}
void operator()(const WorldSnapshot &snapshot) const;
private:
ActorId _sensor_id;
geom::GeoLocation _geo_reference;
Sensor::CallbackFunctionType _callback;
};
void GnssCallback::operator()(const WorldSnapshot &snapshot) const {
try {
auto actor_snapshot = snapshot.Find(_sensor_id);
if (actor_snapshot.has_value()) {
auto transform = actor_snapshot->transform;
_callback(MakeShared<sensor::data::GnssEvent>(
snapshot.GetTimestamp().frame,
snapshot.GetTimestamp().elapsed_seconds,
transform,
_geo_reference.Transform(transform.location)));
}
} catch (const std::exception &e) {
log_error("GnssSensor:", e.what());
}
}
// ===========================================================================
// -- GnssSensor -------------------------------------------------------------
// ===========================================================================
GnssSensor::~GnssSensor() {
Stop();
}
void GnssSensor::Listen(CallbackFunctionType callback) {
auto episode = GetEpisode().Lock();
SharedPtr<Map> map = episode->GetCurrentMap();
DEBUG_ASSERT(map != nullptr);
const size_t callback_id = episode->RegisterOnTickEvent(GnssCallback(
GetId(),
map->GetGeoReference(),
std::move(callback)));
const size_t previous = _callback_id.exchange(callback_id);
if (previous != 0u) {
episode->RemoveOnTickEvent(previous);
}
}
void GnssSensor::Stop() {
const size_t previous = _callback_id.exchange(0u);
auto episode = GetEpisode().TryLock();
if ((previous != 0u) && (episode != nullptr)) {
episode->RemoveOnTickEvent(previous);
}
}
} // namespace client
} // namespace carla

View File

@ -1,46 +0,0 @@
// Copyright (c) 2019 Intel Labs.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/client/ClientSideSensor.h"
#include <atomic>
namespace carla {
namespace client {
class GnssSensor final : public ClientSideSensor {
public:
using ClientSideSensor::ClientSideSensor;
~GnssSensor();
/// Register a @a callback to be executed each time a new measurement is
/// received.
///
/// @warning Calling this function on a sensor that is already listening
/// steals the data stream from the previously set callback. Note that
/// several instances of Sensor (even in different processes) may point to
/// the same sensor in the simulator.
void Listen(CallbackFunctionType callback) override;
/// Stop listening for new measurements.
void Stop() override;
/// Return whether this Sensor instance is currently listening to the
/// associated sensor in the simulator.
bool IsListening() const override {
return _callback_id != 0u;
}
private:
std::atomic_size_t _callback_id{0u};
};
} // namespace client
} // namespace carla

View File

@ -9,7 +9,6 @@
#include "carla/Logging.h"
#include "carla/StringUtil.h"
#include "carla/client/Actor.h"
#include "carla/client/GnssSensor.h"
#include "carla/client/LaneInvasionSensor.h"
#include "carla/client/ServerSideSensor.h"
#include "carla/client/TrafficLight.h"
@ -75,8 +74,6 @@ namespace detail {
auto init = ActorInitializer{description, episode};
if (description.description.id == "sensor.other.lane_invasion") {
return MakeActorImpl<LaneInvasionSensor>(std::move(init), gc);
} else if (description.description.id == "sensor.other.gnss") {
return MakeActorImpl<GnssSensor>(std::move(init), gc);
} else if (description.HasAStream()) {
return MakeActorImpl<ServerSideSensor>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "vehicle.")) {

View File

@ -18,6 +18,7 @@
#include "carla/sensor/s11n/EpisodeStateSerializer.h"
#include "carla/sensor/s11n/ImageSerializer.h"
#include "carla/sensor/s11n/IMUSerializer.h"
#include "carla/sensor/s11n/GnssSerializer.h"
#include "carla/sensor/s11n/LidarSerializer.h"
#include "carla/sensor/s11n/NoopSerializer.h"
#include "carla/sensor/s11n/ObstacleDetectionEventSerializer.h"
@ -52,7 +53,7 @@ namespace sensor {
std::pair<ASemanticSegmentationCamera *, s11n::ImageSerializer>,
std::pair<ARayCastLidar *, s11n::LidarSerializer>,
std::pair<ACollisionSensor *, s11n::CollisionEventSerializer>,
std::pair<AGnssSensor *, s11n::NoopSerializer>,
std::pair<AGnssSensor *, s11n::GnssSerializer>,
std::pair<ALaneInvasionSensor *, s11n::NoopSerializer>,
std::pair<AObstacleDetectionSensor *, s11n::ObstacleDetectionEventSerializer>
>;

View File

@ -8,23 +8,34 @@
#include "carla/geom/GeoLocation.h"
#include "carla/sensor/SensorData.h"
#include "carla/sensor/s11n/GnssSerializer.h"
namespace carla {
namespace sensor {
namespace data {
/// A change of GNSS data.
class GnssEvent : public SensorData {
/// A change of GNSS Measurement.
class GnssMeasurement : public SensorData {
using Super = SensorData;
protected:
using Serializer = s11n::GnssSerializer;
friend Serializer;
explicit GnssMeasurement(const RawData &&data)
: Super(data){
s11n::GnssSerializer::Data gnss_data = Serializer::DeserializeRawData(data);
_geo_location = {gnss_data.latitude, gnss_data.longitude, gnss_data.altitude};
}
public:
explicit GnssEvent(
size_t frame,
double timestamp,
const rpc::Transform &sensor_transform,
const geom::GeoLocation &geo_location)
: SensorData(frame, timestamp, sensor_transform),
_geo_location(geo_location) {}
const geom::GeoLocation &GetGeoLocation() const {
geom::GeoLocation GetGeoLocation() const {
return _geo_location;
}
@ -43,6 +54,7 @@ namespace data {
private:
geom::GeoLocation _geo_location;
};
} // namespace data

View File

@ -0,0 +1,20 @@
// Copyright (c) 2019 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/GnssMeasurement.h"
#include "carla/sensor/s11n/GnssSerializer.h"
namespace carla {
namespace sensor {
namespace s11n {
SharedPtr<SensorData> GnssSerializer::Deserialize(RawData &&data) {
return SharedPtr<SensorData>(new data::GnssMeasurement(std::move(data)));
}
} // namespace s11n
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,54 @@
// Copyright (c) 2019 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/Memory.h"
#include "carla/geom/GeoLocation.h"
#include "carla/rpc/ActorId.h"
#include "carla/sensor/RawData.h"
#include <cstdint>
#include <cstring>
namespace carla {
namespace sensor {
class SensorData;
namespace s11n {
class GnssSerializer {
public:
struct Data {
double latitude;
double longitude;
double altitude;
MSGPACK_DEFINE_ARRAY(latitude, longitude, altitude)
};
static Data DeserializeRawData(const RawData &message) {
return MsgPack::UnPack<Data>(message.begin(), message.size());
}
template <typename SensorT>
static Buffer Serialize(
const SensorT &,
const double &latitude,
const double &longitude,
const double &altitude) {
return MsgPack::Pack(Data{latitude, longitude, altitude});
}
static SharedPtr<SensorData> Deserialize(RawData &&data);
};
} // namespace s11n
} // namespace sensor
} // namespace carla

View File

@ -6,7 +6,6 @@
#include <carla/PythonUtil.h>
#include <carla/client/ClientSideSensor.h>
#include <carla/client/GnssSensor.h>
#include <carla/client/LaneInvasionSensor.h>
#include <carla/client/Sensor.h>
#include <carla/client/ServerSideSensor.h>
@ -41,8 +40,4 @@ void export_sensor() {
.def(self_ns::str(self_ns::self))
;
class_<cc::GnssSensor, bases<cc::Sensor>, boost::noncopyable, boost::shared_ptr<cc::GnssSensor>>
("GnssSensor", no_init)
.def(self_ns::str(self_ns::self))
;
}

View File

@ -16,7 +16,7 @@
#include <carla/sensor/data/Image.h>
#include <carla/sensor/data/LaneInvasionEvent.h>
#include <carla/sensor/data/LidarMeasurement.h>
#include <carla/sensor/data/GnssEvent.h>
#include <carla/sensor/data/GnssMeasurement.h>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
@ -66,12 +66,12 @@ namespace data {
return out;
}
std::ostream &operator<<(std::ostream &out, const GnssEvent &meas) {
out << "GnssEvent(frame=" << std::to_string(meas.GetFrame())
<< ", timestamp=" << std::to_string(meas.GetTimestamp())
<< ", lat=" << std::to_string(meas.GetLatitude())
<< ", lon=" << std::to_string(meas.GetLongitude())
<< ", alt=" << std::to_string(meas.GetAltitude())
std::ostream &operator<<(std::ostream &out, const GnssMeasurement &meas) {
out << "GnssMeasurement(frame=" << meas.GetFrame()
<< ", timestamp=" << meas.GetTimestamp()
<< ", lat=" << meas.GetLatitude()
<< ", lon=" << meas.GetLongitude()
<< ", alt=" << meas.GetAltitude()
<< ')';
return out;
}
@ -240,10 +240,10 @@ void export_sensor_data() {
.def(self_ns::str(self_ns::self))
;
class_<csd::GnssEvent, bases<cs::SensorData>, boost::noncopyable, boost::shared_ptr<csd::GnssEvent>>("GnssEvent", no_init)
.add_property("latitude", &csd::GnssEvent::GetLatitude)
.add_property("longitude", &csd::GnssEvent::GetLongitude)
.add_property("altitude", &csd::GnssEvent::GetAltitude)
class_<csd::GnssMeasurement, bases<cs::SensorData>, boost::noncopyable, boost::shared_ptr<csd::GnssMeasurement>>("GnssMeasurement", no_init)
.add_property("latitude", &csd::GnssMeasurement::GetLatitude)
.add_property("longitude", &csd::GnssMeasurement::GetLongitude)
.add_property("altitude", &csd::GnssMeasurement::GetAltitude)
.def(self_ns::str(self_ns::self))
;

View File

@ -12,6 +12,9 @@
#include <carla/rpc/WeatherParameters.h>
#include <compiler/enable-ue4-macros.h>
#include "carla/opendrive/OpenDriveParser.h"
#include "Carla/OpenDrive/OpenDrive.h"
ACarlaGameModeBase::ACarlaGameModeBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
@ -90,6 +93,15 @@ void ACarlaGameModeBase::InitGame(
// make connection between Episode and Recorder
Recorder->SetEpisode(Episode);
Episode->SetRecorder(Recorder);
std::string opendrive_xml = TCHAR_TO_UTF8(*UOpenDrive::LoadXODR(MapName));
boost::optional<carla::road::Map> map = carla::opendrive::OpenDriveParser::Load(opendrive_xml);
if (!map.has_value()) {
UE_LOG(LogCarla, Error, TEXT("Invalid Map"));
} else {
CurrentGeoLocation = map->GetGeoReference();
}
}
void ACarlaGameModeBase::RestartPlayer(AController *NewPlayer)

View File

@ -14,6 +14,10 @@
#include "Carla/Settings/CarlaSettingsDelegate.h"
#include "Carla/Weather/Weather.h"
#include <compiler/disable-ue4-macros.h>
#include "carla/geom/GeoLocation.h"
#include <compiler/enable-ue4-macros.h>
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
@ -35,6 +39,12 @@ public:
return *Episode;
}
const carla::geom::GeoLocation &GeoLocation() const
{
return CurrentGeoLocation;
}
protected:
void InitGame(const FString &MapName, const FString &Options, FString &ErrorMessage) override;
@ -77,4 +87,6 @@ private:
UPROPERTY()
TArray<ACarlaActorFactory *> ActorFactoryInstances;
carla::geom::GeoLocation CurrentGeoLocation;
};

View File

@ -1,18 +1,51 @@
// Copyright (c) 2019 Intel Labs.
// Copyright (c) 2019 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/GnssSensor.h"
#include "Carla/Game/CarlaGameModeBase.h"
FActorDefinition AGnssSensor::GetSensorDefinition()
{
return UActorBlueprintFunctionLibrary::MakeGenericSensorDefinition(TEXT("other"), TEXT("gnss"));
}
#include <compiler/disable-ue4-macros.h>
#include "carla/geom/Vector3D.h"
#include <compiler/enable-ue4-macros.h>
AGnssSensor::AGnssSensor(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = false;
PrimaryActorTick.bCanEverTick = true;
}
FActorDefinition AGnssSensor::GetSensorDefinition()
{
return UActorBlueprintFunctionLibrary::MakeGenericSensorDefinition(
TEXT("other"),
TEXT("gnss"));
}
void AGnssSensor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
carla::geom::Vector3D location = GetActorLocation();
location /= 100.0f;
carla::geom::GeoLocation current_location = CurrentGeoLocation.Transform(location);
auto Stream = GetDataStream(*this);
double latitude = current_location.latitude;
double longitude = current_location.longitude;
double altitude = current_location.altitude;
Stream.Send(*this, latitude, longitude, altitude);
}
void AGnssSensor::BeginPlay()
{
Super::BeginPlay();
ACarlaGameModeBase* game_mode = Cast<ACarlaGameModeBase>(GetWorld()->GetAuthGameMode());
CurrentGeoLocation = game_mode->GeoLocation();
}

View File

@ -1,13 +1,19 @@
// Copyright (c) 2019 Intel Labs.
// Copyright (c) 2019 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/ShaderBasedSensor.h"
#include "Carla/Sensor/Sensor.h"
#include "Carla/Actor/ActorDefinition.h"
#include "Carla/Actor/ActorDescription.h"
#include <compiler/disable-ue4-macros.h>
#include "carla/geom/GeoLocation.h"
#include <compiler/enable-ue4-macros.h>
#include "GnssSensor.generated.h"
@ -20,7 +26,19 @@ class CARLA_API AGnssSensor : public ASensor
public:
AGnssSensor(const FObjectInitializer &ObjectInitializer);
static FActorDefinition GetSensorDefinition();
AGnssSensor(const FObjectInitializer &ObjectInitializer);
void Tick(float DeltaSeconds) override;
protected:
virtual void BeginPlay() override;
private:
carla::geom::GeoLocation CurrentGeoLocation;
};