Add on_tick event

This commit is contained in:
nsubiron 2018-10-21 16:49:43 +02:00
parent aa83b8abf8
commit b80f70b8b9
10 changed files with 103 additions and 25 deletions

View File

@ -25,6 +25,7 @@
- `spawn_actor(blueprint, transform, attach_to=None)`
- `try_spawn_actor(blueprint, transform, attach_to=None)`
- `wait_for_tick(seconds=1.0)`
- `on_tick(callback)`
## `carla.BlueprintLibrary`

View File

@ -74,5 +74,9 @@ namespace client {
return _episode.Lock()->WaitForTick(timeout);
}
void World::OnTick(std::function<void(Timestamp)> callback) {
return _episode.Lock()->RegisterOnTickEvent(std::move(callback));
}
} // namespace client
} // namespace carla

View File

@ -58,6 +58,8 @@ namespace client {
Timestamp WaitForTick(time_duration timeout) const;
void OnTick(std::function<void(Timestamp)> callback);
private:
detail::EpisodeProxy _episode;

View File

@ -0,0 +1,50 @@
// 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 <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/AtomicSharedPtr.h"
#include "carla/NonCopyable.h"
#include <functional>
#include <vector>
namespace carla {
namespace client {
namespace detail {
template <typename... InputsT>
class CallbackList : private NonCopyable {
public:
using CallbackType = std::function<void(InputsT...)>;
CallbackList() : _list(std::make_shared<ListType>()) {}
void Call(InputsT... args) const {
auto list = _list.load();
for (auto &callback : *list) {
callback(args...);
}
}
/// @todo This function cannot be called concurrently.
void RegisterCallback(CallbackType callback) {
auto new_list = std::make_shared<ListType>(*_list.load());
new_list->emplace_back(std::move(callback));
_list = new_list;
}
private:
using ListType = std::vector<CallbackType>;
AtomicSharedPtr<const ListType> _list;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -39,6 +39,7 @@ namespace detail {
/// @todo Check that this state occurred after.
self->_state = next;
self->_timestamp.SetValue(next->GetTimestamp());
self->_on_tick_callbacks.Call(next->GetTimestamp());
}
});
}

View File

@ -11,6 +11,7 @@
#include "carla/RecurrentSharedFuture.h"
#include "carla/client/Timestamp.h"
#include "carla/client/detail/CachedActorList.h"
#include "carla/client/detail/CallbackList.h"
#include "carla/client/detail/EpisodeState.h"
#include "carla/rpc/EpisodeInfo.h"
@ -32,10 +33,6 @@ namespace detail {
void Listen();
Timestamp WaitForState(time_duration timeout) {
return _timestamp.WaitFor(timeout);
}
auto GetId() const {
return _description.id;
}
@ -56,6 +53,14 @@ namespace detail {
std::vector<rpc::Actor> GetActors();
Timestamp WaitForState(time_duration timeout) {
return _timestamp.WaitFor(timeout);
}
void RegisterOnTickEvent(std::function<void(Timestamp)> callback) {
_on_tick_callbacks.RegisterCallback(std::move(callback));
}
private:
Client &_client;
@ -67,6 +72,8 @@ namespace detail {
AtomicSharedPtr<const EpisodeState> _state;
CachedActorList _actors;
CallbackList<Timestamp> _on_tick_callbacks;
};
} // namespace detail

View File

@ -106,6 +106,11 @@ namespace detail {
return _episode->WaitForState(timeout);
}
void RegisterOnTickEvent(std::function<void(Timestamp)> callback) {
DEBUG_ASSERT(_episode != nullptr);
_episode->RegisterOnTickEvent(std::move(callback));
}
/// @}
// =========================================================================
/// @name Access to global objects in the episode

View File

@ -8,27 +8,7 @@
#include <carla/client/Sensor.h>
static void SubscribeToStream(carla::client::Sensor &self, boost::python::object callback) {
namespace py = boost::python;
// Make sure the callback is actually callable.
if (!PyCallable_Check(callback.ptr())) {
PyErr_SetString(PyExc_TypeError, "callback argument must be callable!");
py::throw_error_already_set();
return;
}
// We need to delete the callback while holding the GIL.
using Deleter = carla::PythonUtil::AcquireGILDeleter;
auto callback_ptr = carla::SharedPtr<py::object>{new py::object(callback), Deleter()};
// Subscribe to the sensor.
self.Listen([callback=std::move(callback_ptr)](auto message) {
carla::PythonUtil::AcquireGIL lock;
try {
py::call<void>(callback->ptr(), py::object(message));
} catch (const py::error_already_set &e) {
PyErr_Print();
}
});
self.Listen(MakeCallback(std::move(callback)));
}
void export_sensor() {

View File

@ -39,6 +39,10 @@ static auto WaitForTick(const carla::client::World &world, double seconds) {
return world.WaitForTick(TimeDurationFromSeconds(seconds));
}
static void OnTick(carla::client::World &self, boost::python::object callback) {
self.OnTick(MakeCallback(std::move(callback)));
}
void export_world() {
using namespace boost::python;
namespace cc = carla::client;
@ -88,6 +92,7 @@ void export_world() {
.def("try_spawn_actor", SPAWN_ACTOR_WITHOUT_GIL(TrySpawnActor))
.def("spawn_actor", SPAWN_ACTOR_WITHOUT_GIL(SpawnActor))
.def("wait_for_tick", &WaitForTick, (arg("seconds")=1.0))
.def("on_tick", &OnTick, (arg("callback")))
.def(self_ns::str(self_ns::self))
;

View File

@ -66,6 +66,29 @@ static carla::time_duration TimeDurationFromSeconds(double seconds) {
return carla::time_duration::milliseconds(ms);
}
static auto MakeCallback(boost::python::object callback) {
namespace py = boost::python;
// Make sure the callback is actually callable.
if (!PyCallable_Check(callback.ptr())) {
PyErr_SetString(PyExc_TypeError, "callback argument must be callable!");
py::throw_error_already_set();
}
// We need to delete the callback while holding the GIL.
using Deleter = carla::PythonUtil::AcquireGILDeleter;
auto callback_ptr = carla::SharedPtr<py::object>{new py::object(callback), Deleter()};
// Make a lambda callback.
return [callback=std::move(callback_ptr)](auto message) {
carla::PythonUtil::AcquireGIL lock;
try {
py::call<void>(callback->ptr(), py::object(message));
} catch (const py::error_already_set &e) {
PyErr_Print();
}
};
}
#include "Actor.cpp"
#include "Blueprint.cpp"
#include "Client.cpp"