cyberbotics / webots

Webots Robot Simulator
https://cyberbotics.com
Apache License 2.0
3.26k stars 1.7k forks source link

Constant force control reach a maximum speed #4922

Open ShuffleWire opened 2 years ago

ShuffleWire commented 2 years ago

Describe the Bug I'm experimenting with the inertiaMatrix and boundingBox, and found this strange behavior. In the following world, I've setup tree object (cubes), which are the same, but not placed the same way : The first one (on the left) is centered on the rotational axis. The second one (on the center) got is origin shifted by 1 meter. The third (on the right) got is origin not shifted, but it's the internal Shape node that is shifted 1 meter. Thus, in the end this object should behave exactly the same than the second one.

Those 3 cubes are powered by RotationalMotor placed on the rotation axis. Those motor apply a constant 1N.m torque.

Considering the geometry, we should expect that the left one accelerate faster that the two others.

World
#VRML_SIM R2022a utf8
WorldInfo {
  lineScale 10
}
Viewpoint {
  orientation -0.34477023131392803 0.41739621840350705 0.8407817103518561 1.5530709344074776
  position 4.053580514106406 -13.21831658643625 12.438780327125025
}
TexturedBackground {
}
TexturedBackgroundLight {
}
Robot {
  children [
    Transform {
      translation 10 0 0
      children [
        HingeJoint {
          jointParameters HingeJointParameters {
            axis 0 0 1
          }
          device [
            RotationalMotor {
              name "motor1"
            }
          ]
          endPoint Solid {
            children [
              DEF t Transform {
                translation 1 0 0
                children [
                  Shape {
                    geometry DEF c Box {
                      size 2.44949 2.44949 2.44949
                    }
                  }
                ]
              }
            ]
            name "solid(2)"
            boundingObject USE t
            physics Physics {
              density -1
              mass 1
            }
          }
        }
      ]
    }
    Transform {
      translation 5 0 0
      children [
        HingeJoint {
          jointParameters HingeJointParameters {
            axis 0 0 1
          }
          device [
            RotationalMotor {
              name "motor2"
            }
          ]
          endPoint Solid {
            translation 1 0 0
            children [
              Shape {
                geometry DEF c Box {
                  size 2.44949 2.44949 2.44949
                }
              }
            ]
            name "solid(1)"
            boundingObject USE c
            physics Physics {
              density -1
              mass 1
            }
          }
        }
      ]
    }
    Transform {
      children [
        HingeJoint {
          jointParameters HingeJointParameters {
            axis 0 0 1
          }
          device [
            RotationalMotor {
              name "motor3"
            }
          ]
          endPoint Solid {
            children [
              Shape {
                geometry DEF c Box {
                  size 2.44949 2.44949 2.44949
                }
              }
            ]
            boundingObject USE c
            physics Physics {
              density -1
              mass 1
            }
          }
        }
      ]
    }
  ]
  name "solid"
  controller "my_controller"
}
Controller
#include 
#include 

int main(int argc, char **argv) {
  wb_robot_init();

  WbDeviceTag motor1 = wb_robot_get_device("motor1");
  WbDeviceTag motor2 = wb_robot_get_device("motor2");
  WbDeviceTag motor3 = wb_robot_get_device("motor3");
  while (wb_robot_step(32) != -1) {
    wb_motor_set_torque(motor1, 1.0);
    wb_motor_set_torque(motor2, 1.0);
    wb_motor_set_torque(motor3, 1.0);
  }

  wb_robot_cleanup();

  return 0;
}

Steps to Reproduce

  1. Open the world, load the controller and build it
  2. Run the world (on fast speed), during 10min
  3. Switch to normal speed
  4. Observe that center and right cube behave the same
  5. Go to the speed tab of left cube
  6. See that the speed (rotational on Z or magnitude) increase regularly (should be near 600 rad/s at that point), That's OK
  7. Same thing with center or right cube, see that the rotational speed is maxed out at 5.34071, and don't increase anymore. That's not OK
  8. At least both center and right cube behave the same, so both way of settings them don't change the result...

Expected behavior I've designed the objects in the way that center and right cube should rotate exactly at half the speed of the left one (thank to the fact that the inertia is exactly twice as high), so it should have reach at least 300 rad/s at this point. Anyway, it should not be constant...

System

ShuffleWire commented 2 years ago

I've made more tests, using this world :

World
#VRML_SIM R2022a utf8
WorldInfo {
  basicTimeStep 20
  lineScale 10
}
Viewpoint {
  orientation -0.34477023131392803 0.41739621840350705 0.8407817103518561 1.5530709344074776
  position 2.9014563775556645 -19.209165146189484 18.453400181273327
}
TexturedBackground {
}
TexturedBackgroundLight {
}
Robot {
  children [
    HingeJoint {
      jointParameters HingeJointParameters {
        axis 0 0 1
      }
      device [
        RotationalMotor {
          name "motor"
        }
      ]
      endPoint DEF solid Solid {
        translation 1.5 0 0
        children [
          Shape {
            geometry DEF c Box {
              size 2.44949 2.44949 2.44949
            }
          }
        ]
        name "solid(1)"
        boundingObject USE c
        physics Physics {
          density -1
          mass 1
        }
      }
    }
  ]
  name "solid"
  controller "my_controller"
  supervisor TRUE
}
Controller
#include 
#include 
#include 
#include 

int main(int argc, char **argv) {
  wb_robot_init();

  wb_motor_set_torque(wb_robot_get_device("motor"), 1.0);
  WbNodeRef node = wb_supervisor_node_get_from_def("solid");

  int i=1;
  double old_v = NAN;
  while (wb_robot_step(20) != -1) {
    const double *v = wb_supervisor_node_get_velocity(node);
    if(i%100 == 0)
      printf("%f %f\n", wb_robot_get_time(), v[5]);
    if(fabs(v[5] - old_v) < 1e-6)
     {
       printf("%f %f\n", wb_robot_get_time(), v[5]);
       break;
      }
    old_v = v[5];
    i++;
  }
  wb_supervisor_simulation_reset();

  wb_robot_cleanup();

  return 0;
}

Cube size and mass chosen to get an inertia matrix being identity.

Again, the motor apply a torque of 1 N.m

I've studied the behavior during cube rotation with different distance to the rotation axis (i.e change the x coordinate of the vector HingeJoint/endPoint/translation) (values are 0.125 , 0.2 , 0.25 , 0.4 , 0.5 , 0.75 , 1 , 1.5 , 2 , 3 , 4 , 6 , 8) We know that for no distance (ie == 0), the cube accelerate correctly, and speed increase to infinity, at exactly 1rad/s²

Take a look at the raw values in this spreadsheet (two sheets), speeds.ods but the interesting one is the following : image

I reiterate that it's not correct to see this behavior, which is not physic : all the speed should keep increasing. Moreover it's not random, as seen in the graph, it follows some rules...

brettle commented 1 month ago

I realize this is old but I just stumbled across this while looking for something else and thought I'd throw out an idea...

Because you are putting an unbalanced load on the motor/joint, the Solid endPoint will tend to pull away from the joint axis as the speed increases. The underlying ODE physics simulator will try to counteract that force but the degree to which it will succeed in doing so will depend on the the ERP and CFM being used. That (possibly combined with the fact that the simulation is discrete in time), might result in a non-zero counter-torque that at higher speeds eventually goes to 1 Nm, resulting in the finite speed.

You can test if the unbalanced load is the cause by using a balanced load with an equivalent moment of inertia.

If the unbalanced load is the cause, you might be able to achieve behavior more like what you expect by changing the ERP and/or CFM fields in WorldInfo.