Allow changing fixed frame rate at runtime
This commit is contained in:
parent
a5f3a3625a
commit
8f2d5b089e
|
@ -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`
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
- `synchronous_mode`
|
||||
- `no_rendering_mode`
|
||||
- `fixed_delta_seconds`
|
||||
- `__eq__(other)`
|
||||
- `__ne__(other)`
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) { \
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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!"));
|
||||
|
|
|
@ -18,4 +18,6 @@ struct CARLA_API FEpisodeSettings
|
|||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool bNoRenderingMode = false;
|
||||
|
||||
TOptional<double> FixedDeltaSeconds;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue