Skip to content

Commit 2821296

Browse files
committed
feat(sim camera): allow camera render on demand
Currently the frames are rendered with a fixed frame rate, this can however slow down the simulation loop quite significantly. Therefore, this feature allows to render only at the time when an image is request. One can switch in this mode by setting frame rate to zero.
1 parent 5cc2455 commit 2821296

7 files changed

Lines changed: 44 additions & 18 deletions

File tree

python/rcsss/_core/sim.pyi

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,18 @@ class SimCameraSet:
159159

160160
class SimCameraSetConfig:
161161
cameras: dict[str, SimCameraConfig]
162-
frame_rate: int
163162
max_buffer_frames: int
164163
resolution_height: int
165164
resolution_width: int
166165
def __init__(self) -> None: ...
166+
@property
167+
def frame_rate(self) -> int:
168+
"""
169+
The frame rate in which the cameras render in Hz. If set to zero, the camera frames will render on demand and without fixed rate which takes away compute effort.
170+
"""
171+
172+
@frame_rate.setter
173+
def frame_rate(self, arg0: int) -> None: ...
167174

168175
def open_gui_window(uuid: str) -> None: ...
169176

python/rcsss/envs/factories.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def __call__( # type: ignore
241241
render_mode: str = "human",
242242
control_mode: ControlMode = ControlMode.CARTESIAN_TRPY,
243243
resolution: tuple[int, int] | None = None,
244-
frame_rate: int = 10,
244+
frame_rate: int = 0,
245245
delta_actions: bool = True,
246246
) -> gym.Env:
247247
if resolution is None:
@@ -272,7 +272,7 @@ def __call__( # type: ignore
272272
render_mode: str = "human",
273273
control_mode: ControlMode = ControlMode.CARTESIAN_TRPY,
274274
resolution: tuple[int, int] | None = None,
275-
frame_rate: int = 10,
275+
frame_rate: int = 0,
276276
delta_actions: bool = True,
277277
) -> gym.Env:
278278
if resolution is None:
@@ -319,7 +319,7 @@ def __call__( # type: ignore
319319
render_mode: str = "human",
320320
control_mode: ControlMode = ControlMode.CARTESIAN_TRPY,
321321
resolution: tuple[int, int] | None = None,
322-
frame_rate: int = 10,
322+
frame_rate: int = 0,
323323
delta_actions: bool = True,
324324
) -> gym.Env:
325325
if resolution is None:

src/pybind/rcsss.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,10 @@ PYBIND11_MODULE(_core, m) {
486486
py::class_<rcs::sim::SimCameraSetConfig>(sim, "SimCameraSetConfig")
487487
.def(py::init<>())
488488
.def_readwrite("cameras", &rcs::sim::SimCameraSetConfig::cameras)
489-
.def_readwrite("frame_rate", &rcs::sim::SimCameraSetConfig::frame_rate)
489+
.def_readwrite("frame_rate", &rcs::sim::SimCameraSetConfig::frame_rate,
490+
"The frame rate in which the cameras render in Hz. If set "
491+
"to zero, the camera frames will render on demand and "
492+
"without fixed rate which takes away compute effort.")
490493
.def_readwrite("resolution_width",
491494
&rcs::sim::SimCameraSetConfig::resolution_width)
492495
.def_readwrite("resolution_height",

src/sim/camera.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@ namespace sim {
2424
SimCameraSet::SimCameraSet(std::shared_ptr<Sim> sim, SimCameraSetConfig cfg)
2525
: sim{sim}, cfg{cfg}, buffer{}, buffer_lock{}, cameras{} {
2626
for (auto const& [id, cam] : cfg.cameras) {
27+
// if frame_rate is zero, then we only render when an image is requested
28+
// this mode is useful when no videos are required as it speeds up the
29+
// simulation significantly
2730
this->sim->register_rendering_callback(
2831
[this](const std::string& id, mjrContext& ctx, mjvScene& scene,
2932
mjvOption& opt) { this->frame_callback(id, ctx, scene, opt); },
30-
id, 1.0 / this->cfg.frame_rate, this->cfg.resolution_width,
33+
id, this->cfg.frame_rate, this->cfg.resolution_width,
3134
this->cfg.resolution_height);
3235

3336
mjvCamera mjcam;
@@ -57,6 +60,9 @@ void SimCameraSet::clear_buffer() {
5760
}
5861

5962
std::optional<FrameSet> SimCameraSet::get_latest_frameset() {
63+
if (this->cfg.frame_rate == 0) {
64+
this->render_all();
65+
}
6066
if (buffer.empty()) {
6167
return std::nullopt;
6268
}
@@ -73,6 +79,14 @@ std::optional<FrameSet> SimCameraSet::get_timestamp_frameset(float ts) {
7379
return std::nullopt;
7480
}
7581

82+
void SimCameraSet::render_all() {
83+
for (auto const& [id, cam] : this->cfg.cameras) {
84+
mjrContext* ctx = this->sim->renderer.get_context(id);
85+
this->frame_callback(id, *ctx, this->sim->renderer.scene,
86+
this->sim->renderer.opt);
87+
}
88+
}
89+
7690
void SimCameraSet::frame_callback(const std::string& id, mjrContext& ctx,
7791
mjvScene& scene, mjvOption& opt) {
7892
mjrRect viewport = mjr_maxViewport(&ctx);

src/sim/camera.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class SimCameraSet {
6666
std::unordered_map<std::string, mjvCamera> cameras;
6767
std::mutex buffer_lock;
6868
mjtNum last_ts = 0;
69+
void render_all();
6970
};
7071
} // namespace sim
7172
} // namespace rcs

src/sim/sim.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,19 @@ void Sim::register_all_cb(std::function<bool(void)> cb,
164164
void Sim::register_rendering_callback(
165165
std::function<void(const std::string&, mjrContext&, mjvScene&, mjvOption&)>
166166
cb,
167-
const std::string& id, mjtNum seconds_between_calls, size_t width,
168-
size_t height) {
167+
const std::string& id, int frame_rate, size_t width, size_t height) {
169168
this->renderer.register_context(id, width, height);
170-
// dont register off screen in normal callback, but special gui callback
171-
this->rendering_callbacks.push_back(
172-
RenderingCallback{.cb = cb,
173-
.id = id,
174-
.seconds_between_calls = seconds_between_calls,
175-
// this is negative so that we will directly render the
176-
// cameras in the first step
177-
.last_call_timestamp = -seconds_between_calls});
169+
// in case frame_rate is zero, rendering needs to be triggered
170+
// manually
171+
if (frame_rate != 0) {
172+
this->rendering_callbacks.push_back(
173+
RenderingCallback{.cb = cb,
174+
.id = id,
175+
.seconds_between_calls = 1.0 / frame_rate,
176+
// this is negative so that we will directly render
177+
// the cameras in the first step
178+
.last_call_timestamp = -1.0 / frame_rate});
179+
}
178180
}
179181

180182
void Sim::start_gui_server(const std::string& id) {

src/sim/sim.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ class Sim {
9898
std::function<void(const std::string& id, mjrContext&, mjvScene&,
9999
mjvOption&)>
100100
cb,
101-
const std::string& id, mjtNum seconds_between_calls, size_t width,
102-
size_t height);
101+
const std::string& id, int frame_rate, size_t width, size_t height);
103102
void start_gui_server(const std::string& id);
104103
void stop_gui_server();
105104
};

0 commit comments

Comments
 (0)