trueaxis.com Forum Index trueaxis.com
True Axis Physics SDK Forum
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Tanks and treaded vehicles example code
Goto page Previous  1, 2, 3  Next
 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    trueaxis.com Forum Index -> General Discussion
View previous topic :: View next topic  
Author Message
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Wed Mar 02, 2005 12:46 pm    Post subject: Reply with quote

The sample code provide here has an extremly over simplified friction model but with a few small changes in the right spot we should be able to get things work roughly as expected.

Stay posted, I'll finish this responce later.
Back to top
View user's profile Send private message Send e-mail
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Thu Mar 03, 2005 11:12 am    Post subject: Reply with quote

Ok, I've updated the tank class to adress some of your problems. Its easier to post the entire thing again rather then specify all the changes so here it is.

Lateral friction is now treated in the typical way used in car simulation (Although very simplified)

m_fLeftTredSpeed and m_fRightTredSpeed have been added and are driven by an engine torque. The tank should now go slower up hill then down hill.

An automatic brake has been added so the tank will not roll down hill if no controls are being activated.

As for your questions:

Instability problems? With this method of friction simulation, higher friction values require a lower supersample time for stability. This is also true for stiffer suspension.

Mass scaling? I would recomend scaling mass down to about 500kg rather then 50,000kg. The SKD probably copes with the mass range of 5.0 to 5000.0 the best. But be careful, changing the mass of the tank in the below code will change the handling responce. Engine torque,suspension forces and friction clamping will have to be changed to componsate.

Good Luck.

Code:

namespace TA
{

class DynamicObjectTank : public DynamicObject
{
public:

   struct Controls
   {
      float fLeftTred;
      float fRightTred;
   };

   void Initialise();
   void Finalise();

   virtual void Update(float fDt);

   void ClearControls();
   void UpdateControls(
      float fLeftTred,
      float fRightTred)
   {
      m_controls.fLeftTred = fLeftTred;
      m_controls.fRightTred = fRightTred;
   }

   static DynamicObjectTank* TAC_CALL CreateNew() { return new DynamicObjectTank; }

protected:
   DynamicObjectTank() : DynamicObject() {}
   ~DynamicObjectTank() {}

private:
   Controls m_controls;
   float m_fLeftTredSpeed;
   float m_fRightTredSpeed;
};

}

