-
Notifications
You must be signed in to change notification settings - Fork 27
Description
Hey @louis-langholtz ,
i have a problem with spurious hiccups in rotation when the angle goes from/to +PI / -PI.
Wrote a GravityJoint, which pulls bodies together. Now i want to rotate the second body to be upright wrt the direction of gravity towards the first body.
In a test a small and a big disk are connected using this joint, and the small disk slides around the surface of the big disk. (see code below)
This seemingly works, however on some rotations, when the small disk passes the point where it's angle flips from +PI to -PI the body has wrong angle values for a frame or two.
The location is not affected, only the rotation. This does not happen every time, but very often.
Console output, see how when the angle wraps, even if the joint sets 3.1258, after Step() the body has a rotation of -1.5201 instead of 3.1258 for a single step, and then continues with the correct values set by the joint in the next step:
Main loop: angle: -3.1135 location: 0.0631x-10.2480
Inside GravityJoint: angle: -3.1354 impulse: -0.0221x3.5819 slop: 0.0349 err: 0.0219 body angle: -3.1354
Main loop: angle: -3.1354 location: -0.1615x-10.2494
Inside GravityJoint: angle: 3.1258 impulse: 0.0564x3.5798 slop: 0.0349 err: 6.2613 body angle: 3.1258
Inside GravityJoint: angle: 3.1258 impulse: 0.0564x3.5798 slop: 0.0349 err: 0.0000 body angle: 3.1258
Main loop: angle: -1.5201 location: -0.3861x-10.2385
Inside GravityJoint: angle: 3.1039 impulse: 0.1351x3.5812 slop: 0.0349 err: 4.6240 body angle: 3.1039
Inside GravityJoint: angle: 3.1039 impulse: 0.1351x3.5812 slop: 0.0349 err: 0.0000 body angle: 3.1039
Main loop: angle: 3.1039 location: -0.6108x-10.2300
A test using said joint:
//g++ -std=c++17 -O3 -march=native -Isubmodules/PlayRho ideas_and_tests/cpp_playrho_gravity.cpp -o /tmp/test libs/libPlayRho.a
#include <PlayRho/PlayRho.hpp>
#include <iostream>
#include <iomanip>
using namespace playrho;
using namespace playrho::d2;
int main()
{
auto world = World{};
std::cout << std::fixed << std::setprecision(4);
const auto planet = world.CreateBody(BodyConf{}
.UseLocation(Length2{0, 0})
.UseType(BodyType::Static));
planet->CreateFixture(Shape{DiskShapeConf{}
.UseRadius(1_m*10)
.UseFriction(10.0)
.UseRestitution(0)
.UseDensity(0.0)
});
auto location = Length2{1_m*10+.25,0};
auto body = world.CreateBody(BodyConf{}
.UseLocation(location)
.UseType(BodyType::Dynamic));
body->CreateFixture(Shape{DiskShapeConf{}
.UseLocation(Length2{0,0})
.UseRadius(1_m*0.25)
.UseFriction(0.0)
.UseRestitution(0)
.UseDensity(1.0)
});
body->SetFixedRotation(true);
GravityJointConf def{};
def.bodyA = planet;
def.bodyB = body;
def.factor = 2000;
def.radius = 50;
auto joint = world.CreateJoint(def);
auto dt = playrho::Second / 50.0;
StepConf stepConfWarm;
stepConfWarm.SetTime(dt);
stepConfWarm.doWarmStart = true;
ApplyLinearImpulse(*body,Length2{0,-2},body->GetWorldCenter());
bool flip{false};
std::size_t i{0},abrt{0};
while(++i < 100000) {
world.Step(stepConfWarm);
std::cout << "Main loop: angle: " << body->GetAngle() << " location: " << body->GetLocation()[0] << "x" << body->GetLocation()[1] << std::endl;
// Abort 4 frames after error detected
if(!abrt) {
if(flip && std::abs(body->GetAngle()) < 2.7) ++abrt;
else if(std::abs(body->GetAngle()) > 3) flip = true;
else flip = false;
} else {
if(++abrt > 4) return 1;
}
}
return 0;
}
Setting rotation in joint solver:
bool GravityJoint::SolvePositionConstraints(BodyConstraintsMap& bodies, const ConstraintSolverConf& conf) const
{
auto& bodyConstraintB = At(bodies, GetBodyB());
auto posB = bodyConstraintB->GetPosition();
// get direction of gravitational force from impulse
const auto targetU = UnitVec::Get(m_impulse[0],m_impulse[1]).first;
const auto targetAngle = GetAngle(targetU.Rotate(UnitVec::GetTop()));
const auto err = abs(posB.angular - targetAngle);
posB.angular = targetAngle;
bodyConstraintB->SetPosition(posB);
std::cout << "Inside GravityJoint: angle: " << targetAngle << " "
<< " impulse: " << m_impulse[0] << "x" << m_impulse[1]
<< " slop: " << conf.angularSlop << " err: " << err << " "
<< " body angle: " << bodyConstraintB->GetPosition().angular
<< std::endl;
return err < conf.angularSlop;
}
Do you have any idea what i am doing wrong here?
This has me clueless.
The full source for the GravityJoint can be found here https://github.com/ninnghazad/PlayRho/tree/gravity_joint .