# 09 – Steering the Vehicle

Much like the linear motor, there is also an angular motor that is always on, and whose direction and magnitude can be set. For example, to make a vehicle turn at 5 degrees/sec around itâ€™s local z-axis (its up-axis) you might
add the following lines to its script:

vector angular_velocity = <0, 0, 5 * PI / 180>;
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, angular_velocity);

The magnitude of the angular motor is capped to be no more than two rotations per second (4*PI radians/sec).

Also like the linear motor it has an efficiency parameter, VEHICLE_ANGULAR_MOTOR_TIMESCALE, and a motor decay parameter, VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, which is set to the maximum possible value of 120 seconds by default.

When steering a vehicle you probably donâ€™t want it to turn very far or for very long. One way to do it using the angular motor would be to leave the decay timescale long, enable a significant amount of angular friction (to quickly slow the vehicle down when the motor is turned off) then set the angular motor to a large vector on a key press, and set it to zero when the key is released. Another way to do it is to set the VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE to a short value and push the vehicle about with a more impulsive method that sets the motor fast on a key press down (and optionally setting the motor to zero on a key up) relying on the automatic exponential decay of the motorâ€™s effectiveness rather than a constant angular friction.

Setting the angular motor to zero magnitude is different from allowing it to decay. When the motor completely decays it no longer affects the motion of the vehicle, however setting it to zero will reset the “grip” of the vehicle and will make the vehicle try to achieve zero angular velocity.

For some vehicles it will be possible to use the “banking feature” to turn. “Banking” is what airplanes and motorcycles do when they turn. When a banking vehicle twists about its roll-axis there is a resultant spin around its yaw-axis. Banking is only available when using the “vertical attractor” which is described below.

11.8. The Vertical Attractor

Some vehicles, like boats, should always keep their up-side up. This can be done by enabling the “vertical attractor” behavior that springs the vehicleâ€™s local z-axis to the world z-axis (a.k.a. “up”). To take advantage of this feature you would set the VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an efficiency of 1.0 will cause the spring to reach itâ€™s equilibrium with exponential decay.

llSetVehicleVectorParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 4.0);
llSetVehicleVectorParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.5);

The vertical attractor is disabled by setting its timescale to anything larger than 300 seconds.

Note that by default the vertical attractor will prevent the vehicle from diving and climbing. So, if you wanted to make a airplane you would probably want to unlock the attractor around the pitch axis by setting the VEHICLE_FLAG_LIMIT_ROLL_ONLY bit:

llSetVehicleFlags(VEHICLE_FLAG_LIMIT_ROLL_ONLY);

11.9. Banking

The vertical attractor feature must be enabled in order for the banking behavior to function. The way banking works is this: a rotation around the vehicleâ€™s roll-axis will produce a angular velocity around the yaw-axis,
causing the vehicle to turn. The magnitude of the yaw effect will be proportional to the VEHICLE_BANKING_COEF, the angle of the roll rotation, and sometimes the vehicleâ€™s velocity along itâ€™s preferred axis of motion.

The VEHICLE_BANKING_COEF can vary between -1 and +1. When itâ€™s positive then any positive rotation (by the right-hand rule) about the roll-axis will effect a (negative) torque around the yaw-axis, making it turn to the right — that is the vehicle will lean into the turn, which is how real airplanes and motorcycleâ€™s work. Negating the banking coefficient will make it so that the vehicle leans to the outside of the turn (not very “physical” but might allow interesting vehicles so why not?).

The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making banking vehicles do what you want rather than what the laws of physics allow. For example, consider a real motorcycle… it must be moving forward in order for it to turn while banking, however video-game motorcycles are often configured to turn in place when at a dead stop — because theyâ€™re often easier to control that way using the limited interface of the keyboard or game controller. The VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic banking by fuctioning as a slider between a banking that is correspondingly totally static (0.0) and totally dynamic (1.0). By “static” we mean that the banking effect depends only on the vehicleâ€™s rotation about itâ€™s roll-axis compared to “dynamic” where the banking is also proportional to itâ€™s velocity along itâ€™s roll-axis. Finding the best value of the “mixture” will probably require trial and error.

The time it takes for the banking behavior to defeat a pre-existing angular velocity about the world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to bank quickly then give it a banking timescale of about a second or less, otherwise you can make a sluggish vehicle by giving it a timescale of several seconds.

11.10. Friction Timescales

VEHICLE_LINEAR_FRICTION_TIMESCALE is a vector parameter that defines the timescales for the vehicle to come to a complete stop along the three local axes of the vehicleâ€™s reference frame. The timescale along each axis is independent of the others. For example, a sliding ground car would probably have very little friction along its x- and z-axes (so it can easily slide forward and fall down) while there would usually significant friction along its y-axis:

llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1000, 1000, 3>);

Remember that a longer timescale corresponds to a weaker friction, hence to effectively disable all linear friction you would set all of the timescales to large values.

Setting the linear friction as a scalar is allowed, and has the effect of setting all of the timescales to the same value. Both code snippets below are equivalent, and both make friction negligible:

