# How to control acceleration

To move a spaceship in unity, I wrote a script that applies a force in Z-direction when hitting the up-key and an opposite force when pressing the down-key. The velocity is limited with a clamp-function.

Now I’m facing several problems with this setup:

-When rotating the ship (using a 2nd mouselook-script), accelleration in the new direction at certain degrees is not possible

-Depending on rotation the ship can fly backwards (even though the clamp-function should avoid that)

-Console-output for speed doesn’t seem to show the real speed / it depends on ships orientation.

-Regulation of a constant speed is not possible

I think the first bunch of problems have something to do with the local/world-axis. However, the forces are applied to the rigidbody and therefore should be local. Am I wrong?

I found several threats where people had trouble with setting/getting the real local velocity. Also I’m not sure if my way of just limiting the speed is messing things up with the applied forces.

What I propably need is some kind of proportional-integral-regulation to automatically and dynamically let the acceleration apply to a wished speed. I know mathematically speed is the derivation of acceleration. Going backwards makes integral-calculation neccesary, based on user-input rather than a mathematical function. This is higher mathematics and usually found only in special devices.

Does unity provide such a regulator-function? I’m talking about something similar to the devices used in modern cars. The driver sets a target speed and the regulator automatically adjusts the acceleration (a lot at the beginning / very few when close to target-speed). My script right now is very simple and posted below.

``````// This script regulates object-movement with the keyboard
//
// -Forward/backward-movements are done with forces
//
// -Sidewards-movements are done with manually changing position
//
// -Booster also is done with position-change
//
// -The forces are limited by min- and max-speed (unity has to cut the accelleration because of the maxspeed
//    											  and has to stop backwards-drift due to min-speed.)

function Update () {

var stepx : float; // Boster
var stepz : float; // Left-Right-Sliding

var accell : float; //Start-Accelleration
var breaks : float; //Max accelleration

var minspeed : float; //Lowest possible speed
var maxsped : int;	 // Fastest speed

minspeed = 10;  	  //
maxspeed = 30;   // Max-Speed

accell = 80; //Acelleration
breaks = -82; //Breaks-strength  (breaks a bit stronger than accell - Problem: backwards-flying occurs)

stepx = 8.5; //  Booster Forward-steps
stepz = 1.5; //Sideward steps Slider

// Local z- and x-axis are switched
//    -> "Vector3.right" must be used instead of "Vector3.forward"

// UP
if(Input.GetKey("w") || Input.GetKey("up")) {
constantForce.relativeForce.x = accell;
}

// DOWN
if(Input.GetKey("s") || Input.GetKey("down")) {

if(rigidbody.velocity.x > 0) {
constantForce.relativeForce = (Vector3.right * breaks);
}
}

//TABULATOR (Booster)
if(Input.GetKey("tab")) {
transform.Translate(Vector3.right * stepx);  //Booster just moves Obj. forward

}

// LEFT-Slide
if(Input.GetKey("q")) {
transform.Translate(Vector3.forward * stepz);

}

// RIGHT-Slide
if(Input.GetKey("e")) {
transform.Translate(Vector3.forward * -stepz);
}

// Clamp speed to the min and max
rigidbody.velocity.x = Mathf.Clamp (rigidbody.velocity.x, minspeed, maxspeed);

Debug.Log("Current Speed:" +rigidbody.velocity.x);
} // EndFunc Update
``````

You’re doing a big mess here! constantForce.relativeForce is local, but rigidbody.velocity is world referenced, and you’re clamping only the x axis! This is causing the weird direction and speed readings.

You should limit the speed with Vector3.ClampMagnitude: this limits the velocity to a max magnitude while keeping its direction. Another solution could be to set rigidbody.velocity directly - but this would require a complete change in your code.

You can solve both problems changing the two last lines:

```    // Clamp speed to max
rigidbody.velocity = Vector3.ClampMagnitude(rigidbody.velocity, maxspeed);
Debug.Log("Current Speed:" +rigidbody.velocity.magnitude);
```

NOTE: forget about what I said about Q, E and Tab: you’re using Translate, which
by default operates in local space - thus the teleport will be ok.

EDITED:

That’s a rigidbody.velocity based version of your script: it’s more predictably, and you stop without that back flight problem. I didn’t test this, but the basic idea is correct - let me know if you have any problems with this script:

