Hi. I'm quite knew to MuJoCo Pro. In the finite difference algorithm is necessary to call the mj_step to evaluate the disturbances in the states, but, if I already have an installed control function at the pipeline and you want to calculate the mj_step without it, what is the best way? I was thinking of using mj_step1 and mj_step2, but it only uses Euler integration, right? Thanks in advance.
Several comments regarding finite differences, control callback and mj_step/1/2: 1. The code sample computes derivatives with respect to applied force (qfrc_applied) and not with respect to control. In general, the number of control signals does not equal the number of degrees of freedom, so if you want to compute such a derivative, it will have different dimensionality. 2. The code sample uses mj_forward and mj_inverse to compute the dynamics at nearby states and applied forces (and then subtract them to obtain numerical derivatives). These functions compute continuous-time quantities. Thus the finite difference results do not directly depend on the integrator. mj_step is only used in the driver function, as a way to generate states along a trajectory of the passive dynamics. The derivatives are then computed at those states. It doesn't actually matter where these states came from and whether or not they form a continuous trajectory; the finite difference computation is the same for any state. 3. mj_step1 followed by mj_step2 still calls the control callback at the end of mj_step1; and gives you the option to modify ctrl or the applied forces before calling mj_step2. So this is not a valid way to disable the control callback. 4. To disable the control callback, simply set the function pointer mjcb_control to a function that does nothing, call mj_step, then set the pointer again to your actual control callback. When modifying the derivatives code sample or developing new code, it is a good idea to find some mathematical identity that allows you to check the numerical results. Even though the basic idea is straightforward, implementing it efficiently (i.e. re-using as many previous results as possible) is tricky as the code sample illustrates, and one can easily get the wrong result.
I will try poniting mjcb_control to some dummy function (or nullptr). Also, if mjcb_control is clear, will mj_step use what is in d->ctrl (e.g. manually set d->ctrl before calling mj_step)? Thanks for the answer!
The simulator never writes anything to ctrl, except when a reset is triggered. And it does not care if ctrl was fill in by the control callback or by user code executed in-between calls to the simulator. Note that mjcb_control cannot be "clear" in the sense of a NULL pointer. That will cause the simulator to crash. It has to point to a function (with the specified format). Maybe I should allow callbacks to be set to NULL without crashing... but as of 1.31 this is not allowed.
It is initialized with a function that does nothing. I just decided to allow NULL in all callbacks starting with release 1.40 btw, so in the future you will not need dummy functions.