namespace TA
{

//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void DynamicObjectTank::Initialise()
{
   m_controls.fLeftTred = 0.0f;
   m_controls.fRightTred = 0.0f;
   m_fLeftTredSpeed = 0.0f;
   m_fRightTredSpeed = 0.0f;

   // Create collision
   AABB aabb(Vec3(0.0f, 0.0f, 0.0f), Vec3(1.3f, 0.5f, 2.2f));
   CollisionObjectCombo* pCombo = CollisionObjectCombo::CreateNew();
   pCombo->Initialise();

   // Create body collision
   CollisionObjectConvex* pBox = CollisionObjectConvex::CreateNew();
   pBox->InitialiseAsABox(aabb);
   pCombo->AddCollisionObject(pBox);
   pBox->Release(); // don't need to keep this pointer

   // Create wheels collision
   CollisionObjectLineList* pLines = CollisionObjectLineList::CreateNew();
   Vec3 v3Lines[20];
   const float fTop = -0.4f;
   const float fBottom = -0.9f;
   const float fSide = 1.2f;
   v3Lines[0] = Vec3(fSide, fTop, 2.0f);
   v3Lines[1] = Vec3(fSide, fBottom + 0.1f, 2.0f);
   v3Lines[2] = Vec3(-fSide, fTop, 2.0f);
   v3Lines[3] = Vec3(-fSide, fBottom + 0.1f, 2.0f);

   v3Lines[4] = Vec3(fSide, fTop, 1.3f);
   v3Lines[5] = Vec3(fSide, fBottom, 1.3f);
   v3Lines[6] = Vec3(-fSide, fTop, 1.3f);
   v3Lines[7] = Vec3(-fSide, fBottom, 1.3f);

   v3Lines[8] = Vec3(fSide, fTop, 0.0f);
   v3Lines[9] = Vec3(fSide, fBottom, 0.0f);
   v3Lines[10] = Vec3(-fSide, fTop, 0.0f);
   v3Lines[11] = Vec3(-fSide, fBottom, 0.0f);

   v3Lines[12] = Vec3(fSide, fTop, -1.3f);
   v3Lines[13] = Vec3(fSide, fBottom, -1.3f);
   v3Lines[14] = Vec3(-fSide, fTop, -1.3f);
   v3Lines[15] = Vec3(-fSide, fBottom, -1.3f);

   v3Lines[16] = Vec3(fSide, fTop, -2.0f);
   v3Lines[17] = Vec3(fSide, fBottom + 0.1f, -2.0f);
   v3Lines[18] = Vec3(-fSide, fTop, -2.0f);
   v3Lines[19] = Vec3(-fSide, fBottom + 0.1f, -2.0f);
   
   pLines->Initialise(v3Lines, 10);
   pCombo->AddCollisionObject(pLines);
   pLines->Release();

   // Initialise dynamic object
   DynamicObject::Initialise(pCombo);

   // Make center of mass a little lower for better handling
   DynamicObject::SetCenterOffset(Vec3(0.0f, -0.2f, 0.0f));
}

//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void DynamicObjectTank::Finalise()
{
   DynamicObject::Finalise();
}

//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void DynamicObjectTank::Update(float fDt)
{
   bool bLeftBrake = false;
   bool bRightBrake = false;

   // A highly simplified update for a treaded vehicle.
   const float fSuspensionSpringConstant = 8000.0f;
   const float fSuspensionDampingConstant = 6000.0f;
   const float fLongitudinalFriction = 1.5f;
   const float fLateralFriction = 1.0f;
   const float fInvTreadInertia = 1.0f / 30.0f;
   const float fEnginTorque = 30.0f;
   const float fBrakeTorque = 10.0f;
   const float fSpeed = 15.0f; // meters per second
   const float fMaxFrictionMult = 2.0f;
   const float fAirResistance = 10.0f;

   // Need run suspension and fruction calculations at a higher frame rate
   // for stability.
   float k_fTargetFrameTime = 1.0f / 300.0f;
   int nNumSuperSamples = FastFloatToInt(ceil(fDt / k_fTargetFrameTime));
   if (nNumSuperSamples < 1)
      nNumSuperSamples = 1;
   float fSuperSampledTime = fDt / (float)nNumSuperSamples;
   float fInvSuperSampledTime = 1.0f / fSuperSampledTime;


   // automatic breaking
   if (m_controls.fLeftTred == 0)
      bLeftBrake = true;
   // automatic breaking
   if (m_controls.fRightTred == 0)
      bRightBrake = true;
   
   // Back up the current position.
   MFrame frameBck = GetFrame();
      
   for (int i = 0; i < nNumSuperSamples; i++)
   {      
      AssertForceAndTorqueCleared();
      AccumulateGravity();

      // engine torque
      m_fLeftTredSpeed += m_controls.fLeftTred * fSuperSampledTime * fEnginTorque;
      m_fRightTredSpeed += m_controls.fRightTred * fSuperSampledTime * fEnginTorque;

      // Wind resistance.
      AccumulateLinearForce(-fAirResistance * GetLinearVelocity().GetMagnitude() * GetLinearVelocity());

      // breaking
      if (bLeftBrake)
      {
         if (m_fLeftTredSpeed > 0.0f)
         {
            m_fLeftTredSpeed -= fSuperSampledTime * fBrakeTorque;
            if (m_fLeftTredSpeed < 0.0f)
               m_fLeftTredSpeed = 0.0f;
         }
         else
         if (m_fLeftTredSpeed < 0.0f)
         {
            m_fLeftTredSpeed += fSuperSampledTime * fBrakeTorque;
            if (m_fLeftTredSpeed > 0.0f)
               m_fLeftTredSpeed = 0.0f;
         }
      }
      if (bRightBrake)
      {
         if (m_fRightTredSpeed > 0.0f)
         {
            m_fRightTredSpeed -= fSuperSampledTime * fBrakeTorque;
            if (m_fRightTredSpeed < 0.0f)
               m_fRightTredSpeed = 0.0f;
         }
         else
         if (m_fRightTredSpeed < 0.0f)
         {
            m_fRightTredSpeed += fSuperSampledTime * fBrakeTorque;
            if (m_fRightTredSpeed > 0.0f)
               m_fRightTredSpeed = 0.0f;
         }
      }


      int nLine;
      // Loop through all the wheel collisions.
      for (nLine = 0; nLine < GetNumLineCollisions(); nLine++)
      {
         const LineIntersection& lineIntersection = GetLineCollision(nLine);
         if (lineIntersection.fIntersectingDepth > 0.0f)
         {
            Vec3 v3Position = lineIntersection.v3Position * GetFrame();

            SurfaceAttribute& surfaceAttribute = Physics::GetInstance().GetSurfaceAttribute(lineIntersection.nAttribute);

            //---------------------------------------------------------------------------------
            // Do spring force
            //---------------------------------------------------------------------------------
            float fNormalForce = (1.0f - lineIntersection.fIntersectingDepth) * fSuspensionSpringConstant;

            // Do velocity damping
            Vec3 v3Velocity = GetVelocityAtWorldPosition(v3Position);
            if (lineIntersection.pDynamicObject &&
               lineIntersection.pDynamicObject->AddedToPhysics())
            {
               v3Velocity -= lineIntersection.pDynamicObject->GetVelocityAtWorldPosition(v3Position);
            }
            float fSeparatingSpeed = lineIntersection.v3Normal.Dot(v3Velocity);   
            
            // fing the veloity at the point of collisoin along the ground
            v3Velocity -= lineIntersection.v3Normal * fSeparatingSpeed;

            if (Fabs(fSeparatingSpeed) > 1.0f)
               fSeparatingSpeed = Sign(fSeparatingSpeed) * 1.0f;
            fNormalForce -= fSuspensionDampingConstant * fSeparatingSpeed;

            // The wheel can push the ground but never pull it.
            if (fNormalForce > 0.0f)
            {
               // Calculate the forward direction of the wheel along the ground
               Vec3 v3WheelForward = GetFrame().m33Rotation.v3Z;
               v3WheelForward -= lineIntersection.v3Normal * lineIntersection.v3Normal.Dot(v3Velocity);
               float fMag = v3WheelForward.GetMagnitude();
               if (fMag < 0.001f)
                  continue;
               v3WheelForward /= fMag;

               //---------------------------------------------------------------------------------
               // longitudinal force
               //---------------------------------------------------------------------------------         
               float fFrictionMult = fNormalForce * fLongitudinalFriction * surfaceAttribute.GetCollisionFriction();
               if (fFrictionMult > fInvSuperSampledTime * fMaxFrictionMult)
                  fFrictionMult = fInvSuperSampledTime * fMaxFrictionMult;               
               float fLongitudinalForce = -Sign(v3WheelForward.Dot(v3Velocity)) * fFrictionMult;
               // Apply driving forces.
               if (nLine & 1)
               {
                  fLongitudinalForce += m_fLeftTredSpeed * fFrictionMult;
                  m_fLeftTredSpeed -= fLongitudinalForce * fInvTreadInertia * fSuperSampledTime;
               }
               else
               {
                  fLongitudinalForce += m_fRightTredSpeed * fFrictionMult;
                  m_fRightTredSpeed -= fLongitudinalForce * fInvTreadInertia * fSuperSampledTime;
               }
               
               //---------------------------------------------------------------------------------
               // Lateral Force
               //---------------------------------------------------------------------------------
               Vec3 v3WheelRight = lineIntersection.v3Normal.Cross(v3WheelForward); // direction along ground to the side of the wheel.
               float fSlipAngle = 0.0f;
               if (v3Velocity.GetMagnitudeSqrd() > 0.05f)
               {
                  fSlipAngle = ATan2(
                     v3WheelRight.Dot(v3Velocity),
                     Fabs(v3WheelForward.Dot(v3Velocity)));   
               }
               else
               {
                  fSlipAngle = Sign(v3WheelRight.Dot(v3Velocity));
               }
               fFrictionMult = fNormalForce * fLateralFriction * surfaceAttribute.GetCollisionFriction();   
               if (fFrictionMult > fInvSuperSampledTime * fMaxFrictionMult)
                  fFrictionMult = fInvSuperSampledTime * fMaxFrictionMult;                        
               float fLateralForce = -fSlipAngle * fFrictionMult;


               //---------------------------------------------------------------------------------
               // Caclulate fore and accumulate
               //---------------------------------------------------------------------------------
               Vec3 v3Force =
                  lineIntersection.v3Normal * fNormalForce +
                  v3WheelRight * fLateralForce +
                  v3WheelForward * fLongitudinalForce;   
               Vec3 v3ForcePos = v3Position;      
               // If we are on top of another object, apply the for to that object aswell.
               if (lineIntersection.pDynamicObject &&
                  lineIntersection.pDynamicObject->AddedToPhysics())
               {
                  Physics::GetInstance().SetDynamicObjectIsMoving(lineIntersection.pDynamicObject);
                  lineIntersection.pDynamicObject->ApplyImpulse(v3Force * -fSuperSampledTime, v3Position);
               }
               AccumulateForceAndTorque(
                  v3Force,
                  v3ForcePos);
            }
         }
      }
      
      ApplyForceAndTorqueToVelocities(fSuperSampledTime);
      ClearForceAndTorque();
      ApplyVelocityToNextFrame(fSuperSampledTime);
               
      // Approximatly update the wheel collision positions as we move the object between supersamples.
      for (nLine = 0; nLine < GetNumLineCollisions(); nLine++)
      {
         const LineIntersection* pTmp = &GetLineCollision(nLine);
         LineIntersection& lineIntersection = *(LineIntersection*)pTmp;
         
         if (lineIntersection.fIntersectingDepth <= 0.0f)
            continue; // no collision

         // Move collision point to match movement
         lineIntersection.v3Position *= GetFrame();
         Vec3 v3Pos = (lineIntersection.v3Position / GetFrame()) * GetNextFrame();
         
         // Move collision point back onto plane where collision occurred
         float fDepth = (lineIntersection.v3Position - v3Pos).Dot(lineIntersection.v3Normal);
         v3Pos += fDepth * lineIntersection.v3Normal;
         lineIntersection.fIntersectingDepth += fDepth;
         lineIntersection.v3Position = v3Pos;
         lineIntersection.v3Position /= GetNextFrame();
      }

      ApplyNextFrame();      
   }
   
   // Reset physics objects frame.
   SetFrameDirect(frameBck);   
   UpdateWorldSpaceInertialTensor();

   // Set velocities based on how much object moved during the above supersampled loop.
   if (fDt > 0.0f)
   {      
      SetLinearVelocity((GetNextCenterOfMass() - GetCenterOfMass()) / fDt);
      Mat33 m33Delta =
         GetFrame().m33Rotation.GetTransposeAsInverse() *
         GetNextFrame().m33Rotation;
      Vec3 v3Axis;
      float fAngle;
      m33Delta.GetRotationAxisAndMagnitude(v3Axis, fAngle);
      SetAngularVelocity(v3Axis * fAngle / fDt);
   }

   ClearLineIntersections();
}

}
Back to top
View user's profile Send private message Send e-mail
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Thu Mar 03, 2005 6:30 pm    Post subject: Reply with quote

