Merge pull request #201 from aftersomemath:refactor-simulate

PiperOrigin-RevId: 465044152
Change-Id: I54e65a30764a444dbd175260314d685fd7ffa6a1
This commit is contained in:
Saran Tunyasuvunakool
2022-08-03 15:32:15 +01:00
25 changed files with 3351 additions and 2286 deletions
+9 -1
View File
@@ -39,10 +39,11 @@ enable_language(CXX)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
option(MUJOCO_BUILD_EXAMPLES "Build samples for MuJoCo" ON)
option(MUJOCO_BUILD_SIMULATE "Build simulate library for MuJoCo" ON)
option(MUJOCO_BUILD_TESTS "Build tests for MuJoCo" ON)
option(MUJOCO_TEST_PYTHON_UTIL "Build and test utility libraries for Python bindings" ON)
if(APPLE AND MUJOCO_BUILD_EXAMPLES)
if(APPLE AND (MUJOCO_BUILD_EXAMPLES OR MUJOCO_BUILD_SIMULATE))
enable_language(OBJC)
enable_language(OBJCXX)
endif()
@@ -152,6 +153,13 @@ add_library(mujoco::mujoco ALIAS mujoco)
add_subdirectory(model)
# `simulate` defines a macro, embed_in_bundle, that's used by `sample`, so that
# subdirectory needs to be added first.
# TODO: Remove this order dependency.
if(MUJOCO_BUILD_SIMULATE)
add_subdirectory(simulate)
endif()
if(MUJOCO_BUILD_EXAMPLES)
add_subdirectory(sample)
endif()
-82
View File
@@ -70,14 +70,6 @@ if(MUJOCO_HARDEN)
endif()
endif()
# Utility library
add_library(uitools STATIC)
target_sources(uitools PRIVATE uitools.h uitools.c)
target_include_directories(uitools PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_options(uitools PUBLIC ${MUJOCO_SAMPLE_COMPILE_OPTIONS})
target_link_libraries(uitools PUBLIC glfw mujoco::mujoco)
target_link_options(uitools PRIVATE ${MUJOCO_SAMPLE_LINK_OPTIONS})
# Build sample binaries
add_executable(compile compile.cc)
target_compile_options(compile PUBLIC ${MUJOCO_SAMPLE_COMPILE_OPTIONS})
@@ -126,85 +118,13 @@ target_link_libraries(
)
target_link_options(record PRIVATE ${MUJOCO_SAMPLE_LINK_OPTIONS})
if(APPLE)
set(SIMULATE_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../dist/mujoco.icns)
elseif(WIN32)
set(SIMULATE_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../dist/appicon.rc)
else()
set(SIMULATE_RESOURCE_FILES "")
endif()
add_executable(simulate simulate.cc array_safety.h ${SIMULATE_RESOURCE_FILES})
target_compile_options(simulate PUBLIC ${MUJOCO_SAMPLE_COMPILE_OPTIONS})
if(WIN32)
add_custom_command(
TARGET simulate
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../dist/mujoco.ico
${CMAKE_CURRENT_SOURCE_DIR}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rm ${CMAKE_CURRENT_SOURCE_DIR}/mujoco.ico
)
endif()
target_link_libraries(
simulate
mujoco::mujoco
uitools
glfw
Threads::Threads
)
target_link_options(simulate PRIVATE ${MUJOCO_SAMPLE_LINK_OPTIONS})
if(APPLE)
target_sources(simulate PRIVATE macos_save.mm)
target_link_libraries(simulate "-framework Cocoa")
endif()
if(APPLE AND MUJOCO_BUILD_MACOS_FRAMEWORKS)
set_target_properties(
simulate
PROPERTIES INSTALL_RPATH @executable_path/../Frameworks
BUILD_WITH_INSTALL_RPATH TRUE
RESOURCE ${SIMULATE_RESOURCE_FILES}
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/../dist/Info.plist.simulate.in
MACOSX_BUNDLE_BUNDLE_NAME "MuJoCo"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.mujoco.app"
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_INFO_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_ICON_FILE "mujoco.icns"
MACOSX_BUNDLE_COPYRIGHT "Copyright 2021 DeepMind Technologies Limited."
)
macro(embed_in_bundle target)
add_dependencies(${target} simulate)
set_target_properties(
${target}
PROPERTIES INSTALL_RPATH @executable_path/../Frameworks
BUILD_WITH_INSTALL_RPATH TRUE
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:simulate>
)
endmacro()
embed_in_bundle(basic simulate)
embed_in_bundle(compile simulate)
embed_in_bundle(derivative simulate)
embed_in_bundle(record simulate)
embed_in_bundle(testspeed simulate)
embed_in_bundle(testxml simulate)
# Embed mujoco.framework inside the App bundle.
add_custom_command(
TARGET simulate
POST_BUILD
COMMAND mkdir -p $<TARGET_FILE_DIR:simulate>/../Frameworks
COMMAND rm -rf $<TARGET_FILE_DIR:simulate>/../Frameworks/mujoco.framework
COMMAND cp -a $<TARGET_FILE_DIR:mujoco::mujoco>/../../../mujoco.framework
$<TARGET_FILE_DIR:simulate>/../Frameworks/
)
endif()
# Do not install if macOS Bundles are created as RPATH is managed manually there.
@@ -225,7 +145,6 @@ if(_INSTALL_SAMPLES)
record
testspeed
testxml
simulate
INSTALL_DIRECTORY
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
LIB_DIRS
@@ -241,7 +160,6 @@ if(_INSTALL_SAMPLES)
record
testspeed
testxml
simulate
EXPORT ${PROJECT_NAME}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT samples
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT samples
-3
View File
@@ -11,6 +11,3 @@ all:
$(CXX) $(COMMON) derivative.cc -lmujoco -fopenmp -o ../bin/derivative
$(CXX) $(COMMON) basic.cc -lmujoco -lglfw -o ../bin/basic
$(CXX) $(COMMON) record.cc -lmujoco -lglfw -o ../bin/record
$(CC) -c -O2 -I../include uitools.c
$(CXX) $(COMMON) uitools.o simulate.cc -lmujoco -lglfw -o ../bin/simulate
rm *.o
-4
View File
@@ -17,7 +17,3 @@ all:
clang++ $(ALLFLAGS) derivative.cc -framework mujoco -o derivative
clang++ $(ALLFLAGS) basic.cc -framework mujoco -lglfw -o basic
clang++ $(ALLFLAGS) record.cc -framework mujoco -lglfw -o record
clang -c $(CFLAGS) uitools.c
clang++ -c $(CXXFLAGS) macos_save.mm
clang++ $(ALLFLAGS) simulate.cc uitools.o macos_save.o -framework mujoco -framework Cocoa -lglfw -o simulate
rm *.o
-1
View File
@@ -15,5 +15,4 @@ all:
cl $(COMMON) derivative.cc /openmp ../lib/mujoco.lib
cl $(COMMON) basic.cc ../lib/glfw3dll.lib ../lib/mujoco.lib
cl $(COMMON) record.cc ../lib/glfw3dll.lib ../lib/mujoco.lib
cl $(COMMON) simulate.cc uitools.c ../lib/glfw3dll.lib ../lib/mujoco.lib
del *.obj
+5 -3
View File
@@ -58,8 +58,10 @@ findorfetch(
EXCLUDE_FROM_ALL
)
option(MUJOCO_SAMPLES_STATIC_GLFW "Link MuJoCo sample apps against GLFW statically." ON)
if(MUJOCO_SAMPLES_STATIC_GLFW)
option(MUJOCO_EXTRAS_STATIC_GLFW
"Link MuJoCo sample apps and simulate libraries against GLFW statically." ON
)
if(MUJOCO_EXTRAS_STATIC_GLFW)
set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS
OFF
@@ -88,7 +90,7 @@ findorfetch(
EXCLUDE_FROM_ALL
)
if(MUJOCO_SAMPLES_STATIC_GLFW)
if(MUJOCO_EXTRAS_STATIC_GLFW)
set(BUILD_SHARED_LIBS
${BUILD_SHARED_LIBS_OLD}
CACHE BOOL "Build SHARED libraries" FORCE
-2185
View File
File diff suppressed because it is too large Load Diff
+216
View File
@@ -0,0 +1,216 @@
# Copyright 2021 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cmake_minimum_required(VERSION 3.16)
# INTERPROCEDURAL_OPTIMIZATION is enforced when enabled.
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
# Default to GLVND if available.
set(CMAKE_POLICY_DEFAULT_CMP0072 NEW)
# This line has to appear before 'PROJECT' in order to be able to disable incremental linking
set(MSVC_INCREMENTAL_DEFAULT ON)
project(
mujoco_simulate
VERSION 2.2.1
DESCRIPTION "MuJoCo simulate binaries"
HOMEPAGE_URL "https://mujoco.org"
)
enable_language(C)
enable_language(CXX)
if(APPLE)
enable_language(OBJC)
enable_language(OBJCXX)
endif()
# Check if we are building as standalone project.
set(SIMULATE_STANDALONE OFF)
set(_INSTALL_SIMULATE ON)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(SIMULATE_STANDALONE ON)
# If standalone, do not install the samples.
set(_INSTALL_SIMULATE OFF)
endif()
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../cmake")
if(SIMULATE_STANDALONE)
include(SimulateOptions)
else()
enforce_mujoco_macosx_min_version()
endif()
include(SimulateDependencies)
set(MUJOCO_SIMULATE_COMPILE_OPTIONS "${AVX_COMPILE_OPTIONS}" "${EXTRA_COMPILE_OPTIONS}")
set(MUJOCO_SIMULATE_LINK_OPTIONS "${EXTRA_LINK_OPTIONS}")
if(MUJOCO_HARDEN)
if(WIN32)
set(MUJOCO_SIMULATE_LINK_OPTIONS "${MUJOCO_SIMULATE_LINK_OPTIONS}" -Wl,/DYNAMICBASE)
else()
set(MUJOCO_SIMULATE_COMPILE_OPTIONS "${MUJOCO_SIMULATE_COMPILE_OPTIONS}" -fPIE -fPIC)
if(APPLE)
set(MUJOCO_SIMULATE_LINK_OPTIONS "${MUJOCO_SIMULATE_LINK_OPTIONS}" -Wl,-pie)
else()
set(MUJOCO_SIMULATE_LINK_OPTIONS "${MUJOCO_SIMULATE_LINK_OPTIONS}" -pie)
endif()
endif()
endif()
# mjsimulate library
add_library(mjsimulate STATIC)
target_sources(
mjsimulate
PUBLIC simulate.h
array_safety.h
simulate.cc
uitools.h
uitools.c
)
target_include_directories(mjsimulate PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(mjsimulate PUBLIC MJSIMULATE_STATIC)
target_compile_options(mjsimulate PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
target_link_libraries(mjsimulate PUBLIC glfw mujoco::mujoco)
target_link_options(mjsimulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
if(APPLE)
target_sources(mjsimulate PRIVATE macos_save.mm)
target_link_libraries(mjsimulate PUBLIC "-framework Cocoa")
endif()
# Build simulate executable
if(APPLE)
set(SIMULATE_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../dist/mujoco.icns)
elseif(WIN32)
set(SIMULATE_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../dist/appicon.rc)
else()
set(SIMULATE_RESOURCE_FILES "")
endif()
add_executable(simulate main.cc array_safety.h ${SIMULATE_RESOURCE_FILES})
target_compile_options(simulate PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
if(WIN32)
add_custom_command(
TARGET simulate
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../dist/mujoco.ico
${CMAKE_CURRENT_SOURCE_DIR}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rm ${CMAKE_CURRENT_SOURCE_DIR}/mujoco.ico
)
endif()
target_link_libraries(
simulate
mjsimulate
mujoco::mujoco
glfw
Threads::Threads
)
target_link_options(simulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
if(APPLE AND MUJOCO_BUILD_MACOS_FRAMEWORKS)
set_target_properties(
simulate
PROPERTIES INSTALL_RPATH @executable_path/../Frameworks
BUILD_WITH_INSTALL_RPATH TRUE
RESOURCE ${SIMULATE_RESOURCE_FILES}
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/../dist/Info.plist.simulate.in
MACOSX_BUNDLE_BUNDLE_NAME "MuJoCo"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.mujoco.mujoco"
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_INFO_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_ICON_FILE "mujoco.icns"
MACOSX_BUNDLE_COPYRIGHT "Copyright 2021 DeepMind Technologies Limited."
)
macro(embed_in_bundle target)
add_dependencies(${target} simulate)
set_target_properties(
${target}
PROPERTIES INSTALL_RPATH @executable_path/../Frameworks
BUILD_WITH_INSTALL_RPATH TRUE
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:simulate>
)
endmacro()
# Embed mujoco.framework inside the App bundle ane move the icon file over too.
add_custom_command(
TARGET simulate
POST_BUILD
COMMAND mkdir -p $<TARGET_FILE_DIR:simulate>/../Frameworks
COMMAND rm -rf $<TARGET_FILE_DIR:simulate>/../Frameworks/mujoco.framework
COMMAND cp -a $<TARGET_FILE_DIR:mujoco::mujoco>/../../../mujoco.framework
$<TARGET_FILE_DIR:simulate>/../Frameworks/
# Delete the symlink and the TBD, otherwise we can't sign and notarize.
COMMAND rm -rf $<TARGET_FILE_DIR:simulate>/../Frameworks/mujoco.framework/mujoco.tbd
COMMAND rm -rf
$<TARGET_FILE_DIR:simulate>/../Frameworks/mujoco.framework/Versions/A/libmujoco.dylib
)
endif()
# Do not install if macOS Bundles are created as RPATH is managed manually there.
if(APPLE AND MUJOCO_BUILD_MACOS_FRAMEWORKS)
set(_INSTALL_SIMULATE OFF)
endif()
if(_INSTALL_SIMULATE)
include(TargetAddRpath)
# Add support to RPATH for the samples.
target_add_rpath(
TARGETS
simulate
INSTALL_DIRECTORY
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
LIB_DIRS
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
DEPENDS
MUJOCO_ENABLE_RPATH
)
install(
TARGETS simulate
EXPORT ${PROJECT_NAME}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT simulate
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT simulate
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT simulate
BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT simulate
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT simulate
)
if(NOT MUJOCO_SIMULATE_USE_SYSTEM_GLFW)
# We downloaded GLFW. Depending if it is a static or shared LIBRARY we might
# need to install it.
get_target_property(MJ_GLFW_LIBRARY_TYPE glfw TYPE)
if(MJ_GLFW_LIBRARY_TYPE STREQUAL SHARED_LIBRARY)
install(
TARGETS glfw
EXPORT ${PROJECT_NAME}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT simulate
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT simulate
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT simulate
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT simulate
)
endif()
endif()
endif()
+11
View File
@@ -0,0 +1,11 @@
# This Makefile assumes that you have GLFW libraries and headers installed on,
# which is commonly available through your distro's package manager.
# On Debian and Ubuntu, GLFW can be installed via `apt install libglfw3-dev`.
COMMON=-O2 -I../include -L../lib -pthread -Wl,-no-as-needed -Wl,-rpath,'$$ORIGIN'/../lib
all:
$(CXX) $(COMMON) -std=c++17 -c simulate.cc
$(CC) $(COMMON) -std=c11 -c uitools.c
$(CXX) $(COMMON) -std=c++17 main.cc simulate.o uitools.o -lmujoco -lglfw -o ../bin/simulate
rm uitools.o simulate.o
+18
View File
@@ -0,0 +1,18 @@
# This Makefile assumes that GLFW is installed via Homebrew.
# If your setup is different, you will need to set GLFWROOT manually.
# This Makefile also assumes that MuJoCo.app is present in /Applications.
GLFWROOT?=$(shell brew --prefix)
MUJOCOPATH?=/Applications/MuJoCo.app/Contents/Frameworks
CFLAGS=-O2 -F$(MUJOCOPATH) -I$(GLFWROOT)/include -pthread
CXXFLAGS=$(CFLAGS) -std=c++17 -stdlib=libc++
ALLFLAGS=$(CXXFLAGS) -L$(GLFWROOT)/lib -Wl,-rpath,$(MUJOCOPATH)
all:
clang++ $(CXXFLAGS) -c macos_save.mm
clang++ $(CXXFLAGS) -c simulate.cc
clang $(CFLAGS) -std=c11 -c uitools.c
clang++ $(CXXFLAGS) main.cc macos_save.o simulate.o uitools.o -framework mujoco -framework Cocoa -lglfw -o simulate
rm *.o
+13
View File
@@ -0,0 +1,13 @@
# A copy of the GLFW library is required to build some sample programs.
# If this is not already installed on your system, download the WIN64 archive
# from https://github.com/glfw/glfw/releases, and copy files as follows:
# - Copy the entire `include/GLFW` subdirectory to `mujoco/include/GLFW`.
# - Copy glfw3dll.lib from the subdirectory corresponding into your compiler
# choice to `mujoco/lib/glfw3dll.lib`.
# - Copy glfw3.dll from the same subdirectory into `mujoco/bin/glfw3.dll`.
COMMON=/O2 /MT /EHsc /arch:AVX /I../include /Fe../bin/
all:
cl $(COMMON) main.cc simulate.cc uitools.c ../lib/glfw3dll.lib ../lib/mujoco.lib
del *.obj
+96
View File
@@ -0,0 +1,96 @@
// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_SAMPLE_ARRAY_SAFETY_H_
#define MUJOCO_SAMPLE_ARRAY_SAFETY_H_
#include <algorithm>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstring>
// Provides safe alternatives to the sizeof() operator and standard library functions for handling
// null-terminated (C-style) strings in raw char arrays.
//
// These functions make use of compile-time array sizes to limit read and write operations to within
// the array bounds. They are designed to trigger a compile error if the array size cannot be
// determined at compile time (e.g. when an array has decayed into a pointer).
//
// They do not perform runtime bound checks.
namespace mujoco {
namespace sample_util {
// returns sizeof(arr)
// use instead of sizeof() to avoid unintended array-to-pointer decay
template <typename T, int N>
static constexpr std::size_t sizeof_arr(const T(&arr)[N]) {
return sizeof(arr);
}
// like std::strcmp but it will not read beyond the bound of either lhs or rhs
template <std::size_t N1, std::size_t N2>
static inline int strcmp_arr(const char (&lhs)[N1], const char (&rhs)[N2]) {
return std::strncmp(lhs, rhs, std::min(N1, N2));
}
// like std::strlen but it will not read beyond the bound of str
// if str is not null-terminated, returns sizeof(str)
template <std::size_t N>
static inline std::size_t strlen_arr(const char (&str)[N]) {
for (std::size_t i = 0; i < N; ++i) {
if (str[i] == '\0') {
return i;
}
}
return N;
}
// like std::sprintf but will not write beyond the bound of dest
// dest is guaranteed to be null-terminated
template <std::size_t N>
static inline int sprintf_arr(char (&dest)[N], const char* format, ...) {
std::va_list vargs;
va_start(vargs, format);
int retval = std::vsnprintf(dest, N, format, vargs);
va_end(vargs);
return retval;
}
// like std::strcat but will not write beyond the bound of dest
// dest is guaranteed to be null-terminated
template <std::size_t N>
static inline char* strcat_arr(char (&dest)[N], const char* src) {
return std::strncat(dest, src, sizeof_arr(dest) - strlen_arr(dest) - 1);
}
// like std::strcpy but won't write beyond the bound of dest
// dest is guaranteed to be null-terminated
template <std::size_t N>
static inline char* strcpy_arr(char (&dest)[N], const char* src) {
{
std::size_t i = 0;
for (; src[i] && i < N - 1; ++i) {
dest[i] = src[i];
}
dest[i] = '\0';
}
return &dest[0];
}
} // namespace sample_util
} // namespace mujoco
#endif // MUJOCO_SAMPLE_ARRAY_SAFETY_H_
+53
View File
@@ -0,0 +1,53 @@
# Copyright 2021 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include(CheckCSourceCompiles)
# Assigns compiler options to the given variable based on availability of AVX.
function(get_avx_compile_options OUTPUT_VAR)
message(VERBOSE "Checking if AVX is available...")
if(MSVC)
set(CMAKE_REQUIRED_FLAGS "/arch:AVX")
else()
set(CMAKE_REQUIRED_FLAGS "-mavx")
endif()
if(APPLE AND "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES)
message(STATUS "Building x86_64 on macOS, forcing CAN_BUILD_AVX to TRUE.")
set(CAN_BUILD_AVX TRUE)
else()
check_c_source_compiles(
"
#include <immintrin.h>
int main(int argc, char* argv[]) {
__m256d ymm;
return 0;
}
"
CAN_BUILD_AVX
)
endif()
if(CAN_BUILD_AVX)
message(VERBOSE "Checking if AVX is available... AVX available.")
set("${OUTPUT_VAR}"
${CMAKE_REQUIRED_FLAGS}
PARENT_SCOPE
)
else()
message(VERBOSE "Checking if AVX is available... AVX not available.")
set("${OUTPUT_VAR}" PARENT_SCOPE)
endif()
endfunction()
+139
View File
@@ -0,0 +1,139 @@
# Copyright 2021 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#.rst:
# FindOrFetch
# ----------------------
#
# Find or fetch a package in order to satisfy target dependencies.
#
# FindOrFetch([USE_SYSTEM_PACKAGE [ON/OFF]]
# [PACKAGE_NAME [name]]
# [LIBRARY_NAME [name]]
# [GIT_REPO [repo]]
# [GIT_TAG [tag]]
# [PATCH_COMMAND [cmd] [args]]
# [TARGETS [targets]]
# [EXCLUDE_FROM_ALL])
#
# The command has the following parameters:
#
# Arguments:
# - ``USE_SYSTEM_PACKAGE`` one-value argument on whether to search for the
# package in the system (ON) or whether to fetch the library using
# FetchContent from the specified Git repository (OFF). Note that
# FetchContent variables will override this behaviour.
# - ``PACKAGE_NAME`` name of the system-package. Ignored if
# ``USE_SYSTEM_PACKAGE`` is ``OFF``.
# - ``LIBRARY_NAME`` name of the library. Ignored if
# ``USE_SYSTEM_PACKAGE`` is ``ON``.
# - ``GIT_REPO`` git repository to fetch the library from. Ignored if
# ``USE_SYSTEM_PACKAGE`` is ``ON``.
# - ``GIT_TAG`` tag reference when fetching the library from the git
# repository. Ignored if ``USE_SYSTEM_PACKAGE`` is ``ON``.
# - ``PATCH_COMMAND`` Specifies a custom command to patch the sources after an
# update. See https://cmake.org/cmake/help/latest/module/ExternalProject.html#command:externalproject_add
# for details on the parameter.
# - ``TARGETS`` list of targets to be satisfied. If any of these targets are
# not currently defined, this macro will attempt to either find or fetch the
# package.
# - ``EXCLUDE_FROM_ALL`` if specified, the targets are not added to the ``all``
# metatarget.
#
# Note: if ``USE_SYSTEM_PACKAGE`` is ``OFF``, FetchContent will be used to
# retrieve the specified targets. It is possible to specify any variable in
# https://cmake.org/cmake/help/latest/module/FetchContent.html#variables to
# override this macro behaviour.
if(COMMAND FindOrFetch)
return()
endif()
macro(FindOrFetch)
if(NOT FetchContent)
include(FetchContent)
endif()
# Parse arguments.
set(options EXCLUDE_FROM_ALL)
set(one_value_args
USE_SYSTEM_PACKAGE
PACKAGE_NAME
LIBRARY_NAME
GIT_REPO
GIT_TAG
)
set(multi_value_args PATCH_COMMAND TARGETS)
cmake_parse_arguments(
_ARGS
"${options}"
"${one_value_args}"
"${multi_value_args}"
${ARGN}
)
# Check if all targets are found.
if(NOT _ARGS_TARGETS)
message(FATAL_ERROR "mujoco::FindOrFetch: TARGETS must be specified.")
endif()
set(targets_found TRUE)
message(CHECK_START
"mujoco::FindOrFetch: checking for targets in package `${_ARGS_PACKAGE_NAME}`"
)
foreach(target ${_ARGS_TARGETS})
if(NOT TARGET ${target})
message(CHECK_FAIL "target `${target}` not defined.")
set(targets_found FALSE)
break()
endif()
endforeach()
# If targets are not found, use `find_package` or `FetchContent...` to get it.
if(NOT targets_found)
if(${_ARGS_USE_SYSTEM_PACKAGE})
message(CHECK_START
"mujoco::FindOrFetch: finding `${_ARGS_PACKAGE_NAME}` in system packages..."
)
find_package(${_ARGS_PACKAGE_NAME} REQUIRED)
message(CHECK_PASS "found")
else()
message(CHECK_START
"mujoco::FindOrFetch: Using FetchContent to retrieve `${_ARGS_LIBRARY_NAME}`"
)
FetchContent_Declare(
${_ARGS_LIBRARY_NAME}
GIT_REPOSITORY ${_ARGS_GIT_REPO}
GIT_TAG ${_ARGS_GIT_TAG}
GIT_SHALLOW FALSE
PATCH_COMMAND ${_ARGS_PATCH_COMMAND}
)
if(${_ARGS_EXCLUDE_FROM_ALL})
FetchContent_GetProperties(${_ARGS_LIBRARY_NAME})
if(NOT ${${_ARGS_LIBRARY_NAME}_POPULATED})
FetchContent_Populate(${_ARGS_LIBRARY_NAME})
add_subdirectory(
${${_ARGS_LIBRARY_NAME}_SOURCE_DIR} ${${_ARGS_LIBRARY_NAME}_BINARY_DIR}
EXCLUDE_FROM_ALL
)
endif()
else()
FetchContent_MakeAvailable(${_ARGS_LIBRARY_NAME})
endif()
message(CHECK_PASS "Done")
endif()
else()
message(CHECK_PASS "found")
endif()
endmacro()
+35
View File
@@ -0,0 +1,35 @@
# Copyright 2022 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
option(MUJOCO_HARDEN "Enable build hardening for MuJoCo." OFF)
if(MUJOCO_HARDEN
AND NOT
CMAKE_CXX_COMPILER_ID
MATCHES
".*Clang.*"
)
message(FATAL_ERROR "MUJOCO_HARDEN is only supported when building with Clang")
endif()
if(MUJOCO_HARDEN)
set(MUJOCO_HARDEN_COMPILE_OPTIONS -D_FORTIFY_SOURCE=2 -fstack-protector)
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(MUJOCO_HARDEN_LINK_OPTIONS -Wl,-bind_at_load)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(MUJOCO_HARDEN_LINK_OPTIONS -Wl,-z,relro -Wl,-z,now)
endif()
else()
set(MUJOCO_HARDEN_COMPILE_OPTIONS "")
set(MUJOCO_HARDEN_LINK_OPTIONS "")
endif()
+67
View File
@@ -0,0 +1,67 @@
# Copyright 2021 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include(CheckCSourceCompiles)
# Gets the appropriate linker options for building MuJoCo, based on features available on the
# linker.
function(get_mujoco_extra_link_options OUTPUT_VAR)
if(MSVC)
set(EXTRA_LINK_OPTIONS /OPT:REF /OPT:ICF=5)
else()
set(EXTRA_LINK_OPTIONS)
if(WIN32)
set(CMAKE_REQUIRED_FLAGS "-fuse-ld=lld-link")
check_c_source_compiles("int main() {}" SUPPORTS_LLD)
if(SUPPORTS_LLD)
set(EXTRA_LINK_OPTIONS
${EXTRA_LINK_OPTIONS}
-fuse-ld=lld-link
-Wl,/OPT:REF
-Wl,/OPT:ICF
)
endif()
else()
set(CMAKE_REQUIRED_FLAGS "-fuse-ld=lld")
check_c_source_compiles("int main() {}" SUPPORTS_LLD)
if(SUPPORTS_LLD)
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} -fuse-ld=lld)
else()
set(CMAKE_REQUIRED_FLAGS "-fuse-ld=gold")
check_c_source_compiles("int main() {}" SUPPORTS_GOLD)
if(SUPPORTS_GOLD)
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} -fuse-ld=gold)
endif()
endif()
set(CMAKE_REQUIRED_FLAGS ${EXTRA_LINK_OPTIONS} "-Wl,--gc-sections")
check_c_source_compiles("int main() {}" SUPPORTS_GC_SECTIONS)
if(SUPPORTS_GC_SECTIONS)
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} -Wl,--gc-sections)
else()
set(CMAKE_REQUIRED_FLAGS ${EXTRA_LINK_OPTIONS} "-Wl,-dead_strip")
check_c_source_compiles("int main() {}" SUPPORTS_DEAD_STRIP)
if(SUPPORTS_DEAD_STRIP)
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} -Wl,-dead_strip)
endif()
endif()
endif()
endif()
set("${OUTPUT_VAR}"
${EXTRA_LINK_OPTIONS}
PARENT_SCOPE
)
endfunction()
+38
View File
@@ -0,0 +1,38 @@
# Copyright 2022 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if(APPLE)
# 10.12 is the oldest version of macOS that supports C++17, launched 2016.
set(MUJOCO_MACOSX_VERSION_MIN 10.12)
# We are setting the -mmacosx-version-min compiler flag directly rather than using the
# CMAKE_OSX_DEPLOYMENT_TARGET variable since we do not want to affect choice of SDK,
# and also we only want to apply the version restriction locally.
set(MUJOCO_MACOS_COMPILE_OPTIONS -mmacosx-version-min=${MUJOCO_MACOSX_VERSION_MIN}
-Werror=partial-availability -Werror=unguarded-availability
)
set(MUJOCO_MACOS_LINK_OPTIONS -mmacosx-version-min=${MUJOCO_MACOSX_VERSION_MIN}
-Wl,-no_weak_imports
)
else()
set(MUJOCO_MACOS_COMPILE_OPTIONS "")
set(MUJOCO_MACOS_LINK_OPTIONS "")
endif()
function(enforce_mujoco_macosx_min_version)
if(APPLE)
add_compile_options(${MUJOCO_MACOS_COMPILE_OPTIONS})
add_link_options(${MUJOCO_MACOS_LINK_OPTIONS})
endif()
endfunction()
+104
View File
@@ -0,0 +1,104 @@
# Copyright 2021 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include(FindOrFetch)
if(SIMULATE_STANDALONE)
# If standalone, by default look for MuJoCo binary version.
set(DEFAULT_USE_SYSTEM_MUJOCO ON)
else()
set(DEFAULT_USE_SYSTEM_MUJOCO OFF)
endif()
option(MUJOCO_SIMULATE_USE_SYSTEM_MUJOCO "Use installed MuJoCo version."
${DEFAULT_USE_SYSTEM_MUJOCO}
)
unset(DEFAULT_USE_SYSTEM_MUJOCO)
option(MUJOCO_SIMULATE_USE_SYSTEM_MUJOCO "Use installed MuJoCo version." OFF)
option(MUJOCO_SIMULATE_USE_SYSTEM_GLFW "Use installed GLFW version." OFF)
set(MUJOCO_DEP_VERSION_glfw
7d5a16ce714f0b5f4efa3262de22e4d948851525 # 3.3.6
CACHE STRING "Version of `glfw` to be fetched."
)
mark_as_advanced(MUJOCO_DEP_VERSION_glfw)
find_package(Threads REQUIRED)
set(MUJOCO_BUILD_EXAMPLES OFF)
set(MUJOCO_BUILD_TESTS OFF)
set(MUJOCO_BUILD_PYTHON OFF)
set(MUJOCO_TEST_PYTHON_UTIL OFF)
findorfetch(
USE_SYSTEM_PACKAGE
MUJOCO_SIMULATE_USE_SYSTEM_MUJOCO
PACKAGE_NAME
mujoco
LIBRARY_NAME
mujoco
GIT_REPO
https://github.com/deepmind/mujoco.git
GIT_TAG
main
TARGETS
mujoco
EXCLUDE_FROM_ALL
)
option(MUJOCO_EXTRAS_STATIC_GLFW
"Link MuJoCo sample apps and simulate libraries against GLFW statically." ON
)
if(MUJOCO_EXTRAS_STATIC_GLFW)
set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS
OFF
CACHE INTERNAL "Build SHARED libraries"
)
endif()
set(GLFW_BUILD_EXAMPLES OFF)
set(GLFW_BUILD_TESTS OFF)
set(GLFW_BUILD_DOCS OFF)
set(GLFW_INSTALL OFF)
findorfetch(
USE_SYSTEM_PACKAGE
MUJOCO_SIMULATE_USE_SYSTEM_GLFW
PACKAGE_NAME
glfw
LIBRARY_NAME
glfw
GIT_REPO
https://github.com/glfw/glfw.git
GIT_TAG
${MUJOCO_DEP_VERSION_glfw}
TARGETS
glfw
EXCLUDE_FROM_ALL
)
if(MUJOCO_EXTRAS_STATIC_GLFW)
set(BUILD_SHARED_LIBS
${BUILD_SHARED_LIBS_OLD}
CACHE BOOL "Build SHARED libraries" FORCE
)
unset(BUILD_SHARED_LIBS_OLD)
endif()
if(NOT SIMULATE_STANDALONE)
target_compile_options(glfw PRIVATE ${MUJOCO_MACOS_COMPILE_OPTIONS})
target_link_options(glfw PRIVATE ${MUJOCO_MACOS_LINK_OPTIONS})
endif()
+106
View File
@@ -0,0 +1,106 @@
# Copyright 2021 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Global compilation settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # For LLVM tooling
if(NOT CMAKE_CONFIGURATION_TYPES)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE
"Release"
CACHE STRING "Choose the type of build, recommanded options are: Debug or Release" FORCE
)
endif()
set(BUILD_TYPES
"Debug"
"Release"
"MinSizeRel"
"RelWithDebInfo"
)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${BUILD_TYPES})
endif()
include(GNUInstallDirs)
# Change the default output directory in the build structure. This is not stricly needed, but helps
# running in Windows, such that all built executables have DLLs in the same folder as the .exe
# files.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(OpenGL_GL_PREFERENCE GLVND)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
if(MSVC)
add_compile_options(/Gy /Gw /Oi)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-fdata-sections -ffunction-sections)
endif()
# We default to shared library.
set(BUILD_SHARED_LIBS
ON
CACHE BOOL "Build Mujoco as shared library."
)
option(MUJOCO_ENABLE_AVX "Build binaries that require AVX instructions, if possible." ON)
option(MUJOCO_ENABLE_AVX_INTRINSICS "Make use of hand-written AVX intrinsics, if possible." ON)
option(MUJOCO_ENABLE_RPATH "Enable RPath support when installing Mujoco." ON)
mark_as_advanced(MUJOCO_ENABLE_RPATH)
if(MUJOCO_ENABLE_AVX)
include(CheckAvxSupport)
get_avx_compile_options(AVX_COMPILE_OPTIONS)
else()
set(AVX_COMPILE_OPTIONS)
endif()
option(MUJOCO_BUILD_MACOS_FRAMEWORKS "Build libraries as macOS Frameworks" OFF)
# Get some extra link options.
include(MujocoLinkOptions)
get_mujoco_extra_link_options(EXTRA_LINK_OPTIONS)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT MSVC))
set(EXTRA_COMPILE_OPTIONS -Wall -Werror)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(EXTRA_COMPILE_OPTIONS
-Wno-int-in-bool-context
-Wno-maybe-uninitialized
-Wno-sign-compare
-Wno-stringop-overflow
-Wno-stringop-truncation
)
endif()
endif()
if(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()
include(MujocoHarden)
set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS})
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS})
+293
View File
@@ -0,0 +1,293 @@
// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <chrono>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <mujoco/mujoco.h>
#include <mujoco/mjxmacro.h>
#include "simulate.h"
#include "array_safety.h"
namespace {
namespace mj = ::mujoco;
namespace mju = ::mujoco::sample_util;
// constants
const double syncmisalign = 0.1; // maximum time mis-alignment before re-sync
const double refreshfactor = 0.7; // fraction of refresh available for simulation
const int kErrorLength = 1024;
// model and data
mjModel* m = nullptr;
mjData* d = nullptr;
// control noise variables
mjtNum* ctrlnoise = nullptr;
//------------------------------------------- simulation -------------------------------------------
mjModel* LoadModel(const char* file, mj::Simulate& sim) {
// this copy is needed so that the mju::strlen call below compiles
char filename[mj::Simulate::kMaxFilenameLength];
mju::strcpy_arr(filename, file);
// make sure filename is not empty
if (!filename[0]) {
return nullptr;
}
// load and compile
char loadError[kErrorLength] = "";
mjModel* mnew = 0;
if (mju::strlen_arr(filename)>4 &&
!std::strncmp(filename + mju::strlen_arr(filename) - 4, ".mjb",
mju::sizeof_arr(filename) - mju::strlen_arr(filename)+4)) {
mnew = mj_loadModel(filename, nullptr);
if (!mnew) {
mju::strcpy_arr(loadError, "could not load binary model");
}
} else {
mnew = mj_loadXML(filename, nullptr, loadError, mj::Simulate::kMaxFilenameLength);
// remove trailing newline character from loadError
if (loadError[0]) {
int error_length = mju::strlen_arr(loadError);
if (loadError[error_length-1] == '\n') {
loadError[error_length-1] = '\0';
}
}
}
mju::strcpy_arr(sim.loadError, loadError);
if (!mnew) {
std::printf("%s\n", loadError);
return nullptr;
}
// compiler warning: print and pause
if (loadError[0]) {
// mj_forward() below will print the warning message
std::printf("Model compiled, but simulation warning (paused):\n %s\n", loadError);
sim.run = 0;
}
return mnew;
}
// simulate in background thread (while rendering in main thread)
void PhysicsLoop(mj::Simulate& sim) {
// cpu-sim syncronization point
double cpusync = 0;
mjtNum simsync = 0;
// run until asked to exit
while (!sim.exitrequest.load()) {
if (sim.droploadrequest.load()) {
mjModel* mnew = LoadModel(sim.dropfilename, sim);
sim.droploadrequest.store(false);
mjData* dnew = nullptr;
if (mnew) dnew = mj_makeData(mnew);
if (dnew) {
sim.load(sim.dropfilename, mnew, dnew, true);
m = mnew;
d = dnew;
mj_forward(m, d);
// allocate ctrlnoise
free(ctrlnoise);
ctrlnoise = (mjtNum*) malloc(sizeof(mjtNum)*m->nu);
mju_zero(ctrlnoise, m->nu);
}
}
if (sim.uiloadrequest.load()) {
sim.uiloadrequest.fetch_sub(1);
mjModel* mnew = LoadModel(sim.filename, sim);
mjData* dnew = nullptr;
if (mnew) dnew = mj_makeData(mnew);
if (dnew) {
sim.load(sim.filename, mnew, dnew, true);
m = mnew;
d = dnew;
mj_forward(m, d);
// allocate ctrlnoise
free(ctrlnoise);
ctrlnoise = static_cast<mjtNum*>(malloc(sizeof(mjtNum)*m->nu));
mju_zero(ctrlnoise, m->nu);
}
}
// sleep for 1 ms or yield, to let main thread run
// yield results in busy wait - which has better timing but kills battery life
if (sim.run && sim.busywait) {
std::this_thread::yield();
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
{
const std::lock_guard<std::mutex> lock(sim.mtx);
// run only if model is present
if (m) {
// running
if (sim.run) {
// record cpu time at start of iteration
double tmstart = glfwGetTime();
// inject noise
if (sim.ctrlnoisestd) {
// convert rate and scale to discrete time given current timestep
mjtNum rate = mju_exp(-m->opt.timestep / sim.ctrlnoiserate);
mjtNum scale = sim.ctrlnoisestd * mju_sqrt(1-rate*rate);
for (int i=0; i<m->nu; i++) {
// update noise
ctrlnoise[i] = rate * ctrlnoise[i] + scale * mju_standardNormal(nullptr);
// apply noise
d->ctrl[i] = ctrlnoise[i];
}
}
// out-of-sync (for any reason)
mjtNum offset = mju_abs((d->time*sim.slow_down-simsync)-(tmstart-cpusync));
if (d->time*sim.slow_down<simsync || tmstart<cpusync || cpusync==0 ||
offset > syncmisalign*sim.slow_down || sim.speed_changed) {
// re-sync
cpusync = tmstart;
simsync = d->time*sim.slow_down;
sim.speed_changed = false;
// clear old perturbations, apply new
mju_zero(d->xfrc_applied, 6*m->nbody);
sim.applyposepertubations(0); // move mocap bodies only
sim.applyforceperturbations();
// run single step, let next iteration deal with timing
mj_step(m, d);
}
// in-sync
else {
// step while simtime lags behind cputime, and within safefactor
while ((d->time*sim.slow_down-simsync) < (glfwGetTime()-cpusync) &&
(glfwGetTime()-tmstart) < refreshfactor/sim.vmode.refreshRate) {
// clear old perturbations, apply new
mju_zero(d->xfrc_applied, 6*m->nbody);
sim.applyposepertubations(0); // move mocap bodies only
sim.applyforceperturbations();
// run mj_step
mjtNum prevtm = d->time*sim.slow_down;
mj_step(m, d);
// break on reset
if (d->time*sim.slow_down<prevtm) {
break;
}
}
}
}
// paused
else {
// apply pose perturbation
sim.applyposepertubations(1); // move mocap and dynamic bodies
// run mj_forward, to update rendering and joint sliders
mj_forward(m, d);
}
}
} // std::lock_guard<std::mutex>
}
}
} // namespace
//-------------------------------------- physics_thread --------------------------------------------
void PhysicsThread(mj::Simulate* sim, const char* filename) {
// request loadmodel if file given (otherwise drag-and-drop)
if (filename != nullptr) {
m = LoadModel(filename, *sim);
if (m) d = mj_makeData(m);
if (d) {
sim->load(filename, m, d, true);
mj_forward(m, d);
// allocate ctrlnoise
free(ctrlnoise);
ctrlnoise = static_cast<mjtNum*>(malloc(sizeof(mjtNum)*m->nu));
mju_zero(ctrlnoise, m->nu);
}
}
PhysicsLoop(*sim);
// delete everything we allocated
free(ctrlnoise);
mj_deleteData(d);
mj_deleteModel(m);
}
//------------------------------------------ main --------------------------------------------------
// run event loop
int main(int argc, const char** argv) {
// print version, check compatibility
std::printf("MuJoCo version %s\n", mj_versionString());
if (mjVERSION_HEADER!=mj_version()) {
mju_error("Headers and library have different versions");
}
// simulate object encapsulates the UI
auto sim = std::make_unique<mj::Simulate>();
// init GLFW
if (!glfwInit()) {
mju_error("could not initialize GLFW");
}
const char* filename = nullptr;
if (argc > 1) {
filename = argv[1];
}
// start physics thread
std::thread physicsthreadhandle = std::thread(&PhysicsThread, sim.get(), filename);
// start simulation UI loop (blocking call)
sim->renderloop();
physicsthreadhandle.join();
// terminate GLFW (crashes with Linux NVidia drivers)
#if defined(__APPLE__) || defined(_WIN32)
glfwTerminate();
#endif
return 0;
}
+1904
View File
File diff suppressed because it is too large Load Diff
+214
View File
@@ -0,0 +1,214 @@
// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_SIMULATE_SIMULATE_H_
#define MUJOCO_SIMULATE_SIMULATE_H_
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <GLFW/glfw3.h>
#include <mujoco/mujoco.h>
#ifdef MJSIMULATE_STATIC
// static library
#define MJSIMULATEAPI
#define MJSIMULATELOCAL
#else
#ifdef MJSIMULATE_DLL_EXPORTS
#define MJSIMULATEAPI MUJOCO_HELPER_DLL_EXPORT
#else
#define MJSIMULATEAPI MUJOCO_HELPER_DLL_IMPORT
#endif
#define MJSIMULATELOCAL MUJOCO_HELPER_DLL_LOCAL
#endif
namespace mujoco {
//-------------------------------- global -----------------------------------------------
// Simulate states not contained in MuJoCo structures
class MJSIMULATEAPI Simulate {
public:
// create object and initialize the simulate ui
Simulate() = default;
// Apply UI pose perturbations to model and data
void applyposepertubations(int flg_paused);
// Apply UI force perturbations to model and data
void applyforceperturbations();
// Request that the Simulate UI thread render a new model
// optionally delete the old model and data when done
void load(const char* file, mjModel* m, mjData* d, bool delete_old_m_d);
// functions below are used by the renderthread
// load mjb or xml model that has been requested by load()
void loadmodel();
// prepare to render
void prepare();
// render the ui to the window
void render();
// clear callbacks registered in external structures
void clearcallback();
// loop to render the UI (must be called from main thread because of MacOS)
// https://discourse.glfw.org/t/multithreading-glfw/573/5
void renderloop();
// constants
static constexpr int kMaxFilenameLength = 1000;
// model and data to be visualized
mjModel* mnew = nullptr;
mjData* dnew = nullptr;
bool delete_old_m_d = false;
mjModel* m = nullptr;
mjData* d = nullptr;
std::mutex mtx;
std::condition_variable cond_loadrequest;
std::atomic_bool exitrequest = false;
// option
int spacing = 0;
int color = 0;
int font = 0;
int ui0_enable = 1;
int ui1_enable = 1;
int help = 0;
int info = 0;
int profiler = 0;
int sensor = 0;
int fullscreen = 0;
int vsync = 1;
int busywait = 0;
// simulation
int run = 1;
// keyframe index
int key = 0;
std::atomic_int uiloadrequest = 0;
std::atomic_bool droploadrequest = false;
// 2: render thread asked to update its model
// 1: showing "loading" label, about to load
// 0: model loaded or no load requested.
int loadrequest = 0;
// strings
char loadError[kMaxFilenameLength] = "";
char dropfilename[kMaxFilenameLength] = "";
char filename[kMaxFilenameLength] = "";
char previous_filename[kMaxFilenameLength] = "";
int slow_down = 1;
bool speed_changed = true;
double ctrlnoisestd = 0.0;
double ctrlnoiserate = 0.0;
// watch
char field[mjMAXUITEXT] = "qpos";
int index = 0;
// physics: need sync
int disable[mjNDISABLE] = {0};
int enable[mjNENABLE] = {0};
// rendering: need sync
int camera = 0;
// abstract visualization
mjvScene scn = {};
mjvCamera cam = {};
mjvOption vopt = {};
mjvPerturb pert = {};
mjvFigure figconstraint = {};
mjvFigure figcost = {};
mjvFigure figtimer = {};
mjvFigure figsize = {};
mjvFigure figsensor = {};
// OpenGL rendering and UI
GLFWvidmode vmode = {};
int windowpos[2] = {0};
int windowsize[2] = {0};
mjrContext con = {};
GLFWwindow* window = nullptr;
mjuiState uistate = {};
mjUI ui0 = {};
mjUI ui1 = {};
// Constant arrays needed for the option section of UI and the UI interface
// TODO setting the size here is not ideal
const mjuiDef defOption[14] = {
{mjITEM_SECTION, "Option", 1, nullptr, "AO"},
{mjITEM_SELECT, "Spacing", 1, &this->spacing, "Tight\nWide"},
{mjITEM_SELECT, "Color", 1, &this->color, "Default\nOrange\nWhite\nBlack"},
{mjITEM_SELECT, "Font", 1, &this->font, "50 %\n100 %\n150 %\n200 %\n250 %\n300 %"},
{mjITEM_CHECKINT, "Left UI (Tab)", 1, &this->ui0_enable, " #258"},
{mjITEM_CHECKINT, "Right UI", 1, &this->ui1_enable, "S#258"},
{mjITEM_CHECKINT, "Help", 2, &this->help, " #290"},
{mjITEM_CHECKINT, "Info", 2, &this->info, " #291"},
{mjITEM_CHECKINT, "Profiler", 2, &this->profiler, " #292"},
{mjITEM_CHECKINT, "Sensor", 2, &this->sensor, " #293"},
#ifdef __APPLE__
{mjITEM_CHECKINT, "Fullscreen", 0, &this->fullscreen, " #294"},
#else
{mjITEM_CHECKINT, "Fullscreen", 1, &this->fullscreen, " #294"},
#endif
{mjITEM_CHECKINT, "Vertical Sync", 1, &this->vsync, ""},
{mjITEM_CHECKINT, "Busy Wait", 1, &this->busywait, ""},
{mjITEM_END}
};
// simulation section of UI
const mjuiDef defSimulation[12] = {
{mjITEM_SECTION, "Simulation", 1, nullptr, "AS"},
{mjITEM_RADIO, "", 2, &this->run, "Pause\nRun"},
{mjITEM_BUTTON, "Reset", 2, nullptr, " #259"},
{mjITEM_BUTTON, "Reload", 2, nullptr, "CL"},
{mjITEM_BUTTON, "Align", 2, nullptr, "CA"},
{mjITEM_BUTTON, "Copy pose", 2, nullptr, "CC"},
{mjITEM_SLIDERINT, "Key", 3, &this->key, "0 0"},
{mjITEM_BUTTON, "Load key", 3},
{mjITEM_BUTTON, "Save key", 3},
{mjITEM_SLIDERNUM, "Noise scale", 2, &this->ctrlnoisestd, "0 2"},
{mjITEM_SLIDERNUM, "Noise rate", 2, &this->ctrlnoiserate, "0 2"},
{mjITEM_END}
};
// watch section of UI
const mjuiDef defWatch[5] = {
{mjITEM_SECTION, "Watch", 0, nullptr, "AW"},
{mjITEM_EDITTXT, "Field", 2, this->field, "qpos"},
{mjITEM_EDITINT, "Index", 2, &this->index, "1"},
{mjITEM_STATIC, "Value", 2, nullptr, " "},
{mjITEM_END}
};
// info strings
char info_title[Simulate::kMaxFilenameLength] = {0};
char info_content[Simulate::kMaxFilenameLength] = {0};
};
} // namespace mujoco
#endif
+22 -3
View File
@@ -13,11 +13,12 @@
// limitations under the License.
#include "uitools.h"
#include <stdio.h>
#include <string.h>
//-------------------------------- Internal GLFW callbacks ------------------------------
//------------------------------------ internal GLFW callbacks -------------------------------------
// update state
static void uiUpdateState(GLFWwindow* wnd) {
@@ -226,8 +227,19 @@ static void uiResize(GLFWwindow* wnd, int width, int height) {
}
static void uiRender(GLFWwindow* wnd) {
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
mjuiState* state = ptr->state;
ptr->uiRender(state);
}
//----------------------------------- Public API ----------------------------------------
static void uiDrop(GLFWwindow* wnd, int count, const char** paths) {
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
mjuiState* state = ptr->state;
ptr->uiDrop(state, count, paths);
}
//------------------------------------------- public API -------------------------------------------
// Compute suitable font scale.
int uiFontScale(GLFWwindow* wnd) {
@@ -262,12 +274,15 @@ int uiFontScale(GLFWwindow* wnd) {
// Set internal and user-supplied UI callbacks in GLFW window.
void uiSetCallback(GLFWwindow* wnd, mjuiState* state,
uiEventFn uiEvent, uiLayoutFn uiLayout) {
uiEventFn uiEvent, uiLayoutFn uiLayout,
uiRenderFn uiUserRender, uiDropFn uiUserDrop) {
// make container with user-supplied objects and set window pointer
uiUserPointer* ptr = (uiUserPointer*) mju_malloc(sizeof(uiUserPointer));
ptr->state = state;
ptr->uiEvent = uiEvent;
ptr->uiLayout = uiLayout;
ptr->uiRender = uiUserRender;
ptr->uiDrop = uiUserDrop;
glfwSetWindowUserPointer(wnd, ptr);
// compute framebuffer-to-window pixel ratio
@@ -282,6 +297,8 @@ void uiSetCallback(GLFWwindow* wnd, mjuiState* state,
glfwSetMouseButtonCallback(wnd, uiMouseButton);
glfwSetScrollCallback(wnd, uiScroll);
glfwSetWindowSizeCallback(wnd, uiResize);
glfwSetWindowRefreshCallback(wnd, uiRender);
glfwSetDropCallback(wnd, uiDrop);
}
@@ -300,6 +317,8 @@ void uiClearCallback(GLFWwindow* wnd) {
glfwSetMouseButtonCallback(wnd, NULL);
glfwSetScrollCallback(wnd, NULL);
glfwSetWindowSizeCallback(wnd, NULL);
glfwSetWindowRefreshCallback(wnd, NULL);
glfwSetDropCallback(wnd, NULL);
}
+8 -4
View File
@@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_UITOOLS_H_
#define MUJOCO_UITOOLS_H_
#ifndef MUJOCO_SIMULATE_UITOOLS_H_
#define MUJOCO_SIMULATE_UITOOLS_H_
#include <GLFW/glfw3.h>
#include <mujoco/mujoco.h>
@@ -28,19 +27,24 @@ extern "C" {
// User-supplied callback function types.
typedef void (*uiEventFn)(mjuiState* state);
typedef void (*uiLayoutFn)(mjuiState* state);
typedef void (*uiRenderFn)(mjuiState* state);
typedef void (*uiDropFn) (mjuiState* state, int count, const char** paths);
// Container for GLFW window pointer.
struct _uiUserPointer {
mjuiState* state;
uiEventFn uiEvent;
uiLayoutFn uiLayout;
uiRenderFn uiRender;
uiDropFn uiDrop;
double buffer2window;
};
typedef struct _uiUserPointer uiUserPointer;
// Set internal and user-supplied UI callbacks in GLFW window.
void uiSetCallback(GLFWwindow* wnd, mjuiState* state,
uiEventFn uiEvent, uiLayoutFn uiLayout);
uiEventFn uiEvent, uiLayoutFn uiLayout,
uiRenderFn uiUserRender, uiDropFn uiUserDrop);
// Clear UI callbacks in GLFW window.
void uiClearCallback(GLFWwindow* wnd);