// set all linear friction timescales to 1000
llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1000, 1000, 1000>);

// same as above, but fewer characters
llSetVehicleFloatParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, 1000);

VEHICLE_ANGULAR_FRICTION_TIMESCALE is also a vector parameter that defines the timescales for the vehicle to stop rotating about the x-, y-, and z-axes, and are set and disabled in the same way as the linear friction.

11.11. Buoyancy

The vehicle has a built-in buoyancy feature that is independent of the llSetBuoyancy call. It is recommended that the two buoyancies do not mix! To make a vehicle buoyant, set the VEHICLE_BUOYANCY parameter to something between 0.0 (no buoyancy whatsoever) to 1.0 (full anti-gravity).

The buoyancy behavior is independent of hover, however in order for hover to work without a large offset of the VEHICLE_HOVER_HEIGHT, the VEHICLE_BUOYANCY should be set to 1.0.

It is not recommended that you mix vehicle buoyancy with the llSetBuoyancy script call. It would probably cause the object to fly up into space.

11.12. Hover

The hover behavior is enabled by setting the VEHICLE_HOVER_TIMESCALE to a value less than 300 seconds; larger timescales totally disable it. Most vehicles will work best with short hover timescales of a few
seconds or less. The shorter the timescale, the faster the vehicle will slave to is target height. Note, that if the values of VEHICLE_LINEAR_FRICTION_TIMESCALE may affect the speed of the hover.

Hover is independent of buoyancy, however the VEHICLE_BUOYANCY should be set to 1.0, otherwise the vehicle will not lift itself off of the ground until the VEHICLE_HOVER_HEIGHT is made large enough to counter the acceleration of gravity, and the vehicle will never float all the way to its target height.

The VEHICLE_HOVER_EFFICIENCY can be thought of as a slider between bouncy (0.0) and smoothed (1.0).

When in the bouncy range the vehicle will tend to hover a little lower than its target height and the VEHICLE_HOVER_TIMESCALE will be approximately the oscillation period of the bounce (the real period will tend to be a little longer than the timescale).

For performance reasons, until improvements are made to the Second Life physics engine the vehicles can only hover over the terrain and water, so they will not be able to hover above objects made out of primitives, such as bridges and houses. By default the hover behavior will float over terrain and water, however this can be changed by setting some flags:

If you wanted to make a boat you should set the VEHICLE_HOVER_WATER_ONLY flag, or if you wanted to drive a hover tank under water you would use the VEHICLE_HOVER_TERRAIN_ONLY flag instead. Finally, if you wanted to make a submarine or a balloon you would use the VEHICLE_HOVER_GLOBAL_HEIGHT.

Note that the flags are independent of each other and that setting two contradictory flags will have undefined behavor. The flags are set using the script call llSetVehicleFlags().

The VEHICLE_HOVER_HEIGHT determines how high the vehicle will hover over the terrain and/or water, or the global height, and has a maximum value of 100 meters. Note that for hovering purposes the “center” of the vehicle is its “center of mass” which is not always obvious to the untrained eye, and it changes when avatarâ€™s sit on the vehicle.

11.13. Reference Frame

The vehicle relies on the x- (at), y- (left), and z- (up) axes in order to figure out which way it preferres to move and which end is up. By default these axes are identical to the local axes of the root primitive of the object, however this means that the vehicleâ€™s root primitive must, by default, be oriented to agree with the designed at, left, and up axes of the vehicle. But, what if the vehicle object was already pre-built with the root primitive in some non-trivial orientation relative to where the vehicle as a whole should move? This is where the VEHICLE_REFERENCE_FRAME parameter becomes useful; the vehicleâ€™s axes can be arbitrarily reoriented by setting this parameter.

As an example, suppose you had built a rocket out of a big cylinder, a cone for the nose, and some stretched cut boxes for the fins, then linked them all together with the cylinder as the root primitive. Ideally the rocket would move nose-first, however the cylinderâ€™s axis of symmetry is its local z-axis while the default “at-axis” of the vehicle, the axis it will want to deflect to forward under angular deflection, is the local x-axis and points out from the curved surface of the cylinder. The script code below will rotate the vehicleâ€™s axes such that the local z-axis becomes the “at-axis” and the local negative x-axis becomes the “up-axis”:

// rotate the vehicle frame -PI/2 about the local y-axis (left-axis)
rotation rot = llEuler2Rot(0, PI/2, 0);
llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, rot);

Another example of how the reference frame parameter could be used is to consider flying craft that uses the vertical attractor for stability during flying but wants to use VTOL (vertical takeoff and landing). During flight the craftâ€™s dorsal axis should point up, but during landing its nose-axis should be up. To land the vehicle: while the vertical attractor is in effect, rotate the existing VEHICLE_REFERENCE_FRAME by +PI/2 about the left-axis, then the vehicle will pitch up such that itâ€™s nose points toward the sky. The vehicle could be allowed to fall to the landing pad under friction, or a decreasing hover effect.