Awesome, thanks Luke. I see you now incorporated engine torque, which gives me an idea how a gearbox can be applied.

I'm not sure why... I tried to experiment a bit but it's pretty difficult. Perhaps you have some insight. I drove the tank downhill fine, and began climbing the next small slope. Near the top of the slope, the tank suddenly wheelies. I immediately released throttle, but it still goes haywire. It does it pretty consistently. But during that time when it's dancing, you can see that no throttle is applied.

Here's a vid: http://www.sonicubegames.com/files/tankproblem.avi
And the dll: http://www.sonicubegames.com/files/demoterrain.rar

I truly appreciate your help Luke
Back to top
View user's profile Send private message
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Thu Mar 03, 2005 9:51 pm    Post subject: Reply with quote

The enging has very high torque and going up hill the center of mass if futher back, this makes it possibly for the tank to doo wheelies.

Lowering the suspension conststants may help stop the dancing, it may be realisic behaviour given the forces involved. But I notice in your demo, that the throtol can only be changed very slowly. Once you are doing wheelies, it takes a long time to realease the throttle and fall back down.

The tank will handle much better if you allow the throttle to change very quickly. I let it change instantly in my test bed and it works greate.

To stop wheelies you can lower engine torque, lower the center of mass or add a down force.
Back to top
View user's profile Send private message Send e-mail
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Fri Mar 04, 2005 1:21 am    Post subject: Reply with quote