```function Update () {
var stepx : float = 8.5; // Booster Forward-steps
var stepz : float = 1.5; // Sideward steps Slider
var accell : float = 30.0; // Max speed forward

private var locVel = Vector3.zero; // local velocity you set
private var curVel = Vector3.zero; // current velocity - follow locVel
var force: float = 2.0; // how fast curVel reaches locVel

// Local z- and x-axis are switched
//    -> "Vector3.right" must be used instead of "Vector3.forward"

// UP
if(Input.GetKey("w") || Input.GetKey("up")) {
locVel = Vector3(accell, 0, 0); // desired velocity = accell forward
}
// DOWN
if(Input.GetKey("s") || Input.GetKey("down")) {
locVel = Vector3.zero; // desired velociy = 0
}
// fake a progressive acceleration with MoveTowards:
curVel = Vector3.MoveTowards(curVel, locVel, force * Time.deltaTime);
// convert to world space and apply to the rigidbody velocity:
rigidbody.velocity = transform.TransformDirection(curVel);
//TABULATOR (Booster)
if(Input.GetKey("tab")) { // it's correct: Translate defaults to local space
transform.Translate(Vector3.right * stepx);  //Booster just moves Obj. forward
}
// LEFT-Slide
if(Input.GetKey("q")) {
transform.Translate(Vector3.forward * stepz);
}
// RIGHT-Slide
if(Input.GetKey("e")) {
transform.Translate(Vector3.forward * -stepz);
}
Debug.Log("Current Speed:" + curVel.x);
}
```

EDITED 2:

PI is a Proportional Integral control (you can read about the more complex PID -Proportional Integral Derivative - control in this article: PID controller - Wikipedia)

A simple P (Proportional) control subtracts the measured speed from the target speed, multiply the difference (called error signal) by PGain and use the result (the Proportional signal) to control the force applied. When the desired speed is reached, the error signal becomes zero, what also reduces to zero the force applied. But if friction or some external force reduce the speed, the system can never stay at zero error: there’s always a small error signal to be multiplied by PGain and supply the force necessary to null these external forces.

To ensure zero error, the I letter enters the scene: the error signal is continuously accumulated (Integrated) and the result is multiplied by IGain and added to the Proportional signal. In a PI control, the Integral (accumulated) error plays the role of the small residual error in a simple P control: it provides the necessary force to keep the speed, allowing for zero error signal. Unless you need to control supersonic missile flight, in practice there’s no need to do complex numerical integrations: just accumulate the error signal in a variable, multiply it by the IGain (usually << 1) and add to the Proportional signal.

Fortunately, in the game environment all this sophistication is rarely needed (unless the game goal is to fine-tune PI Control parameters, hardly a block-buster game!) In most cases, we just calculate the ideal behavior and make the objects follow our orders! In my script, for instance, the speed varies linearly up to the desired value, and obediently gets stuck there: it’s the dream-come-true of any control engineer! In real life, one must tweak the gains and available power to barely follow an ideal case - and the wrong parameters very often cause oscillation, overshoot, big residual errors, slow response - it’s hell on earth!

Anyway, if you really really really need to implement a servo control, you can avoid the Integral part (there’s no friction or other forces, so it’s not needed): just calculate the difference between current and target speeds, multiply by a gain factor, clamp to some limit and use the result to apply the force. But if you want to check the PI controller, go ahead and use the code below:

```var targetSpeed = Vector3.zero; // the desired speed
var maxForce: float = 100; // the max force available
var pGain: float = 20; // the proportional gain
var iGain: float = 0.5; // the integral gain
private var integrator = Vector3.zero; // error accumulator
var curSpeed = Vector3.zero; // actual speed
var force = Vector3.zero; //

function FixedUpdate(){
curSpeed = rigidbody.velocity; // measure actual speed
var error = targetSpeed - curSpeed; // generate the error signal
integrator += error;
// calculate the force and limit it to the max force available:
force = error * pGain + integrator * iGain;
force = Vector3.ClampMagnitude(force, maxForce);
// apply the force to accelerate the rigidbody:
}
```

This code uses AddForce instead of constantForce - remember to zero any constantForce currently in your code. NOTE: targetSpeed is in world space: if you want do use local speed, define it, convert to world space with transform.TransformDirection and store in targetSpeed.

