+ Reply to Thread
Results 1 to 9 of 9

Thread: Using applyForce(V) and applyOffsetForce(V,V)

  1. #1
    Wire Amateur zentiger's Avatar
    Join Date
    Jul 2007
    Location
    Norfolk, VA
    Posts
    98

    Default Using applyForce(V) and applyOffsetForce(V,V)

    In utilizing these outstanding methods I am beginning to understand the great potential available for E2. I will give a simple example of a quick experiment I had and then would like to ask a few questions
    Code:
    @inputs T:entity Up
    @outputs
    @persist 
    interval(30)
    if(T) {
        CUp = T:up()
        Mass = T:mass()
        if(Up){
            T:applyForce(CUp * Mass * 100)
        }
    }
    This, again, is very simple.
    My first question involves the unit that is used in applyForce(). Are these in newtons or some other unit?
    If I want to determine the minimum amount of force to apply to arrest the fall of an entity, can I somehow involve the gravity() value in finding it?

    I am simply trying (for now, anyway) to determine a good multiplier for any entity to stop it's fall, rather than using the value I have (100) which is by far too much.
    Thanks!

    "Not everything that counts can be counted, and not everything that can be counted counts." -Sign hanging in Albert Einstein's office at Princeton


  2. #2
    Wire Amateur Lt. NIbbles's Avatar
    Join Date
    Dec 2008
    Posts
    83

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    Position. GPS coordinates, V means vector. my best gusse for an example would be,<I just made this up it may not work>
    Code:
    @name ApplyForce examp
    @inputs Target:entity On
    @outputs
    @persist
    
    interval(10)
    EP=entity():pos()
    TP=Target:pos()
    if(On){T:applyForce(EP-TP+vec(0,0,50))}
    This should get a phx 1x1 plate to the expression its self. And to increase strength you can multiply the vector like
    Code:
    if(On){T:applyForce((EP-TP+vec(0,0,50))*100)}

  3. #3
    Wirererer Jeremydeath's Avatar
    Join Date
    Jun 2008
    Location
    Texas, USA
    Posts
    383

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    The applyForce(V) and applyOffsetForce(V,V) are definitely very powerful and helpful functions. To answer your question, the Havok physics engine uses very strange units. The applyForce(V) function actually uses lb*in/s^2 (pound-inches per second squared) as apposed to newtons which are kg*m/s^2 (kilogram-meters per second squared). The gravity of Garry's Mod is measured in in/s^2 (inches per second squared) and the default value is 600 in/s^2, so using this, the force needed to float an object is the gravity times the mass of the entity. This needs to be changed slightly though in the e2 gate because of the interval() function. If we just multiply the gravity by the mass of the object, we would need to set the interval to 1000 ms in order to get the desired effect. This is a problem though because if we set the interval to 1000 ms, the movement will be very jerky. To fix this we multiply the calculated needed force by the interval divided by 1000 (Interval/1000). In theory this should give you a floating effect (kind of like if you had no graved the prop), but because of inaccuracies in the physics, you must also multiply this by an error corrector that you have to find by hand. Here is some sample code to make a prop float like it has been no graved:
    Code:
    @name NoGrav
    @inputs T:entity Up
    @outputs
    @persist Interval
    Interval = 10
    interval(Interval)
    ConversionToSeconds = Interval/1000
    ErrorMultiplier = 1.5022
    
    if(T) {
        Mass = T:mass()
        if(Up){
            T:applyForce(vec(0,0,1)*ErrorMultiplier*T:mass()*gravity()*ConversionToSeconds)
        }
    }
    This will make the prop float, but in order to make a prop stop in midair, you must use a different method. This can be using delta or a more complicated linear control system like PID. Here is a very good description of PID (the pseudo code section is the most useful). I have used PID in my expressions to move props. Here is an example of a rocket controller expression gate that I made that uses PID:
    Code:
    @name Torpedo Controler
    @inputs Target:entity
    @inputs Launch
    @outputs Detonate
    
    @persist TargetPos:vector TargetAngle:angle TargetRoll Torpedo:entity
    
    @persist PreviousError:vector Error:vector
    @persist Integral:vector
    
    @persist AnglePreviousError:angle AngleError:angle
    @persist AngleIntegral:angle Counter
    
    interval(1)
    
    if(first())
    {
        TargetPos = Torpedo:pos()
        Torpedo = entity():isWeldedTo()
    }
    
    if(Launch)
    {
    
    MovedTarget = Torpedo:pos() - (Target:pos()+vec(0,0,30))
    
    TargetPitch = angnorm( atan( MovedTarget:z()/(sqrt(MovedTarget:y()^2+MovedTarget:x()^2)) ) )
    
    if(MovedTarget:x() < 0)
    {
        TargetYaw = atan( MovedTarget:y()/MovedTarget:x() )
    }
    elseif(MovedTarget:x() >= 0)
    {
        TargetYaw = angnorm( atan( MovedTarget:y()/MovedTarget:x() ) + 180)
    }
    
    TargetAngle = ang(clamp(TargetPitch, -50, 50),TargetYaw,0)
    
    #Movement
    Speed = 20
    
    TargetPos = Launch * Speed * Torpedo:forward() + Torpedo:pos()
    
    #Detonation
    Distance = Torpedo:pos():distance(Target:pos())
    
    if(Distance < 100 & Launch)
    {
        Detonate = 1    
    }
    else
    {
        Detonate = 0
    }
    
    #Position Stabilization
    Kp = 30
    Ki = 1
    Kd = 0.06
    
    Error = TargetPos - Torpedo:pos()
    Integral = Integral + Error*0.001
    Derivative = (Error - PreviousError)/0.001
    
    PosForceUC = Kp*Error + Ki*Integral + Kd*Derivative
    
    PreviousError = Error
    
    PosForceMulti = Torpedo:mass()
    
    PosForceUC = PosForceUC*PosForceMulti
    
    PosForce = PosForceUC
    
    Torpedo:applyForce( PosForce )
    
    
    #Angle Stabilization
    Kp = 500
    Ki = 1
    Kd = 20
    
    AngleError = (TargetAngle - Torpedo:angles())
    AngleIntegral = AngleIntegral + AngleError*0.01
    AngleDerivative = (AngleError - AnglePreviousError)/0.01
    
    AngleForceUC = Kp*AngleError + Ki*AngleIntegral + Kd*AngleDerivative
    
    AnglePreviousError = AngleError
    
    AngForceMulti = ang(Torpedo:inertia():y(), Torpedo:inertia():z(), Torpedo:inertia():x())
    
    AngleForceUC = AngleForceUC*AngForceMulti
    
    AngleForce = ang( clamp(AngleForceUC:pitch(), -1000000000, 1000000000), clamp(AngleForceUC:yaw(), -1000000000, 1000000000), clamp(AngleForceUC:roll(), -1000000000, 1000000000) )
    
    Torpedo:applyAngForce( AngleForce )
    }
    I hope this helped. Good luck coding and if you have any questions don't be afraid to ask.

  4. #4
    Wire Amateur zentiger's Avatar
    Join Date
    Jul 2007
    Location
    Norfolk, VA
    Posts
    98

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    Thank you very much for such a prompt and detailed reply! This was exactly what I was looking for. Not only did you provide a code example but you explained it in detail. I do appreciate it.
    After reading the WP article on PID tuning and seeing your example, I applied it to the following expression to completely stabilize an entity
    Code:
    @name PID Stabilizer
    @inputs T:entity Active
    @outputs 
    @persist GoalPos:vector GoalAng:angle
    @persist PreErrorPos:vector ErrorPos:vector IntegralPos:vector
    @persist PreErrorAng:angle ErrorAng:angle IntegralAng:angle
    interval(1)
    if(first()) {
        if(T){ GoalAng = ang(T:angles():pitch(), T:angles():yaw(), 0) }
    }
    if(T) {
        if(!Active) {
            GoalPos = T:pos()
            GoalAng = ang(T:angles():pitch(), T:angles():yaw(), 0)
        }
        else {
            # Stabilize Position
            Kp = 30
            Ki = 1
            Kd = 0.06
            ErrorPos = GoalPos - T:pos()
            IntegralPos += ErrorPos * 0.001
            Derivative = (ErrorPos - PreErrorPos)/0.001
            PForceUC = Kp*ErrorPos + Ki*IntegralPos + Kd*Derivative
            PreErrorPos = ErrorPos
            PForceMult = T:mass()
            PForceUC = PForceUC * PForceMult
            PForce = PForceUC
            T:applyForce(PForce)
            
            # Stabilize Angles
            Kp = 500
            Ki = 1
            Kd = 20
            ErrorAng = GoalAng - T:angles()
            IntegralAng += ErrorAng * 0.01
            DerivativeAng = (ErrorAng - PreErrorAng)/0.01
            AForceUC = Kp*ErrorAng + Ki*IntegralAng + Kd*DerivativeAng
            PreErrorAng = ErrorAng
            AForceMult = ang(T:inertia():y(), T:inertia():z(), T:inertia():x())
            AForceUC = AForceUC * AForceMult
            AForce = ang(clamp(AForceUC:pitch(),-1000000000,1000000000),clamp(AForceUC:yaw(),-1000000000,1000000000),clamp(AForceUC:roll(),-1000000000,1000000000))
            T:applyAngForce(AForce)
        }
    }
    Thanks again for all your help!
    Last edited by zentiger; 03-13-2009 at 07:44 AM. Reason: added code

    "Not everything that counts can be counted, and not everything that can be counted counts." -Sign hanging in Albert Einstein's office at Princeton


  5. #5
    Wirererer 1xinfusion's Avatar
    Join Date
    Apr 2007
    Location
    Toronto, Canada
    Posts
    112

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    Quote Originally Posted by Jeremydeath View Post
    The applyForce(V) and applyOffsetForce(V,V) are definitely very powerful and helpful functions. To answer your question, the Havok physics engine uses very strange units. The applyForce(V) function actually uses lb*in/s^2 (pound-inches per second squared) as apposed to newtons which are kg*m/s^2 (kilogram-meters per second squared). The gravity of Garry's Mod is measured in in/s^2 (inches per second squared) and the default value is 600 in/s^2, so using this, the force needed to float an object is the gravity times the mass of the entity. This needs to be changed slightly though in the e2 gate because of the interval() function. If we just multiply the gravity by the mass of the object, we would need to set the interval to 1000 ms in order to get the desired effect. This is a problem though because if we set the interval to 1000 ms, the movement will be very jerky. To fix this we multiply the calculated needed force by the interval divided by 1000 (Interval/1000). In theory this should give you a floating effect (kind of like if you had no graved the prop), but because of inaccuracies in the physics, you must also multiply this by an error corrector that you have to find by hand. Here is some sample code to make a prop float like it has been no graved:
    Code:
    @name NoGrav
    @inputs T:entity Up
    @outputs
    @persist Interval
    Interval = 10
    interval(Interval)
    ConversionToSeconds = Interval/1000
    ErrorMultiplier = 1.5022
    
    if(T) {
        Mass = T:mass()
        if(Up){
            T:applyForce(vec(0,0,1)*ErrorMultiplier*T:mass()*gravity()*ConversionToSeconds)
        }
    }
    This will make the prop float, but in order to make a prop stop in midair, you must use a different method. This can be using delta or a more complicated linear control system like PID. Here is a very good description of PID (the pseudo code section is the most useful). I have used PID in my expressions to move props. Here is an example of a rocket controller expression gate that I made that uses PID:
    Code:
    @name Torpedo Controler
    @inputs Target:entity
    @inputs Launch
    @outputs Detonate
    
    @persist TargetPos:vector TargetAngle:angle TargetRoll Torpedo:entity
    
    @persist PreviousError:vector Error:vector
    @persist Integral:vector
    
    @persist AnglePreviousError:angle AngleError:angle
    @persist AngleIntegral:angle Counter
    
    interval(1)
    
    if(first())
    {
        TargetPos = Torpedo:pos()
        Torpedo = entity():isWeldedTo()
    }
    
    if(Launch)
    {
    
    MovedTarget = Torpedo:pos() - (Target:pos()+vec(0,0,30))
    
    TargetPitch = angnorm( atan( MovedTarget:z()/(sqrt(MovedTarget:y()^2+MovedTarget:x()^2)) ) )
    
    if(MovedTarget:x() < 0)
    {
        TargetYaw = atan( MovedTarget:y()/MovedTarget:x() )
    }
    elseif(MovedTarget:x() >= 0)
    {
        TargetYaw = angnorm( atan( MovedTarget:y()/MovedTarget:x() ) + 180)
    }
    
    TargetAngle = ang(clamp(TargetPitch, -50, 50),TargetYaw,0)
    
    #Movement
    Speed = 20
    
    TargetPos = Launch * Speed * Torpedo:forward() + Torpedo:pos()
    
    #Detonation
    Distance = Torpedo:pos():distance(Target:pos())
    
    if(Distance < 100 & Launch)
    {
        Detonate = 1    
    }
    else
    {
        Detonate = 0
    }
    
    #Position Stabilization
    Kp = 30
    Ki = 1
    Kd = 0.06
    
    Error = TargetPos - Torpedo:pos()
    Integral = Integral + Error*0.001
    Derivative = (Error - PreviousError)/0.001
    
    PosForceUC = Kp*Error + Ki*Integral + Kd*Derivative
    
    PreviousError = Error
    
    PosForceMulti = Torpedo:mass()
    
    PosForceUC = PosForceUC*PosForceMulti
    
    PosForce = PosForceUC
    
    Torpedo:applyForce( PosForce )
    
    
    #Angle Stabilization
    Kp = 500
    Ki = 1
    Kd = 20
    
    AngleError = (TargetAngle - Torpedo:angles())
    AngleIntegral = AngleIntegral + AngleError*0.01
    AngleDerivative = (AngleError - AnglePreviousError)/0.01
    
    AngleForceUC = Kp*AngleError + Ki*AngleIntegral + Kd*AngleDerivative
    
    AnglePreviousError = AngleError
    
    AngForceMulti = ang(Torpedo:inertia():y(), Torpedo:inertia():z(), Torpedo:inertia():x())
    
    AngleForceUC = AngleForceUC*AngForceMulti
    
    AngleForce = ang( clamp(AngleForceUC:pitch(), -1000000000, 1000000000), clamp(AngleForceUC:yaw(), -1000000000, 1000000000), clamp(AngleForceUC:roll(), -1000000000, 1000000000) )
    
    Torpedo:applyAngForce( AngleForce )
    }
    I hope this helped. Good luck coding and if you have any questions don't be afraid to ask.
    i'm guessing they didn't want to convert stuff from their measurement unit which is imperial

    but thats just retarded

    anyway. i just looked at your pid based controller. can you explain to me how this works ? i've read up about pid controllers but i've failed to grasp what p,i,d actually does. I think some compensate for error and stuff but will you explain in depth ?

    please ? =p
    rawrererer

  6. #6
    Wire Amateur zentiger's Avatar
    Join Date
    Jul 2007
    Location
    Norfolk, VA
    Posts
    98

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    You are correct as it is an error compensation algorithm.
    In general, "The proportional value determines the reaction to the current error, the integral value determines the reaction based on the sum of recent errors, and the derivative value determines the reaction based on the rate at which the error has been changing."

    Kp would be how it would correct that particular error at that time.
    Ki would be how it would take into account the total of the error values to that point.
    Kd would be how it would take into account the frequency of change of that error value.

    If you are referring to the actual values used for the Proportional, Integral, and Derivative gains (Kp, Ki, and Kd), then that deals with the actual tuning of the controller, which is a science in itself.

    So:
    • Proportional gain, Kp: larger values typically mean faster response since the larger the error, the larger the Proportional term compensation. An excessively large proportional gain will lead to process instability and oscillation.
    • Integral gain, Ki: larger values imply steady state errors are eliminated more quickly. The trade-off is larger overshoot: any negative error integrated during transient response must be integrated away by positive error before we reach steady state.
    • Derivative gain, Kd: larger values decrease overshoot, but slows down transient response and may lead to instability due to signal noise amplification in the differentiation of the error.

    "Not everything that counts can be counted, and not everything that can be counted counts." -Sign hanging in Albert Einstein's office at Princeton


  7. #7
    Wire Tutor chinoto's Avatar
    Join Date
    Apr 2008
    Location
    Brooklyn Park, MN. Lost my thumbdrive yet again...
    Posts
    1,983

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    You can't use a constant value to stop a fall, you need to know it's velocity for that.
    Code:
    interval(10)
    E=entity()
    E:applyForce((vec(0,0,9.015)-E:vel())*E:mass())
    #Gravitional acceleration times mass gives the force to defy gravity
    #Negative velocity times mass gives instant stopping power
    (\__/) Expression 2 Resources: E2 Beginner's Guide | E2 Formatting Guide | E2 Function Reference | E2 Examples | Me
    (='.'=) PM me code and I'll send it back optimized if possible. (I find it fun dammit!)
    (")_(") Drunkie referring to an E2: "It's obvious that Chinoto made this, his coding style is all over it."

  8. #8
    Wirererer Blaylock1988's Avatar
    Join Date
    Apr 2009
    Location
    North Carolina
    Posts
    280

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    What is the difference between applyforce and applyoffsetforce?

  9. #9
    Wire Sofaking ZeikJT's Avatar
    Join Date
    Dec 2008
    Location
    California
    Posts
    1,391

    Default Re: Using applyForce(V) and applyOffsetForce(V,V)

    applyForce defaults to the origin of the entity, with the offset you can apply the force from a position that isn't the entity's center. Hence you can make an object rotate with the offset.
    Against stupidity the Gods themselves contend in vain.
    -Friedrich Schiller

    The flame puts me in the mood to "Do it!".
    -Dart, Legend of Dragoon

+ Reply to Thread

Similar Threads

  1. applyForce() help?
    By BlackholeWM in forum Expression 2 Discussion & Help
    Replies: 6
    Last Post: 03-20-2009, 12:19 PM
  2. applyOffsetForce help
    By steelseeker in forum Installation and Malfunctions Support
    Replies: 2
    Last Post: 03-03-2009, 04:03 AM
  3. applyOffsetForce(V,V) trouble
    By NEMESiS in forum Installation and Malfunctions Support
    Replies: 4
    Last Post: 02-23-2009, 09:35 AM
  4. Problem with E:applyOffsetForce(VV)
    By mjmr89 in forum Installation and Malfunctions Support
    Replies: 7
    Last Post: 02-03-2009, 01:26 PM
  5. Using applyOffsetForce for Yaw stabalization?
    By mjmr89 in forum Expression 2 Discussion & Help
    Replies: 4
    Last Post: 02-03-2009, 11:03 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
proceed-collector
proceed-collector
proceed-collector
proceed-collector
linguistic-parrots
linguistic-parrots
linguistic-parrots
linguistic-parrots