PID controller for Box2D movement/turning

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
nfey
Citizen
Posts: 63
Joined: Tue Feb 18, 2014 9:50 am
Location: Romania

PID controller for Box2D movement/turning

Post by nfey »

I've been reading this very interesting article on gamedev.net

http://www.gamedev.net/page/resources/_ ... dies-r3885

It's about applying natural movement and turning to your in-game entities, using box2D as the physics engine, in order to preserve the collision detection but also have smooth movement. I found out that using :setPosition() and :setAngle() doesn't work well for collisions.

My question is: does anyone know of a PID controller implemented in lua floating around? Or will I have to translate the PID in the article above from C++ to Lua?
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: PID controller for Box2D movement/turning

Post by ivan »

Interesting. I suppose this is somewhat related to path following.
Reynolds has a nice path following algorithm and is not too hard to port it to Lua.

"setPosition" and "setAngle" basically teleport or instantly rotate the body which makes the physics look less realistic.
User avatar
nfey
Citizen
Posts: 63
Joined: Tue Feb 18, 2014 9:50 am
Location: Romania

Re: PID controller for Box2D movement/turning

Post by nfey »

I would say it's even worse than less realistic. When using forces, the collision detection and, most importantly, the collision feedback work out of the box and your entities behave naturally. When using :setPosition() and :setAngle(), collision detection still works but you can teleport one entity inside another and have all sorts of weird behavior, because (I guess) the system can't calculate where your body will end up in the next frame and apply the necessary forces to deny an invalid state.
In the best case scenario, with teleporting, you need to write your own code to keep entities from glitching. In the worst case scenario, collisions will simply not work properly.
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: PID controller for Box2D movement/turning

Post by ivan »

True but it depends on the gameplay 'feel' you are going for.
Also note that if you override the linear of angular velocity (using SetLinearVelocity or SetAngularVelocity) of a body then the collision response will not look realistic.
Collisions modify the velocity of bodies so you rarely want to change them to a constant value.
For example:

Code: Select all

body:setLinearVelocity(-gravity) -- assuming linear damping is off
Will not only make the object freeze in the air but it will make it non-responsive to collisions.
Under the hood, forces and impulses basically add acceleration to the current velocity, something along the lines of:

Code: Select all

acceleration = force / body.mass
body.velocity = body.velocity + acceleration
User avatar
nfey
Citizen
Posts: 63
Joined: Tue Feb 18, 2014 9:50 am
Location: Romania

Re: PID controller for Box2D movement/turning

Post by nfey »

Well I guess the system was meant to be used by applying forces to it's bodies (i.e. applyAngularImpulse()/applyForce()/etc.) and letting it manage the outcome.

I'm looking to use this for a top-down shooter, so the gravity is basically 0; I need to figure out what the restitution is and find a way to apply forces for natural movement and turning, but no wall glitching :P. If you're wondering why use love.physics at all, it's because I'm currently using it for raycasting (bullets), point testing (mouse clicks and other tests), rotation matrix related stuff (body.getWorldPoints()) and am looking to add some physics effects like walls blowing up and people flying around in grenade blasts (although I haven't yet defined the finer details and have no idea if it's doable in 2D without investing a lot in art and FX).

And by the activity on this topic it seems I'm going to have to implement that PID in Lua myself and see how it works :D
User avatar
togFox
Party member
Posts: 774
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: PID controller for Box2D movement/turning

Post by togFox »

I appreciate this is a 7 year old thread but it is perfectly relevant. I have a top-down 2D zero-g box2D project and I need to apply force in a way that is smooth and then hold force at a certain value before slowing reducing to zero again.

Thinking some pid algorithm might be useful - just like the op. Google provides very little. Has anyone done a pid controller before?
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
pgimeno
Party member
Posts: 3548
Joined: Sun Oct 18, 2015 2:58 pm

Re: PID controller for Box2D movement/turning

Post by pgimeno »

