-
Notifications
You must be signed in to change notification settings - Fork 53
Add frictionless LCP #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 9 commits
3af4db7
145cbe4
f978001
f9f921d
1925247
7a0982d
6e5fc8d
b84b540
3ff7b11
769e26d
48f777e
363f1a4
9765693
18b11c7
d4222fa
f679a2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -296,12 +296,20 @@ void World(py::module& m) | |
| "runConstraintEngine", | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference between |
||
| +[](dart::simulation::World* self, bool _resetCommand) -> void { | ||
| return self->runConstraintEngine(_resetCommand); | ||
| }) | ||
| }, | ||
| ::py::arg("resetCommand")) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want default args on this? Generally we have |
||
| .def( | ||
| "runLcpConstraintEngine", | ||
| +[](dart::simulation::World* self, bool _resetCommand) -> void { | ||
| return self->runLcpConstraintEngine(_resetCommand); | ||
| }) | ||
| }, | ||
| ::py::arg("resetCommand")) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's another place where we could have default args, if you want them |
||
| .def( | ||
| "runFrictionlessLcpConstraintEngine", | ||
| +[](dart::simulation::World* self, bool _resetCommand) -> void { | ||
| return self->runFrictionlessLcpConstraintEngine(_resetCommand); | ||
| }, | ||
| ::py::arg("resetCommand")) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And the last place where we could put them |
||
| .def( | ||
| "replaceConstraintEngineFn", | ||
| &dart::simulation::World::replaceConstraintEngineFn) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,7 +41,7 @@ | |
|
|
||
| using namespace dart; | ||
|
|
||
| TEST(ConstraintSolver, SIMPLE) | ||
| std::shared_ptr<simulation::World> loadWorldAndIntegrateNonConstraintForces() | ||
| { | ||
| // Load a world where a cube is colliding with the ground. | ||
| std::shared_ptr<simulation::World> world | ||
|
|
@@ -59,9 +59,17 @@ TEST(ConstraintSolver, SIMPLE) | |
| skel->integrateVelocities(world->getTimeStep()); | ||
| // 0, 0, 0, 0, -0.00981, 0 | ||
| EXPECT_TRUE(box->getRelativeSpatialVelocity()[4] < 0); | ||
| return world; | ||
| } | ||
|
|
||
| // Collision detection. | ||
| TEST(ConstraintSolver, Simple) | ||
| { | ||
| auto world = loadWorldAndIntegrateNonConstraintForces(); | ||
| auto skel = world->getSkeleton("box skeleton"); | ||
| auto box = skel->getBodyNode("box"); | ||
| auto solver = world->getConstraintSolver(); | ||
|
|
||
| // Collision detection. | ||
| solver->updateConstraints(); | ||
| solver->buildConstrainedGroups(); | ||
| EXPECT_TRUE(solver->getLastCollisionResult().getNumContacts() > 0); | ||
|
|
@@ -81,3 +89,24 @@ TEST(ConstraintSolver, SIMPLE) | |
| skel->computeImpulseForwardDynamics(); | ||
| EXPECT_TRUE(box->getRelativeSpatialVelocity()[4] >= 0); | ||
| } | ||
|
|
||
| TEST(ConstraintSolver, ReplaceConstraintEngineWithFrictionlessLcp) | ||
| { | ||
| auto world = loadWorldAndIntegrateNonConstraintForces(); | ||
| auto skel = world->getSkeleton("box skeleton"); | ||
| auto box = skel->getBodyNode("box"); | ||
| auto solver = world->getConstraintSolver(); | ||
|
|
||
| world->replaceConstraintEngineFn([world](bool _resetCommand) { | ||
| return world->runFrictionlessLcpConstraintEngine(_resetCommand); | ||
| }); | ||
| world->runConstraintEngine(false); | ||
|
|
||
| // Collision detection. | ||
| EXPECT_TRUE(solver->getLastCollisionResult().getNumContacts() > 0); | ||
| EXPECT_TRUE(solver->getNumConstrainedGroups() > 0); | ||
|
|
||
| // Integrate velocities from solved impulses. Should have non-negative normal | ||
| // velocity after integration. | ||
| EXPECT_TRUE(box->getRelativeSpatialVelocity()[4] >= 0); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need one more check here to check that having no friction actually made a difference in this case. Maybe we apply a small horizontal velocity before we run the constraints engine, and check that it's still there afterwards? It would make sense to apply the same small horizontal velocity to the test for the LCP with friction as well, and check that the friction ends up zeroing out the velocity. |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it actually make sense to have
_resetCommandhere? Doesn't the LCP create the impulses in the first place? Why would we ever not want to reset after that?