btGeneric6DofConstraint motor ineffective at limits

Post Reply
jamesm6162
Posts: 6
Joined: Fri Mar 23, 2012 7:18 am

btGeneric6DofConstraint motor ineffective at limits

Post by jamesm6162 » Thu Feb 28, 2013 9:01 am

I have come across a situation where the btGeneric6DofConstraint gets stuck at its limit, regardless of what motor force I apply in the opposite direction (away from the limit)

Below is an extract from the get_limit_motor_info2 function in btGeneric6DofConstraint.cpp:

Code: Select all

if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0;
        info->m_constraintError[srow] = btScalar(0.f);
        if (powered)
        {
			info->cfm[srow] = limot->m_normalCFM;
            if(!limit)
            {
				btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;

				btScalar mot_fact = getMotorFactor(	limot->m_currentPosition, 
													limot->m_loLimit,
													limot->m_hiLimit, 
													tag_vel, 
													info->fps * limot->m_stopERP);
				info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
                info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
                info->m_upperLimit[srow] = limot->m_maxMotorForce;
            }
        }
        if(limit)
        {
            btScalar k = info->fps * limot->m_stopERP;
			if(!rotational)
			{
				info->m_constraintError[srow] += k * limot->m_currentLimitError;
			}
			else
			{
				info->m_constraintError[srow] += -k * limot->m_currentLimitError;
			}
			info->cfm[srow] = limot->m_stopCFM;
            if (limot->m_loLimit == limot->m_hiLimit)
            {   // limited low and high simultaneously
                info->m_lowerLimit[srow] = -SIMD_INFINITY;
                info->m_upperLimit[srow] = SIMD_INFINITY;
            }
            else
            {
                if (limit == 1)
                {
                    info->m_lowerLimit[srow] = 0;
                    info->m_upperLimit[srow] = SIMD_INFINITY;
                }
                else
                {
                    info->m_lowerLimit[srow] = -SIMD_INFINITY;
                    info->m_upperLimit[srow] = 0;
                }
                // deal with bounce
                if (limot->m_bounce > 0)
                {                    
                    ...
                }
            }
        }
The problem line is the condition

Code: Select all

if (!limit)
{
   ...
}
Which is where the force from the motor is actually added.
The result is that when the constraint is outside its limit, the only effort to move the constraint back into its limits is the code:

Code: Select all

 btScalar k = info->fps * limot->m_stopERP;
 if(!rotational)
 {
  info->m_constraintError[srow] += k * limot->m_currentLimitError;
 }
 else
 {
    info->m_constraintError[srow] += -k * limot->m_currentLimitError;
 }
And this ERP is often not sufficient to get the constraint back within its limits, due to external forces applied elsewhere.

Removing the if condition

Code: Select all

if (!limit)
inside the powered branch seems to resolve the issue. In fact looking at the btHingeConstraint, this is exactly the what the hinge does. getMotorFactor already takes care of limiting the m_constraintError in the direction of the limit, so the extra test should never be necessary.

Is there something I am missing in this regard?

Post Reply