togFox wrote: Fri Sep 02, 2022 9:39 am I appreciate this is a 7 year old thread but it is perfectly relevant. I have a top-down 2D zero-g box2D project and I need to apply force in a way that is smooth and then hold force at a certain value before slowing reducing to zero again.

Thinking some pid algorithm might be useful - just like the op. Google provides very little. Has anyone done a pid controller before?
I've worked with PIDs in industrial PLCs and implemented Proportional control myself (the P in PID). Your description is too vague - maybe you can open a new thread with more details on what you need.
User avatar
zorg
Party member
Posts: 3441
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: PID controller for Box2D movement/turning

Post by zorg »

From discord by Keyslam:
"Stolen from Stormworks steam community" :3

Code: Select all

function pid(p,i,d)
    return{p=p,i=i,d=d,E=0,D=0,I=0,
        run=function(s,sp,pv)
            local E,D,A
            E = sp-pv
            D = E-s.E
            A = math.abs(D-s.D)
            s.E = E
            s.D = D
            s.I = A<E and s.I +E*s.i or s.I*0.5
            return E*s.p +(A<E and s.I or 0) +D*s.d
        end
    }
end

-- example
pid1 = pid(0.01,0.0005, 0.05)
pid2 = pid(0.1,0.00001, 0.005)
function onTick()
    setpoint = input.getNumber(1)
    pv1 = input.getNumber(2)
    pv2 = input.getNumber(3)
    output.setNumber(1,pid1:run(setpoint,pv1))
    output.setNumber(2,pid2:run(setpoint,pv2))
end
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
pgimeno
Party member
Posts: 3548
Joined: Sun Oct 18, 2015 2:58 pm

Re: PID controller for Box2D movement/turning

Post by pgimeno »

I said:
pgimeno wrote: Fri Sep 02, 2022 11:42 am Your description is too vague - maybe you can open a new thread with more details on what you need.

Since you haven't opened a new thread, let me elaborate:
togFox wrote: Fri Sep 02, 2022 9:39 am I have a top-down 2D zero-g box2D project and I need to apply force in a way that is smooth and then hold force at a certain value before slowing reducing to zero again.
I have my doubts that this is what you actually want.

Force is mass times acceleration, so for an object of constant mass, if you keep force at a constant value, you'll apply a constant acceleration, i.e. the velocity will keep growing and growing. And while the force gets slowly reduced to zero, the velocity will still keep growing until it's zero, and then it will remain at the last value (that's unless there's drag, but drag needs to be applied separately by the user in box2d in most cases).

If it's for a spaceship in space, where there's no drag, then yes, it's correct that the velocity constantly grows as the engine applies force, but typically it's an on-off situation, i.e. the engine is either on (and you accelerate) or off (and you don't accelerate). The engine may take a little bit to get to full throttle (not too realistic, but plausible if it's fast) but to me it looks quite unrealistic for it to reduce power very slowly.

Even if that's really the situation you want, I don't see any need for a PID. You just use Body:applyForce(x, y) using a unit vector for the direction, multiplied by the magnitude of the force you want to apply; so if you want it to slowly rise, you can use a timer. Just remember that Body:applyForce() applies only to the next World:update(), so you need to keep calling it while you want to apply the force. It doesn't harm if you apply it every update, using a zero vector when you don't want to apply anything.

If you want the acceleration to follow a curve rather than be a straight line, you can use several strategies, e.g. tween or damp.
User avatar
togFox
Party member
Posts: 774
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: PID controller for Box2D movement/turning

Post by togFox »

I did some reading and realised PID is a science in itself so I paused and re-considered. Tuning specifically is a black art.

For completeness, my vessel rotates in zero-g and the player can say "turn to face east" (x-axis). Assuming the vessel is pointing north then it needs to apply enough force to reach east but then to apply counter-force at the right time so that it 'settles' in a roughly easterly facing. So, the applyforce does indeed work - but it's when to apply the counter-force and the strength of the counterforce where I thought a PID might be useful, so much so it can even return to "east" if it overshot.
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 176 guests