Can the parameters of a model be changed on the fly ?

Discussion in 'Modeling' started by Sarvjeet, Jul 13, 2016.

  1. By parameters I mean friction, gear of a motor, length of a part etc. Can we change these things when the simulation is running?

    If not, can you please suggest some way around. We are trying to test our agent's robustness to the parameters variation.
     
    Kyokushin likes this.
  2. To provide a little more context to the question: most of the model parameters are defined in the xml file (eg mass of a part). In some cases, we may not know these parameters exactly and hence might want to consider a distribution over these parameters. To develop "robust" controllers under this scenario, we would like to dynamically pick a mass and then simulate the system under present controller to iteratively improve it.

    Is there any way to programatically handle such a situations? At a coarse level, what we would like to do is this:
    params = draw_from_distribution()
    mj_model_set_params(params)
    # something analogous to setting qpos values
    mj_step(action)


    Thank you
     
    Last edited: Jul 14, 2016
  3. Emo Todorov

    Emo Todorov Administrator Staff Member

    Yes, you can change all real-valued parameters in mjModel between steps. Furthermore, when you save the XML, the new values will be copied back and saved in the XML.

    Integer parameters are usually structural and cannot be changed after compilation. And if you change them, the changes will not be reflected in the XML. But you can save the model as MJB in which case all changes are saved.
     
    Kyokushin and aravindr93 like this.
  4. Thanks for the quick response! Can you provide a short example (2-3 code lines) of how to go about doing this? I tried the same using mujoco-py by modifying env.model.data.mass but the changes did not take effect in the mjModel or the XML file. I assume this is because mujoco-py interface just keeps track of the model params as a dictionary and not update them in between steps. I have asked the developers of the wrapper about this. If we were to do this in the C/C++ interface, can you provide a short example/pseudo-code. Thanks!

    Based on my rough understanding, what you suggest is something along the lines of:
    m = mj_loadXML("mean_model.xml");
    body_mass_adr = m->body_mass;
    *body_mass_adr = new_mass_value
     
    Last edited: Jul 13, 2016
  5. Emo Todorov

    Emo Todorov Administrator Staff Member

    You seem to be talking about the Berkeley/OpenAI python wrapper -- which I am not really familiar with, but it is possible that this functionality is not exposed.

    In a C/C++ program, you can simply do:

    m->body_mass[5] = 3.2;

    and now the mass of body 5 is 3.2.
     
    Kyokushin and aravindr93 like this.
  6. Following up on this, we've seen issues where changing the size of objects to be larger sometimes results in them not getting contacts properly.

    Is there some pre-processing for contact detection that isn't re-run if geom sizes are modified? Is there a way to force that to happen?
     
    Kyokushin likes this.
  7. Emo Todorov

    Emo Todorov Administrator Staff Member

    The sizes of geometric primitives (sphere, cube etc) can be changed between steps and the software will always use the latest settings for collision detection. You also have to change mjModel.geom_rbound which is the radius of a bounding sphere used to exclude collisions without a detailed check.

    If you change the size of a mesh geom, that has no effect at runtime. The mesh vertices are scaled at compile time and written in mjModel.mesh_vert. To scale meshes at runtime, you have to go through the list of vertices and scale all their coordinates.

    The function mj_setConst() sets derived quantities in the model (whose name ends with "0") from the corresponding primary quantities, and can be called after compilation. But rbound is handled by the compiler and there is no automated way to compute it after the compile stage. Same applies to any masses and inertias computer from the geom sizes.
     
    Kyokushin likes this.
  8. m->body_mass[5] = 3.2;

    Won't that yield a physically inconsistent simulation?

    All of the below are functions of the body mass.
    Do we have to manually update those as well in order to retrieve a physically consistent update?

    mjtNum* body_mass; // mass (nbody x 1)
    mjtNum* body_subtreemass; // mass of subtree starting at this body (nbody x 1)
    mjtNum* body_inertia; // diagonal inertia in ipos/iquat frame (nbody x 3)
    mjtNum* body_invweight0; // mean inv inert in qpos0 (trn, rot) (nbody x 2)
     
  9. Emo Todorov

    Emo Todorov Administrator Staff Member

    If you change masses or anything else that affects the derived quantities in mjModel, you should call mj_setConst to recompute these quantities. I just noticed however that body_subtreemass is being computed in the compiler outside the mj_setConst function, so currently it will not be updated. I will fix that in the 1.60 release.

    Note that inertia is not a derived quantity. Mass and inertia are independent parameters -- one is for translation, the other for rotation.