myosuite icon indicating copy to clipboard operation
myosuite copied to clipboard

Muscle Fatigue doesn't work for most model

Open vikashplus opened this issue 1 year ago • 4 comments

I started debugging this issue. Either I don't understand what's going on, or there is something really wrong with our implementation. I'd need more information about our Fatigue model to understand what is being implemented. Let me articulate what I have found so far

  • Issue seems to be with the way self.f_load is being calculated
  • f_load seems to depend on actuator_moment whose size is (nu x nv)
  • The implementation seems to be checking for nv==1 as a special case here. This conceptually seems wrong. Why would ndof = 1 be any different than many dof?
  • The implementation further goes on to only look at the first DoF for all its calculations and ignores all others. This seems seriously off.

My guess is that -- it was implemented for a single muscle single dof system and it has never been tested with a system with higher dof. -- I also think that the arm and hand fatigue results are wrong -- I also think the implementation has a massive memory leak. We keep appending f_load to the buffer throughout the existence of the env. The size of the buffer keys growing. We either need a cyclic buffer here, or f_load needs to be cleaned with at reset.

vikashplus avatar Dec 24 '23 04:12 vikashplus

The fatigue works in isolation in a code example:

import mujoco
import mujoco.viewer as viewer
import os
import numpy as np
import time
​
curr_dir = os.path.dirname(os.path.abspath(__file__))
​
model_path = os.path.join(curr_dir, 'myolegs_v0.56(mj237).mjb')
mj_model = mujoco.MjModel.from_xml_path(model_path)
mj_data = mujoco.MjData(mj_model)
window = viewer.launch_passive(mj_model, mj_data)
​
​
​
# mj_model.actuator('connection_muscle').gainprm[2] = 2000
​
for i in range(10000):
    mj_data.ctrl[:] = 1.0
    if i > 300:
        for i in range(mj_model.na):
            mj_model.actuator(i).gainprm[2] = 0
            mj_model.actuator(i).biasprm[2] = 0
    mujoco.mj_step(mj_model, mj_data)
    time.sleep(0.01)
    window.sync()
    print(mj_data.actuator_force)

so it's something inside myosuite somewhere

P-Schumacher avatar Dec 25 '23 12:12 P-Schumacher

I tried it both on the sim and the env. The results seem sensible. I'm attaching my snippets below. Let me know if I'm missing something.

check for fatigue using sim

import mujoco
import mujoco.viewer as viewer
import os
import numpy as np
import time

curr_dir = os.path.dirname(os.path.abspath(__file__))

model_path = os.path.join(curr_dir, '../simhive/myo_sim/leg/myolegs_v0.56(mj237).mjb')
mj_model = mujoco.MjModel.from_binary_path(model_path)
mj_data = mujoco.MjData(mj_model)
window = viewer.launch_passive(mj_model, mj_data)

for i in range(200):
    mj_data.ctrl[:] = 1.0
    if i > 100:
        for j in range(mj_model.na):
            mj_model.actuator(j).gainprm[2] = 0
            mj_model.actuator(j).biasprm[2] = 0
    mujoco.mj_step(mj_model, mj_data)
    time.sleep(0.01)
    window.sync()
    print(f"frame={i}, act_force={mj_data.actuator_force}")

check for fatigue using env

import myosuite
import gym 
import time

env = gym.make('myoLegWalk-v0')
env.reset()
env.mj_render()

for i in range(200):
    act = env.action_space.sample()

    if i > 100:
        for j in range(env.sim.model.na):
            env.sim.model.actuator(j).gainprm[2] = 0
            env.sim.model.actuator(j).biasprm[2] = 0

    env.step(act)
    time.sleep(0.01)
    print(f"frame={i}, act_force={env.sim.data.actuator_force}")

vikashplus avatar Dec 27 '23 06:12 vikashplus

Is this issue still relevant? IIRC we pushed a different fatigue model?

P-Schumacher avatar Jan 18 '24 03:01 P-Schumacher

let's close this once we merge the new fatigue model in main

Vittorio-Caggiano avatar Jan 18 '24 12:01 Vittorio-Caggiano