Thanks for the feedback.

What I should probably do is connect up a basic gearbox. I noticed the torque is set to "30". Should I consider this N*m, or is it arbitrary?

I'll keep u posted Smile
Back to top
View user's profile Send private message
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Sat Mar 05, 2005 12:03 am    Post subject: Reply with quote

Torque is arbitrary in the code provided.

To make it a true torque in N.m this code should be used.

Code:

// engine torque
      m_fLeftTredSpeed += m_controls.fLeftTred * fSuperSampledTime * fEnginTorque * fWheelRadius * fInvTreadInertia;
      m_fRightTredSpeed += m_controls.fRightTred * fSuperSampledTime * fEnginTorque * fWheelRadius * fInvTreadInertia;


But obviously a real tank would have a gear box. Plus and the amount of Torque that an engine provides isn't cosntant. I changes with RMP. But you can get away with out this kind of detail if you don't need it.
Back to top
View user's profile Send private message Send e-mail
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Sat Mar 05, 2005 1:18 am    Post subject: Reply with quote

Well I've developed a gearbox in the past that handles the torque curve, gear ratios, and differential ratios, & engine RPM. For a tank I could just use a torque curve with estimated RPM and gear ratios.

What's with fInvTreadInertia? Me=clueless on that one. Cool
Back to top
View user's profile Send private message
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Sat Mar 05, 2005 1:31 am    Post subject: Reply with quote

