Closed ronansgd closed 1 year ago
I have the same issue. The mj_objectVelocity
seems to be correct, but mj_objectVelocity
always return zero.
@happygaoxiao Presumably you meant acceleration? Could you try using an accelerometer sensor? If not, please provide a MWE?
Regarding @ronansgd's OP (sorry, clearly dropped the ball here), the errors one would expect for accelerations, given your code, should be 1/dt larger than the velocity errors, so I think this WAI. Do you disagree?
Hello, sorry, I mean the acceleration always return zero. Here is a simple test. An object falls from a height of 1m.
import numpy as np
import mujoco
import time
from mujoco import viewer
cylinder_falling = """
<mujoco model="cylinder">
<option>
<flag gravity="enable"/>
</option>
<default class="obj">
<geom condim="6" friction="1 0.5 0.01" solimp="1.1 1.2 0.001 0.5 2" solref="0.02 2"/>
</default>
<worldbody>
<light directional="true" diffuse=".4 .4 .4" specular="0.1 0.1 0.1" pos="0 0 5.0" dir="0 0 -1" castshadow="false"/>
<light directional="true" diffuse=".6 .6 .6" specular="0.2 0.2 0.2" pos="0 0 4" dir="0 0 -1"/>
<body name="table" pos="0.0 0 0.1">
<geom name="table1" class="obj" type="box" size="0.3 0.6 0.1" pos="0 0 0" mass="10"/>
</body>
<body name="cylinder1" pos="0 0 1" quat="1 1. 0. 0.">
<joint name="cylinder1:joint" type="free"/>
<geom name="cylinder1" class="obj" mass="0.1" pos="0 0 0" rgba="0 1 0 1" size="0.02 0.15" type="cylinder"/>
</body>
</worldbody>
</mujoco>
"""
model = mujoco.MjModel.from_xml_string(cylinder_falling)
data = mujoco.MjData(model)
view = viewer.launch_passive(model, data)
mujoco.mj_forward(model, data)
t0 = time.time()
while 1:
t = time.time() - t0
if t > 1:
break
mujoco.mj_step(model, data)
view.sync()
vel = np.zeros(6)
body_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, "cylinder1")
mujoco.mj_objectVelocity(model, data, mujoco.mjtObj.mjOBJ_BODY,
body_id, vel, 0) # 1 for local, 0 for world frame
acc = np.zeros(6)
mujoco.mj_objectAcceleration(model, data, mujoco.mjtObj.mjOBJ_BODY,
body_id, acc, 0)
print(t, vel, acc)
time.sleep(0.002)
Here is the print output:
2.384185791015625e-06 [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] 0.0027878284454345703 [ 0. 0. 0. 0. 0. -0.01962] [0. 0. 0. 0. 0. 0.] 0.00539851188659668 [ 0. 0. 0. 0. 0. -0.03924] [0. 0. 0. 0. 0. 0.] 0.007817983627319336 [ 0. 0. 0. 0. 0. -0.05886] [0. 0. 0. 0. 0. 0.] 0.01036381721496582 [ 0. 0. 0. 0. 0. -0.07848] [0. 0. 0. 0. 0. 0.] 0.012817621231079102 [ 0. 0. 0. 0. 0. -0.0981] [0. 0. 0. 0. 0. 0.] 0.01527857780456543 [ 0. 0. 0. 0. 0. -0.11772] [0. 0. 0. 0. 0. 0.] 0.01778888702392578 [ 0. 0. 0. 0. 0. -0.13734] [0. 0. 0. 0. 0. 0.] 0.02035379409790039 [ 0. 0. 0. 0. 0. -0.15696] [0. 0. 0. 0. 0. 0.] 0.022930145263671875 [ 0. 0. 0. 0. 0. -0.17658] [0. 0. 0. 0. 0. 0.] 0.02557849884033203 [ 0. 0. 0. 0. 0. -0.1962] [0. 0. 0. 0. 0. 0.] 0.02804088592529297 [ 0. 0. 0. 0. 0. -0.21582] [0. 0. 0. 0. 0. 0.] 0.03049755096435547 [ 0. 0. 0. 0. 0. -0.23544] [0. 0. 0. 0. 0. 0.] 0.03313016891479492 [ 0. 0. 0. 0. 0. -0.25506] [0. 0. 0. 0. 0. 0.] 0.03551840782165527 [ 0. 0. 0. 0. 0. -0.27468] [0. 0. 0. 0. 0. 0.]
I have checked that the model.opt.gravity
is [0,0,-9.81]
, and model.opt.timestep=0.002
.
The velocity is correct and is increasing 0.002*9.81=0.01962 m/s in each step. But the acceleration is always zero.
Okay there are two parts to the answer, neither are obvious and should be properly documented, which we will take care of soon. In the meantime this reply can act as documentation.
In order for mj_objectAcceleration
to report anything, you need to call mj_rnePostConstraint
. Why is this? Recursive Newton Euler is run in the middle part of the pipeline (step 17), not taking into account the constraint forces. In order to calculate things like F/T sensors and accelerometers, another call to RNE is required, taking into account constraint forces and induced accelerations, calculating the quantities:
// computed by mj_sensorAcc/mj_rnePostConstraint if needed; rotation:translation format
mjtNum* cacc; // com-based acceleration (nbody x 6)
mjtNum* cfrc_int; // com-based interaction force with parent (nbody x 6)
mjtNum* cfrc_ext; // com-based external force on body (nbody x 6)
Because these quantities are not required for the next step, it would be wasteful to always compute them. MuJoCo therefore only calls mj_rnePostConstraint
if a sensor which requires these quantities is defined. Of course the user can always call the function manually.
Understanding the computed values is also perhaps unintuitive, and requires a bit of (surprise!) general relativity. Consider the following MWE:
xml = """
<mujoco>
<worldbody>
<geom name="floor" type="plane" size="1 1 .1"/>
<body name="falling" pos="0 0 10">
<freejoint/>
<geom size="0.1"/>
</body>
<body name="resting" pos="0 0 .1">
<freejoint/>
<geom size="0.1"/>
</body>
</worldbody>
</mujoco>
"""
model = mujoco.MjModel.from_xml_string(xml)
data = mujoco.MjData(model)
while data.time < 0.2: mujoco.mj_step(model, data)
mujoco.mj_rnePostConstraint(model, data)
id_falling = model.body('falling').id id_resting = model.body('resting').id id_world = model.body('world').id
assert id_world == 0
xacc = np.zeros(6) type_body = mujoco.mjtObj.mjOBJ_BODY flg_local = 0 mujoco.mj_objectAcceleration(model, data, type_body, id_world, xacc, flg_local) print('world acceleration', xacc) mujoco.mj_objectAcceleration(model, data, type_body, id_resting, xacc, flg_local) print('resting acceleration', xacc) mujoco.mj_objectAcceleration(model, data, type_body, id_falling, xacc, flg_local) print('falling acceleration', xacc)
This code will output
world acceleration [0. 0. 0. 0. 0. 9.81] resting acceleration [0. 0. 0. 0. 0. 9.81] falling acceleration [0. 0. 0. 0. 0. 0.]
In MuJoCo, *gravity is not implemented as a force*. Instead, we use Einstein's [Equivalence Principle](https://en.wikipedia.org/wiki/Equivalence_principle), modeling gravity as an *upward acceleration of the world frame*. This might seem strange if you're used to high-school mechanics, but is more consistent with reality: Take an accelerometer and throw it in the air. During the flight phase it will report no acceleration, even though the trajectory is curved. Once it reaches the ground and stops moving, it will report gravity, even though it is stationary w.r.t the world. To summarise, accelerations reported by MuJoCo take into account the fact that the *world is accelerating up*. This is actually happening in reality, due to the local curvature between the vertical direction and the temporal direction, induced by the mass of the earth.
Hi, I am a student using MuJoCo for a university project; I precisely use the version 2.2.2 of the Python bindings on Ubuntu 20.04
I wanted to compute the acceleration in global cartesian coordinates of a body using the function
mj_objectAcceleration
.To test that I created a simple pendulum model
pendulum.xml
, and wrote a python scriptswing.py
letting the pendulum swing.pendulum.xml
swing.py
import os import mujoco as mjc from mujoco import mjtObj, MjModel, MjData import numpy as np model_path = "path/to/pendulum.xml" assert os.path.isfile(model_path) model = MjModel.from_xml_path(model_path) sim = MjData(model) mjc.mj_forward(model, sim) pend_body_id = mjc.mj_name2id(model, mjtObj.mjOBJ_BODY, "pendulum") n_steps = 200 pos_array = np.zeros((n_steps, 3)) vel_array = np.zeros((n_steps, 3)) acc_array = np.zeros((n_steps, 3)) for idx in range(n_steps): mjc.mj_step(model, sim) pos_array[idx] = sim.xipos[pend_body_id] # get velocity res_array = np.zeros(6) mjc.mj_objectVelocity(model, sim, mjtObj.mjOBJ_BODY, pend_body_id, res_array, 0) vel_array[idx] = res_array[-3:] # get acceleration mjc.mj_objectAcceleration( model, sim, mjtObj.mjOBJ_BODY, pend_body_id, res_array, 0) acc_array[idx] = res_array[-3:] approx_vel = (pos_array[1:] - pos_array[:-1]) / model.opt.timestep print("vel error: ", np.linalg.norm(approx_vel - vel_array[1:]) / (n_steps - 1)) approx_acc = (vel_array[1:] - vel_array[:-1]) / model.opt.timestep print("acc error: ", np.linalg.norm(approx_acc - acc_array[1:]) / (n_steps - 1)) print("init acc: ", acc_array[0])Running the script, I get a
vel error
of roughly 0.000759, which sounds reasonable.However, the
acc error
is close to 0.582496, which doesn't look good. Moreover, theinit acc
is displayed as [0. 0. 0.], while I would have expected it to be close to gravity (ie [0. 0. -9.81]) given that initially the pendulum is horizontal.I guess that I misunderstood something about
mj_objectAcceleration
, can someone point out what I got wrong?Thank you for your time.