e272e46770
Example formatting: ``` # default precision <key time="2.99" qpos="9.4287e-07 3.02972e-07 1.19963 0.999999 -9.3978e-06 0.00102591 8.06948e-06 -0.000337469 -0.000182994 -0.00282448 -0.000358084 -0.00370829 0.0631084 0.0996347 -0.00161963 0.0260658 -2.09992 -0.00459387 0.0474729 -0.0171906 0.0018216 0.72549 0.00133026 0.724951 0.000816735 0.724389 0.000454671 0.724 -0.00146646 -1.12233e-05 -0.0995942 0.00159877 0.0261695 -2.09993 0.00458912 0.0473279 0.0171317 0.00177837 0.725447 0.00131597 0.724941 0.00081406 0.724393 0.000465918 0.72402 -0.00140271 -1.42355e-05 0.0949171 0.0790632 -0.461397 1.02664 -9.42133e-05 -0.55539 -0.0952333 -0.0790705 -0.460978 1.02899 8.38339e-05 -0.671707 0.401772 0.197427 1.00101 0.999979 0.00125793 -0.00100982 -0.00631542" qvel="0.000132784 3.49155e-05 0.000536692 -0.000560519 -0.0242142 0.00693928 0.00119816 -0.000234844 0.00350923 -0.00036047 0.00137217 0.026605 0.000647559 -0.000813737 0.00151335 0.00158296 -0.000628786 0.0184574 -0.000751955 8.75972e-05 0.00017462 9.47749e-05 0.00018949 7.40435e-05 0.000170318 -2.65743e-05 5.67808e-05 0.000256585 -8.77605e-05 -0.00070146 5.90881e-05 0.00186213 0.00150788 0.000645196 0.0183261 -0.00189709 0.000234144 0.000180699 0.00020344 0.000161977 0.000154203 0.000127231 2.28526e-05 -2.85628e-06 0.000232213 2.32483e-05 -0.000415728 0.000285987 0.00873081 0.00361353 5.70155e-05 0.000316513 -0.00778618 0.00404914 -0.0239508 -0.0375704 -0.000528571 4.92965 3.51479e-15 -4.54231e-16 -9.39907e-15 -7.5733e-14 -1.54433e-14 8.71183e-14" ctrl="0 0 0 0 0 0 0.106158 0 0 -2.1308 0 0 0 0 0 0 0 0 0 -0.106158 0 0 -2.1308 0 0 0 0 0 0 0 0 0 0.1 0.08 -0.477 1.033 0 -0.556 -0.1 -0.08 -0.477 1.033 0 -0.556" mpos="0.5 0 0.5 0.5 0 0.5 0.5 0 0.5" mquat="1 0 0 0 1 0 0 0 1 0 0 0" /> # full precision <key time="19.78000000000035 " qpos="-5.456931939182209e-13 4.210058291674657e-14 1.199596868198444 0.9999997705632744 -1.123107929038176e-05 -0.000677308838908712 -4.574736052563342e-13 4.81467762006399e-06 -0.0001470530836508491 -0.01285126600561344 -0.0003314670141921113 -0.003753266058087929 0.06165064101255623 0.01573179146576803 -3.013291189105153e-05 0.00898818165332332 -0.0005543865919957537 0.001960768693378906 0.003171337599202657 0.05998529721754536 -0.006869809693640725 0.7108455550986151 -2.768022862919269e-05 0.7234287700347743 -2.65358465809282e-05 0.7234305602907817 -2.427451970418236e-05 0.7234340023869628 0.0001444026830625057 0.004779116304496144 -0.01556918200171751 2.367030531882565e-05 0.00887857821391661 -0.0005393749458389281 -0.002002170464405725 0.004065365245773832 -0.059404381452836 -0.006700853036263364 0.7112073591870905 -2.793780628594305e-05 0.7234283783336887 -2.67570932686378e-05 0.7234302250735107 -2.446320244250625e-05 0.7234337167312712 0.0001441442525519209 0.004776981844081063 0.001964241516442131 -0.001279289930183057 0.0009901921906584617 0.005102724602622095 -0.0001969944416873799 0.0006055390861509305 -0.001981889349334628 0.001289775046291938 0.0009924227912350586 0.005084179458414934 0.0001970337430004949 0.0006055492125132441 0.4000059982468001 0.2000006330421453 1.001005166968155 0.9999986986616857 0.001264259603338192 -0.00100188514175821 -2.342548568520312e-05" qvel="8.028421913635349e-14 -7.933623204015651e-15 -1.766955416585763e-09 -1.242788325114248e-10 1.380680257623891e-08 4.072776622758517e-13 -2.152263214542579e-08 -3.878177040643757e-09 -7.698904695669224e-07 1.032750347898222e-09 -1.203279562630678e-09 -7.551458300921444e-08 2.469496246057255e-06 8.917880101195273e-08 -6.756803792056489e-06 -2.872076666906819e-06 1.785650772865195e-06 -5.01959632083366e-06 -5.599940213931672e-06 8.890181416091634e-07 1.64456042549838e-06 -1.371426840474208e-09 -2.120678515220117e-09 -2.024654983099582e-09 -3.146661587304676e-09 -2.584650818327909e-09 -4.007447393764789e-09 3.46515937628953e-09 1.271775029987075e-08 -2.488928508740539e-06 -8.746797042033161e-08 -6.8499144406484e-06 -2.901446048768352e-06 -1.790798673741401e-06 -5.013863339758384e-06 5.931327072492727e-06 9.379458926032098e-07 1.728266244061688e-06 -1.546731198107214e-09 -2.391411625987869e-09 -2.205072839286403e-09 -3.425520861505272e-09 -2.768770278332858e-09 -4.29204657928239e-09 3.77970711367913e-09 1.210836106515995e-08 2.48779855243758e-07 1.794262457563144e-08 2.425338558609319e-07 -4.490996387632652e-09 1.5470867213074e-10 -1.056275279772894e-10 -2.528203830071622e-07 -1.984360361016969e-08 2.432485190492325e-07 -4.490126811319184e-09 -1.553085076375719e-10 -1.050844929338509e-10 -5.03087850573677e-15 -3.069973955284326e-15 1.263049899085103e-14 -2.132657422360499e-13 1.240631051776082e-14 7.346260313161907e-14 " ctrl="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " mpos="0.5 0 0.5 0.5 0 0.5 0.5 0 0.5 " mquat="1 0 0 0 1 0 0 0 1 0 0 0 " /> ``` PiperOrigin-RevId: 741427042 Change-Id: Ib33f3e6215b7933d9267fc4c222d7a0abc75dbb4
331 lines
10 KiB
C++
331 lines
10 KiB
C++
// 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 <chrono>
|
|
#include <condition_variable>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <ratio>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <mujoco/mjui.h>
|
|
#include <mujoco/mujoco.h>
|
|
#include "platform_ui_adapter.h"
|
|
|
|
namespace mujoco {
|
|
|
|
// The viewer itself doesn't require a reentrant mutex, however we use it in
|
|
// order to provide a Python sync API that doesn't require separate locking
|
|
// (since sync is by far the most common operation), but that also won't
|
|
// deadlock if called when a lock is already held by the user script on the
|
|
// same thread.
|
|
class SimulateMutex : public std::recursive_mutex {};
|
|
using MutexLock = std::unique_lock<std::recursive_mutex>;
|
|
|
|
// Simulate states not contained in MuJoCo structures
|
|
class Simulate {
|
|
public:
|
|
using Clock = std::chrono::steady_clock;
|
|
static_assert(std::ratio_less_equal_v<Clock::period, std::milli>);
|
|
|
|
static constexpr int kMaxGeom = 20000;
|
|
|
|
// create object and initialize the simulate ui
|
|
Simulate(
|
|
std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
|
|
mjvCamera* cam, mjvOption* opt, mjvPerturb* pert, bool is_passive);
|
|
|
|
// Synchronize mjModel and mjData state with UI inputs, and update
|
|
// visualization.
|
|
void Sync();
|
|
|
|
void UpdateHField(int hfieldid);
|
|
void UpdateMesh(int meshid);
|
|
void UpdateTexture(int texid);
|
|
|
|
// Request that the Simulate UI display a "loading" message
|
|
// Called prior to Load or LoadMessageClear
|
|
void LoadMessage(const char* displayed_filename);
|
|
|
|
// Request that the Simulate UI thread render a new model
|
|
void Load(mjModel* m, mjData* d, const char* displayed_filename);
|
|
|
|
// Clear the loading message
|
|
// Can be called instead of Load to clear the message without
|
|
// requesting the UI load a model
|
|
void LoadMessageClear(void);
|
|
|
|
// functions below are used by the renderthread
|
|
// load mjb or xml model that has been requested by load()
|
|
void LoadOnRenderThread();
|
|
|
|
// render the ui to the window
|
|
void Render();
|
|
|
|
// loop to render the UI (must be called from main thread because of MacOS)
|
|
void RenderLoop();
|
|
|
|
// add state to history buffer
|
|
void AddToHistory();
|
|
|
|
// inject control noise
|
|
void InjectNoise();
|
|
|
|
// constants
|
|
static constexpr int kMaxFilenameLength = 1000;
|
|
|
|
// whether the viewer is operating in passive mode, where it cannot assume
|
|
// that it has exclusive access to mjModel, mjData, and various mjv objects
|
|
bool is_passive_ = false;
|
|
|
|
// model and data to be visualized
|
|
mjModel* mnew_ = nullptr;
|
|
mjData* dnew_ = nullptr;
|
|
|
|
mjModel* m_ = nullptr;
|
|
mjData* d_ = nullptr;
|
|
|
|
int ncam_ = 0;
|
|
int nkey_ = 0;
|
|
int state_size_ = 0; // number of mjtNums in a history buffer state
|
|
int nhistory_ = 0; // number of states saved in history buffer
|
|
int history_cursor_ = 0; // cursor pointing at last saved state
|
|
|
|
std::vector<int> body_parentid_;
|
|
|
|
std::vector<int> jnt_type_;
|
|
std::vector<int> jnt_group_;
|
|
std::vector<int> jnt_qposadr_;
|
|
std::vector<std::optional<std::pair<mjtNum, mjtNum>>> jnt_range_;
|
|
std::vector<std::string> jnt_names_;
|
|
|
|
std::vector<int> actuator_group_;
|
|
std::vector<std::optional<std::pair<mjtNum, mjtNum>>> actuator_ctrlrange_;
|
|
std::vector<std::string> actuator_names_;
|
|
|
|
std::vector<mjtNum> history_; // history buffer (nhistory x state_size)
|
|
|
|
// mjModel and mjData fields that can be modified by the user through the GUI
|
|
std::vector<mjtNum> qpos_;
|
|
std::vector<mjtNum> qpos_prev_;
|
|
std::vector<mjtNum> ctrl_;
|
|
std::vector<mjtNum> ctrl_prev_;
|
|
|
|
mjvSceneState scnstate_;
|
|
mjOption mjopt_prev_;
|
|
mjvOption opt_prev_;
|
|
mjvCamera cam_prev_;
|
|
|
|
int warn_vgeomfull_prev_;
|
|
|
|
// pending GUI-driven actions, to be applied at the next call to Sync
|
|
struct {
|
|
std::optional<std::string> save_xml;
|
|
std::optional<std::string> save_mjb;
|
|
std::optional<std::string> print_model;
|
|
std::optional<std::string> print_data;
|
|
bool reset;
|
|
bool align;
|
|
bool copy_key;
|
|
bool copy_key_full_precision;
|
|
bool load_from_history;
|
|
bool load_key;
|
|
bool save_key;
|
|
bool zero_ctrl;
|
|
int newperturb;
|
|
bool select;
|
|
mjuiState select_state;
|
|
bool ui_update_simulation;
|
|
bool ui_update_physics;
|
|
bool ui_update_rendering;
|
|
bool ui_update_joint;
|
|
bool ui_update_ctrl;
|
|
bool ui_remake_ctrl;
|
|
} pending_ = {};
|
|
|
|
SimulateMutex mtx;
|
|
std::condition_variable_any cond_loadrequest;
|
|
|
|
int frames_ = 0;
|
|
std::chrono::time_point<Clock> last_fps_update_;
|
|
double fps_ = 0;
|
|
|
|
// options
|
|
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 pause_update = 1;
|
|
int fullscreen = 0;
|
|
int vsync = 1;
|
|
int busywait = 0;
|
|
|
|
// keyframe index
|
|
int key = 0;
|
|
|
|
// index of history-scrubber slider
|
|
int scrub_index = 0;
|
|
|
|
// simulation
|
|
int run = 1;
|
|
|
|
// atomics for cross-thread messages
|
|
std::atomic_int exitrequest = 0;
|
|
std::atomic_int droploadrequest = 0;
|
|
std::atomic_int screenshotrequest = 0;
|
|
std::atomic_int uiloadrequest = 0;
|
|
|
|
// loadrequest
|
|
// 3: display a loading message
|
|
// 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 load_error[kMaxFilenameLength] = "";
|
|
char dropfilename[kMaxFilenameLength] = "";
|
|
char filename[kMaxFilenameLength] = "";
|
|
char previous_filename[kMaxFilenameLength] = "";
|
|
|
|
// time synchronization
|
|
int real_time_index = 0;
|
|
bool speed_changed = true;
|
|
float measured_slowdown = 1.0;
|
|
// logarithmically spaced real-time slow-down coefficients (percent)
|
|
static constexpr float 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
|
|
};
|
|
|
|
// control noise
|
|
double ctrl_noise_std = 0.0;
|
|
double ctrl_noise_rate = 0.0;
|
|
|
|
// watch
|
|
char field[mjMAXUITEXT] = "qpos";
|
|
int index = 0;
|
|
|
|
// physics: need sync
|
|
int disable[mjNDISABLE] = {0};
|
|
int enable[mjNENABLE] = {0};
|
|
int enableactuator[mjNGROUP] = {0};
|
|
|
|
// rendering: need sync
|
|
int camera = 0;
|
|
|
|
// abstract visualization
|
|
mjvScene scn;
|
|
mjvCamera& cam;
|
|
mjvOption& opt;
|
|
mjvPerturb& pert;
|
|
mjvFigure figconstraint = {};
|
|
mjvFigure figcost = {};
|
|
mjvFigure figtimer = {};
|
|
mjvFigure figsize = {};
|
|
mjvFigure figsensor = {};
|
|
|
|
// additional user-defined visualization geoms (used in passive mode)
|
|
mjvScene* user_scn = nullptr;
|
|
mjtByte user_scn_flags_prev_[mjNRNDFLAG];
|
|
std::vector<std::pair<mjrRect, mjvFigure>> user_figures_;
|
|
|
|
// OpenGL rendering and UI
|
|
int refresh_rate = 60;
|
|
int window_pos[2] = {0};
|
|
int window_size[2] = {0};
|
|
std::unique_ptr<PlatformUIAdapter> platform_ui;
|
|
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 def_option[13] = {
|
|
{mjITEM_SECTION, "Option", mjPRESERVE, nullptr, "AO"},
|
|
{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"},
|
|
{mjITEM_CHECKINT, "Pause update", 2, &this->pause_update, ""},
|
|
#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_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_END}
|
|
};
|
|
|
|
|
|
// simulation section of UI
|
|
const mjuiDef def_simulation[14] = {
|
|
{mjITEM_SECTION, "Simulation", mjPRESERVE, nullptr, "AS"},
|
|
{mjITEM_RADIO, "", 5, &this->run, "Pause\nRun"},
|
|
{mjITEM_BUTTON, "Reset", 2, nullptr, " #259"},
|
|
{mjITEM_BUTTON, "Reload", 5, nullptr, "CL"},
|
|
{mjITEM_BUTTON, "Align", 2, nullptr, "CA"},
|
|
{mjITEM_BUTTON, "Copy state", 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", 5, &this->ctrl_noise_std, "0 1"},
|
|
{mjITEM_SLIDERNUM, "Noise rate", 5, &this->ctrl_noise_rate, "0 4"},
|
|
{mjITEM_SEPARATOR, "History", 1},
|
|
{mjITEM_SLIDERINT, "", 5, &this->scrub_index, "0 0"},
|
|
{mjITEM_END}
|
|
};
|
|
|
|
|
|
// watch section of UI
|
|
const mjuiDef def_watch[5] = {
|
|
{mjITEM_SECTION, "Watch", mjPRESERVE, 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};
|
|
|
|
// pending uploads
|
|
std::condition_variable_any cond_upload_;
|
|
int texture_upload_ = -1;
|
|
int mesh_upload_ = -1;
|
|
int hfield_upload_ = -1;
|
|
};
|
|
} // namespace mujoco
|
|
|
|
#endif
|