Allow changing fixed frame rate at runtime

This commit is contained in:
nsubiron 2019-07-02 16:31:38 +02:00 committed by Néstor Subirón
parent a5f3a3625a
commit 8f2d5b089e
12 changed files with 114 additions and 23 deletions

View File

@ -32,6 +32,7 @@
* API extension: `world.tick()` now synchronizes with the simulator and returns the id of the newly started frame
* API extension: `world.apply_settings(settings)` now synchronizes with the simulator and returns the id of the frame when the settings took effect
* API extension: added `world.remove_on_tick(id)` to allow removing on tick callbacks
* API extension: allow setting fixed frame-rate from client-side, now is part of `carla.WorldSettings`
* API change: Rename `frame_count` and `frame_number` as `frame`, old members are kept as deprecated
* API change: `world.wait_for_tick()` now returns a `carla.WorldSnapshot`
* API change: the callback of `world.on_tick(callback)` now receives a `carla.WorldSnapshot`

View File

@ -23,20 +23,26 @@ CARLA can be run in both modes.
The simulation tries to keep up with real-time. To do so, the time-step is
slightly adjusted each update. Simulations are not repeatable. By default, the
simulator starts in this mode
simulator starts in this mode, but it can be re-enabled if changed with
```py
settings = world.get_settings()
settings.fixed_delta_seconds = None
world.apply_settings(settings)
```
<h4>Fixed time-step</h4>
The simulation runs as fast as possible, simulating the same time increment on
each step. To run the simulator this way you need to pass two parameters in the
command-line, one to enable the fixed time-step mode, and the second to specify
the FPS of the simulation (i.e. the inverse of the time step). For instance, to
run the simulation at a fixed time-step of 0.1 seconds we execute
each step. To enable this mode set a fixed delta seconds in the world settings.
For instance, to run the simulation at a fixed time-step of 0.05 seconds (20
FPS) apply the following settings
$ ./CarlaUE4.sh -benchmark -fps=10
It is important to note that this mode can only be enabled when launching the
simulator since this is actually a feature of Unreal Engine.
```py
settings = world.get_settings()
settings.fixed_delta_seconds = 0.05
world.apply_settings(settings)
```
!!! important
**Do not decrease the frame-rate below 10 FPS.**<br>

View File

@ -49,6 +49,7 @@
- `synchronous_mode`
- `no_rendering_mode`
- `fixed_delta_seconds`
- `__eq__(other)`
- `__ne__(other)`

View File

