simulate python: fix cmake, glfw usage, update Python version of physics loop
This commit is contained in:
@@ -62,7 +62,6 @@ add_compile_options("${MUJOCO_HARDEN_COMPILE_OPTIONS}")
|
|||||||
add_link_options("${MUJOCO_HARDEN_LINK_OPTIONS}")
|
add_link_options("${MUJOCO_HARDEN_LINK_OPTIONS}")
|
||||||
|
|
||||||
find_package(Python3 COMPONENTS Interpreter Development)
|
find_package(Python3 COMPONENTS Interpreter Development)
|
||||||
find_package(glfw3 3.3 REQUIRED)
|
|
||||||
|
|
||||||
include(FindOrFetch)
|
include(FindOrFetch)
|
||||||
|
|
||||||
@@ -116,37 +115,37 @@ if(NOT TARGET mujoco)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ==================== MJSIMULATE LIBRARY ==========================================
|
# ==================== LIBSIMULATE LIBRARY ==========================================
|
||||||
if(NOT TARGET mjsimulate)
|
if(NOT TARGET libsimulate)
|
||||||
find_library(MJSIMULATE_LIBRARY mjsimulate mjsimulate HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED)
|
find_library(LIBSIMULATE_LIBRARY libsimulate libsimulate HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED)
|
||||||
find_path(MJSIMULATE_INCLUDE mujoco/simulate.h mujoco/uitools.h mujoco/array_safety.h HINTS ${MUJOCO_INCLUDE_DIR} REQUIRED)
|
find_path(LIBSIMULATE_INCLUDE mujoco/simulate.h mujoco/uitools.h mujoco/array_safety.h HINTS ${MUJOCO_INCLUDE_DIR} REQUIRED)
|
||||||
message("MuJoCo Simulate is at ${MJSIMULATE_LIBRARY}")
|
message("MuJoCo Simulate is at ${LIBSIMULATE_LIBRARY}")
|
||||||
message("MuJoCo Simulate headers are at ${MJSIMULATE_INCLUDE}")
|
message("MuJoCo Simulate headers are at ${LIBSIMULATE_INCLUDE}")
|
||||||
add_library(mjsimulate SHARED IMPORTED)
|
add_library(libsimulate SHARED IMPORTED)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set_target_properties(mjsimulate PROPERTIES IMPORTED_IMPLIB "${MJSIMULATE_LIBRARY}")
|
set_target_properties(libsimulate PROPERTIES IMPORTED_IMPLIB "${LIBSIMULATE_LIBRARY}")
|
||||||
else()
|
else()
|
||||||
set_target_properties(mjsimulate PROPERTIES IMPORTED_LOCATION "${MJSIMULATE_LIBRARY}")
|
set_target_properties(libsimulate PROPERTIES IMPORTED_LOCATION "${LIBSIMULATE_LIBRARY}")
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(mjsimulate INTERFACE "${MJSIMULATE_INCLUDE}")
|
target_include_directories(libsimulate INTERFACE "${LIBSIMULATE_INCLUDE}")
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND otool -XD ${MJSIMULATE_LIBRARY}
|
COMMAND otool -XD ${LIBSIMULATE_LIBRARY}
|
||||||
COMMAND head -n 1
|
COMMAND head -n 1
|
||||||
COMMAND xargs dirname
|
COMMAND xargs dirname
|
||||||
COMMAND xargs echo -n
|
COMMAND xargs echo -n
|
||||||
OUTPUT_VARIABLE MJSIMULATE_INSTALL_NAME_DIR
|
OUTPUT_VARIABLE LIBSIMULATE_INSTALL_NAME_DIR
|
||||||
)
|
)
|
||||||
set_target_properties(mjsimulate PROPERTIES INSTALL_NAME_DIR "${MJSIMULATE_INSTALL_NAME_DIR}")
|
set_target_properties(libsimulate PROPERTIES INSTALL_NAME_DIR "${LIBSIMULATE_INSTALL_NAME_DIR}")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND objdump -p ${MJSIMULATE_LIBRARY}
|
COMMAND objdump -p ${LIBSIMULATE_LIBRARY}
|
||||||
COMMAND grep SONAME
|
COMMAND grep SONAME
|
||||||
COMMAND grep -Po [^\\s]+$
|
COMMAND grep -Po [^\\s]+$
|
||||||
COMMAND xargs echo -n
|
COMMAND xargs echo -n
|
||||||
OUTPUT_VARIABLE MJSIMULATE_SONAME
|
OUTPUT_VARIABLE LIBSIMULATE_SONAME
|
||||||
)
|
)
|
||||||
set_target_properties(mjsimulate PROPERTIES IMPORTED_SONAME "${MJSIMULATE_SONAME}")
|
set_target_properties(libsimulate PROPERTIES IMPORTED_SONAME "${LIBSIMULATE_SONAME}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -266,7 +265,7 @@ target_link_libraries(errors_header INTERFACE crossplatform func_wrap mujoco)
|
|||||||
add_library(raw INTERFACE)
|
add_library(raw INTERFACE)
|
||||||
target_sources(raw INTERFACE raw.h)
|
target_sources(raw INTERFACE raw.h)
|
||||||
set_target_properties(raw PROPERTIES PUBLIC_HEADER raw.h)
|
set_target_properties(raw PROPERTIES PUBLIC_HEADER raw.h)
|
||||||
target_link_libraries(raw INTERFACE mujoco mjsimulate)
|
target_link_libraries(raw INTERFACE mujoco)
|
||||||
|
|
||||||
add_library(structs_header INTERFACE)
|
add_library(structs_header INTERFACE)
|
||||||
target_sources(
|
target_sources(
|
||||||
@@ -344,7 +343,7 @@ target_link_libraries(
|
|||||||
)
|
)
|
||||||
|
|
||||||
mujoco_pybind11_module(_constants constants.cc)
|
mujoco_pybind11_module(_constants constants.cc)
|
||||||
target_link_libraries(_constants PRIVATE mujoco mjsimulate)
|
target_link_libraries(_constants PRIVATE mujoco)
|
||||||
|
|
||||||
mujoco_pybind11_module(_enums enums.cc)
|
mujoco_pybind11_module(_enums enums.cc)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
@@ -408,10 +407,9 @@ target_link_libraries(
|
|||||||
mujoco_pybind11_module(_simulate simulate.cc)
|
mujoco_pybind11_module(_simulate simulate.cc)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
_simulate
|
_simulate
|
||||||
PRIVATE mjsimulate
|
PRIVATE libsimulate
|
||||||
mujoco
|
mujoco
|
||||||
raw
|
raw
|
||||||
glfw
|
|
||||||
structs_header)
|
structs_header)
|
||||||
target_link_options(_simulate PRIVATE -Wl,-no-as-needed)
|
target_link_options(_simulate PRIVATE -Wl,-no-as-needed)
|
||||||
|
|
||||||
@@ -426,7 +424,7 @@ set(LIBRARIES_FOR_WHEEL
|
|||||||
"$<TARGET_FILE:_simulate>"
|
"$<TARGET_FILE:_simulate>"
|
||||||
"$<TARGET_FILE:_structs>"
|
"$<TARGET_FILE:_structs>"
|
||||||
"$<TARGET_FILE:mujoco>"
|
"$<TARGET_FILE:mujoco>"
|
||||||
"$<TARGET_FILE:mjsimulate>"
|
"$<TARGET_FILE:libsimulate>"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(MUJOCO_PYTHON_MAKE_WHEEL)
|
if(MUJOCO_PYTHON_MAKE_WHEEL)
|
||||||
@@ -455,6 +453,6 @@ if(MUJOCO_PYTHON_MAKE_WHEEL)
|
|||||||
_simulate
|
_simulate
|
||||||
_structs
|
_structs
|
||||||
mujoco
|
mujoco
|
||||||
mjsimulate
|
libsimulate
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <mujoco/mjmodel.h>
|
#include <mujoco/mjmodel.h>
|
||||||
#include <mujoco/simulate.h>
|
|
||||||
#include <mujoco/mjvisualize.h>
|
#include <mujoco/mjvisualize.h>
|
||||||
#include <mujoco/mujoco.h>
|
#include <mujoco/mujoco.h>
|
||||||
#include <pybind11/cast.h>
|
#include <pybind11/cast.h>
|
||||||
@@ -79,9 +78,6 @@ PYBIND11_MODULE(_constants, pymodule) {
|
|||||||
// from mujoco.h
|
// from mujoco.h
|
||||||
X(mjVERSION_HEADER);
|
X(mjVERSION_HEADER);
|
||||||
|
|
||||||
// from simulate.h
|
|
||||||
X(mujoco::Simulate::kMaxFilenameLength);
|
|
||||||
|
|
||||||
#undef X
|
#undef X
|
||||||
pymodule.attr("mjDISABLESTRING") = MakeTuple(mjDISABLESTRING);
|
pymodule.attr("mjDISABLESTRING") = MakeTuple(mjDISABLESTRING);
|
||||||
pymodule.attr("mjENABLESTRING") = MakeTuple(mjENABLESTRING);
|
pymodule.attr("mjENABLESTRING") = MakeTuple(mjENABLESTRING);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include <mujoco/mjmodel.h>
|
#include <mujoco/mjmodel.h>
|
||||||
#include <mujoco/mjrender.h>
|
#include <mujoco/mjrender.h>
|
||||||
#include <mujoco/mjvisualize.h>
|
#include <mujoco/mjvisualize.h>
|
||||||
#include <mujoco/simulate.h>
|
|
||||||
|
|
||||||
// Type aliases for MuJoCo C structs to allow us refer to consistently refer
|
// Type aliases for MuJoCo C structs to allow us refer to consistently refer
|
||||||
// to them under the "raw" namespace.
|
// to them under the "raw" namespace.
|
||||||
@@ -56,9 +55,6 @@ using MjvOption = ::mjvOption;
|
|||||||
using MjvScene = ::mjvScene;
|
using MjvScene = ::mjvScene;
|
||||||
using MjvFigure = ::mjvFigure;
|
using MjvFigure = ::mjvFigure;
|
||||||
|
|
||||||
// From simulate.h
|
|
||||||
using Simulate = ::mujoco::Simulate;
|
|
||||||
|
|
||||||
} // namespace mujoco::raw
|
} // namespace mujoco::raw
|
||||||
|
|
||||||
#endif // MUJOCO_PYTHON_RAW_H_
|
#endif // MUJOCO_PYTHON_RAW_H_
|
||||||
|
|||||||
+32
-38
@@ -34,107 +34,101 @@ namespace {
|
|||||||
|
|
||||||
namespace py = ::pybind11;
|
namespace py = ::pybind11;
|
||||||
|
|
||||||
const auto simulate_doc = R"(
|
|
||||||
Python wrapper for the Simulate class
|
|
||||||
)";
|
|
||||||
|
|
||||||
// We define SimulateWrapper here instead of in structs because
|
|
||||||
// we do not want to make _structs dependent on gflw
|
|
||||||
|
|
||||||
PYBIND11_MODULE(_simulate, pymodule) {
|
PYBIND11_MODULE(_simulate, pymodule) {
|
||||||
namespace py = ::pybind11;
|
namespace py = ::pybind11;
|
||||||
|
|
||||||
py::class_<mujoco::raw::Simulate>(pymodule, "Simulate")
|
py::class_<mujoco::Simulate>(pymodule, "Simulate")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def("renderloop",
|
.def("renderloop",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
simulate.renderloop();
|
simulate.renderloop();
|
||||||
},
|
},
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
.def("load",
|
.def("load",
|
||||||
[](mujoco::raw::Simulate& simulate, std::string filename, const MjModelWrapper& m, MjDataWrapper& d, bool delete_old_m_d) {
|
[](mujoco::Simulate& simulate, std::string filename, const MjModelWrapper& m, MjDataWrapper& d) {
|
||||||
const raw::MjModel* m_ptr = m.get();
|
const raw::MjModel* m_ptr = m.get();
|
||||||
raw::MjData* d_ptr = d.get();
|
raw::MjData* d_ptr = d.get();
|
||||||
simulate.load(filename.c_str(), (mjModel*)m_ptr, d_ptr, delete_old_m_d);
|
simulate.load(filename.c_str(), (mjModel*)m_ptr, d_ptr);
|
||||||
},
|
},
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
.def("applyposepertubations", &mujoco::raw::Simulate::applyposepertubations)
|
.def("applyposepertubations", &mujoco::Simulate::applyposepertubations)
|
||||||
.def("applyforceperturbations", &mujoco::raw::Simulate::applyforceperturbations)
|
.def("applyforceperturbations", &mujoco::Simulate::applyforceperturbations)
|
||||||
|
|
||||||
.def("lock", // TODO wrap mutex properly as as seperate pybind11 object?
|
.def("lock", // TODO wrap mutex properly as as seperate pybind11 object?
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
simulate.mtx.lock();
|
simulate.mtx.lock();
|
||||||
},
|
},
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
.def("unlock",
|
.def("unlock",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
simulate.mtx.unlock();
|
simulate.mtx.unlock();
|
||||||
},
|
},
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
.def_readwrite("ctrlnoisestd", &mujoco::raw::Simulate::ctrlnoisestd)
|
.def_readwrite("ctrlnoisestd", &mujoco::Simulate::ctrlnoisestd)
|
||||||
.def_readwrite("ctrlnoiserate", &mujoco::raw::Simulate::ctrlnoiserate)
|
.def_readwrite("ctrlnoiserate", &mujoco::Simulate::ctrlnoiserate)
|
||||||
.def_readwrite("slow_down", &mujoco::raw::Simulate::slow_down)
|
|
||||||
.def_readwrite("speed_changed", &mujoco::raw::Simulate::speed_changed)
|
.def_readwrite("realtimeindex", &mujoco::Simulate::realTimeIndex)
|
||||||
.def("getrefreshRate",
|
.def_readwrite("speedchanged", &mujoco::Simulate::speedChanged)
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
.def_readwrite("measuredslowdown", &mujoco::Simulate::measuredSlowdown)
|
||||||
return simulate.vmode.refreshRate;
|
.def_readwrite("refreshrate", &mujoco::Simulate::refreshRate)
|
||||||
})
|
|
||||||
|
.def_readwrite("busywait", &mujoco::Simulate::busywait)
|
||||||
|
.def_readwrite("run", &mujoco::Simulate::run)
|
||||||
|
|
||||||
.def_readwrite("busywait", &mujoco::raw::Simulate::busywait)
|
|
||||||
.def_readwrite("run", &mujoco::raw::Simulate::run)
|
|
||||||
//.def_readwrite("exitrequest", &mujoco::raw::Simulate::exitrequest)
|
|
||||||
.def("getexitrequest",
|
.def("getexitrequest",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
return simulate.exitrequest.load();
|
return simulate.exitrequest.load();
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("setexitrequest",
|
.def("setexitrequest",
|
||||||
[](mujoco::raw::Simulate& simulate, bool exitrequest) {
|
[](mujoco::Simulate& simulate, bool exitrequest) {
|
||||||
simulate.exitrequest.store(exitrequest);
|
simulate.exitrequest.store(exitrequest);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// .def_readwrite("uiloadrequest", &mujoco::raw::Simulate::uiloadrequest)
|
|
||||||
.def("getuiloadrequest",
|
.def("getuiloadrequest",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
return simulate.uiloadrequest.load();
|
return simulate.uiloadrequest.load();
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("setuiloadrequest",
|
.def("setuiloadrequest",
|
||||||
[](mujoco::raw::Simulate& simulate, int uiloadrequest) {
|
[](mujoco::Simulate& simulate, int uiloadrequest) {
|
||||||
simulate.uiloadrequest.store(uiloadrequest);
|
simulate.uiloadrequest.store(uiloadrequest);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("uiloadrequest_fetch_sub",
|
.def("uiloadrequest_fetch_sub",
|
||||||
[](mujoco::raw::Simulate& simulate, int arg) {
|
[](mujoco::Simulate& simulate, int arg) {
|
||||||
simulate.uiloadrequest.fetch_sub(arg);
|
simulate.uiloadrequest.fetch_sub(arg);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// .def_readwrite("droploadrequest", &mujoco::raw::Simulate::droploadrequest)
|
|
||||||
.def("getdroploadrequest",
|
.def("getdroploadrequest",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
return simulate.droploadrequest.load();
|
return simulate.droploadrequest.load();
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("setdroploadrequest",
|
.def("setdroploadrequest",
|
||||||
[](mujoco::raw::Simulate& simulate, bool droploadrequest) {
|
[](mujoco::Simulate& simulate, bool droploadrequest) {
|
||||||
simulate.droploadrequest.store(droploadrequest);
|
simulate.droploadrequest.store(droploadrequest);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("getdropfilename",
|
.def("getdropfilename",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
return (char*)simulate.dropfilename;
|
return (char*)simulate.dropfilename;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("getfilename",
|
.def("getfilename",
|
||||||
[](mujoco::raw::Simulate& simulate) {
|
[](mujoco::Simulate& simulate) {
|
||||||
return (char*)simulate.filename;
|
return (char*)simulate.filename;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.def("setloadError",
|
.def("setloadError",
|
||||||
[](mujoco::raw::Simulate& simulate, std::string& loadError) {
|
[](mujoco::Simulate& simulate, std::string& loadError) {
|
||||||
strncpy(simulate.loadError, loadError.c_str(), simulate.kMaxFilenameLength);
|
strncpy(simulate.loadError, loadError.c_str(), simulate.kMaxFilenameLength);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pymodule.def("setglfwdlhandle", [](std::uintptr_t dlhandle) { mujoco::setglfwdlhandle(reinterpret_cast<void*>(dlhandle)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
+55
-26
@@ -18,6 +18,9 @@ import mujoco
|
|||||||
from mujoco import _simulate
|
from mujoco import _simulate
|
||||||
|
|
||||||
import glfw
|
import glfw
|
||||||
|
from glfw import _glfw
|
||||||
|
_simulate.setglfwdlhandle(_glfw._handle)
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
@@ -29,6 +32,14 @@ class Simulate(_simulate.Simulate):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
# logarithmically spaced realtime slow-down coefficients (percent)
|
||||||
|
self.percentrealtime = [
|
||||||
|
100, 80, 66, 50, 40, 33, 25, 20, 16, 13,
|
||||||
|
10, 8, 6.6, 5.0, 4, 3.3, 2.5, 2, 1.6, 1.3,
|
||||||
|
1, .8, .66, .5, .4, .33, .25, .2, .16, .13,
|
||||||
|
.1
|
||||||
|
]
|
||||||
|
|
||||||
def _get_refreshRate(self):
|
def _get_refreshRate(self):
|
||||||
return self.getrefreshRate()
|
return self.getrefreshRate()
|
||||||
|
|
||||||
@@ -107,14 +118,14 @@ def load_and_step_model(m, d, simulate, filename, preload_callback=None, load_ca
|
|||||||
|
|
||||||
if mnew is not None:
|
if mnew is not None:
|
||||||
dnew = mujoco.MjData(mnew)
|
dnew = mujoco.MjData(mnew)
|
||||||
simulate.load(filename, mnew, dnew, False)
|
simulate.load(filename, mnew, dnew)
|
||||||
mujoco.mj_forward(mnew, dnew)
|
mujoco.mj_forward(mnew, dnew)
|
||||||
else:
|
else:
|
||||||
mnew = None
|
mnew = None
|
||||||
dnew = None
|
dnew = None
|
||||||
|
|
||||||
if load_callback is not None:
|
if load_callback is not None:
|
||||||
load_callback(mnew, dnew, loadError)
|
load_callback(mnew, dnew)
|
||||||
|
|
||||||
return mnew, dnew, loadError
|
return mnew, dnew, loadError
|
||||||
|
|
||||||
@@ -132,11 +143,11 @@ def run_physics_loop(simulate, preload_callback=None, load_callback=None, file=N
|
|||||||
|
|
||||||
# constants
|
# constants
|
||||||
syncmisalign = 0.1 # maximum time mis-alignment before re-sync
|
syncmisalign = 0.1 # maximum time mis-alignment before re-sync
|
||||||
refreshfactor = 0.7 # fraction of refresh available for simulation
|
simrefreshfraction = 0.7 # fraction of refresh available for simulation
|
||||||
|
|
||||||
# cpu-sim synchronization point
|
# cpu-sim synchronization point
|
||||||
cpusync = 0.0
|
synccpu = 0.0
|
||||||
simsync = 0.0
|
syncsim = 0.0
|
||||||
|
|
||||||
# run until asked to exit
|
# run until asked to exit
|
||||||
while not simulate.exitrequest:
|
while not simulate.exitrequest:
|
||||||
@@ -144,7 +155,6 @@ def run_physics_loop(simulate, preload_callback=None, load_callback=None, file=N
|
|||||||
simulate.droploadrequest = 0
|
simulate.droploadrequest = 0
|
||||||
m_, d_, loadError = load_and_step_model(m, d, simulate, simulate.dropfilename,
|
m_, d_, loadError = load_and_step_model(m, d, simulate, simulate.dropfilename,
|
||||||
preload_callback, load_callback)
|
preload_callback, load_callback)
|
||||||
|
|
||||||
if m_ is not None:
|
if m_ is not None:
|
||||||
m = m_
|
m = m_
|
||||||
d = d_
|
d = d_
|
||||||
@@ -178,28 +188,36 @@ def run_physics_loop(simulate, preload_callback=None, load_callback=None, file=N
|
|||||||
# running
|
# running
|
||||||
if simulate.run != 0:
|
if simulate.run != 0:
|
||||||
# record cpu time at start of iteration
|
# record cpu time at start of iteration
|
||||||
tmstart = glfw.get_time()
|
startcpu = glfw.get_time()
|
||||||
|
|
||||||
|
elapsedcpu = startcpu - synccpu
|
||||||
|
elapsedsim = d.time - syncsim
|
||||||
|
|
||||||
# inject noise
|
# inject noise
|
||||||
if simulate.ctrlnoisestd != 0.0:
|
if simulate.ctrlnoisestd != 0.0:
|
||||||
# convert rate and scale to discrete time given current timestep
|
# convert rate and scale to discrete time (Ornstein–Uhlenbeck)
|
||||||
rate = math.exp(-m.opt.timestep / simulate.ctrlnoiserate)
|
rate = math.exp(-m.opt.timestep / simulate.ctrlnoiserate)
|
||||||
scale = simulate.ctrlnoisestd * math.sqrt(1-rate*rate)
|
scale = simulate.ctrlnoisestd * math.sqrt(1-rate*rate)
|
||||||
|
|
||||||
for i in range(m.nu):
|
for i in range(m.nu):
|
||||||
# update noise
|
# update noise
|
||||||
ctrlnoise[i] = rate * ctrlnoise[i] + scale * mujoco.mju_standardNormal(None)
|
ctrlnoise[i] = rate * ctrlnoise[i] + scale * mujoco.mju_standardNormal(None)
|
||||||
|
|
||||||
# apply noise
|
# apply noise
|
||||||
d.ctrl[i] = ctrlnoise[i]
|
d.ctrl[i] = ctrlnoise[i]
|
||||||
|
|
||||||
# out-of-sync (for any reason)
|
# requested slow-down factor
|
||||||
offset = abs((d.time*simulate.slow_down - simsync) - (tmstart - cpusync))
|
slowdown = 100 / simulate.percentrealtime[simulate.realtimeindex]
|
||||||
if (d.time*simulate.slow_down < simsync or tmstart < cpusync or cpusync == 0.0 or
|
|
||||||
offset > syncmisalign*simulate.slow_down or simulate.speed_changed):
|
# misalignment condition: distance from target sim time is bigger than syncmisalign
|
||||||
|
misaligned = abs(elapsedcpu/slowdown - elapsedsim) > syncmisalign
|
||||||
|
|
||||||
|
# out-of-sync (for any reason): reset sync times, step
|
||||||
|
if elapsedsim < 0 or elapsedcpu < 0 or synccpu == 0 or misaligned or simulate.speedchanged:
|
||||||
# re-sync
|
# re-sync
|
||||||
cpusync = tmstart
|
synccpu = startcpu
|
||||||
simsync = d.time*simulate.slow_down
|
syncsim = d.time
|
||||||
simulate.speed_changed = False
|
simulate.speedchanged = False
|
||||||
|
|
||||||
# clear old perturbations, apply new
|
# clear old perturbations, apply new
|
||||||
d.xfrc_applied[:, :] = 0
|
d.xfrc_applied[:, :] = 0
|
||||||
@@ -209,21 +227,30 @@ def run_physics_loop(simulate, preload_callback=None, load_callback=None, file=N
|
|||||||
# run single step, let next iteration deal with timing
|
# run single step, let next iteration deal with timing
|
||||||
mujoco.mj_step(m, d)
|
mujoco.mj_step(m, d)
|
||||||
|
|
||||||
# in-sync
|
# in-sync: step until ahead of cpu
|
||||||
else:
|
else:
|
||||||
while ((d.time*simulate.slow_down - simsync) < (glfw.get_time() - cpusync) and
|
measured = False
|
||||||
(glfw.get_time() - tmstart) < (refreshfactor/simulate.refreshRate)):
|
prevsim = d.time
|
||||||
|
refreshtime = simrefreshfraction/simulate.refreshrate;
|
||||||
|
|
||||||
|
# step while sim lags behind cpu and within refreshtime
|
||||||
|
while (((d.time - syncsim)*slowdown < (glfw.get_time() - synccpu))
|
||||||
|
and ((glfw.get_time() - startcpu) < refreshtime)):
|
||||||
|
# measure slowdown before first step
|
||||||
|
if not measured and elapsedsim:
|
||||||
|
simulate.measuredslowdown = elapsedcpu / elapsedsim
|
||||||
|
measured = True
|
||||||
|
|
||||||
# clear old perturbations, apply new
|
# clear old perturbations, apply new
|
||||||
d.xfrc_applied[:, :] = 0
|
d.xfrc_applied[:, :] = 0
|
||||||
simulate.applyposepertubations(0) # move mocap bodies only
|
simulate.applyposepertubations(0) # move mocap bodies only
|
||||||
simulate.applyforceperturbations()
|
simulate.applyforceperturbations()
|
||||||
|
|
||||||
# run mj_step
|
# call mj_step
|
||||||
prevtm = d.time*simulate.slow_down
|
|
||||||
mujoco.mj_step(m, d)
|
mujoco.mj_step(m, d)
|
||||||
|
|
||||||
# break on reset
|
# break if reset
|
||||||
if d.time*simulate.slow_down < prevtm:
|
if d.time < prevsim:
|
||||||
break
|
break
|
||||||
|
|
||||||
# paused
|
# paused
|
||||||
@@ -237,13 +264,14 @@ def run_physics_loop(simulate, preload_callback=None, load_callback=None, file=N
|
|||||||
# end exclusive access
|
# end exclusive access
|
||||||
simulate.unlock()
|
simulate.unlock()
|
||||||
|
|
||||||
def run_simulate_and_physics(file=None, preload_callback=None, load_callback=None):
|
def run_simulate_and_physics(file=None, preload_callback=None, load_callback=None, init=True, terminate=True):
|
||||||
# simulate object encapsulates the UI
|
# simulate object encapsulates the UI
|
||||||
simulate = Simulate()
|
simulate = Simulate()
|
||||||
|
|
||||||
# init GLFW
|
# init GLFW
|
||||||
if not glfw.init():
|
if init:
|
||||||
raise mujoco.FatalError('could not initialize GLFW')
|
if not glfw.init():
|
||||||
|
raise mujoco.FatalError('could not initialize GLFW')
|
||||||
|
|
||||||
# if m is not None:
|
# if m is not None:
|
||||||
physics_thread = threading.Thread(target=lambda: run_physics_loop(simulate, preload_callback=preload_callback, load_callback=load_callback, file=file))
|
physics_thread = threading.Thread(target=lambda: run_physics_loop(simulate, preload_callback=preload_callback, load_callback=load_callback, file=file))
|
||||||
@@ -253,4 +281,5 @@ def run_simulate_and_physics(file=None, preload_callback=None, load_callback=Non
|
|||||||
simulate.renderloop()
|
simulate.renderloop()
|
||||||
physics_thread.join()
|
physics_thread.join()
|
||||||
|
|
||||||
glfw.terminate()
|
if terminate:
|
||||||
|
glfw.terminate()
|
||||||
|
|||||||
+5
-4
@@ -63,11 +63,11 @@ def get_mujoco_lib_pattern():
|
|||||||
|
|
||||||
def get_external_lib_patterns():
|
def get_external_lib_patterns():
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
return ['mujoco.dll', 'mjsimulate.dll']
|
return ['mujoco.dll', 'libsimulate.dll']
|
||||||
elif platform.system() == 'Darwin':
|
elif platform.system() == 'Darwin':
|
||||||
return ['libmujoco.*.dylib', 'libmjsimulate.*.dylib']
|
return ['libmujoco.*.dylib', 'liblibsimulate.*.dylib']
|
||||||
else:
|
else:
|
||||||
return ['libmujoco.so.*', 'libmjsimulate.so*']
|
return ['libmujoco.so.*', 'liblibsimulate.so*']
|
||||||
|
|
||||||
def start_and_end(iterable):
|
def start_and_end(iterable):
|
||||||
it = iter(iterable)
|
it = iter(iterable)
|
||||||
@@ -318,7 +318,8 @@ setup(
|
|||||||
'libmujoco*.so.*',
|
'libmujoco*.so.*',
|
||||||
'mujoco.dll',
|
'mujoco.dll',
|
||||||
'include/mujoco/*.h',
|
'include/mujoco/*.h',
|
||||||
'libmjsimulate*.so*',
|
'liblibsimulate.*.dylib',
|
||||||
|
'liblibsimulate*.so*',
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
+33
-11
@@ -97,8 +97,8 @@ if(NOT TARGET lodepng)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Simulate library
|
# Simulate shared library
|
||||||
add_library(libsimulate STATIC)
|
add_library(libsimulate SHARED simulate.cc uitools.cc glfw_dispatch.cc)
|
||||||
add_library(mujoco::libsimulate ALIAS libsimulate)
|
add_library(mujoco::libsimulate ALIAS libsimulate)
|
||||||
|
|
||||||
target_sources(
|
target_sources(
|
||||||
@@ -106,19 +106,16 @@ target_sources(
|
|||||||
PUBLIC simulate.h
|
PUBLIC simulate.h
|
||||||
array_safety.h
|
array_safety.h
|
||||||
glfw_dispatch.h
|
glfw_dispatch.h
|
||||||
glfw_dispatch.cc
|
|
||||||
simulate.cc
|
|
||||||
uitools.h
|
uitools.h
|
||||||
uitools.cc
|
|
||||||
)
|
)
|
||||||
target_include_directories(libsimulate PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(libsimulate PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_compile_definitions(libsimulate PUBLIC MJSIMULATE_STATIC)
|
target_compile_definitions(libsimulate PUBLIC LIBSIMULATE_DLL_EXPORTS mjGLFW_DYNAMIC_SYMBOLS)
|
||||||
target_compile_options(libsimulate PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
|
target_compile_options(libsimulate PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
|
||||||
target_link_libraries(libsimulate PUBLIC glfw lodepng mujoco::mujoco)
|
target_link_libraries(libsimulate PUBLIC lodepng glfw mujoco::mujoco)
|
||||||
target_link_options(libsimulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
|
target_link_options(libsimulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
|
||||||
|
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
mjsimulate PROPERTIES VERSION "${mujoco_VERSION}" PUBLIC_HEADER "simulate.h"
|
libsimulate PROPERTIES VERSION "${mujoco_VERSION}" PUBLIC_HEADER "simulate.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
@@ -126,6 +123,31 @@ if(APPLE)
|
|||||||
target_link_libraries(libsimulate PUBLIC "-framework Cocoa")
|
target_link_libraries(libsimulate PUBLIC "-framework Cocoa")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Simulate static library
|
||||||
|
add_library(libsimulatestatic STATIC simulate.cc uitools.cc glfw_dispatch.cc)
|
||||||
|
add_library(mujoco::libsimulatestatic ALIAS libsimulatestatic)
|
||||||
|
target_sources(
|
||||||
|
libsimulatestatic
|
||||||
|
PUBLIC simulate.h
|
||||||
|
array_safety.h
|
||||||
|
glfw_dispatch.h
|
||||||
|
uitools.h
|
||||||
|
)
|
||||||
|
target_include_directories(libsimulatestatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_compile_definitions(libsimulatestatic PUBLIC LIBSIMULATE_STATIC)
|
||||||
|
target_compile_options(libsimulatestatic PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
|
||||||
|
target_link_libraries(libsimulatestatic PUBLIC lodepng glfw mujoco::mujoco)
|
||||||
|
target_link_options(libsimulatestatic PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
libsimulatestatic PROPERTIES VERSION "${mujoco_VERSION}" PUBLIC_HEADER "simulate.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
target_sources(libsimulatestatic PRIVATE macos_save.mm)
|
||||||
|
target_link_libraries(libsimulatestatic PUBLIC "-framework Cocoa")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Build simulate executable
|
# Build simulate executable
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(SIMULATE_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../dist/mujoco.icns)
|
set(SIMULATE_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../dist/mujoco.icns)
|
||||||
@@ -150,7 +172,7 @@ endif()
|
|||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
simulate
|
simulate
|
||||||
libsimulate
|
libsimulatestatic
|
||||||
mujoco::mujoco
|
mujoco::mujoco
|
||||||
glfw
|
glfw
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
@@ -225,7 +247,7 @@ if(_INSTALL_SIMULATE)
|
|||||||
|
|
||||||
target_add_rpath(
|
target_add_rpath(
|
||||||
TARGETS
|
TARGETS
|
||||||
mjsimulate
|
libsimulate
|
||||||
INSTALL_DIRECTORY
|
INSTALL_DIRECTORY
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
|
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
|
||||||
LIB_DIRS
|
LIB_DIRS
|
||||||
@@ -245,7 +267,7 @@ if(_INSTALL_SIMULATE)
|
|||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS mjsimulate
|
TARGETS libsimulate
|
||||||
EXPORT ${PROJECT_NAME}
|
EXPORT ${PROJECT_NAME}
|
||||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT simulate
|
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT simulate
|
||||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT simulate
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT simulate
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ const struct Glfw& Glfw(void* dlhandle) {
|
|||||||
|
|
||||||
// go/keep-sorted start
|
// go/keep-sorted start
|
||||||
mjGLFW_INITIALIZE_SYMBOL(glfwCreateWindow);
|
mjGLFW_INITIALIZE_SYMBOL(glfwCreateWindow);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwDestroyWindow);
|
||||||
mjGLFW_INITIALIZE_SYMBOL(glfwGetCursorPos);
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetCursorPos);
|
||||||
mjGLFW_INITIALIZE_SYMBOL(glfwGetFramebufferSize);
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetFramebufferSize);
|
||||||
mjGLFW_INITIALIZE_SYMBOL(glfwGetKey);
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetKey);
|
||||||
@@ -115,10 +116,6 @@ const struct Glfw& Glfw(void* dlhandle) {
|
|||||||
|
|
||||||
#undef mjGLFW_INITIALIZE_SYMBOL
|
#undef mjGLFW_INITIALIZE_SYMBOL
|
||||||
|
|
||||||
#if defined(mjGLFW_DYNAMIC_SYMBOLS) && !defined(_MSC_VER)
|
|
||||||
dlclose(dlhandle);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return glfw;
|
return glfw;
|
||||||
}();
|
}();
|
||||||
return glfw;
|
return glfw;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ struct Glfw {
|
|||||||
#define mjGLFW_DECLARE_SYMBOL(func) decltype(&::func) func
|
#define mjGLFW_DECLARE_SYMBOL(func) decltype(&::func) func
|
||||||
// go/keep-sorted start
|
// go/keep-sorted start
|
||||||
mjGLFW_DECLARE_SYMBOL(glfwCreateWindow);
|
mjGLFW_DECLARE_SYMBOL(glfwCreateWindow);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwDestroyWindow);
|
||||||
mjGLFW_DECLARE_SYMBOL(glfwGetCursorPos);
|
mjGLFW_DECLARE_SYMBOL(glfwGetCursorPos);
|
||||||
mjGLFW_DECLARE_SYMBOL(glfwGetFramebufferSize);
|
mjGLFW_DECLARE_SYMBOL(glfwGetFramebufferSize);
|
||||||
mjGLFW_DECLARE_SYMBOL(glfwGetKey);
|
mjGLFW_DECLARE_SYMBOL(glfwGetKey);
|
||||||
|
|||||||
+9
-3
@@ -337,7 +337,10 @@ void PhysicsLoop(mj::Simulate& sim) {
|
|||||||
mjData* dnew = nullptr;
|
mjData* dnew = nullptr;
|
||||||
if (mnew) dnew = mj_makeData(mnew);
|
if (mnew) dnew = mj_makeData(mnew);
|
||||||
if (dnew) {
|
if (dnew) {
|
||||||
sim.load(sim.dropfilename, mnew, dnew, true);
|
sim.load(sim.dropfilename, mnew, dnew);
|
||||||
|
|
||||||
|
if (d) mj_deleteData(d);
|
||||||
|
if (m) mj_deleteModel(m);
|
||||||
|
|
||||||
m = mnew;
|
m = mnew;
|
||||||
d = dnew;
|
d = dnew;
|
||||||
@@ -356,7 +359,10 @@ void PhysicsLoop(mj::Simulate& sim) {
|
|||||||
mjData* dnew = nullptr;
|
mjData* dnew = nullptr;
|
||||||
if (mnew) dnew = mj_makeData(mnew);
|
if (mnew) dnew = mj_makeData(mnew);
|
||||||
if (dnew) {
|
if (dnew) {
|
||||||
sim.load(sim.filename, mnew, dnew, true);
|
sim.load(sim.filename, mnew, dnew);
|
||||||
|
|
||||||
|
if (d) mj_deleteData(d);
|
||||||
|
if (m) mj_deleteModel(m);
|
||||||
|
|
||||||
m = mnew;
|
m = mnew;
|
||||||
d = dnew;
|
d = dnew;
|
||||||
@@ -482,7 +488,7 @@ void PhysicsThread(mj::Simulate* sim, const char* filename) {
|
|||||||
m = LoadModel(filename, *sim);
|
m = LoadModel(filename, *sim);
|
||||||
if (m) d = mj_makeData(m);
|
if (m) d = mj_makeData(m);
|
||||||
if (d) {
|
if (d) {
|
||||||
sim->load(filename, m, d, true);
|
sim->load(filename, m, d);
|
||||||
mj_forward(m, d);
|
mj_forward(m, d);
|
||||||
|
|
||||||
// allocate ctrlnoise
|
// allocate ctrlnoise
|
||||||
|
|||||||
+45
-45
@@ -934,7 +934,7 @@ void copykey(mj::Simulate* sim) {
|
|||||||
mju::strcat_arr(clipboard, "'/>");
|
mju::strcat_arr(clipboard, "'/>");
|
||||||
|
|
||||||
// copy to clipboard
|
// copy to clipboard
|
||||||
Glfw().glfwSetClipboardString(sim->window, clipboard);
|
Glfw().glfwSetClipboardString(reinterpret_cast<GLFWwindow*>(sim->window), clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// millisecond timer, for MuJoCo built-in profiler
|
// millisecond timer, for MuJoCo built-in profiler
|
||||||
@@ -974,7 +974,7 @@ void copycamera(mj::Simulate* sim) {
|
|||||||
camera[0].up[0], camera[0].up[1], camera[0].up[2]);
|
camera[0].up[0], camera[0].up[1], camera[0].up[2]);
|
||||||
|
|
||||||
// copy spec into clipboard
|
// copy spec into clipboard
|
||||||
Glfw().glfwSetClipboardString(sim->window, clipboard);
|
Glfw().glfwSetClipboardString(reinterpret_cast<GLFWwindow*>(sim->window), clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update UI 0 when MuJoCo structures change (except for joint sliders)
|
// update UI 0 when MuJoCo structures change (except for joint sliders)
|
||||||
@@ -1035,7 +1035,7 @@ void uiLayout(mjuiState* state) {
|
|||||||
// rect 0: entire framebuffer
|
// rect 0: entire framebuffer
|
||||||
rect[0].left = 0;
|
rect[0].left = 0;
|
||||||
rect[0].bottom = 0;
|
rect[0].bottom = 0;
|
||||||
Glfw().glfwGetFramebufferSize(sim->window, &rect[0].width, &rect[0].height);
|
Glfw().glfwGetFramebufferSize(reinterpret_cast<GLFWwindow*>(sim->window), &rect[0].width, &rect[0].height);
|
||||||
|
|
||||||
// rect 1: UI 0
|
// rect 1: UI 0
|
||||||
rect[1].left = 0;
|
rect[1].left = 0;
|
||||||
@@ -1128,21 +1128,24 @@ void uiEvent(mjuiState* state) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 9: // Full screen
|
case 9: // Full screen
|
||||||
if (Glfw().glfwGetWindowMonitor(sim->window)) {
|
if (Glfw().glfwGetWindowMonitor(reinterpret_cast<GLFWwindow*>(sim->window))) {
|
||||||
// restore window from saved data
|
// restore window from saved data
|
||||||
Glfw().glfwSetWindowMonitor(sim->window, nullptr, sim->windowpos[0], sim->windowpos[1],
|
Glfw().glfwSetWindowMonitor(reinterpret_cast<GLFWwindow*>(sim->window),
|
||||||
|
nullptr, sim->windowpos[0], sim->windowpos[1],
|
||||||
sim->windowsize[0], sim->windowsize[1], 0);
|
sim->windowsize[0], sim->windowsize[1], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// currently windowed: switch to full screen
|
// currently windowed: switch to full screen
|
||||||
else {
|
else {
|
||||||
// save window data
|
// save window data
|
||||||
Glfw().glfwGetWindowPos(sim->window, sim->windowpos, sim->windowpos+1);
|
Glfw().glfwGetWindowPos(reinterpret_cast<GLFWwindow*>(sim->window), sim->windowpos, sim->windowpos+1);
|
||||||
Glfw().glfwGetWindowSize(sim->window, sim->windowsize, sim->windowsize+1);
|
Glfw().glfwGetWindowSize(reinterpret_cast<GLFWwindow*>(sim->window), sim->windowsize, sim->windowsize+1);
|
||||||
|
|
||||||
// switch
|
// switch
|
||||||
Glfw().glfwSetWindowMonitor(sim->window, Glfw().glfwGetPrimaryMonitor(), 0, 0,
|
Glfw().glfwSetWindowMonitor(reinterpret_cast<GLFWwindow*>(sim->window), Glfw().glfwGetPrimaryMonitor(), 0, 0,
|
||||||
sim->vmode.width, sim->vmode.height, sim->vmode.refreshRate);
|
reinterpret_cast<const GLFWvidmode*>(sim->vmode)->width,
|
||||||
|
reinterpret_cast<const GLFWvidmode*>(sim->vmode)->height,
|
||||||
|
reinterpret_cast<const GLFWvidmode*>(sim->vmode)->refreshRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reinstante vsync, just in case
|
// reinstante vsync, just in case
|
||||||
@@ -1155,8 +1158,8 @@ void uiEvent(mjuiState* state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// modify UI
|
// modify UI
|
||||||
uiModify(sim->window, &sim->ui0, state, &sim->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(sim->window), &sim->ui0, state, &sim->con);
|
||||||
uiModify(sim->window, &sim->ui1, state, &sim->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(sim->window), &sim->ui1, state, &sim->con);
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulation section
|
// simulation section
|
||||||
@@ -1263,7 +1266,7 @@ void uiEvent(mjuiState* state) {
|
|||||||
sim->ui1.nsect = SECT_JOINT;
|
sim->ui1.nsect = SECT_JOINT;
|
||||||
makejoint(sim, sim->ui1.sect[SECT_JOINT].state);
|
makejoint(sim, sim->ui1.sect[SECT_JOINT].state);
|
||||||
sim->ui1.nsect = NSECT1;
|
sim->ui1.nsect = NSECT1;
|
||||||
uiModify(sim->window, &sim->ui1, state, &sim->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(sim->window), &sim->ui1, state, &sim->con);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remake control section if actuator group changed
|
// remake control section if actuator group changed
|
||||||
@@ -1271,7 +1274,7 @@ void uiEvent(mjuiState* state) {
|
|||||||
sim->ui1.nsect = SECT_CONTROL;
|
sim->ui1.nsect = SECT_CONTROL;
|
||||||
makecontrol(sim, sim->ui1.sect[SECT_CONTROL].state);
|
makecontrol(sim, sim->ui1.sect[SECT_CONTROL].state);
|
||||||
sim->ui1.nsect = NSECT1;
|
sim->ui1.nsect = NSECT1;
|
||||||
uiModify(sim->window, &sim->ui1, state, &sim->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(sim->window), &sim->ui1, state, &sim->con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1574,11 +1577,9 @@ void Simulate::applyforceperturbations() {
|
|||||||
//------------------------- Tell the render thread to load a file and wait -------------------------
|
//------------------------- Tell the render thread to load a file and wait -------------------------
|
||||||
void Simulate::load(const char* file,
|
void Simulate::load(const char* file,
|
||||||
mjModel* mnew,
|
mjModel* mnew,
|
||||||
mjData* dnew,
|
mjData* dnew) {
|
||||||
bool delete_old_m_d) {
|
|
||||||
this->mnew = mnew;
|
this->mnew = mnew;
|
||||||
this->dnew = dnew;
|
this->dnew = dnew;
|
||||||
this->delete_old_m_d = delete_old_m_d;
|
|
||||||
mju::strcpy_arr(this->filename, file);
|
mju::strcpy_arr(this->filename, file);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1594,16 +1595,6 @@ void Simulate::load(const char* file,
|
|||||||
|
|
||||||
//------------------------------------- load mjb or xml model --------------------------------------
|
//------------------------------------- load mjb or xml model --------------------------------------
|
||||||
void Simulate::loadmodel() {
|
void Simulate::loadmodel() {
|
||||||
if (this->delete_old_m_d) {
|
|
||||||
// delete old model if requested
|
|
||||||
if (this->d) {
|
|
||||||
mj_deleteData(d);
|
|
||||||
}
|
|
||||||
if (this->m) {
|
|
||||||
mj_deleteModel(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m = this->mnew;
|
this->m = this->mnew;
|
||||||
this->d = this->dnew;
|
this->d = this->dnew;
|
||||||
|
|
||||||
@@ -1626,10 +1617,10 @@ void Simulate::loadmodel() {
|
|||||||
mjv_updateScene(this->m, this->d, &this->vopt, &this->pert, &this->cam, mjCAT_ALL, &this->scn);
|
mjv_updateScene(this->m, this->d, &this->vopt, &this->pert, &this->cam, mjCAT_ALL, &this->scn);
|
||||||
|
|
||||||
// set window title to model name
|
// set window title to model name
|
||||||
if (this->window && this->m->names) {
|
if (reinterpret_cast<GLFWwindow*>(this->window) && this->m->names) {
|
||||||
char title[200] = "Simulate : ";
|
char title[200] = "Simulate : ";
|
||||||
mju::strcat_arr(title, this->m->names);
|
mju::strcat_arr(title, this->m->names);
|
||||||
Glfw().glfwSetWindowTitle(this->window, title);
|
Glfw().glfwSetWindowTitle(reinterpret_cast<GLFWwindow*>(this->window), title);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set keyframe range and divisions
|
// set keyframe range and divisions
|
||||||
@@ -1641,8 +1632,8 @@ void Simulate::loadmodel() {
|
|||||||
makesections(this);
|
makesections(this);
|
||||||
|
|
||||||
// full ui update
|
// full ui update
|
||||||
uiModify(this->window, &this->ui0, &this->uistate, &this->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(this->window), &this->ui0, &this->uistate, &this->con);
|
||||||
uiModify(this->window, &this->ui1, &this->uistate, &this->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(this->window), &this->ui1, &this->uistate, &this->con);
|
||||||
updatesettings(this);
|
updatesettings(this);
|
||||||
|
|
||||||
// clear request
|
// clear request
|
||||||
@@ -1758,7 +1749,7 @@ void Simulate::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
Glfw().glfwSwapBuffers(this->window);
|
Glfw().glfwSwapBuffers(reinterpret_cast<GLFWwindow*>(this->window));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1865,13 +1856,13 @@ void Simulate::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
Glfw().glfwSwapBuffers(this->window);
|
Glfw().glfwSwapBuffers(reinterpret_cast<GLFWwindow*>(this->window));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// clear callbacks registered in external structures
|
// clear callbacks registered in external structures
|
||||||
void Simulate::clearcallback() {
|
void Simulate::clearcallback() {
|
||||||
uiClearCallback(this->window);
|
uiClearCallback(reinterpret_cast<GLFWwindow*>(this->window));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Simulate::renderloop() {
|
void Simulate::renderloop() {
|
||||||
@@ -1883,25 +1874,27 @@ void Simulate::renderloop() {
|
|||||||
Glfw().glfwWindowHint(GLFW_VISIBLE, 1);
|
Glfw().glfwWindowHint(GLFW_VISIBLE, 1);
|
||||||
|
|
||||||
// get videomode and save
|
// get videomode and save
|
||||||
this->vmode = *Glfw().glfwGetVideoMode(Glfw().glfwGetPrimaryMonitor());
|
this->vmode = Glfw().glfwGetVideoMode(Glfw().glfwGetPrimaryMonitor());
|
||||||
|
|
||||||
// use videomode refreshrate if nonzero
|
// use videomode refreshrate if nonzero
|
||||||
if (this->vmode.refreshRate) this->refreshRate = this->vmode.refreshRate;
|
if (reinterpret_cast<const GLFWvidmode*>(this->vmode)->refreshRate)
|
||||||
|
this->refreshRate = reinterpret_cast<const GLFWvidmode*>(this->vmode)->refreshRate;
|
||||||
|
|
||||||
// create window
|
// create window
|
||||||
this->window = Glfw().glfwCreateWindow((2*this->vmode.width)/3, (2*this->vmode.height)/3,
|
this->window = Glfw().glfwCreateWindow((2*reinterpret_cast<const GLFWvidmode*>(this->vmode)->width)/3,
|
||||||
|
(2*reinterpret_cast<const GLFWvidmode*>(this->vmode)->height)/3,
|
||||||
"Simulate", nullptr, nullptr);
|
"Simulate", nullptr, nullptr);
|
||||||
if (!this->window) {
|
if (!reinterpret_cast<GLFWwindow*>(this->window)) {
|
||||||
Glfw().glfwTerminate();
|
Glfw().glfwTerminate();
|
||||||
mju_error("could not create window");
|
mju_error("could not create window");
|
||||||
}
|
}
|
||||||
|
|
||||||
// save window position and size
|
// save window position and size
|
||||||
Glfw().glfwGetWindowPos(this->window, this->windowpos, this->windowpos+1);
|
Glfw().glfwGetWindowPos(reinterpret_cast<GLFWwindow*>(this->window), this->windowpos, this->windowpos+1);
|
||||||
Glfw().glfwGetWindowSize(this->window, this->windowsize, this->windowsize+1);
|
Glfw().glfwGetWindowSize(reinterpret_cast<GLFWwindow*>(this->window), this->windowsize, this->windowsize+1);
|
||||||
|
|
||||||
// make context current, set v-sync
|
// make context current, set v-sync
|
||||||
Glfw().glfwMakeContextCurrent(this->window);
|
Glfw().glfwMakeContextCurrent(reinterpret_cast<GLFWwindow*>(this->window));
|
||||||
Glfw().glfwSwapInterval(this->vsync);
|
Glfw().glfwSwapInterval(this->vsync);
|
||||||
|
|
||||||
// init abstract visualization
|
// init abstract visualization
|
||||||
@@ -1915,7 +1908,7 @@ void Simulate::renderloop() {
|
|||||||
mjv_makeScene(nullptr, &this->scn, maxgeom);
|
mjv_makeScene(nullptr, &this->scn, maxgeom);
|
||||||
|
|
||||||
// select default font
|
// select default font
|
||||||
int fontscale = uiFontScale(this->window);
|
int fontscale = uiFontScale(reinterpret_cast<GLFWwindow*>(this->window));
|
||||||
this->font = fontscale/50 - 1;
|
this->font = fontscale/50 - 1;
|
||||||
|
|
||||||
// make empty context
|
// make empty context
|
||||||
@@ -1939,7 +1932,7 @@ void Simulate::renderloop() {
|
|||||||
|
|
||||||
// set GLFW callbacks
|
// set GLFW callbacks
|
||||||
this->uistate.userdata = this;
|
this->uistate.userdata = this;
|
||||||
uiSetCallback(this->window, &this->uistate, uiEvent, uiLayout, uiRender, uiDrop);
|
uiSetCallback(reinterpret_cast<GLFWwindow*>(this->window), &this->uistate, uiEvent, uiLayout, uiRender, uiDrop);
|
||||||
|
|
||||||
// populate uis with standard sections
|
// populate uis with standard sections
|
||||||
this->ui0.userdata = this;
|
this->ui0.userdata = this;
|
||||||
@@ -1948,11 +1941,11 @@ void Simulate::renderloop() {
|
|||||||
mjui_add(&this->ui0, this->defOption);
|
mjui_add(&this->ui0, this->defOption);
|
||||||
mjui_add(&this->ui0, this->defSimulation);
|
mjui_add(&this->ui0, this->defSimulation);
|
||||||
mjui_add(&this->ui0, this->defWatch);
|
mjui_add(&this->ui0, this->defWatch);
|
||||||
uiModify(this->window, &this->ui0, &this->uistate, &this->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(this->window), &this->ui0, &this->uistate, &this->con);
|
||||||
uiModify(this->window, &this->ui1, &this->uistate, &this->con);
|
uiModify(reinterpret_cast<GLFWwindow*>(this->window), &this->ui1, &this->uistate, &this->con);
|
||||||
|
|
||||||
// run event loop
|
// run event loop
|
||||||
while (!Glfw().glfwWindowShouldClose(this->window) && !this->exitrequest.load()) {
|
while (!Glfw().glfwWindowShouldClose(reinterpret_cast<GLFWwindow*>(this->window)) && !this->exitrequest.load()) {
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(this->mtx);
|
const std::lock_guard<std::mutex> lock(this->mtx);
|
||||||
|
|
||||||
@@ -1979,6 +1972,13 @@ void Simulate::renderloop() {
|
|||||||
this->clearcallback();
|
this->clearcallback();
|
||||||
mjv_freeScene(&this->scn);
|
mjv_freeScene(&this->scn);
|
||||||
mjr_freeContext(&this->con);
|
mjr_freeContext(&this->con);
|
||||||
|
|
||||||
|
Glfw().glfwDestroyWindow(reinterpret_cast<GLFWwindow*>(this->window));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------ setup the glfw dispatch table -------------------------------
|
||||||
|
void setglfwdlhandle(void* dlhandle) {
|
||||||
|
Glfw(dlhandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|||||||
+17
-12
@@ -23,17 +23,17 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <mujoco/mujoco.h>
|
#include <mujoco/mujoco.h>
|
||||||
|
|
||||||
#ifdef MJSIMULATE_STATIC
|
#ifdef LIBSIMULATE_STATIC
|
||||||
// static library
|
// static library
|
||||||
#define MJSIMULATEAPI
|
#define LIBSIMULATEAPI
|
||||||
#define MJSIMULATELOCAL
|
#define LIBSIMULATELOCAL
|
||||||
#else
|
#else
|
||||||
#ifdef MJSIMULATE_DLL_EXPORTS
|
#ifdef LIBSIMULATE_DLL_EXPORTS
|
||||||
#define MJSIMULATEAPI MUJOCO_HELPER_DLL_EXPORT
|
#define LIBSIMULATEAPI MUJOCO_HELPER_DLL_EXPORT
|
||||||
#else
|
#else
|
||||||
#define MJSIMULATEAPI MUJOCO_HELPER_DLL_IMPORT
|
#define LIBSIMULATEAPI MUJOCO_HELPER_DLL_IMPORT
|
||||||
#endif
|
#endif
|
||||||
#define MJSIMULATELOCAL MUJOCO_HELPER_DLL_LOCAL
|
#define LIBSIMULATELOCAL MUJOCO_HELPER_DLL_LOCAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace mujoco {
|
namespace mujoco {
|
||||||
@@ -41,7 +41,7 @@ namespace mujoco {
|
|||||||
//-------------------------------- global -----------------------------------------------
|
//-------------------------------- global -----------------------------------------------
|
||||||
|
|
||||||
// Simulate states not contained in MuJoCo structures
|
// Simulate states not contained in MuJoCo structures
|
||||||
class MJSIMULATEAPI Simulate {
|
class LIBSIMULATEAPI Simulate {
|
||||||
public:
|
public:
|
||||||
// create object and initialize the simulate ui
|
// create object and initialize the simulate ui
|
||||||
Simulate() = default;
|
Simulate() = default;
|
||||||
@@ -54,7 +54,7 @@ class MJSIMULATEAPI Simulate {
|
|||||||
|
|
||||||
// Request that the Simulate UI thread render a new model
|
// Request that the Simulate UI thread render a new model
|
||||||
// optionally delete the old model and data when done
|
// optionally delete the old model and data when done
|
||||||
void load(const char* file, mjModel* m, mjData* d, bool delete_old_m_d);
|
void load(const char* file, mjModel* m, mjData* d);
|
||||||
|
|
||||||
// functions below are used by the renderthread
|
// functions below are used by the renderthread
|
||||||
// load mjb or xml model that has been requested by load()
|
// load mjb or xml model that has been requested by load()
|
||||||
@@ -79,7 +79,6 @@ class MJSIMULATEAPI Simulate {
|
|||||||
// model and data to be visualized
|
// model and data to be visualized
|
||||||
mjModel* mnew = nullptr;
|
mjModel* mnew = nullptr;
|
||||||
mjData* dnew = nullptr;
|
mjData* dnew = nullptr;
|
||||||
bool delete_old_m_d = false;
|
|
||||||
|
|
||||||
mjModel* m = nullptr;
|
mjModel* m = nullptr;
|
||||||
mjData* d = nullptr;
|
mjData* d = nullptr;
|
||||||
@@ -163,12 +162,14 @@ class MJSIMULATEAPI Simulate {
|
|||||||
mjvFigure figsensor = {};
|
mjvFigure figsensor = {};
|
||||||
|
|
||||||
// OpenGL rendering and UI
|
// OpenGL rendering and UI
|
||||||
GLFWvidmode vmode = {};
|
// Use void* for GLFW objects to avoid requiring users of the shared library
|
||||||
|
// from needing GLFW headers (in particular Python should not need them)
|
||||||
|
const void* vmode = {}; // const GLFWvidmode*
|
||||||
int refreshRate = 60;
|
int refreshRate = 60;
|
||||||
int windowpos[2] = {0};
|
int windowpos[2] = {0};
|
||||||
int windowsize[2] = {0};
|
int windowsize[2] = {0};
|
||||||
mjrContext con = {};
|
mjrContext con = {};
|
||||||
GLFWwindow* window = nullptr;
|
void* window = nullptr; // GLFWwindow*
|
||||||
mjuiState uistate = {};
|
mjuiState uistate = {};
|
||||||
mjUI ui0 = {};
|
mjUI ui0 = {};
|
||||||
mjUI ui1 = {};
|
mjUI ui1 = {};
|
||||||
@@ -228,6 +229,10 @@ class MJSIMULATEAPI Simulate {
|
|||||||
char info_content[Simulate::kMaxFilenameLength] = {0};
|
char info_content[Simulate::kMaxFilenameLength] = {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// setup the glfw dispatch table
|
||||||
|
// if set, must be called prior to other Simulate functions
|
||||||
|
LIBSIMULATEAPI void setglfwdlhandle(void* dlhandle);
|
||||||
|
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user