diff --git a/.gitignore b/.gitignore index cd83d1f32..9cf0d1ea3 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ Install .codelite .gdb_history .gtest +.idea .tags* .vs .vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 956909872..05c6fd5fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Latest Changes + * Allow user to disable rendering and set the server timeout from the command line + * Add timestamp to SensorData * Allow usage of hostname for carla::Client and resolve them to IP address + * Added `map.transform_to_geolocation` to transform Location to GNSS GeoLocation + * Added `id` property to waypoints, uniquely identifying waypoints up to half centimetre precision + * Added OpenDrive's road offset `s` as property to waypoints * Fixed python client DLL error on Windows ## CARLA 0.9.4 diff --git a/Docs/cameras_and_sensors.md b/Docs/cameras_and_sensors.md index f6f0cd394..50e3c0460 100644 --- a/Docs/cameras_and_sensors.md +++ b/Docs/cameras_and_sensors.md @@ -30,10 +30,13 @@ sensor.listen(lambda data: do_something(data)) ``` Note that each sensor has a different set of attributes and produces different -type of data. However, the data produced by a sensor comes always tagged with a -**frame number** and a **transform**. The frame number is used to identify the -frame at which the measurement took place, the transform gives you the -transformation in world coordinates of the sensor at that same frame. +type of data. However, the data produced by a sensor comes always tagged with: + +| Sensor data attribute | Type | Description | +| --------------------- | ------ | ----------- | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | +| `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | Most sensor data objects, like images and lidar measurements, have a function for saving the measurements to disk. @@ -59,7 +62,7 @@ The "RGB" camera acts as a regular camera capturing images from the scene. | ------------------- | ---- | ------- | ----------- | | `image_size_x` | int | 800 | Image width in pixels | | `image_size_y` | int | 600 | Image height in pixels | -| `fov` | float | 90.0 | Field of view in degrees | +| `fov` | float | 90.0 | Horizontal field of view in degrees | | `enable_postprocess_effects` | bool | True | Whether the post-process effect in the scene affect the image | | `sensor_tick` | float | 0.0 | Seconds between sensor captures (ticks) | @@ -81,11 +84,12 @@ objects. | Sensor data attribute | Type | Description | | --------------------- | ---- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `width` | int | Image width in pixels | | `height` | int | Image height in pixels | -| `fov` | float | Field of view in degrees | +| `fov` | float | Horizontal field of view in degrees | | `raw_data` | bytes | Array of BGRA 32-bit pixels | sensor.camera.depth @@ -100,7 +104,7 @@ pixel to the camera (also known as **depth buffer** or **z-buffer**). | ------------------- | ---- | ------- | ----------- | | `image_size_x` | int | 800 | Image width in pixels | | `image_size_y` | int | 600 | Image height in pixels | -| `fov` | float | 90.0 | Field of view in degrees | +| `fov` | float | 90.0 | Horizontal field of view in degrees | | `sensor_tick` | float | 0.0 | Seconds between sensor captures (ticks) | This sensor produces [`carla.Image`](python_api.md#carlaimagecarlasensordata) @@ -108,11 +112,12 @@ objects. | Sensor data attribute | Type | Description | | --------------------- | ---- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `width` | int | Image width in pixels | | `height` | int | Image height in pixels | -| `fov` | float | Field of view in degrees | +| `fov` | float | Horizontal field of view in degrees | | `raw_data` | bytes | Array of BGRA 32-bit pixels | @@ -138,7 +143,7 @@ pedestrians appear in a different color than vehicles. | ------------------- | ---- | ------- | ----------- | | `image_size_x` | int | 800 | Image width in pixels | | `image_size_y` | int | 600 | Image height in pixels | -| `fov` | float | 90.0 | Field of view in degrees | +| `fov` | float | 90.0 | Horizontal field of view in degrees | | `sensor_tick` | float | 0.0 | Seconds between sensor captures (ticks) | This sensor produces [`carla.Image`](python_api.md#carlaimagecarlasensordata) @@ -146,11 +151,12 @@ objects. | Sensor data attribute | Type | Description | | --------------------- | ---- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `width` | int | Image width in pixels | | `height` | int | Image height in pixels | -| `fov` | float | Field of view in degrees | +| `fov` | float | Horizontal field of view in degrees | | `raw_data` | bytes | Array of BGRA 32-bit pixels | The server provides an image with the tag information **encoded in the red @@ -213,7 +219,8 @@ objects. | Sensor data attribute | Type | Description | | -------------------------- | ---------- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `horizontal_angle` | float | Angle in XY plane of the lidar this frame (in degrees) | | `channels` | int | Number of channels (lasers) of the lidar | @@ -251,7 +258,8 @@ object for each collision registered | Sensor data attribute | Type | Description | | ---------------------- | ----------- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `actor` | carla.Actor | Actor that measured the collision ("self" actor) | | `other_actor` | carla.Actor | Actor against whom we collide | @@ -282,7 +290,8 @@ object for each lane marking crossed by the actor | Sensor data attribute | Type | Description | | ----------------------- | ----------- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `actor` | carla.Actor | Actor that invaded another lane ("self" actor) | | `crossed_lane_markings` | carla.LaneMarking list | List of lane markings that have been crossed | @@ -300,7 +309,8 @@ objects. | Sensor data attribute | Type | Description | | ---------------------- | ----------- | ----------- | -| `frame_number` | int | Frame count when the measurement took place | +| `frame_number` | int | Frame number when the measurement took place | +| `timestamp` | double | Timestamp of the measurement in simulation seconds since the beginning of the epispode | | `transform` | carla.Transform | Transform in world coordinates of the sensor at the time of the measurement | | `latitude` | double | Latitude position of the actor | | `longitude` | double | Longitude position of the actor | @@ -328,4 +338,4 @@ objects. | ---------------------- | ----------- | ----------- | | `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 | \ No newline at end of file +| `distance ` | float | Distance from actor to other_actor | diff --git a/Docs/configuring_the_simulation.md b/Docs/configuring_the_simulation.md index d229456e3..a70493964 100644 --- a/Docs/configuring_the_simulation.md +++ b/Docs/configuring_the_simulation.md @@ -88,6 +88,8 @@ Other command-line options * `-carla-port=N` Listen for client connections at port N, streaming port is set to N+1. * `-quality-level={Low,Epic}` Change graphics quality level, "Low" mode runs significantly faster. + * `-carla-server-timeout=10000ms` Set server timeout. + * `-no-rendering` Disable rendering. * [Full list of UE4 command-line arguments][ue4clilink]. [ue4clilink]: https://docs.unrealengine.com/en-US/Programming/Basics/CommandLineArguments diff --git a/Docs/python_api.md b/Docs/python_api.md index 96f64dc35..440bf9bd1 100644 --- a/Docs/python_api.md +++ b/Docs/python_api.md @@ -159,6 +159,7 @@ ## `carla.SensorData` - `frame_number` +- `timestamp` - `transform` ## `carla.Image(carla.SensorData)` @@ -254,6 +255,7 @@ - `get_waypoint(location, project_to_road=True)` - `get_topology()` - `generate_waypoints(distance)` +- `transform_to_geolocation(location)` - `to_opendrive()` - `save_to_disk(path=self.name)` diff --git a/LibCarla/cmake/CMakeLists.txt b/LibCarla/cmake/CMakeLists.txt index bdfa52501..4bc128e2d 100644 --- a/LibCarla/cmake/CMakeLists.txt +++ b/LibCarla/cmake/CMakeLists.txt @@ -1,13 +1,21 @@ cmake_minimum_required(VERSION 3.5.1) project(libcarla) -message(STATUS "Building ${PROJECT_NAME} version ${CARLA_VERSION}") +option(LIBCARLA_BUILD_DEBUG "Build debug configuration" ON) +option(LIBCARLA_BUILD_RELEASE "Build release configuration" ON) +option(LIBCARLA_BUILD_TEST "Build unit tests" ON) + +message(STATUS "Build debug: ${LIBCARLA_BUILD_DEBUG}") +message(STATUS "Build release: ${LIBCARLA_BUILD_RELEASE}") +message(STATUS "Build test: ${LIBCARLA_BUILD_TEST}") set(libcarla_source_path "${PROJECT_SOURCE_DIR}/../source") include_directories(${libcarla_source_path}) -configure_file(${libcarla_source_path}/carla/Version.h.in ${libcarla_source_path}/carla/Version.h) +if (CARLA_VERSION) + configure_file(${libcarla_source_path}/carla/Version.h.in ${libcarla_source_path}/carla/Version.h) +endif() if (CMAKE_BUILD_TYPE STREQUAL "Client") add_subdirectory("client") @@ -18,6 +26,10 @@ else () endif () # GTest is not compiled on Windows. -if (NOT WIN32) +if ((LIBCARLA_BUILD_TEST) AND (NOT WIN32)) add_subdirectory("test") endif() + +unset(LIBCARLA_BUILD_TEST CACHE) +unset(LIBCARLA_BUILD_RELEASE CACHE) +unset(LIBCARLA_BUILD_DEBUG CACHE) diff --git a/LibCarla/cmake/client/CMakeLists.txt b/LibCarla/cmake/client/CMakeLists.txt index 67a1212cc..c4aea4d96 100644 --- a/LibCarla/cmake/client/CMakeLists.txt +++ b/LibCarla/cmake/client/CMakeLists.txt @@ -84,11 +84,9 @@ file(GLOB libcarla_carla_pointcloud_sources set(libcarla_sources "${libcarla_sources};${libcarla_carla_pointcloud_sources}") install(FILES ${libcarla_carla_pointcloud_sources} DESTINATION include/carla/pointcloud) -file(GLOB libcarla_carla_profiler_sources - "${libcarla_source_path}/carla/profiler/*.cpp" +file(GLOB libcarla_carla_profiler_headers "${libcarla_source_path}/carla/profiler/*.h") -set(libcarla_sources "${libcarla_sources};${libcarla_carla_profiler_sources}") -install(FILES ${libcarla_carla_profiler_sources} DESTINATION include/carla/profiler) +install(FILES ${libcarla_carla_profiler_headers} DESTINATION include/carla/profiler) file(GLOB libcarla_carla_road_sources "${libcarla_source_path}/carla/road/*.cpp" @@ -165,23 +163,35 @@ install(FILES ${libcarla_moodycamel_sources} DESTINATION include/moodycamel) # Create targets for debug and release in the same build type. # ============================================================================== -foreach(target carla_client_debug carla_client) - add_library(${target} STATIC ${libcarla_sources}) +if (LIBCARLA_BUILD_RELEASE) - target_include_directories(${target} PRIVATE + add_library(carla_client STATIC ${libcarla_sources}) + + target_include_directories(carla_client PRIVATE "${BOOST_INCLUDE_PATH}" "${RPCLIB_INCLUDE_PATH}") - install(TARGETS ${target} DESTINATION lib) -endforeach(target) + install(TARGETS carla_client DESTINATION lib) -# Specific options for debug. -set_target_properties(carla_client_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) -target_compile_definitions(carla_client_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (WIN32) # @todo Fix PythonAPI build on Windows. + set_target_properties(carla_client PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) + else () + set_target_properties(carla_client PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE_CLIENT}) + endif (WIN32) -# Specific options for release. -if (WIN32) # @todo Fix PythonAPI build on Windows. - set_target_properties(carla_client PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) -else () - set_target_properties(carla_client PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE_CLIENT}) -endif (WIN32) +endif() + +if (LIBCARLA_BUILD_DEBUG) + + add_library(carla_client_debug STATIC ${libcarla_sources}) + + target_include_directories(carla_client_debug PRIVATE + "${BOOST_INCLUDE_PATH}" + "${RPCLIB_INCLUDE_PATH}") + + install(TARGETS carla_client_debug DESTINATION lib) + + set_target_properties(carla_client_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) + target_compile_definitions(carla_client_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + +endif() diff --git a/LibCarla/cmake/server/CMakeLists.txt b/LibCarla/cmake/server/CMakeLists.txt index ef5e1c865..aef492a3f 100644 --- a/LibCarla/cmake/server/CMakeLists.txt +++ b/LibCarla/cmake/server/CMakeLists.txt @@ -107,20 +107,35 @@ file(GLOB libcarla_server_sources "${libcarla_source_path}/carla/streaming/detail/tcp/*.h" "${libcarla_source_path}/carla/streaming/low_level/*.h") +# ============================================================================== # Create targets for debug and release in the same build type. -foreach(target carla_server_debug carla_server) - add_library(${target} STATIC ${libcarla_server_sources}) +# ============================================================================== - target_include_directories(${target} PRIVATE +if (LIBCARLA_BUILD_RELEASE) + + add_library(carla_server STATIC ${libcarla_server_sources}) + + target_include_directories(carla_server PRIVATE "${BOOST_INCLUDE_PATH}" "${RPCLIB_INCLUDE_PATH}") - install(TARGETS ${target} DESTINATION lib) -endforeach(target) + install(TARGETS carla_server DESTINATION lib OPTIONAL) -# Specific options for debug. -set_target_properties(carla_server_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) -target_compile_definitions(carla_server_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + set_target_properties(carla_server PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) -# Specific options for release. -set_target_properties(carla_server PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) +endif() + +if (LIBCARLA_BUILD_DEBUG) + + add_library(carla_server_debug STATIC ${libcarla_server_sources}) + + target_include_directories(carla_server_debug PRIVATE + "${BOOST_INCLUDE_PATH}" + "${RPCLIB_INCLUDE_PATH}") + + install(TARGETS carla_server_debug DESTINATION lib OPTIONAL) + + set_target_properties(carla_server_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) + target_compile_definitions(carla_server_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + +endif() diff --git a/LibCarla/cmake/test/CMakeLists.txt b/LibCarla/cmake/test/CMakeLists.txt index 910da9943..806ac211d 100644 --- a/LibCarla/cmake/test/CMakeLists.txt +++ b/LibCarla/cmake/test/CMakeLists.txt @@ -23,38 +23,51 @@ file(GLOB libcarla_test_sources file(GLOB libcarla_test_client_sources "") +if (LIBCARLA_BUILD_DEBUG) + list(APPEND build_targets libcarla_test_${carla_config}_debug) +endif() + +if (LIBCARLA_BUILD_RELEASE) + list(APPEND build_targets libcarla_test_${carla_config}_release) +endif() + # Create targets for debug and release in the same build type. -foreach(target libcarla_test_${carla_config}_debug libcarla_test_${carla_config}_release) - add_executable(${target} ${libcarla_test_sources}) +foreach(target ${build_targets}) - target_compile_definitions(${target} PUBLIC - -DLIBCARLA_ENABLE_PROFILER - -DLIBCARLA_WITH_GTEST) + add_executable(${target} ${libcarla_test_sources}) - target_include_directories(${target} PRIVATE - "${BOOST_INCLUDE_PATH}" - "${RPCLIB_INCLUDE_PATH}" - "${GTEST_INCLUDE_PATH}" - "${libcarla_source_path}/test") + target_compile_definitions(${target} PUBLIC + -DLIBCARLA_ENABLE_PROFILER + -DLIBCARLA_WITH_GTEST) - if (WIN32) - target_link_libraries(${target} "gtest_main.lib") - target_link_libraries(${target} "gtest.lib") - target_link_libraries(${target} "rpc.lib") - else() - target_link_libraries(${target} "-lrpc") - target_link_libraries(${target} "-lgtest_main") - target_link_libraries(${target} "-lgtest") - endif() + target_include_directories(${target} PRIVATE + "${BOOST_INCLUDE_PATH}" + "${RPCLIB_INCLUDE_PATH}" + "${GTEST_INCLUDE_PATH}" + "${libcarla_source_path}/test") - install(TARGETS ${target} DESTINATION test) + if (WIN32) + target_link_libraries(${target} "gtest_main.lib") + target_link_libraries(${target} "gtest.lib") + target_link_libraries(${target} "rpc.lib") + else() + target_link_libraries(${target} "-lrpc") + target_link_libraries(${target} "-lgtest_main") + target_link_libraries(${target} "-lgtest") + endif() + + install(TARGETS ${target} DESTINATION test OPTIONAL) endforeach(target) -# Specific options for debug. -set_target_properties(libcarla_test_${carla_config}_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) -target_link_libraries(libcarla_test_${carla_config}_debug "carla_${carla_config}_debug") -target_compile_definitions(libcarla_test_${carla_config}_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING) +if (LIBCARLA_BUILD_DEBUG) + # Specific options for debug. + set_target_properties(libcarla_test_${carla_config}_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) + target_link_libraries(libcarla_test_${carla_config}_debug "carla_${carla_config}_debug") + target_compile_definitions(libcarla_test_${carla_config}_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING) +endif() -# Specific options for release. -set_target_properties(libcarla_test_${carla_config}_release PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) -target_link_libraries(libcarla_test_${carla_config}_release "carla_${carla_config}") +if (LIBCARLA_BUILD_RELEASE) + # Specific options for release. + set_target_properties(libcarla_test_${carla_config}_release PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) + target_link_libraries(libcarla_test_${carla_config}_release "carla_${carla_config}") +endif() diff --git a/LibCarla/source/carla/Buffer.h b/LibCarla/source/carla/Buffer.h index bd8e4f4bc..2cb1a93a9 100644 --- a/LibCarla/source/carla/Buffer.h +++ b/LibCarla/source/carla/Buffer.h @@ -85,10 +85,19 @@ namespace carla { copy_from(source); } - Buffer(const value_type *data, size_type size) { + explicit Buffer(const value_type *data, size_type size) { copy_from(data, size); } + /// @copydoc Buffer(size_type) + explicit Buffer(const value_type *data, uint64_t size) + : Buffer(data, [size]() { + if (size > max_size()) { + throw_exception(std::invalid_argument("message size too big")); + } + return static_cast(size); + } ()) {} + Buffer(const Buffer &) = delete; Buffer(Buffer &&rhs) noexcept @@ -326,7 +335,7 @@ namespace carla { /// Copy @a size bytes of the memory pointed by @a data into this buffer, /// leaving at the front an offset of @a offset bytes uninitialized. /// Allocates memory if necessary. - void copy_from(size_t offset, const value_type *data, size_type size) { + void copy_from(size_type offset, const value_type *data, size_type size) { copy_from(offset, boost::asio::buffer(data, size)); } diff --git a/LibCarla/source/carla/ThreadGroup.h b/LibCarla/source/carla/ThreadGroup.h index 13e4638bf..86ad6dace 100644 --- a/LibCarla/source/carla/ThreadGroup.h +++ b/LibCarla/source/carla/ThreadGroup.h @@ -6,6 +6,7 @@ #pragma once +#include "carla/Debug.h" #include "carla/NonCopyable.h" #include diff --git a/LibCarla/source/carla/client/GnssSensor.cpp b/LibCarla/source/carla/client/GnssSensor.cpp index 2e98b695e..af49e8d9d 100644 --- a/LibCarla/source/carla/client/GnssSensor.cpp +++ b/LibCarla/source/carla/client/GnssSensor.cpp @@ -8,60 +8,13 @@ #include "carla/Logging.h" #include "carla/client/Map.h" #include "carla/client/detail/Simulator.h" -#include "carla/geom/Math.h" #include "carla/sensor/data/GnssEvent.h" -#include "carla/StringUtil.h" #include -#include -#include -#include - -#if defined(_WIN32) && !defined(_USE_MATH_DEFINES) -#define _USE_MATH_DEFINES -#include // cmath is not enough for MSVC -#endif namespace carla { namespace client { - const double EARTH_RADIUS_EQUA = 6378137.0;// earth radius at equator [m] - - // inlined functions to avoid multiple definitions - - /// @brief convert latitude to scale, which is needed by mercator transformations - /// @param lat latitude in degrees (DEG) - /// @return scale factor - /// @note when converting from lat/lon -> mercator and back again, - /// or vice versa, use the same scale in both transformations! - inline double LatToScale (double lat) { - return cos(lat * geom::Math::pi() / 180.0); - } - - /// @brief converts lat/lon/scale to mx/my (mx/my in meters if correct scale is given) - /// - template - inline void LatLonToMercator (double lat, double lon, double scale, float_type &mx, float_type &my) { - mx = scale * lon * geom::Math::pi() * EARTH_RADIUS_EQUA / 180.0; - my = scale * EARTH_RADIUS_EQUA * log( tan((90.0+lat) * geom::Math::pi() / 360.0) ); - } - - /// @brief converts mx/my/scale to lat/lon (mx/my in meters if correct scale is given) - inline void MercatorToLatLon (double mx, double my, double scale, double &lat, double &lon) { - lon = mx * 180.0 / (geom::Math::pi() * EARTH_RADIUS_EQUA * scale); - lat = 360.0 * atan( exp(my/(EARTH_RADIUS_EQUA * scale)) ) / geom::Math::pi() - 90.0; - } - - /// @brief adds meters dx/dy to given lat/lon and returns new lat/lon - inline void LatLonAddMeters (double lat_start, double lon_start, double dx, double dy, double &lat_end, double &lon_end) { - double scale = LatToScale (lat_start); - double mx,my; - LatLonToMercator (lat_start, lon_start, scale, mx, my); - mx += dx; - my += dy; - MercatorToLatLon (mx, my, scale, lat_end, lon_end); - } - GnssSensor::~GnssSensor() = default; void GnssSensor::Listen(CallbackFunctionType callback) { @@ -76,40 +29,11 @@ namespace client { } SharedPtr map = GetWorld().GetMap(); - DEBUG_ASSERT(map != nullptr); + _geo_reference = map->GetGeoReference(); auto self = boost::static_pointer_cast(shared_from_this()); - //parse geo reference string - _map_latitude = std::numeric_limits::quiet_NaN(); - _map_longitude = std::numeric_limits::quiet_NaN(); - std::vector geo_ref_splitted; - StringUtil::Split(geo_ref_splitted, map->GetGeoReference(), " "); - - for (auto element: geo_ref_splitted) { - std::vector geo_ref_key_value; - StringUtil::Split(geo_ref_key_value, element, "="); - if (geo_ref_key_value.size() != 2u) { - continue; - } - - if (geo_ref_key_value[0] == "+lat_0") { - _map_latitude = ParseDouble(geo_ref_key_value[1]); - } else if (geo_ref_key_value[0] == "+lon_0") { - _map_longitude = ParseDouble(geo_ref_key_value[1]); - } - } - - - if (std::isnan(_map_latitude) || std::isnan(_map_longitude)) { - log_warning(GetDisplayId(), ": cannot parse georeference: '" + map->GetGeoReference() + "'. Using default values."); - _map_latitude = 42.0; - _map_longitude = 2.0; - } - - log_debug(GetDisplayId(), ": map geo reference: latitude ", _map_latitude, ", longitude ", _map_longitude); - log_debug(GetDisplayId(), ": subscribing to tick event"); GetEpisode().Lock()->RegisterOnTickEvent([ cb=std::move(callback), @@ -122,43 +46,27 @@ namespace client { } } }); - _is_listening = true; - } - double GnssSensor::ParseDouble(std::string const &stringValue) const { - double value; - std::istringstream istr(stringValue); - istr.imbue(std::locale("C")); - istr >> value; - if (istr.fail() || !istr.eof()) { - value = std::numeric_limits::quiet_NaN(); - } - return value; + _is_listening = true; } SharedPtr GnssSensor::TickGnssSensor( const Timestamp ×tamp) { try { - const auto location = GetLocation(); - double current_lat, current_lon; - - LatLonAddMeters(_map_latitude, _map_longitude, location.x, location.y, current_lat, current_lon); - return MakeShared( timestamp.frame_count, + timestamp.elapsed_seconds, GetTransform(), - current_lat, - current_lon, - location.z); + _geo_reference.Transform(GetLocation())); } catch (const std::exception &e) { /// @todo We need to unsubscribe the sensor. // log_error("LaneDetector:", e.what()); return nullptr; } - } void GnssSensor::Stop() { + /// @todo We need unsubscribe from the world on tick. _is_listening = false; } diff --git a/LibCarla/source/carla/client/GnssSensor.h b/LibCarla/source/carla/client/GnssSensor.h index de37c52a5..9cf6a60a3 100644 --- a/LibCarla/source/carla/client/GnssSensor.h +++ b/LibCarla/source/carla/client/GnssSensor.h @@ -6,14 +6,11 @@ #pragma once #include "carla/client/Sensor.h" -#include +#include "carla/geom/GeoLocation.h" namespace carla { namespace client { - class Map; - class Vehicle; - class GnssSensor final : public Sensor { public: @@ -43,14 +40,9 @@ namespace client { SharedPtr TickGnssSensor(const Timestamp ×tamp); - double ParseDouble(std::string const &stringValue) const; - - double _map_latitude; - - double _map_longitude; + geom::GeoLocation _geo_reference; bool _is_listening = false; - }; } // namespace client diff --git a/LibCarla/source/carla/client/LaneDetector.cpp b/LibCarla/source/carla/client/LaneDetector.cpp index 0809b3d66..d0ce1d2b3 100644 --- a/LibCarla/source/carla/client/LaneDetector.cpp +++ b/LibCarla/source/carla/client/LaneDetector.cpp @@ -92,6 +92,7 @@ namespace client { nullptr : MakeShared( timestamp.frame_count, + timestamp.elapsed_seconds, _vehicle->GetTransform(), _vehicle, crossed_lanes); diff --git a/LibCarla/source/carla/client/Map.cpp b/LibCarla/source/carla/client/Map.cpp index 0fa22f35c..f9e5b8a2d 100644 --- a/LibCarla/source/carla/client/Map.cpp +++ b/LibCarla/source/carla/client/Map.cpp @@ -23,14 +23,17 @@ namespace client { Map::Map(rpc::MapInfo description) : _description(std::move(description)), - _map(MakeMap(_description.open_drive_file)) {} + _map(MakeMap(_description.open_drive_file)) { + if (_map == nullptr) { + throw_exception(std::runtime_error("failed to generate map")); + } + } Map::~Map() = default; SharedPtr Map::GetWaypoint( const geom::Location &location, bool project_to_road) const { - DEBUG_ASSERT(_map != nullptr); boost::optional waypoint; if (project_to_road) { waypoint = _map->GetClosestWaypointOnRoad(location); @@ -43,7 +46,6 @@ namespace client { } Map::TopologyList Map::GetTopology() const { - DEBUG_ASSERT(_map != nullptr); namespace re = carla::road::element; std::unordered_map>> waypoints; @@ -82,14 +84,12 @@ namespace client { std::vector Map::CalculateCrossedLanes( const geom::Location &origin, const geom::Location &destination) const { - DEBUG_ASSERT(_map != nullptr); return _map->CalculateCrossedLanes(origin, destination); } - - std::string Map::GetGeoReference() const { - DEBUG_ASSERT(_map != nullptr); + const geom::GeoLocation &Map::GetGeoReference() const { return _map->GetData().GetGeoReference(); } + } // namespace client } // namespace carla diff --git a/LibCarla/source/carla/client/Map.h b/LibCarla/source/carla/client/Map.h index b68022264..ae3beb408 100644 --- a/LibCarla/source/carla/client/Map.h +++ b/LibCarla/source/carla/client/Map.h @@ -14,6 +14,7 @@ #include namespace carla { +namespace geom { class GeoLocation; } namespace road { class Map; } namespace client { @@ -54,13 +55,13 @@ namespace client { const geom::Location &origin, const geom::Location &destination) const; - std::string GetGeoReference() const; + const geom::GeoLocation &GetGeoReference() const; private: - rpc::MapInfo _description; + const rpc::MapInfo _description; - SharedPtr _map; + const SharedPtr _map; }; } // namespace client diff --git a/LibCarla/source/carla/client/Waypoint.h b/LibCarla/source/carla/client/Waypoint.h index dcbd41dea..b9a86fede 100644 --- a/LibCarla/source/carla/client/Waypoint.h +++ b/LibCarla/source/carla/client/Waypoint.h @@ -8,8 +8,9 @@ #include "carla/Memory.h" #include "carla/NonCopyable.h" -#include "carla/road/element/Waypoint.h" #include "carla/road/element/RoadInfoMarkRecord.h" +#include "carla/road/element/Waypoint.h" +#include "carla/road/element/WaypointHash.h" namespace carla { namespace client { @@ -31,6 +32,14 @@ namespace client { ~Waypoint(); + /// Returns an unique Id identifying this waypoint. + /// + /// The Id takes into account OpenDrive's road Id, lane Id, and s distance + /// on its road segment up to half-centimetre precision. + uint64_t GetId() const { + return road::element::WaypointHash()(_waypoint); + } + const geom::Transform &GetTransform() const { return _transform; } @@ -51,6 +60,10 @@ namespace client { return _waypoint.GetLaneId(); } + double GetDistance() const { + return _waypoint.GetDistance(); + } + std::string GetType() const { return _waypoint.GetType(); } diff --git a/LibCarla/source/carla/client/detail/Simulator.h b/LibCarla/source/carla/client/detail/Simulator.h index c3af82083..33c7a7374 100644 --- a/LibCarla/source/carla/client/detail/Simulator.h +++ b/LibCarla/source/carla/client/detail/Simulator.h @@ -9,7 +9,6 @@ #include "carla/Debug.h" #include "carla/Memory.h" #include "carla/NonCopyable.h" -#include "carla/Version.h" #include "carla/client/Actor.h" #include "carla/client/GarbageCollectionPolicy.h" #include "carla/client/TrafficLight.h" diff --git a/LibCarla/source/carla/geom/GeoLocation.cpp b/LibCarla/source/carla/geom/GeoLocation.cpp new file mode 100644 index 000000000..a951c3ac3 --- /dev/null +++ b/LibCarla/source/carla/geom/GeoLocation.cpp @@ -0,0 +1,76 @@ +// 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 . + +#include "carla/geom/GeoLocation.h" + +#include "carla/geom/Location.h" +#include "carla/geom/Math.h" + +#include + +#if defined(_WIN32) && !defined(_USE_MATH_DEFINES) +# define _USE_MATH_DEFINES +# include // cmath is not enough for MSVC +#endif + +namespace carla { +namespace geom { + + /// Earth radius at equator [m]. + static constexpr double EARTH_RADIUS_EQUA = 6378137.0; + + /// Convert latitude to scale, which is needed by mercator + /// transformations + /// @param lat latitude in degrees (DEG) + /// @return scale factor + /// @note when converting from lat/lon -> mercator and back again, + /// or vice versa, use the same scale in both transformations! + static double LatToScale(double lat) { + return std::cos(Math::to_radians(lat)); + } + + /// Converts lat/lon/scale to mx/my (mx/my in meters if correct scale + /// is given). + template + static void LatLonToMercator(double lat, double lon, double scale, float_type &mx, float_type &my) { + mx = scale * Math::to_radians(lon) * EARTH_RADIUS_EQUA; + my = scale * EARTH_RADIUS_EQUA * std::log(std::tan((90.0 + lat) * Math::pi() / 360.0)); + } + + /// Converts mx/my/scale to lat/lon (mx/my in meters if correct scale + /// is given). + static void MercatorToLatLon(double mx, double my, double scale, double &lat, double &lon) { + lon = mx * 180.0 / (Math::pi() * EARTH_RADIUS_EQUA * scale); + lat = 360.0 * std::atan(std::exp(my / (EARTH_RADIUS_EQUA * scale))) / Math::pi() - 90.0; + } + + /// Adds meters dx/dy to given lat/lon and returns new lat/lon. + static void LatLonAddMeters( + double lat_start, + double lon_start, + double dx, + double dy, + double &lat_end, + double &lon_end) { + double scale = LatToScale(lat_start); + double mx, my; + LatLonToMercator(lat_start, lon_start, scale, mx, my); + mx += dx; + my += dy; + MercatorToLatLon(mx, my, scale, lat_end, lon_end); + } + + GeoLocation GeoLocation::Transform(const Location &location) const { + GeoLocation result{0.0, 0.0, altitude + location.z}; + LatLonAddMeters( + latitude, longitude, + location.x, location.y, + result.latitude, result.longitude); + return result; + } + +} // namespace geom +} // namespace carla diff --git a/LibCarla/source/carla/geom/GeoLocation.h b/LibCarla/source/carla/geom/GeoLocation.h new file mode 100644 index 000000000..eff7d9e58 --- /dev/null +++ b/LibCarla/source/carla/geom/GeoLocation.h @@ -0,0 +1,62 @@ +// 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 . + +#pragma once + +namespace carla { +namespace geom { + + class Location; + + class GeoLocation { + public: + + // ========================================================================= + // -- Public data members -------------------------------------------------- + // ========================================================================= + + double latitude = 0.0; + + double longitude = 0.0; + + double altitude = 0.0; + + // ========================================================================= + // -- Constructors --------------------------------------------------------- + // ========================================================================= + + GeoLocation() = default; + + GeoLocation(const GeoLocation &) = default; + + GeoLocation(double latitude, double longitude, double altitude) + : latitude(latitude), + longitude(longitude), + altitude(altitude) {} + + // ========================================================================= + // -- Transform locations -------------------------------------------------- + // ========================================================================= + + /// Transform the given @a location to a GeoLocation using this as + /// geo-reference. + GeoLocation Transform(const Location &location) const; + + // ========================================================================= + // -- Comparison operators ------------------------------------------------- + // ========================================================================= + + bool operator==(const GeoLocation &rhs) const { + return (latitude == rhs.latitude) && (longitude == rhs.longitude) && (altitude == rhs.altitude); + } + + bool operator!=(const GeoLocation &rhs) const { + return !(*this == rhs); + } + }; + +} // namespace geom +} // namespace carla diff --git a/LibCarla/source/carla/opendrive/parser/GeoReferenceParser.cpp b/LibCarla/source/carla/opendrive/parser/GeoReferenceParser.cpp new file mode 100644 index 000000000..469b4c5e3 --- /dev/null +++ b/LibCarla/source/carla/opendrive/parser/GeoReferenceParser.cpp @@ -0,0 +1,67 @@ +// 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 . + +#include "carla/opendrive/parser/GeoReferenceParser.h" + +#include "carla/Logging.h" +#include "carla/StringUtil.h" + +#include +#include +#include + +namespace carla { +namespace opendrive { +namespace parser { + + static double ParseDouble(const std::string &string_value) { + double value; + std::istringstream istr(string_value); + istr.imbue(std::locale("C")); + istr >> value; + if (istr.fail() || !istr.eof()) { + value = std::numeric_limits::quiet_NaN(); + } + return value; + } + + geom::GeoLocation GeoReferenceParser::Parse(const std::string &geo_reference_string) { + geom::GeoLocation result{ + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + 0.0}; + + std::vector geo_ref_splitted; + StringUtil::Split(geo_ref_splitted, geo_reference_string, " "); + + for (auto element: geo_ref_splitted) { + std::vector geo_ref_key_value; + StringUtil::Split(geo_ref_key_value, element, "="); + if (geo_ref_key_value.size() != 2u) { + continue; + } + + if (geo_ref_key_value[0] == "+lat_0") { + result.latitude = ParseDouble(geo_ref_key_value[1]); + } else if (geo_ref_key_value[0] == "+lon_0") { + result.longitude = ParseDouble(geo_ref_key_value[1]); + } + } + + if (std::isnan(result.latitude) || std::isnan(result.longitude)) { + log_warning("cannot parse georeference: '" + geo_reference_string + "'. Using default values."); + result.latitude = 42.0; + result.longitude = 2.0; + } + + log_debug("map geo reference: latitude ", result.latitude, ", longitude ", result.longitude); + + return result; + } + +} // parser +} // opendrive +} // carla diff --git a/LibCarla/source/carla/opendrive/parser/GeoReferenceParser.h b/LibCarla/source/carla/opendrive/parser/GeoReferenceParser.h new file mode 100644 index 000000000..e20e6b533 --- /dev/null +++ b/LibCarla/source/carla/opendrive/parser/GeoReferenceParser.h @@ -0,0 +1,25 @@ +// 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 . + +#pragma once + +#include "carla/geom/GeoLocation.h" + +#include + +namespace carla { +namespace opendrive { +namespace parser { + + class GeoReferenceParser { + public: + + static geom::GeoLocation Parse(const std::string &geo_reference_string); + }; + +} // parser +} // opendrive +} // carla diff --git a/LibCarla/source/carla/opendrive/parser/OpenDriveParser.cpp b/LibCarla/source/carla/opendrive/parser/OpenDriveParser.cpp new file mode 100644 index 000000000..e85e6465f --- /dev/null +++ b/LibCarla/source/carla/opendrive/parser/OpenDriveParser.cpp @@ -0,0 +1,102 @@ +// 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 . + +#include "carla/opendrive/parser/OpenDriveParser.h" + +#include "carla/geom/GeoLocation.h" +#include "carla/opendrive/parser/GeoReferenceParser.h" +#include "carla/opendrive/parser/GeometryParser.h" +#include "carla/opendrive/parser/JunctionParser.h" +#include "carla/opendrive/parser/LaneParser.h" +#include "carla/opendrive/parser/ProfilesParser.h" +#include "carla/opendrive/parser/RoadLinkParser.h" +#include "carla/opendrive/parser/TrafficGroupParser.h" +#include "carla/opendrive/parser/TrafficSignParser.h" +#include "carla/opendrive/parser/TrafficSignalsParser.h" + +#include "./pugixml/pugixml.hpp" + +bool OpenDriveParser::Parse( + const char *xml, + carla::opendrive::types::OpenDriveData &out_open_drive_data, + XmlInputType inputType, + std::string *out_error) { + namespace odp = carla::opendrive::parser; + + pugi::xml_document xmlDoc; + pugi::xml_parse_result pugiParseResult; + + switch (inputType) { + case XmlInputType::FILE: { + pugiParseResult = xmlDoc.load_file(xml); + } break; + + case XmlInputType::CONTENT: { + pugiParseResult = xmlDoc.load_string(xml); + } break; + + default: { + // TODO(Andrei): Log some kind of error + return false; + } break; + } + + if (pugiParseResult == false) { + if (out_error != nullptr) { + *out_error = pugiParseResult.description(); + } + + return false; + } + + for (pugi::xml_node road = xmlDoc.child("OpenDRIVE").child("road"); + road; + road = road.next_sibling("road")) { + carla::opendrive::types::RoadInformation openDriveRoadInformation; + + openDriveRoadInformation.attributes.name = road.attribute("name").value(); + openDriveRoadInformation.attributes.id = std::atoi(road.attribute("id").value()); + openDriveRoadInformation.attributes.length = std::stod(road.attribute("length").value()); + openDriveRoadInformation.attributes.junction = std::atoi(road.attribute("junction").value()); + + /////////////////////////////////////////////////////////////////////////////// + + odp::ProfilesParser::Parse(road, openDriveRoadInformation.road_profiles); + + odp::RoadLinkParser::Parse(road.child("link"), openDriveRoadInformation.road_link); + odp::TrafficSignalsParser::Parse(road.child("signals"), + openDriveRoadInformation.trafic_signals); + + odp::LaneParser::Parse(road.child("lanes"), openDriveRoadInformation.lanes); + odp::GeometryParser::Parse(road.child("planView"), + openDriveRoadInformation.geometry_attributes); + + out_open_drive_data.roads.emplace_back(std::move(openDriveRoadInformation)); + } + + for (pugi::xml_node junction = xmlDoc.child("OpenDRIVE").child("junction"); + junction; + junction = junction.next_sibling("junction")) { + odp::JunctionParser::Parse(junction, out_open_drive_data.junctions); + } + + for (pugi::xml_node tlgroup = xmlDoc.child("OpenDRIVE").child("tlGroup"); + tlgroup; + tlgroup = tlgroup.next_sibling("tlGroup")) { + odp::TrafficGroupParser::Parse(tlgroup, out_open_drive_data.trafficlightgroups); + } + + for (pugi::xml_node trafficsigns = xmlDoc.child("OpenDRIVE").child("trafficsign"); + trafficsigns; + trafficsigns = trafficsigns.next_sibling("trafficsign")) { + odp::TrafficSignParser::Parse(trafficsigns, out_open_drive_data.trafficsigns); + } + + out_open_drive_data.geoReference = odp::GeoReferenceParser::Parse( + xmlDoc.child("OpenDRIVE").child("header").child_value("geoReference")); + + return true; +} diff --git a/LibCarla/source/carla/opendrive/parser/OpenDriveParser.h b/LibCarla/source/carla/opendrive/parser/OpenDriveParser.h index 1f409870a..fb7870435 100644 --- a/LibCarla/source/carla/opendrive/parser/OpenDriveParser.h +++ b/LibCarla/source/carla/opendrive/parser/OpenDriveParser.h @@ -6,20 +6,7 @@ #pragma once -#include "TrafficSignalsParser.h" -#include "RoadLinkParser.h" -#include "JunctionParser.h" - -#include "ProfilesParser.h" -#include "GeometryParser.h" -#include "LaneParser.h" - -#include "TrafficGroupParser.h" -#include "TrafficSignParser.h" - -#include "./pugixml/pugixml.hpp" - -#include +#include "carla/opendrive/types.h" enum class XmlInputType : int { FILE, @@ -31,78 +18,5 @@ struct OpenDriveParser { const char *xml, carla::opendrive::types::OpenDriveData &out_open_drive_data, XmlInputType inputType, - std::string *out_error = nullptr) { - pugi::xml_document xmlDoc; - pugi::xml_parse_result pugiParseResult; - - switch (inputType) { - case XmlInputType::FILE: { - pugiParseResult = xmlDoc.load_file(xml); - } break; - - case XmlInputType::CONTENT: { - pugiParseResult = xmlDoc.load_string(xml); - } break; - - default: { - // TODO(Andrei): Log some kind of error - return false; - } break; - } - - if (pugiParseResult == false) { - if (out_error != nullptr) { - *out_error = pugiParseResult.description(); - } - - return false; - } - - for (pugi::xml_node road = xmlDoc.child("OpenDRIVE").child("road"); - road; - road = road.next_sibling("road")) { - carla::opendrive::types::RoadInformation openDriveRoadInformation; - - openDriveRoadInformation.attributes.name = road.attribute("name").value(); - openDriveRoadInformation.attributes.id = std::atoi(road.attribute("id").value()); - openDriveRoadInformation.attributes.length = std::stod(road.attribute("length").value()); - openDriveRoadInformation.attributes.junction = std::atoi(road.attribute("junction").value()); - - /////////////////////////////////////////////////////////////////////////////// - - carla::opendrive::parser::ProfilesParser::Parse(road, openDriveRoadInformation.road_profiles); - - carla::opendrive::parser::RoadLinkParser::Parse(road.child("link"), openDriveRoadInformation.road_link); - carla::opendrive::parser::TrafficSignalsParser::Parse(road.child("signals"), - openDriveRoadInformation.trafic_signals); - - carla::opendrive::parser::LaneParser::Parse(road.child("lanes"), openDriveRoadInformation.lanes); - carla::opendrive::parser::GeometryParser::Parse(road.child("planView"), - openDriveRoadInformation.geometry_attributes); - - out_open_drive_data.roads.emplace_back(std::move(openDriveRoadInformation)); - } - - for (pugi::xml_node junction = xmlDoc.child("OpenDRIVE").child("junction"); - junction; - junction = junction.next_sibling("junction")) { - carla::opendrive::parser::JunctionParser::Parse(junction, out_open_drive_data.junctions); - } - - for (pugi::xml_node tlgroup = xmlDoc.child("OpenDRIVE").child("tlGroup"); - tlgroup; - tlgroup = tlgroup.next_sibling("tlGroup")) { - carla::opendrive::parser::TrafficGroupParser::Parse(tlgroup, out_open_drive_data.trafficlightgroups); - } - - for (pugi::xml_node trafficsigns = xmlDoc.child("OpenDRIVE").child("trafficsign"); - trafficsigns; - trafficsigns = trafficsigns.next_sibling("trafficsign")) { - carla::opendrive::parser::TrafficSignParser::Parse(trafficsigns, out_open_drive_data.trafficsigns); - } - - out_open_drive_data.geoReference = xmlDoc.child("OpenDRIVE").child("header").child_value("geoReference"); - - return true; - } + std::string *out_error = nullptr); }; diff --git a/LibCarla/source/carla/opendrive/types.h b/LibCarla/source/carla/opendrive/types.h index 795e74523..36c27ddcb 100644 --- a/LibCarla/source/carla/opendrive/types.h +++ b/LibCarla/source/carla/opendrive/types.h @@ -6,6 +6,8 @@ #pragma once +#include "carla/geom/GeoLocation.h" + #include #include #include @@ -305,7 +307,7 @@ namespace types { ///////////////////////////////////////////////////////////////// struct OpenDriveData { - std::string geoReference; + geom::GeoLocation geoReference; std::vector roads; std::vector junctions; std::vector trafficlightgroups; diff --git a/LibCarla/source/carla/road/MapBuilder.h b/LibCarla/source/carla/road/MapBuilder.h index 8f19df322..48739f6a8 100644 --- a/LibCarla/source/carla/road/MapBuilder.h +++ b/LibCarla/source/carla/road/MapBuilder.h @@ -23,7 +23,7 @@ namespace road { _map_data.SetJunctionInformation(junctionInfo); } - void SetGeoReference(const std::string &geoReference) { + void SetGeoReference(const geom::GeoLocation &geoReference) { _map_data.SetGeoReference(geoReference); } diff --git a/LibCarla/source/carla/road/MapData.h b/LibCarla/source/carla/road/MapData.h index a7a3c02f6..0d51b6aac 100644 --- a/LibCarla/source/carla/road/MapData.h +++ b/LibCarla/source/carla/road/MapData.h @@ -53,7 +53,7 @@ namespace road { return _junction_information; } - const std::string &GetGeoReference() const { + const geom::GeoLocation &GetGeoReference() const { return _geo_reference; } @@ -83,7 +83,7 @@ namespace road { _junction_information = junctionInfo; } - void SetGeoReference(const std::string &geoReference) { + void SetGeoReference(const geom::GeoLocation &geoReference) { _geo_reference = geoReference; } @@ -95,7 +95,7 @@ namespace road { _traffic_signs = trafficSignData; } - std::string _geo_reference; + geom::GeoLocation _geo_reference; std::vector _junction_information; diff --git a/LibCarla/source/carla/road/element/RoadInfo.h b/LibCarla/source/carla/road/element/RoadInfo.h index 447e776f6..1f54af34b 100644 --- a/LibCarla/source/carla/road/element/RoadInfo.h +++ b/LibCarla/source/carla/road/element/RoadInfo.h @@ -8,8 +8,9 @@ #include "carla/road/element/RoadInfoVisitor.h" -#include #include +#include +#include namespace carla { namespace road { diff --git a/LibCarla/source/carla/road/element/Waypoint.h b/LibCarla/source/carla/road/element/Waypoint.h index 85de78a5b..72bbb150d 100644 --- a/LibCarla/source/carla/road/element/Waypoint.h +++ b/LibCarla/source/carla/road/element/Waypoint.h @@ -37,6 +37,10 @@ namespace element { return _lane_id; } + double GetDistance() const { + return _dist; + } + const std::string &GetType() const; const RoadSegment &GetRoadSegment() const; diff --git a/LibCarla/source/carla/road/element/WaypointHash.cpp b/LibCarla/source/carla/road/element/WaypointHash.cpp new file mode 100644 index 000000000..63bd1ae19 --- /dev/null +++ b/LibCarla/source/carla/road/element/WaypointHash.cpp @@ -0,0 +1,27 @@ +// 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 . + +#include "carla/road/element/WaypointHash.h" + +#include "carla/road/element/Waypoint.h" + +#include + +namespace carla { +namespace road { +namespace element { + + uint64_t WaypointHash::operator()(const Waypoint &waypoint) const { + uint64_t seed = 0u; + boost::hash_combine(seed, waypoint.GetRoadId()); + boost::hash_combine(seed, waypoint.GetLaneId()); + boost::hash_combine(seed, static_cast(std::floor(waypoint.GetDistance() * 200.0))); + return seed; + } + +} // namespace element +} // namespace road +} // namespace carla diff --git a/LibCarla/source/carla/road/element/WaypointHash.h b/LibCarla/source/carla/road/element/WaypointHash.h new file mode 100644 index 000000000..73057bf45 --- /dev/null +++ b/LibCarla/source/carla/road/element/WaypointHash.h @@ -0,0 +1,31 @@ +// 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 . + +#pragma once + +#include + +namespace carla { +namespace road { +namespace element { + + class Waypoint; + + struct WaypointHash { + + using argument_type = Waypoint; + + using result_type = uint64_t; + + /// Generates an unique id for @a waypoint based on its road_id, lane_id, + /// and "s" offset. The "s" offset is truncated to half centimetre + /// precision. + uint64_t operator()(const Waypoint &waypoint) const; + }; + +} // namespace element +} // namespace road +} // namespace carla diff --git a/LibCarla/source/carla/sensor/RawData.h b/LibCarla/source/carla/sensor/RawData.h index a4f4c13d5..51af63ffb 100644 --- a/LibCarla/source/carla/sensor/RawData.h +++ b/LibCarla/source/carla/sensor/RawData.h @@ -37,6 +37,11 @@ namespace sensor { return GetHeader().frame_number; } + /// Timestamp when the data was generated. + double GetTimestamp() const { + return GetHeader().timestamp; + } + /// Sensor's transform when the data was generated. const rpc::Transform &GetSensorTransform() const { return GetHeader().sensor_transform; diff --git a/LibCarla/source/carla/sensor/SensorData.h b/LibCarla/source/carla/sensor/SensorData.h index 19fabf565..d5378281e 100644 --- a/LibCarla/source/carla/sensor/SensorData.h +++ b/LibCarla/source/carla/sensor/SensorData.h @@ -23,12 +23,13 @@ namespace sensor { private NonCopyable { protected: - SensorData(size_t frame_number, const rpc::Transform &sensor_transform) + SensorData(size_t frame_number, double timestamp, const rpc::Transform &sensor_transform) : _frame_number(frame_number), + _timestamp(timestamp), _sensor_transform(sensor_transform) {} explicit SensorData(const RawData &data) - : SensorData(data.GetFrameNumber(), data.GetSensorTransform()) {} + : SensorData(data.GetFrameNumber(), data.GetTimestamp(), data.GetSensorTransform()) {} public: @@ -39,6 +40,11 @@ namespace sensor { return _frame_number; } + /// Time the data was generated. + double GetTimestamp() const { + return _timestamp; + } + /// Sensor's transform when the data was generated. const rpc::Transform &GetSensorTransform() const { return _sensor_transform; @@ -58,6 +64,8 @@ namespace sensor { const size_t _frame_number; + const double _timestamp; + const rpc::Transform _sensor_transform; }; diff --git a/LibCarla/source/carla/sensor/data/GnssEvent.h b/LibCarla/source/carla/sensor/data/GnssEvent.h index 785c0be5f..631f2151b 100644 --- a/LibCarla/source/carla/sensor/data/GnssEvent.h +++ b/LibCarla/source/carla/sensor/data/GnssEvent.h @@ -5,49 +5,44 @@ #pragma once -#include "carla/road/element/LaneMarking.h" +#include "carla/geom/GeoLocation.h" #include "carla/sensor/SensorData.h" -#include - namespace carla { namespace sensor { namespace data { - /// A change of gnss data + /// A change of GNSS data. class GnssEvent : public SensorData { public: explicit GnssEvent( size_t frame_number, + double timestamp, const rpc::Transform &sensor_transform, - double lat, - double lon, - double alt) - : SensorData(frame_number, sensor_transform), - _lat(std::move(lat)), - _lon(std::move(lon)), - _alt(std::move(alt)) {} + const geom::GeoLocation &geo_location) + : SensorData(frame_number, timestamp, sensor_transform), + _geo_location(geo_location) {} - const double &GetLatitude() const { - return _lat; + const geom::GeoLocation &GetGeoLocation() const { + return _geo_location; } - const double &GetLongitude() const { - return _lon; + double GetLongitude() const { + return _geo_location.longitude; } - const double &GetAltitude() const { - return _alt; + double GetLatitude() const { + return _geo_location.latitude; + } + + double GetAltitude() const { + return _geo_location.altitude; } private: - double _lat; - - double _lon; - - double _alt; + geom::GeoLocation _geo_location; }; } // namespace data diff --git a/LibCarla/source/carla/sensor/data/LaneInvasionEvent.h b/LibCarla/source/carla/sensor/data/LaneInvasionEvent.h index bf10e642b..6bee186a0 100644 --- a/LibCarla/source/carla/sensor/data/LaneInvasionEvent.h +++ b/LibCarla/source/carla/sensor/data/LaneInvasionEvent.h @@ -23,10 +23,11 @@ namespace data { explicit LaneInvasionEvent( size_t frame_number, + double timestamp, const rpc::Transform &sensor_transform, SharedPtr self_actor, std::vector crossed_lane_markings) - : SensorData(frame_number, sensor_transform), + : SensorData(frame_number, timestamp, sensor_transform), _self_actor(std::move(self_actor)), _crossed_lane_markings(std::move(crossed_lane_markings)) {} diff --git a/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.cpp b/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.cpp index dd79a9399..e6cce206b 100644 --- a/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.cpp +++ b/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.cpp @@ -13,7 +13,7 @@ namespace sensor { namespace s11n { static_assert( - SensorHeaderSerializer::header_offset == 2u * 8u + 6u * 4u, + SensorHeaderSerializer::header_offset == 3u * 8u + 6u * 4u, "Header size missmatch"); static Buffer PopBufferFromPool() { @@ -24,10 +24,12 @@ namespace s11n { Buffer SensorHeaderSerializer::Serialize( const uint64_t index, const uint64_t frame, + double timestamp, const rpc::Transform transform) { Header h; h.sensor_type = index; h.frame_number = frame; + h.timestamp = timestamp; h.sensor_transform = transform; auto buffer = PopBufferFromPool(); buffer.copy_from(reinterpret_cast(&h), sizeof(h)); diff --git a/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.h b/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.h index 8e4831349..1a2b4acb5 100644 --- a/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.h +++ b/LibCarla/source/carla/sensor/s11n/SensorHeaderSerializer.h @@ -21,13 +21,14 @@ namespace s11n { struct Header { uint64_t sensor_type; uint64_t frame_number; + double timestamp; rpc::Transform sensor_transform; }; #pragma pack(pop) constexpr static auto header_offset = sizeof(Header); - static Buffer Serialize(uint64_t index, uint64_t frame, rpc::Transform transform); + static Buffer Serialize(uint64_t index, uint64_t frame, double timestamp, rpc::Transform transform); static const Header &Deserialize(const Buffer &message) { return *reinterpret_cast(message.data()); diff --git a/LibCarla/source/carla/streaming/EndPoint.h b/LibCarla/source/carla/streaming/EndPoint.h index f97fcabf6..2b4263c56 100644 --- a/LibCarla/source/carla/streaming/EndPoint.h +++ b/LibCarla/source/carla/streaming/EndPoint.h @@ -75,7 +75,7 @@ namespace detail { static inline auto make_address(const std::string &address) { boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver(io_service); - boost::asio::ip::tcp::resolver::query query(address, ""); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), address, "", boost::asio::ip::tcp::resolver::query::canonical_name); boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query); boost::asio::ip::tcp::resolver::iterator end; while (iter != end) diff --git a/LibCarla/source/carla/streaming/detail/MultiStreamState.h b/LibCarla/source/carla/streaming/detail/MultiStreamState.h index 8d4811f93..df8e9c75b 100644 --- a/LibCarla/source/carla/streaming/detail/MultiStreamState.h +++ b/LibCarla/source/carla/streaming/detail/MultiStreamState.h @@ -24,7 +24,7 @@ namespace detail { using StreamStateBase::StreamStateBase; template - void Write(Buffers... buffers) { + void Write(Buffers &&... buffers) { auto message = Session::MakeMessage(std::move(buffers)...); std::lock_guard lock(_mutex); for (auto &session : _sessions) { diff --git a/LibCarla/source/carla/streaming/detail/Stream.h b/LibCarla/source/carla/streaming/detail/Stream.h index bc696e3d8..fc32e4a9f 100644 --- a/LibCarla/source/carla/streaming/detail/Stream.h +++ b/LibCarla/source/carla/streaming/detail/Stream.h @@ -48,7 +48,7 @@ namespace detail { /// Flush @a buffers down the stream. No copies are made. template - void Write(Buffers... buffers) { + void Write(Buffers &&... buffers) { _shared_state->Write(std::move(buffers)...); } diff --git a/LibCarla/source/carla/streaming/detail/StreamState.h b/LibCarla/source/carla/streaming/detail/StreamState.h index d384a5c9d..88ab1d1d6 100644 --- a/LibCarla/source/carla/streaming/detail/StreamState.h +++ b/LibCarla/source/carla/streaming/detail/StreamState.h @@ -20,7 +20,7 @@ namespace detail { using StreamStateBase::StreamStateBase; template - void Write(Buffers... buffers) { + void Write(Buffers &&... buffers) { auto session = _session.load(); if (session != nullptr) { session->Write(std::move(buffers)...); diff --git a/LibCarla/source/carla/streaming/detail/tcp/Message.h b/LibCarla/source/carla/streaming/detail/tcp/Message.h index d9bac397d..fe761c95d 100644 --- a/LibCarla/source/carla/streaming/detail/tcp/Message.h +++ b/LibCarla/source/carla/streaming/detail/tcp/Message.h @@ -44,7 +44,7 @@ namespace tcp { MessageTmpl(size_t) {} template - MessageTmpl(size_t size, Buffer buffer, Buffers... buffers) + MessageTmpl(size_t size, Buffer &&buffer, Buffers &&... buffers) : MessageTmpl(size, std::move(buffers)...) { ++_number_of_buffers; _total_size += buffer.size(); @@ -55,7 +55,7 @@ namespace tcp { public: template - MessageTmpl(Buffer buf, Buffers... buffers) + MessageTmpl(Buffer &&buf, Buffers &&... buffers) : MessageTmpl(sizeof...(Buffers) + 1u, std::move(buf), std::move(buffers)...) { static_assert(sizeof...(Buffers) < max_size(), "Too many buffers!"); _buffer_views[0u] = boost::asio::buffer(&_total_size, sizeof(_total_size)); diff --git a/LibCarla/source/carla/streaming/detail/tcp/ServerSession.h b/LibCarla/source/carla/streaming/detail/tcp/ServerSession.h index 7aaa4d244..f43f63808 100644 --- a/LibCarla/source/carla/streaming/detail/tcp/ServerSession.h +++ b/LibCarla/source/carla/streaming/detail/tcp/ServerSession.h @@ -53,7 +53,7 @@ namespace tcp { } template - static auto MakeMessage(Buffers... buffers) { + static auto MakeMessage(Buffers &&... buffers) { static_assert( are_same::value, "This function only accepts arguments of type Buffer."); @@ -65,7 +65,7 @@ namespace tcp { /// Writes some data to the socket. template - void Write(Buffers... buffers) { + void Write(Buffers &&... buffers) { Write(MakeMessage(std::move(buffers)...)); } diff --git a/PythonAPI/setup.py b/PythonAPI/setup.py index 439525873..f976c81b1 100755 --- a/PythonAPI/setup.py +++ b/PythonAPI/setup.py @@ -38,8 +38,7 @@ def get_libcarla_extensions(): os.path.join(pwd, 'dependencies/lib', pylib)] extra_compile_args = [ '-fPIC', '-std=c++14', '-Wno-missing-braces', - '-DBOOST_ERROR_CODE_HEADER_ONLY', '-DLIBCARLA_WITH_PYTHON_SUPPORT', - '-DLIBCARLA_ENABLE_LIFETIME_PROFILER', + '-DBOOST_ERROR_CODE_HEADER_ONLY', '-DLIBCARLA_WITH_PYTHON_SUPPORT' ] if 'TRAVIS' in os.environ and os.environ['TRAVIS'] == 'true': print('Travis CI build detected: disabling PNG support.') diff --git a/PythonAPI/source/libcarla/Geom.cpp b/PythonAPI/source/libcarla/Geom.cpp index 1e4146a61..c56fad933 100644 --- a/PythonAPI/source/libcarla/Geom.cpp +++ b/PythonAPI/source/libcarla/Geom.cpp @@ -5,6 +5,7 @@ // For a copy, see . #include +#include #include #include #include @@ -68,6 +69,13 @@ namespace geom { return out; } + std::ostream &operator<<(std::ostream &out, const GeoLocation &geo_location) { + out << "GeoLocation(latitude=" << geo_location.latitude + << ", longitude=" << geo_location.longitude + << ", altitude=" << geo_location.altitude << ')'; + return out; + } + } // namespace geom } // namespace carla @@ -129,7 +137,7 @@ void export_geom() { .def(self_ns::str(self_ns::self)) ; -class_>("Location") + class_>("Location") .def(init((arg("x")=0.0f, arg("y")=0.0f, arg("z")=0.0f))) .def(init((arg("rhs")))) .add_property("x", +[](const cg::Location &self) { return self.x; }, +[](cg::Location &self, float x) { self.x = x; }) @@ -177,4 +185,14 @@ class_>("Location") .def("__ne__", &cg::BoundingBox::operator!=) .def(self_ns::str(self_ns::self)) ; + + class_("GeoLocation") + .def(init((arg("latitude")=0.0, arg("longitude")=0.0, arg("altitude")=0.0))) + .def_readwrite("latitude", &cg::GeoLocation::latitude) + .def_readwrite("longitude", &cg::GeoLocation::longitude) + .def_readwrite("altitude", &cg::GeoLocation::altitude) + .def("__eq__", &cg::GeoLocation::operator==) + .def("__ne__", &cg::GeoLocation::operator!=) + .def(self_ns::str(self_ns::self)) + ; } diff --git a/PythonAPI/source/libcarla/Map.cpp b/PythonAPI/source/libcarla/Map.cpp index 38a936148..9435621d5 100644 --- a/PythonAPI/source/libcarla/Map.cpp +++ b/PythonAPI/source/libcarla/Map.cpp @@ -47,6 +47,12 @@ static auto GetTopology(const carla::client::Map &self) { return result; } +static carla::geom::GeoLocation ToGeolocation( + const carla::client::Map &self, + const carla::geom::Location &location) { + return self.GetGeoReference().Transform(location); +} + void export_map() { using namespace boost::python; namespace cc = carla::client; @@ -58,6 +64,7 @@ void export_map() { .def("get_waypoint", &cc::Map::GetWaypoint, (arg("location"), arg("project_to_road")=true)) .def("get_topology", &GetTopology) .def("generate_waypoints", CALL_RETURNING_LIST_1(cc::Map, GenerateWaypoints, double), (args("distance"))) + .def("transform_to_geolocation", &ToGeolocation, (arg("location"))) .def("to_opendrive", CALL_RETURNING_COPY(cc::Map, GetOpenDrive)) .def("save_to_disk", &SaveOpenDriveToDisk, (arg("path")="")) .def(self_ns::str(self_ns::self)) @@ -71,11 +78,13 @@ void export_map() { ; class_>("Waypoint", no_init) + .add_property("id", &cc::Waypoint::GetId) .add_property("transform", CALL_RETURNING_COPY(cc::Waypoint, GetTransform)) .add_property("is_intersection", &cc::Waypoint::IsIntersection) .add_property("lane_width", &cc::Waypoint::GetLaneWidth) .add_property("road_id", &cc::Waypoint::GetRoadId) .add_property("lane_id", &cc::Waypoint::GetLaneId) + .add_property("s", &cc::Waypoint::GetDistance) .add_property("lane_change", &cc::Waypoint::GetLaneChange) .add_property("lane_type", &cc::Waypoint::GetType) .def("next", CALL_RETURNING_LIST_1(cc::Waypoint, Next, double), (args("distance"))) diff --git a/PythonAPI/source/libcarla/SensorData.cpp b/PythonAPI/source/libcarla/SensorData.cpp index a0944983b..716b9320b 100644 --- a/PythonAPI/source/libcarla/SensorData.cpp +++ b/PythonAPI/source/libcarla/SensorData.cpp @@ -28,6 +28,7 @@ namespace data { std::ostream &operator<<(std::ostream &out, const Image &image) { out << "Image(frame=" << image.GetFrameNumber() + << ", timestamp=" << image.GetTimestamp() << ", size=" << image.GetWidth() << 'x' << image.GetHeight() << ')'; return out; @@ -35,6 +36,7 @@ namespace data { std::ostream &operator<<(std::ostream &out, const LidarMeasurement &meas) { out << "LidarMeasurement(frame=" << meas.GetFrameNumber() + << ", timestamp=" << meas.GetTimestamp() << ", number_of_points=" << meas.size() << ')'; return out; @@ -42,6 +44,7 @@ namespace data { std::ostream &operator<<(std::ostream &out, const CollisionEvent &meas) { out << "CollisionEvent(frame=" << meas.GetFrameNumber() + << ", timestamp=" << meas.GetTimestamp() << ", other_actor=" << meas.GetOtherActor() << ')'; return out; @@ -49,18 +52,22 @@ namespace data { std::ostream &operator<<(std::ostream &out, const ObstacleDetectionEvent &meas) { out << "ObstacleDetectionEvent(frame=" << meas.GetFrameNumber() + << ", timestamp=" << meas.GetTimestamp() << ", other_actor=" << meas.GetOtherActor() << ')'; return out; } std::ostream &operator<<(std::ostream &out, const LaneInvasionEvent &meas) { - out << "LaneInvasionEvent(frame=" << meas.GetFrameNumber() << ')'; + out << "LaneInvasionEvent(frame=" << meas.GetFrameNumber() + << ", timestamp=" << meas.GetTimestamp() + << ')'; return out; } std::ostream &operator<<(std::ostream &out, const GnssEvent &meas) { out << "GnssEvent(frame=" << meas.GetFrameNumber() + << ", timestamp=" << meas.GetTimestamp() << ", lat=" << meas.GetLatitude() << ", lon=" << meas.GetLongitude() << ", alt=" << meas.GetAltitude() @@ -156,6 +163,7 @@ void export_sensor_data() { class_>("SensorData", no_init) .add_property("frame_number", &cs::SensorData::GetFrameNumber) + .add_property("timestamp", &cs::SensorData::GetTimestamp) .add_property("transform", CALL_RETURNING_COPY(cs::SensorData, GetSensorTransform)) ; @@ -228,9 +236,9 @@ void export_sensor_data() { ; class_, boost::noncopyable, boost::shared_ptr>("GnssEvent", no_init) - .add_property("latitude", CALL_RETURNING_COPY(csd::GnssEvent, GetLatitude)) - .add_property("longitude", CALL_RETURNING_COPY(csd::GnssEvent, GetLongitude)) - .add_property("altitude", CALL_RETURNING_COPY(csd::GnssEvent, GetAltitude)) + .add_property("latitude", &csd::GnssEvent::GetLatitude) + .add_property("longitude", &csd::GnssEvent::GetLongitude) + .add_property("altitude", &csd::GnssEvent::GetAltitude) .def(self_ns::str(self_ns::self)) ; } diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/AsyncDataStream.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/AsyncDataStream.h index 6bdd8c113..9bfbd5033 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/AsyncDataStream.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/AsyncDataStream.h @@ -63,7 +63,7 @@ private: /// @pre This functions needs to be called in the game-thread. template - explicit FAsyncDataStreamTmpl(const SensorT &InSensor, StreamType InStream); + explicit FAsyncDataStreamTmpl(const SensorT &InSensor, float Timepoint, StreamType InStream); StreamType Stream; @@ -95,13 +95,15 @@ template template inline FAsyncDataStreamTmpl::FAsyncDataStreamTmpl( const SensorT &Sensor, + float Timepoint, StreamType InStream) : Stream(std::move(InStream)), - Header([&Sensor]() { + Header([&Sensor, Timepoint]() { check(IsInGameThread()); using Serializer = carla::sensor::s11n::SensorHeaderSerializer; return Serializer::Serialize( carla::sensor::SensorRegistry::template get::index, GFrameCounter, + Timepoint, Sensor.GetActorTransform()); }()) {} diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/CollisionSensor.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/CollisionSensor.cpp index 15504622d..0ad68670f 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/CollisionSensor.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/CollisionSensor.cpp @@ -62,7 +62,7 @@ void ACollisionSensor::OnCollisionEvent( { constexpr float TO_METERS = 1e-2; NormalImpulse *= TO_METERS; - GetDataStream(*this).Send( + GetDataStream(*this, Actor->GetWorld()->GetTimeSeconds()).Send( *this, Episode->SerializeActor(Episode->FindOrFakeActor(Actor)), Episode->SerializeActor(Episode->FindOrFakeActor(OtherActor)), diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/DataStream.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/DataStream.h index 1b945c72c..04106edb3 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/DataStream.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/DataStream.h @@ -37,10 +37,10 @@ public: /// /// @pre This functions needs to be called in the game-thread. template - auto MakeAsyncDataStream(const SensorT &Sensor) + auto MakeAsyncDataStream(const SensorT &Sensor, float Timestamp) { check(Stream.has_value()); - return FAsyncDataStreamTmpl{Sensor, *Stream}; + return FAsyncDataStreamTmpl{Sensor, Timestamp, *Stream}; } /// Return the token that allows subscribing to this stream. diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.cpp index d35db568b..aa23168a6 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.cpp @@ -134,7 +134,7 @@ void AObstacleDetectionSensor::Tick(float DeltaSeconds) if (isHitReturned) { - OnObstacleDetectionEvent(this, HitOut.Actor.Get(), HitOut.Distance, HitOut); + OnObstacleDetectionEvent(this, HitOut.Actor.Get(), HitOut.Distance, HitOut, currentWorld->GetTimeSeconds()); } } @@ -142,11 +142,12 @@ void AObstacleDetectionSensor::OnObstacleDetectionEvent( AActor *Actor, AActor *OtherActor, float HitDistance, - const FHitResult &Hit) + const FHitResult &Hit, + float Timestamp) { if ((Episode != nullptr) && (Actor != nullptr) && (OtherActor != nullptr)) { - GetDataStream(*this).Send(*this, + GetDataStream(*this, Timestamp).Send(*this, Episode->SerializeActor(Episode->FindOrFakeActor(Actor)), Episode->SerializeActor(Episode->FindOrFakeActor(OtherActor)), HitRadius); diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.h index 75c553e08..fea186d22 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/ObstacleDetectionSensor.h @@ -38,7 +38,8 @@ private: AActor *Actor, AActor *OtherActor, float Distance, - const FHitResult &Hit); + const FHitResult &Hit, + float Timestamp); UPROPERTY() const UCarlaEpisode *Episode = nullptr; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/PixelReader.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/PixelReader.h index 8cf045d2c..c72f55f01 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/PixelReader.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/PixelReader.h @@ -87,7 +87,7 @@ void FPixelReader::SendPixelsInRenderThread(TSensor &Sensor) // First we create the message header (needs to be created in the // game-thread). - auto AsyncStream = Sensor.GetDataStream(Sensor); + auto AsyncStream = Sensor.GetDataStream(Sensor, Sensor.GetWorld()->GetTimeSeconds()); // We need a shared ptr here because UE4 macros do not move the arguments -_- auto StreamPtr = std::make_shared(std::move(AsyncStream)); diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/RayCastLidar.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/RayCastLidar.cpp index 3219f9784..e7f4c1517 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/RayCastLidar.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/RayCastLidar.cpp @@ -69,7 +69,7 @@ void ARayCastLidar::Tick(const float DeltaTime) ReadPoints(DeltaTime); - auto DataStream = GetDataStream(*this); + auto DataStream = GetDataStream(*this, GetWorld()->GetTimeSeconds()); DataStream.Send(*this, LidarMeasurement, DataStream.PopBufferFromPool()); } diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/Sensor.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/Sensor.h index 021e098f3..cb7e24b26 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/Sensor.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/Sensor.h @@ -47,9 +47,9 @@ protected: /// You need to provide a reference to self, this is necessary for template /// deduction. template - FAsyncDataStream GetDataStream(const SensorT &Self) + FAsyncDataStream GetDataStream(const SensorT &Self, float Timestamp) { - return Stream.MakeAsyncDataStream(Self); + return Stream.MakeAsyncDataStream(Self, Timestamp); } private: diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp index 31803e64c..0b8c9ff37 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/WorldObserver.cpp @@ -150,7 +150,7 @@ static carla::Buffer FWorldObserver_Serialize( void FWorldObserver::BroadcastTick(const UCarlaEpisode &Episode, float DeltaSeconds) { - auto AsyncStream = Stream.MakeAsyncDataStream(*this); + auto AsyncStream = Stream.MakeAsyncDataStream(*this, Episode.GetWorld()->GetTimeSeconds()); auto buffer = FWorldObserver_Serialize( AsyncStream.PopBufferFromPool(), diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CarlaSettings.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CarlaSettings.cpp index 23a32e745..0edb3476e 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CarlaSettings.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CarlaSettings.cpp @@ -178,6 +178,14 @@ void UCarlaSettings::LoadSettings() { QualityLevel = QualityLevelFromString(StringQualityLevel, EQualityLevel::Epic); } + if (FParse::Value(FCommandLine::Get(), TEXT("-carla-server-timeout="), Value)) + { + ServerTimeOut = Value; + } + if (FParse::Param(FCommandLine::Get(), TEXT("-no-rendering"))) + { + bDisableRendering = true; + } } } diff --git a/Util/BuildTools/BuildLibCarla.sh b/Util/BuildTools/BuildLibCarla.sh index b29d8ecc5..a8060597d 100755 --- a/Util/BuildTools/BuildLibCarla.sh +++ b/Util/BuildTools/BuildLibCarla.sh @@ -8,13 +8,34 @@ source $(dirname "$0")/Environment.sh DOC_STRING="Build LibCarla." -USAGE_STRING="Usage: $0 [-h|--help] [--rebuild] [--server] [--client] [--clean]" +USAGE_STRING=$(cat <<- END +Usage: $0 [-h|--help] + +Choose one or more build configurations + + [--server] Build server-side configuration. + [--client] Build client-side configuration. + +and choose one or more build options + + [--debug] Build debug targets. + [--release] Build release targets. + +Other commands + + [--clean] Clean intermediate files. + [--rebuild] Clean and rebuild both configurations. +END +) REMOVE_INTERMEDIATE=false BUILD_SERVER=false BUILD_CLIENT=false +BUILD_OPTION_DEBUG=false +BUILD_OPTION_RELEASE=false +BUILD_OPTION_DUMMY=false -OPTS=`getopt -o h --long help,rebuild,server,client,clean -n 'parse-options' -- "$@"` +OPTS=`getopt -o h --long help,rebuild,server,client,clean,debug,release -n 'parse-options' -- "$@"` if [ $? != 0 ] ; then echo "$USAGE_STRING" ; exit 2 ; fi @@ -26,6 +47,8 @@ while true; do REMOVE_INTERMEDIATE=true; BUILD_SERVER=true; BUILD_CLIENT=true; + BUILD_OPTION_DEBUG=true; + BUILD_OPTION_RELEASE=true; shift ;; --server ) BUILD_SERVER=true; @@ -35,6 +58,13 @@ while true; do shift ;; --clean ) REMOVE_INTERMEDIATE=true; + BUILD_OPTION_DUMMY=true; + shift ;; + --debug ) + BUILD_OPTION_DEBUG=true; + shift ;; + --release ) + BUILD_OPTION_RELEASE=true; shift ;; -h | --help ) echo "$DOC_STRING" @@ -50,6 +80,10 @@ if ! { ${REMOVE_INTERMEDIATE} || ${BUILD_SERVER} || ${BUILD_CLIENT}; }; then fatal_error "Nothing selected to be done." fi +if ! { ${BUILD_OPTION_DUMMY} || ${BUILD_OPTION_DEBUG} || ${BUILD_OPTION_RELEASE} ; }; then + fatal_error "Choose --debug and/or --release." +fi + # ============================================================================== # -- Clean intermediate files -------------------------------------------------- # ============================================================================== @@ -58,30 +92,57 @@ if ${REMOVE_INTERMEDIATE} ; then log "Cleaning intermediate files and folders." - rm -Rf ${LIBCARLA_BUILD_SERVER_FOLDER} ${LIBCARLA_BUILD_CLIENT_FOLDER} + rm -Rf ${LIBCARLA_BUILD_SERVER_FOLDER}* ${LIBCARLA_BUILD_CLIENT_FOLDER}* rm -Rf ${LIBCARLA_INSTALL_SERVER_FOLDER} ${LIBCARLA_INSTALL_CLIENT_FOLDER} - rm -f ${LIBCARLA_ROOT_FOLDER}/source/carla/Version.h fi # ============================================================================== -# -- Build Server configuration ------------------------------------------------ +# -- Define build function ----------------------------------------------------- # ============================================================================== -if ${BUILD_SERVER} ; then +# Build LibCarla for the given configuration. +# +# usage: build_libcarla {Server,Client} {Debug,Release} +# +function build_libcarla { - log "Building LibCarla \"Server\" configuration." + if [ $1 == Server ] ; then + M_TOOLCHAIN=${LIBCPP_TOOLCHAIN_FILE} + M_BUILD_FOLDER=${LIBCARLA_BUILD_SERVER_FOLDER}.$(echo "$2" | tr '[:upper:]' '[:lower:]') + M_INSTALL_FOLDER=${LIBCARLA_INSTALL_SERVER_FOLDER} + elif [ $1 == Client ] ; then + M_TOOLCHAIN=${LIBSTDCPP_TOOLCHAIN_FILE} + M_BUILD_FOLDER=${LIBCARLA_BUILD_CLIENT_FOLDER}.$(echo "$2" | tr '[:upper:]' '[:lower:]') + M_INSTALL_FOLDER=${LIBCARLA_INSTALL_CLIENT_FOLDER} + else + fatal_error "Invalid build configuration \"$1\"" + fi - mkdir -p ${LIBCARLA_BUILD_SERVER_FOLDER} - pushd "${LIBCARLA_BUILD_SERVER_FOLDER}" >/dev/null + if [ $2 == Debug ] ; then + M_DEBUG=ON + M_RELEASE=OFF + elif [ $2 == Release ] ; then + M_DEBUG=OFF + M_RELEASE=ON + else + fatal_error "Invalid build option \"$2\"" + fi + + log "Building LibCarla \"$1.$2\" configuration." + + mkdir -p ${M_BUILD_FOLDER} + pushd "${M_BUILD_FOLDER}" >/dev/null if [ ! -f "build.ninja" ]; then cmake \ -G "Ninja" \ - -DCMAKE_BUILD_TYPE=Server \ - -DCMAKE_TOOLCHAIN_FILE=${LIBCPP_TOOLCHAIN_FILE} \ - -DCMAKE_INSTALL_PREFIX=${LIBCARLA_INSTALL_SERVER_FOLDER} \ + -DCMAKE_BUILD_TYPE=$1 \ + -DLIBCARLA_BUILD_DEBUG=${M_DEBUG} \ + -DLIBCARLA_BUILD_RELEASE=${M_RELEASE} \ + -DCMAKE_TOOLCHAIN_FILE=${M_TOOLCHAIN} \ + -DCMAKE_INSTALL_PREFIX=${M_INSTALL_FOLDER} \ -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \ ${CARLA_ROOT_FOLDER} @@ -92,37 +153,33 @@ if ${BUILD_SERVER} ; then ninja install | grep -v "Up-to-date:" popd >/dev/null +} + +# ============================================================================== +# -- Build all possible configurations ----------------------------------------- +# ============================================================================== + +if { ${BUILD_SERVER} && ${BUILD_OPTION_DEBUG}; }; then + + build_libcarla Server Debug fi -# ============================================================================== -# -- Build Client configuration ------------------------------------------------ -# ============================================================================== +if { ${BUILD_SERVER} && ${BUILD_OPTION_RELEASE}; }; then -if ${BUILD_CLIENT} ; then + build_libcarla Server Release - log "Building LibCarla \"Client\" configuration." +fi - mkdir -p ${LIBCARLA_BUILD_CLIENT_FOLDER} - pushd "${LIBCARLA_BUILD_CLIENT_FOLDER}" >/dev/null +if { ${BUILD_CLIENT} && ${BUILD_OPTION_DEBUG}; }; then - if [ ! -f "build.ninja" ]; then + build_libcarla Client Debug - cmake \ - -G "Ninja" \ - -DCMAKE_BUILD_TYPE=Client \ - -DCMAKE_TOOLCHAIN_FILE=${LIBSTDCPP_TOOLCHAIN_FILE} \ - -DCMAKE_INSTALL_PREFIX=${LIBCARLA_INSTALL_CLIENT_FOLDER} \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \ - ${CARLA_ROOT_FOLDER} +fi - fi +if { ${BUILD_CLIENT} && ${BUILD_OPTION_RELEASE}; }; then - ninja - - ninja install | grep -v "Up-to-date:" - - popd >/dev/null + build_libcarla Client Release fi diff --git a/Util/BuildTools/Linux.mk b/Util/BuildTools/Linux.mk index e0e041222..a3b3cc466 100644 --- a/Util/BuildTools/Linux.mk +++ b/Util/BuildTools/Linux.mk @@ -3,7 +3,7 @@ default: help help: @less ${CARLA_BUILD_TOOLS_FOLDER}/Linux.mk.help -launch: LibCarla.server +launch: LibCarla.server.release @${CARLA_BUILD_TOOLS_FOLDER}/BuildCarlaUE4.sh --build --launch launch-only: @@ -41,10 +41,10 @@ check: LibCarla PythonAPI check.LibCarla: LibCarla @${CARLA_BUILD_TOOLS_FOLDER}/Check.sh --libcarla-debug --libcarla-release $(ARGS) -check.LibCarla.debug: LibCarla +check.LibCarla.debug: LibCarla.debug @${CARLA_BUILD_TOOLS_FOLDER}/Check.sh --libcarla-debug $(ARGS) -check.LibCarla.release: LibCarla +check.LibCarla.release: LibCarla.release @${CARLA_BUILD_TOOLS_FOLDER}/Check.sh --libcarla-release $(ARGS) check.PythonAPI: PythonAPI @@ -56,31 +56,40 @@ check.PythonAPI.2: PythonAPI.2 check.PythonAPI.3: PythonAPI.3 @${CARLA_BUILD_TOOLS_FOLDER}/Check.sh --python-api-3 $(ARGS) -benchmark: LibCarla.server +benchmark: LibCarla.release @${CARLA_BUILD_TOOLS_FOLDER}/Check.sh --benchmark $(ARGS) @cat profiler.csv -CarlaUE4Editor: LibCarla.server +CarlaUE4Editor: LibCarla.server.release @${CARLA_BUILD_TOOLS_FOLDER}/BuildCarlaUE4.sh --build .PHONY: PythonAPI -PythonAPI: LibCarla.client +PythonAPI: LibCarla.client.release @${CARLA_BUILD_TOOLS_FOLDER}/BuildPythonAPI.sh --py2 --py3 -PythonAPI.2: LibCarla.client +PythonAPI.2: LibCarla.client.release @${CARLA_BUILD_TOOLS_FOLDER}/BuildPythonAPI.sh --py2 -PythonAPI.3: LibCarla.client +PythonAPI.3: LibCarla.client.release @${CARLA_BUILD_TOOLS_FOLDER}/BuildPythonAPI.sh --py3 .PHONY: LibCarla LibCarla: LibCarla.server LibCarla.client -LibCarla.server: setup - @${CARLA_BUILD_TOOLS_FOLDER}/BuildLibCarla.sh --server +LibCarla.debug: LibCarla.server.debug LibCarla.client.debug +LibCarla.release: LibCarla.server.release LibCarla.client.release -LibCarla.client: setup - @${CARLA_BUILD_TOOLS_FOLDER}/BuildLibCarla.sh --client +LibCarla.server: LibCarla.server.debug LibCarla.server.release +LibCarla.server.debug: setup + @${CARLA_BUILD_TOOLS_FOLDER}/BuildLibCarla.sh --server --debug +LibCarla.server.release: setup + @${CARLA_BUILD_TOOLS_FOLDER}/BuildLibCarla.sh --server --release + +LibCarla.client: LibCarla.client.debug LibCarla.client.release +LibCarla.client.debug: setup + @${CARLA_BUILD_TOOLS_FOLDER}/BuildLibCarla.sh --client --debug +LibCarla.client.release: setup + @${CARLA_BUILD_TOOLS_FOLDER}/BuildLibCarla.sh --client --release setup: @${CARLA_BUILD_TOOLS_FOLDER}/Setup.sh diff --git a/Util/BuildTools/Linux.mk.help b/Util/BuildTools/Linux.mk.help index da5fd11d2..95a443f58 100644 --- a/Util/BuildTools/Linux.mk.help +++ b/Util/BuildTools/Linux.mk.help @@ -73,7 +73,7 @@ for developers: Build and package the Python API module for Python 2 and/or 3. - LibCarla(.server|.client): + LibCarla(.server|.client)(.debug|.release): Build LibCarla, "Server" and/or "Client" configurations. diff --git a/Util/BuildTools/Setup.sh b/Util/BuildTools/Setup.sh index 4fd1d748d..b193c9b53 100755 --- a/Util/BuildTools/Setup.sh +++ b/Util/BuildTools/Setup.sh @@ -280,6 +280,21 @@ fi unset GTEST_BASENAME +# ============================================================================== +# -- Generate Version.h -------------------------------------------------------- +# ============================================================================== + +CARLA_VERSION=$(get_carla_version) + +log "CARLA version ${CARLA_VERSION}." + +VERSION_H_FILE=${LIBCARLA_ROOT_FOLDER}/source/carla/Version.h +VERSION_H_FILE_GEN=${CARLA_BUILD_FOLDER}/Version.h + +sed -e "s|\${CARLA_VERSION}|${CARLA_VERSION}|g" ${VERSION_H_FILE}.in > ${VERSION_H_FILE_GEN} + +move_if_changed "${VERSION_H_FILE_GEN}" "${VERSION_H_FILE}" + # ============================================================================== # -- Generate CMake toolchains and config -------------------------------------- # ============================================================================== @@ -298,7 +313,7 @@ set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -std=c++14 -pthread -fPIC" CACHE STRING set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra" CACHE STRING "" FORCE) # @todo These flags need to be compatible with setup.py compilation. -set(CMAKE_CXX_FLAGS_RELEASE_CLIENT "\${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -std=c++14 -Wno-missing-braces -DBOOST_ERROR_CODE_HEADER_ONLY -DLIBCARLA_ENABLE_LIFETIME_PROFILER -DLIBCARLA_WITH_PYTHON_SUPPORT" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_RELEASE_CLIENT "\${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -std=c++14 -Wno-missing-braces -DBOOST_ERROR_CODE_HEADER_ONLY -DLIBCARLA_WITH_PYTHON_SUPPORT" CACHE STRING "" FORCE) EOL # -- LIBCPP_TOOLCHAIN_FILE ----------------------------------------------------- @@ -320,8 +335,6 @@ EOL cat >${CMAKE_CONFIG_FILE}.gen <