Page 1 of 2
Measuring Contact Force in Forward Simulation
Posted: Wed Aug 23, 2017 9:28 am
by kenechukwu
Hello there,
I am trying to study how the contact forces are applied on OpenSim. I have used contact spheres to model object-ground contact. It's modeled as an ElasticFoundationForce.
What I want to do is to be able to measure the contact force generated during simulation at every time-step. My goal is to eventually use this as a means of measuring the external force on my model for a force feedback controller.
Can I get any pointers on what methods/functions to use in obtaining this in the C++ API?
Thank you.
Kenechukwu
Re: Measuring Contact Force in Forward Simulation
Posted: Wed Aug 23, 2017 1:00 pm
by mitkof6
Re: Measuring Contact Force in Forward Simulation
Posted: Mon Aug 28, 2017 5:39 pm
by kenechukwu
Thank you very much, Dimitar.
I went through the example code and I have made a simple example using my model.
Code: Select all
class forceReport : public PeriodicEventReporter {
public:
forceReport(const MultibodySystem& system,
const CompliantContactSubsystem& contactForces,
Real reportInterval)
: PeriodicEventReporter(reportInterval), m_system(system), m_contactForces(contactForces) {}
void handleEvent(const State& state) const override {
m_system.realize(state, Stage::Dynamics);
const int ncont = m_contactForces.getNumContactForces(state);
for (int i = 0; i < ncont; ++i) {
const ContactForce& force = m_contactForces.getContactForce(state, i);
std::cout << force << std::endl;
}
}
private:
const MultibodySystem& m_system;
const CompliantContactSubsystem& m_contactForces;
};
int main()
{
try {
Model osimModel("my_model.osim");
State& s = osimModel.initSystem();
MultibodySystem system = osimModel.updMultibodySystem();
ContactTrackerSubsystem tracker(system);
CompliantContactSubsystem contactForces(system, tracker);
osimModel.buildSystem();
State& s_new = osimModel.initializeState();
system.addEventReporter(new forceReport(system, contactForces, 0.1));
const State& s_new = system.realizeTopology();
SimTK::RungeKuttaMersonIntegrator integrator(osimModel.getMultibodySystem());
integrator.setAccuracy(1.0e-3);
Manager manager(osimModel, integrator);
manager.setInitialTime(0.0); manager.setFinalTime(1.0);
manager.integrate(s_new);
I find that the code throws an exception at the "system.realizeTopology()" line:
Code: Select all
Exception thrown at 0x00007FFC4183472C (OpenSim_SimTKcommon.dll) in exampleController.exe: 0xC0000005: Access violation reading location 0x000003E0EFE6D1D0.
It seems like it is failing to realize the topology of the system. I am not sure what I am doing wrong here. Any pointers would be helpful.
Thank you.
Kenechukwu
Re: Measuring Contact Force in Forward Simulation
Posted: Mon Aug 28, 2017 10:08 pm
by tkuchida
I haven't compiled your code to investigate in detail, but at first glance it looks like
Code: Select all
// this line
MultibodySystem system = osimModel.updMultibodySystem();
// should be
MultibodySystem& system = osimModel.updMultibodySystem();
In the first case, it looks like you are constructing a new MultibodySystem rather than fetching a writable reference to the MultibodySystem associated with osimModel.
Re: Measuring Contact Force in Forward Simulation
Posted: Tue Aug 29, 2017 9:53 am
by kenechukwu
Thank you Tom.
I made that correction as well as some other few modifications. The system realizes to topology now, but the concern is that it throws an unknown exception at the "manager.integrate(s_new)" line.
Code: Select all
class forceReport : public PeriodicEventReporter {
public:
forceReport(const MultibodySystem& system,
const CompliantContactSubsystem& contactForces,
Real reportInterval)
: PeriodicEventReporter(reportInterval), m_system(system), m_contactForces(contactForces) {}
void handleEvent(const State& state) const override {
m_system.realize(state, Stage::Dynamics);
const int ncont = m_contactForces.getNumContactForces(state);
std::cout << ncont << std::endl;
for (int i = 0; i < ncont; ++i) {
const ContactForce& force = m_contactForces.getContactForce(state, i);
std::cout << force << std::endl;
}
}
private:
const MultibodySystem& m_system;
const CompliantContactSubsystem& m_contactForces;
};
int main()
{
try {
Model osimModel("my_model.osim");
State& s = osimModel.initSystem();
MultibodySystem& system = osimModel.updMultibodySystem();
ContactTrackerSubsystem tracker(system);
CompliantContactSubsystem contactForces(system, tracker);
State& s_new = osimModel.initializeState();
forceReport* conforceReporter = new forceReport(system, contactForces, 0.1);
system.addEventReporter(conforceReporter);
system.realizeTopology();
SimTK::RungeKuttaMersonIntegrator integrator(system);
integrator.setAccuracy(1.0e-3);
Manager manager(osimModel, integrator);
manager.setInitialTime(0.0); manager.setFinalTime(1.0);
manager.integrate(s_new);
}
I have added the code and the model here. Any pointers here would be very much appreciated.
Kenechukwu
Re: Measuring Contact Force in Forward Simulation
Posted: Tue Aug 29, 2017 3:38 pm
by tkuchida
I don't think you should need State& s_new = osimModel.initializeState();. Is it possible to remove that line and call manager.integrate(system); instead?
Re: Measuring Contact Force in Forward Simulation
Posted: Tue Aug 29, 2017 4:47 pm
by kenechukwu
Hello Tom,
Thanks for the comment. I just tried that; it seems that the integrate method only takes values of type "SimTK::State&".
Here's the error I get: "a reference of type 'SimTK::State&' cannot be initialized with a value of type 'SimTK::MultibodySystem' "
I thought that it would be useful to initialize the state after we add the new subsystems to the multibodysystem.
Kenechukwu
Re: Measuring Contact Force in Forward Simulation
Posted: Tue Aug 29, 2017 5:39 pm
by tkuchida
Ah, sorry; you're right. Is there a reason you want to use the Manager rather than the TimeStepper as in ExampleContactPlayground.cpp? I will try to build your code and investigate in more detail later tonight.
Re: Measuring Contact Force in Forward Simulation
Posted: Wed Aug 30, 2017 12:23 am
by tkuchida
You can use a TimeStepper (
https://simtk.org/api_docs/simbody/3.5/ ... epper.html) and make a couple small changes:
Code: Select all
Model& model = Model("my_model.osim");
model.initSystem();
MultibodySystem& system = model.updMultibodySystem();
ContactTrackerSubsystem tracker(system);
CompliantContactSubsystem contactForces(system, tracker);
forceReport* myForceReport = new forceReport(system, contactForces, 0.1);
system.addEventReporter(myForceReport);
const State& state = system.realizeTopology();
SimTK::RungeKuttaMersonIntegrator integrator(model.getSystem());
SimTK::TimeStepper ts(model.getSystem(), integrator);
ts.initialize(state);
ts.stepTo(10.);
I'm guessing that you want to model contact between the seat and the driver. If so, it looks like you will need to add a degree of freedom to get meaningful forces from the CompliantContactSubsystem (the pelvis is currently welded to the seat).
Re: Measuring Contact Force in Forward Simulation
Posted: Wed Aug 30, 2017 10:37 am
by kenechukwu
Thank you Tom.
With your comments, I was able to have the code compile and run successfully, however, as you noted, the contact observer doesn't measure any active contacts during simulation. I ran the same model in the OpenSim GUI using the forward dynamics and force reporter tools and I was able to observe contact forces through the various contact interfaces in the model (the hip/femur to seat and the foot to ground).
As you stated, there'll be no contact forces from the contact interfaces connected to the pelvis (because its welded to the seat), but we're trying to measure the forces from the other interfaces.
Please see images here: (I had some trouble uploading images directly onto this window)
Full model after 1s of simulation showing the contact forces:
https://goo.gl/2iK7fu
Plot of contact force on the femur (force "a"):
https://goo.gl/x8mc37
Plot of contact force on the foot (force "b"):
https://goo.gl/wH4qVA
I am guessing that my definition of the Compliant Contact Subsystem might be inaccurate because no contact forces or surfaces are being observed.