From be37d2233504e77a0b69e98bca8c656cef518336 Mon Sep 17 00:00:00 2001 From: bernatx Date: Tue, 5 Mar 2019 18:01:17 +0100 Subject: [PATCH] Added replayer speed (time factor for slow/fast motion) --- CHANGELOG.md | 2 + Docs/python_api.md | 1 + Docs/python_api_tutorial.md | 10 +++ LibCarla/source/carla/client/Client.h | 4 ++ .../source/carla/client/detail/Client.cpp | 4 ++ LibCarla/source/carla/client/detail/Client.h | 2 + .../source/carla/client/detail/Simulator.h | 4 ++ PythonAPI/carla/source/libcarla/Client.cpp | 1 + PythonAPI/examples/start_replaying.py | 7 ++ PythonAPI/set_replayer_speed.py | 70 +++++++++++++++++++ .../Source/Carla/Recorder/CarlaRecorder.cpp | 5 ++ .../Source/Carla/Recorder/CarlaRecorder.h | 1 + .../Source/Carla/Recorder/CarlaReplayer.cpp | 19 +++-- .../Source/Carla/Recorder/CarlaReplayer.h | 5 ++ .../Carla/Recorder/CarlaReplayerHelper.cpp | 20 ++++-- .../Source/Carla/Server/TheNewCarlaServer.cpp | 7 ++ 16 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 PythonAPI/set_replayer_speed.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c459fcd5..22a7daa45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## CARLA 0.9.5 + * Added playback speed (slow/fast motion) for the replayer + * We can use an absolute path for the recorded files (to choose where to 'write to' or 'read from') * New Town07, rural environment with narrow roads * Reworked OpenDRIVE parser and waypoints API - Fixed several situations in which the XODR was incorrectly parsed diff --git a/Docs/python_api.md b/Docs/python_api.md index ca93be48e..65e8c9c36 100644 --- a/Docs/python_api.md +++ b/Docs/python_api.md @@ -20,6 +20,7 @@ - `show_recorder_file_info(string filename)` - `show_recorder_collisions(string filename, char category1, char category2)` - `show_recorder_actors_blocked(string filename, float min_time, float min_distance)` +- `set_replayer_speed(float time_factor)` - `apply_batch(commands, do_tick=False)` - `apply_batch_sync(commands, do_tick=False) -> list(carla.command.Response)` diff --git a/Docs/python_api_tutorial.md b/Docs/python_api_tutorial.md index 3f332b4b8..37c12a852 100644 --- a/Docs/python_api_tutorial.md +++ b/Docs/python_api_tutorial.md @@ -449,6 +449,16 @@ client.replay_file("recording01.log", start, duration, camera) * **duration**: we can say how many seconds we want to play. If the simulation has not reached the end, then all actors will have autopilot enabled automatically. The intention here is to allow for replaying a piece of a simulation and then let all actors start driving in autopilot again. * **camera**: we can specify the Id of an actor and then the camera will follow that actor while replaying. Continue reading to know which Id has an actor. +We can specify the speed for the replayer at any moment, using the next API: + +```py +client.set_replayer_speed(2.0) +``` +A value greater than 1.0 will play in fast motion, and a value below 1.0 will play in slow motion, being 1.0 the default value for normal playback. +As a performance trick, with values over 2.0 the interpolation of positions is disabled. + +The call of this API will not stop the replayer in course, it will change just the speed, so you can change that several times while the replayer is running. + We can know details about a recorded simulation, using this API: ```py diff --git a/LibCarla/source/carla/client/Client.h b/LibCarla/source/carla/client/Client.h index fe248e97f..e4a169329 100644 --- a/LibCarla/source/carla/client/Client.h +++ b/LibCarla/source/carla/client/Client.h @@ -84,6 +84,10 @@ namespace client { return _simulator->ReplayFile(name, start, duration, follow_id); } + void SetReplayerSpeed(double time_factor) { + _simulator->SetReplayerSpeed(time_factor); + } + void ApplyBatch( std::vector commands, bool do_tick_cue = false) const { diff --git a/LibCarla/source/carla/client/detail/Client.cpp b/LibCarla/source/carla/client/detail/Client.cpp index 0c7ba2b79..70dc07703 100644 --- a/LibCarla/source/carla/client/detail/Client.cpp +++ b/LibCarla/source/carla/client/detail/Client.cpp @@ -291,6 +291,10 @@ namespace detail { return _pimpl->CallAndWait("replay_file", name, start, duration, follow_id); } + void Client::SetReplayerSpeed(double time_factor) { + _pimpl->AsyncCall("set_replayer_speed", time_factor); + } + void Client::SubscribeToStream( const streaming::Token &token, std::function callback) { diff --git a/LibCarla/source/carla/client/detail/Client.h b/LibCarla/source/carla/client/detail/Client.h index dcd021558..eca24ee47 100644 --- a/LibCarla/source/carla/client/detail/Client.h +++ b/LibCarla/source/carla/client/detail/Client.h @@ -182,6 +182,8 @@ namespace detail { std::string ReplayFile(std::string name, double start, double duration, uint32_t follow_id); + void SetReplayerSpeed(double time_factor); + void SubscribeToStream( const streaming::Token &token, std::function callback); diff --git a/LibCarla/source/carla/client/detail/Simulator.h b/LibCarla/source/carla/client/detail/Simulator.h index c468cff29..b3b9c3bde 100644 --- a/LibCarla/source/carla/client/detail/Simulator.h +++ b/LibCarla/source/carla/client/detail/Simulator.h @@ -293,6 +293,10 @@ namespace detail { return _client.ReplayFile(std::move(name), start, duration, follow_id); } + void SetReplayerSpeed(double time_factor) { + _client.SetReplayerSpeed(time_factor); + } + /// @} // ========================================================================= /// @name Operations with sensors diff --git a/PythonAPI/carla/source/libcarla/Client.cpp b/PythonAPI/carla/source/libcarla/Client.cpp index 146493ee3..4b51f5f20 100644 --- a/PythonAPI/carla/source/libcarla/Client.cpp +++ b/PythonAPI/carla/source/libcarla/Client.cpp @@ -68,6 +68,7 @@ void export_client() { .def("show_recorder_collisions", CALL_WITHOUT_GIL_3(cc::Client, ShowRecorderCollisions, std::string, char, char), (arg("name"), arg("type1"), arg("type2"))) .def("show_recorder_actors_blocked", CALL_WITHOUT_GIL_3(cc::Client, ShowRecorderActorsBlocked, std::string, float, float), (arg("name"), arg("min_time"), arg("min_distance"))) .def("replay_file", CALL_WITHOUT_GIL_4(cc::Client, ReplayFile, std::string, float, float, int), (arg("name"), arg("time_start"), arg("duration"), arg("follow_id"))) + .def("set_replayer_speed", &cc::Client::SetReplayerSpeed, (arg("time_factor"))) .def("apply_batch", &ApplyBatchCommands, (arg("commands"), arg("do_tick")=false)) .def("apply_batch_sync", &ApplyBatchCommandsSync, (arg("commands"), arg("do_tick")=false)) ; diff --git a/PythonAPI/examples/start_replaying.py b/PythonAPI/examples/start_replaying.py index a574ba0bb..75adc3a23 100755 --- a/PythonAPI/examples/start_replaying.py +++ b/PythonAPI/examples/start_replaying.py @@ -61,6 +61,12 @@ def main(): default=0, type=int, help='camera follows an actor (ex: 82)') + argparser.add_argument( + '-x', '--speed', + metavar='X', + default=1.0, + type=float, + help='time factor(default 1.0)') args = argparser.parse_args() try: @@ -68,6 +74,7 @@ def main(): client = carla.Client(args.host, args.port) client.set_timeout(60.0) + client.set_replayer_speed(args.speed) print(client.replay_file(args.recorder_filename, args.start, args.duration, args.camera)) finally: diff --git a/PythonAPI/set_replayer_speed.py b/PythonAPI/set_replayer_speed.py new file mode 100644 index 000000000..53f465a3c --- /dev/null +++ b/PythonAPI/set_replayer_speed.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +# 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 . + +import glob +import os +import sys + +try: + sys.path.append(glob.glob('**/*%d.%d-%s.egg' % ( + sys.version_info.major, + sys.version_info.minor, + 'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0]) +except IndexError: + pass + +import carla + +import argparse +import random +import time + + +def main(): + + argparser = argparse.ArgumentParser( + description=__doc__) + argparser.add_argument( + '--host', + metavar='H', + default='127.0.0.1', + help='IP of the host server (default: 127.0.0.1)') + argparser.add_argument( + '-p', '--port', + metavar='P', + default=2000, + type=int, + help='TCP port to listen to (default: 2000)') + argparser.add_argument( + '-x', '--speed', + metavar='X', + default=1.0, + type=float, + help='time factor(default 1.0)') + args = argparser.parse_args() + + try: + + client = carla.Client(args.host, args.port) + client.set_timeout(2.0) + + # client.load_world("Town03") + + client.set_replayer_speed(args.speed) + + finally: + pass + +if __name__ == '__main__': + + try: + main() + except KeyboardInterrupt: + pass + finally: + print('\ndone.') diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.cpp index 8a54fe0d7..fcfb557cc 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.cpp @@ -45,6 +45,11 @@ std::string ACarlaRecorder::ReplayFile(std::string Path, std::string Name, doubl return Replayer.ReplayFile(Path + Name, TimeStart, Duration, FollowId); } +inline void ACarlaRecorder::SetReplayerSpeed(double TimeFactor) +{ + return Replayer.SetSpeed(TimeFactor); +} + void ACarlaRecorder::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.h index 94a7943b6..9f77f933a 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaRecorder.h @@ -103,6 +103,7 @@ public: std::string ShowFileCollisions(std::string Path, std::string Name, char Type1, char Type2); std::string ShowFileActorsBlocked(std::string Path, std::string Name, double MinTime = 30, double MinDistance = 10); std::string ReplayFile(std::string Path, std::string Name, double TimeStart, double Duration, uint32_t FollowId); + void SetReplayerSpeed(double TimeFactor); void Tick(float DeltaSeconds) final; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.cpp index 24705fe2a..d02a8f4c8 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.cpp @@ -467,13 +467,18 @@ void CarlaReplayer::UpdatePositions(double Per) auto Result = TempMap.find(CurrPos[i].DatabaseId); if (Result != TempMap.end()) { - // interpolate - InterpolatePosition(PrevPos[Result->second], CurrPos[i], Per); + // check if time factor is high + if (TimeFactor >= 2.0) + // assign first position + InterpolatePosition(PrevPos[Result->second], CurrPos[i], 0.0); + else + // interpolate + InterpolatePosition(PrevPos[Result->second], CurrPos[i], Per); } else { // assign last position (we don't have previous one) - InterpolatePosition(CurrPos[i], CurrPos[i], 0); + InterpolatePosition(CurrPos[i], CurrPos[i], 0.0); } // move the camera to follow this actor if required @@ -502,8 +507,14 @@ void CarlaReplayer::Tick(float Delta) // check if there are events to process if (Enabled) { - ProcessToTime(Delta); + ProcessToTime(Delta * TimeFactor); } // UE_LOG(LogCarla, Log, TEXT("Replayer tick")); } + +// speed (time factor) +inline void CarlaReplayer::SetSpeed(double NewTimeFactor) +{ + TimeFactor = NewTimeFactor; +} \ No newline at end of file diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.h index a819d4721..e286eb245 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayer.h @@ -60,6 +60,9 @@ public: Helper.SetEpisode(ThisEpisode); } + // playback speed (time factor) + void SetSpeed(double NewTimeFactor); + // tick for the replayer void Tick(float Time); @@ -85,6 +88,8 @@ private: CarlaReplayerHelper Helper; // follow camera uint32_t FollowId; + // speed (time factor) + double TimeFactor { 1.0 }; // utils bool ReadHeader(); diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayerHelper.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayerHelper.cpp index 8dc74acc9..00b1ac5c2 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayerHelper.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Recorder/CarlaReplayerHelper.cpp @@ -228,11 +228,21 @@ bool CarlaReplayerHelper::ProcessReplayerPosition(CarlaRecorderPosition Pos1, Ca AActor *Actor = Episode->GetActorRegistry().Find(Pos1.DatabaseId).GetActor(); if (Actor && !Actor->IsPendingKill()) { - // interpolate transform - FVector Location = FMath::Lerp(FVector(Pos1.Location), FVector(Pos2.Location), Per); - FRotator Rotation = FMath::Lerp(FRotator::MakeFromEuler(Pos1.Rotation), FRotator::MakeFromEuler(Pos2.Rotation), Per); - FTransform Trans(Rotation, Location, FVector(1, 1, 1)); - Actor->SetActorTransform(Trans, false, nullptr, ETeleportType::TeleportPhysics); + // check to assign first position or interpolate between both + if (Per == 0.0) + { + // assign position 1 + FTransform Trans(FRotator::MakeFromEuler(Pos1.Rotation), FVector(Pos1.Location), FVector(1, 1, 1)); + Actor->SetActorTransform(Trans, false, nullptr, ETeleportType::TeleportPhysics); + } + else + { + // interpolate positions + FVector Location = FMath::Lerp(FVector(Pos1.Location), FVector(Pos2.Location), Per); + FRotator Rotation = FMath::Lerp(FRotator::MakeFromEuler(Pos1.Rotation), FRotator::MakeFromEuler(Pos2.Rotation), Per); + FTransform Trans(Rotation, Location, FVector(1, 1, 1)); + Actor->SetActorTransform(Trans, false, nullptr, ETeleportType::TeleportPhysics); + } // reset velocities ResetVelocities(Actor); return true; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp index ec36c6c69..cdfa8c706 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Server/TheNewCarlaServer.cpp @@ -761,6 +761,13 @@ void FTheNewCarlaServer::FPimpl::BindActions() follow_id)); }; + BIND_SYNC(set_replayer_speed) << [this](double time_factor) -> R + { + REQUIRE_CARLA_EPISODE(); + Episode->GetRecorder()->SetReplayerSpeed(time_factor); + return R::Success(); + }; + // ~~ Draw debug shapes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BIND_SYNC(draw_debug_shape) << [this](const cr::DebugShape &shape) -> R