EDITED 3:

The integration above doesn’t take into account the time elapsed since the last frame. It’s an usual practice in the microcontroller world, because the integration occurs at a fixed rate, and this saves an expensive multiplication (iGain compensates for the different integration result). FixedUpdate also occurs at a fixed rate - or at least tries to do it: in very slow machines, FixedUpdate may not be able to keep a constant pace. To avoid problems in these cases, the integration can include Time.deltaTime, like this:

```var targetSpeed = Vector3.zero; // the desired speed
var maxForce: float = 100; // the max force available
var pGain: float = 20; // the proportional gain
var iGain: float = 0.5; // the integral gain
private var integrator = Vector3.zero; // error accumulator
var curSpeed = Vector3.zero; // actual speed
var force = Vector3.zero; //

function FixedUpdate(){
curSpeed = rigidbody.velocity; // measure actual speed
var error = targetSpeed - curSpeed; // generate the error signal
integrator += error * Time.deltaTime; // integrate the error signal
// calculate the force:
force = error * pGain + integrator * iGain;
// clamp to the max force available:
force = Vector3.ClampMagnitude(force, maxForce);
// apply the force to accelerate the rigidbody:
}
```

The iGain in this case must be about 50 times greater, since the regular deltaTime is 1/50 second.

Solution for 2nd part - How to do an autopilot:

“A simple P (Proportional) control subtracts the measured speed from the target speed, multiply the difference (called error signal) by PGain and use the result (the Proportional signal) to control the force applied. When the desired speed is reached, the error signal becomes zero, what also reduces to zero the force applied”, as aldonaletto wrote.

Furthermore the integral part of a P-I-regulator is doing this:
“To ensure zero error […] the error signal is continuously accumulated (Integrated) and the result is multiplied by IGain and added to the Proportional signal. In a PI control, the Integral (accumulated) error plays the role of the small residual error in a simple P control: it provides the necessary force to keep the speed, allowing for zero error signal.”

…Meaning a P - or even better - a P-I-regulator is the motor of the idea. Is there one in unity’s physics-engine?

If not: Did someone write a script already to compensate the lack?

I searched the web for P-I- and P-I-D-controllers and indeed found some code. No Javascript but at least C and C#-versions as well as pseudo-code and a Basic-example.

Some good pictures what P- and PI-controllers do can be found in this well-done explanation.

P-only accelerates longer and higher around the target-value. P-I-controllers make the system getting stable faster and better. In slow responding systems, P-only-controllers sometimes never stabilize on the target-value and always oscillate around the target.

However, my problem now is: I want to transfer the found code into a javascript-version but I can’t find the lines where they calculate the integral. The code in general is not too difficult and basically always the same:

Pseudo-code from Wikipedia:

````
previous_error = 0
integral = 0
start:
error = setpoint - PV [actual_position]
integral = integral + error*dt
derivative = (error - previous_error)/dt
output = Kp*error + Ki*integral + Kd*derivative
previous_error = error
wait(dt)
goto start
```
`

I don’t get the thing with the integral. According to Wikipedia, there are several methods to choose from to integrate (e.g. Romberg). But the PID-code-examples just use

integral = integral + error*dt

for calculating the integral. What am I missing?

C-version of a PID-controller (from Embedded’s Heaven):

 #ifndef PID_H_ #define PID_H_ #include //Define parameter #define epsilon 0.01 #define dt 0.01             //100ms loop time #define MAX  4                   //For Current Saturation #define MIN -4 #define Kp  0.1 #define Kd  0.01 #define Ki  0.005 float PIDcal(float setpoint,float actual_position) { static float pre_error = 0; static float integral = 0; float error; float derivative; float output; //Caculate P,I,D error = setpoint - actual_position; //In case of error too small then stop intergration if(abs(error) > epsilon) { integral = integral + error*dt; } derivative = (error pre_error)/dt; output = Kperror + Kiintegral + Kd*derivative; //Saturation Filter if(output > MAX) { output = MAX; } else if(output < MIN) { output = MIN; } //Update error pre_error = error; return output; } #endif /PID_H_/

An extensive C#-version of a PID-controller (from Codeproject.com):