The wheels and tread of a tank will have a mass and therefore have intertia.

When applying a force you use the formular:
acceleration = force / mass;
therefore:
change in velocity = force / mass * time.

The value of fInvTreadInertia is used to represent the mass of the wheels and tread combined.
Back to top
View user's profile Send private message Send e-mail
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Sat Mar 05, 2005 1:45 am    Post subject: Reply with quote

Gotcha... if fInvTreadInertia is a sum of the wheel/tread masses, then it makes sense to me.

Thx again Smile
Back to top
View user's profile Send private message
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Wed Mar 09, 2005 7:37 am    Post subject: Reply with quote

hi Luke,

Would you be so kind as to help me understand this snippet:

Code:

            float fSeparatingSpeed = lineIntersection.v3Normal.Dot(v3Velocity);   
             
            // fing the veloity at the point of collisoin along the ground
            v3Velocity -= lineIntersection.v3Normal * fSeparatingSpeed;

            if (Fabs(fSeparatingSpeed) > 1.0f)
               fSeparatingSpeed = Sign(fSeparatingSpeed) * 1.0f;
            fNormalForce -= fSuspensionDampingConstant * fSeparatingSpeed;


What exactly is the separating speed, and why is it necessary? Any help is appreciated Smile
Back to top
View user's profile Send private message
Guest






PostPosted: Wed Mar 09, 2005 8:51 am    Post subject: Reply with quote

Bits of that code was cut and past from the car handling class of True Axis so use some of the interal termanology.

The seperating speed here is the difference in velocity between the car wheel and the ground. All velocity horazontal to the ground has been removed by the dot product.

The seperating speed is then subtracted leaving only the component of velocity along the ground at the point of contact. We can then use this horazontal velocity later for doing friction.

The seperating speed is then clamped beforce applying it to the normal force. The normal force is effectivly the force due to suspension. Suspension is modeled by a spring damper system. This part models the motion damping.

The seperating speed is clamped to +or-1.0f here to make sure we don't get a really high force if the car hits the ground from a big fall or something. Normal Force can also used later on to modulate friction.
Back to top
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Wed Mar 09, 2005 1:19 pm    Post subject: Reply with quote

opps, I obviously forgot to log in before making that last post.
Back to top
View user's profile Send private message Send e-mail
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Wed Mar 09, 2005 7:58 pm    Post subject: Reply with quote

Cool, thanks for the info Luke.

I'm just trying to get a better understanding of your code. I like some things about both implementations - about the first, I think the tank's friction with the ground is more realistic. In the second, if you drive on a a hill, then drop throttle, the brakes are applied but the tank still slides sideways a bit. On the other hand, I like the fact that it's using engine torque in the second.

I'm thinking that my best bet is to study both and come up with something that has the best of both worlds.
Back to top
View user's profile Send private message
luke
Site Admin


Joined: 15 Oct 2004
Posts: 621

PostPosted: Wed Mar 09, 2005 10:09 pm    Post subject: Reply with quote

yeah, you can sped a lot of time tweeking this kind of thing to get the feeling your looking for. The basics are there though.

Sometimes the more realistic you try to make things, the harder they are to tweek and get to feel the way you want.
Back to top
View user's profile Send private message Send e-mail
Ultrasauce



Joined: 28 Feb 2005
Posts: 62

PostPosted: Thu Mar 10, 2005 12:11 am    Post subject: Reply with quote

Since it doesn't hurt to ask, do you happen to know of any good white papers or sources that describe the theory behind ray-cast cars in general?
Back to top
View user's profile Send private message
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    trueaxis.com Forum Index -> General Discussion All times are GMT
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group