@ -136,6 +136,11 @@ namespace detail {
}
uint64_t Simulator::SetEpisodeSettings(const rpc::EpisodeSettings &settings) {
if (settings.synchronous_mode && !settings.fixed_delta_seconds) {
log_warning(
"synchronous mode enabled with variable delta seconds. It is highly "
"recommended to set 'fixed_delta_seconds' when running on synchronous mode.");
}
const auto frame = _client.SetEpisodeSettings(settings);
SynchronizeFrame(frame, *_episode);
return frame;

View File

@ -7,11 +7,14 @@
#pragma once
#include "carla/MsgPack.h"
#include "carla/MsgPackAdaptors.h"
#ifdef LIBCARLA_INCLUDED_FROM_UE4
# include "Carla/Settings/EpisodeSettings.h"
#endif // LIBCARLA_INCLUDED_FROM_UE4
#include <boost/optional.hpp>
namespace carla {
namespace rpc {
@ -26,7 +29,9 @@ namespace rpc {
bool no_rendering_mode = false;
MSGPACK_DEFINE_ARRAY(synchronous_mode, no_rendering_mode);
boost::optional<double> fixed_delta_seconds;
MSGPACK_DEFINE_ARRAY(synchronous_mode, no_rendering_mode, fixed_delta_seconds);
// =========================================================================
// -- Constructors ---------------------------------------------------------
@ -36,9 +41,12 @@ namespace rpc {
EpisodeSettings(
bool synchronous_mode,
bool no_rendering_mode)
bool no_rendering_mode,
double fixed_delta_seconds = 0.0)
: synchronous_mode(synchronous_mode),
no_rendering_mode(no_rendering_mode) {}
no_rendering_mode(no_rendering_mode),
fixed_delta_seconds(
fixed_delta_seconds > 0.0 ? fixed_delta_seconds : boost::optional<double>{}) {}
// =========================================================================
// -- Comparison operators -------------------------------------------------
@ -47,7 +55,8 @@ namespace rpc {
bool operator==(const EpisodeSettings &rhs) const {
return
(synchronous_mode == rhs.synchronous_mode) &&
(no_rendering_mode == rhs.no_rendering_mode);
(no_rendering_mode == rhs.no_rendering_mode) &&
(fixed_delta_seconds == rhs.fixed_delta_seconds);
}
bool operator!=(const EpisodeSettings &rhs) const {
@ -61,13 +70,18 @@ namespace rpc {
#ifdef LIBCARLA_INCLUDED_FROM_UE4
EpisodeSettings(const FEpisodeSettings &Settings)
: synchronous_mode(Settings.bSynchronousMode),
no_rendering_mode(Settings.bNoRenderingMode) {}
: EpisodeSettings(
Settings.bSynchronousMode,
Settings.bNoRenderingMode,
Settings.FixedDeltaSeconds.Get(0.0)) {}
operator FEpisodeSettings() const {
FEpisodeSettings Settings;
Settings.bSynchronousMode = synchronous_mode;
Settings.bNoRenderingMode = no_rendering_mode;
if (fixed_delta_seconds.has_value()) {
Settings.FixedDeltaSeconds = *fixed_delta_seconds;
}
return Settings;
}

View File

@ -96,11 +96,20 @@ void export_world() {
;
class_<cr::EpisodeSettings>("WorldSettings")
.def(init<bool, bool>(
.def(init<bool, bool, double>(
(arg("synchronous_mode")=false,
arg("no_rendering_mode")=false)))
arg("no_rendering_mode")=false,
arg("fixed_delta_seconds")=0.0)))
.def_readwrite("synchronous_mode", &cr::EpisodeSettings::synchronous_mode)
.def_readwrite("no_rendering_mode", &cr::EpisodeSettings::no_rendering_mode)
.add_property("fixed_delta_seconds",
+[](const cr::EpisodeSettings &self) {
return OptionalToPythonObject(self.fixed_delta_seconds);
},
+[](cr::EpisodeSettings &self, object value) {
double fds = (value == object{} ? 0.0 : extract<double>(value));
self.fixed_delta_seconds = fds > 0.0 ? fds : boost::optional<double>{};
})
.def("__eq__", &cc::Timestamp::operator==)
.def("__ne__", &cc::Timestamp::operator!=)
.def(self_ns::str(self_ns::self))

View File

@ -12,6 +12,11 @@
#include <type_traits>
#include <vector>
template <typename OptionalT>
static boost::python::object OptionalToPythonObject(OptionalT &optional) {
return optional.has_value() ? boost::python::object(*optional) : boost::python::object();
}
// Convenient for requests without arguments.
#define CALL_WITHOUT_GIL(cls, fn) +[](cls &self) { \
carla::PythonUtil::ReleaseGIL unlock; \
@ -88,12 +93,12 @@
#define CALL_RETURNING_OPTIONAL(cls, fn) +[](const cls &self) { \
auto optional = self.fn(); \
return optional.has_value() ? boost::python::object(*optional) : boost::python::object(); \
return OptionalToPythonObject(optional); \
}
#define CALL_RETURNING_OPTIONAL_1(cls, fn, T1_) +[](const cls &self, T1_ t1) { \
auto optional = self.fn(std::forward<T1_>(t1)); \
return optional.has_value() ? boost::python::object(*optional) : boost::python::object(); \
return OptionalToPythonObject(optional); \
}
#define CALL_RETURNING_OPTIONAL_WITHOUT_GIL(cls, fn) +[](const cls &self) { \

View File

@ -39,7 +39,8 @@ class SyncSmokeTest(SmokeTest):
self.settings = self.world.get_settings()
settings = carla.WorldSettings(
no_rendering_mode=False,
synchronous_mode=True)
synchronous_mode=True,
fixed_delta_seconds=0.05)
self.world.apply_settings(settings)
def tearDown(self):

View File

@ -0,0 +1,23 @@
# 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>.
from . import SmokeTest
class TestWorld(SmokeTest):
def test_fixed_delta_seconds(self):
world = self.client.get_world()
settings = world.get_settings()
self.assertFalse(settings.synchronous_mode)
for expected_delta_seconds in [0.1, 0.066667, 0.05, 0.033333, 0.016667, 0.011112]:
settings.fixed_delta_seconds = expected_delta_seconds
world.apply_settings(settings)
for _ in range(0, 20):
delta_seconds = world.wait_for_tick().timestamp.delta_seconds
self.assertAlmostEqual(expected_delta_seconds, delta_seconds)
settings.fixed_delta_seconds = None
world.apply_settings(settings)

View File

@ -12,13 +12,34 @@
#include "Carla/Settings/CarlaSettings.h"
#include "Carla/Settings/EpisodeSettings.h"
#include "Runtime/Core/Public/Misc/App.h"
#include <thread>
static uint32 GetNumberOfThreadsForRPCServer()
// =============================================================================
// -- Static local methods -----------------------------------------------------
// =============================================================================
static uint32 FCarlaEngine_GetNumberOfThreadsForRPCServer()
{
return std::max(std::thread::hardware_concurrency(), 4u) - 2u;
}
static TOptional<double> FCarlaEngine_GetFixedDeltaSeconds()
{
return FApp::IsBenchmarking() ? FApp::GetFixedDeltaTime() : TOptional<double>{};
}
static void FCarlaEngine_SetFixedDeltaSeconds(TOptional<double> FixedDeltaSeconds)
{
FApp::SetBenchmarking(FixedDeltaSeconds.IsSet());
FApp::SetFixedDeltaTime(FixedDeltaSeconds.Get(0.0));
}
// =============================================================================
// -- FCarlaEngine -------------------------------------------------------------
// =============================================================================
FCarlaEngine::~FCarlaEngine()
{
if (bIsRunning)
@ -35,7 +56,7 @@ void FCarlaEngine::NotifyInitGame(const UCarlaSettings &Settings)
{
const auto StreamingPort = Settings.StreamingPort.Get(Settings.RPCPort + 1u);
auto BroadcastStream = Server.Start(Settings.RPCPort, StreamingPort);
Server.AsyncRun(GetNumberOfThreadsForRPCServer());
Server.AsyncRun(FCarlaEngine_GetNumberOfThreadsForRPCServer());
WorldObserver.SetStream(BroadcastStream);
@ -55,6 +76,7 @@ void FCarlaEngine::NotifyInitGame(const UCarlaSettings &Settings)
void FCarlaEngine::NotifyBeginEpisode(UCarlaEpisode &Episode)
{
Episode.EpisodeSettings.FixedDeltaSeconds = FCarlaEngine_GetFixedDeltaSeconds();
CurrentEpisode = &Episode;
Server.NotifyBeginEpisode(Episode);
}
@ -91,4 +113,6 @@ void FCarlaEngine::OnEpisodeSettingsChanged(const FEpisodeSettings &Settings)
{
GEngine->GameViewport->bDisableWorldRendering = Settings.bNoRenderingMode;
}
FCarlaEngine_SetFixedDeltaSeconds(Settings.FixedDeltaSeconds);
}

View File

@ -158,7 +158,7 @@ void UCarlaEpisode::InitializeAtBeginPlay()
{
auto World = GetWorld();
check(World != nullptr);
auto PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
auto PlayerController = UGameplayStatics::GetPlayerController(World, 0);
if (PlayerController == nullptr)
{
UE_LOG(LogCarla, Error, TEXT("Can't find player controller!"));

View File

@ -18,4 +18,6 @@ struct CARLA_API FEpisodeSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bNoRenderingMode = false;
TOptional<double> FixedDeltaSeconds;
};