Can't figure out how to make my raycast obstacle avoidance less jittery

I'm currently using a raycast obstacle avoidance solution that I cobbled together, and it works okay, but has a few problems.

Chief among them is that when my AI object is avoiding, it is very jittery. I know exactly why its jittery, because I'm adding the hit.normal (multiplied by a modifier) of the raycast to my target direction for my eventual slerp, so the frames that the AI is avoiding the target direction is instantly changed, resulting in a jitter.

I know I need to probably Vector3.Lerp my avoidance direction (the original target direction plus the offset from the raycast hit.normal) and my original target direction, I just have no idea where to put it!

Here's my whole script in its current incarnation:

var rayLength : float = 10.0;

private var rayArray : Vector3[];

function Start(){
    rayArray = new Vector3[3];
}

function MoveTowardsAndAvoid(target : Transform, speed : float, rotSpeed : float){

    var targetPos : Vector3 = target.position;
    targetPos.y = transform.position.y; //set y to zero so we only rotate on one plane
    var targetDir : Vector3 = targetPos - transform.position;

    rayArray[0] = transform.TransformDirection(-0.20,0,0.5); //ray pointed slightly left 
    rayArray[2] = transform.TransformDirection(0.20,0,0.5); //ray pointed slightly right 
    rayArray[1] = transform.forward; //ray 1 is pointed straight ahead

    //loop through the rays
    for (i=0; i<3; i++) {
        var hit : RaycastHit;
        // if you hit something with the ray......
        if (Physics.Raycast (transform.position, rayArray*, hit, rayLength)) {* 
 *Debug.DrawLine(transform.position, hit.point, Color.magenta);*
 _targetDir += 50*hit.normal;_
 *}*
 *}*
 *// rotation and movement code* 
 *var targetRotation = Quaternion.LookRotation(targetDir);*
 _transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotSpeed*Time.deltaTime);_
 _transform.Translate(Vector3.forward*Time.deltaTime*speed);_
*}*
*```*
*<p>Any ideas?</p>*

Try this:

var rayLength : float = 10.0;
var lerpSpeed : float = 1.0;
var theTarget : GameObject;
var mult : float = 1.0;
var speed : float = 1.0;
var rotSpeed : float = .15;

private var rayArray : Vector3[];
private var lerpedTargetDir : Vector3;

function Start(){
    rayArray = new Vector3[3];
}

function Update(){

    MoveTowardsAndAvoid(theTarget.transform);

}

function MoveTowardsAndAvoid(target : Transform){

    var targetPos : Vector3 = target.position;
    targetPos.y = transform.position.y; //set y to zero so we only rotate on one plane
    var targetDir : Vector3 = targetPos - transform.position;

    rayArray[0] = transform.TransformDirection(-0.20,0,0.5); //ray pointed slightly left 
    rayArray[2] = transform.TransformDirection(0.20,0,0.5); //ray pointed slightly right 
    rayArray[1] = transform.forward; //ray 1 is pointed straight ahead

    moveIt = false;

    //loop through the rays
    for (i=0; i<3; i++) {
        var hit : RaycastHit;
        // if you hit something with the ray......
        if (Physics.Raycast (transform.position, rayArray*, hit, rayLength)) {* 
 *Debug.DrawLine(transform.position, hit.point, Color.magenta);*
 _targetDir += mult * hit.normal;_
 *} else {*
 *moveIt = true;*
 *}*
 *}*
 *// rotation and movement code* 
 _lerpedTargetDir = Vector3.Lerp(lerpedTargetDir,targetDir,Time.deltaTime * lerpSpeed);_
 *var targetRotation = Quaternion.LookRotation(lerpedTargetDir);*
 _transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotSpeed*Time.deltaTime);_
 _if(moveIt){     transform.Translate(Vector3.forward*Time.deltaTime*speed);  }_
*}*
*```*

One thing you might try is to respond only to one of the raycasts, rather than (potentially) to all three. For example, you could respond to the closest one, or to the one for which the normal is most aligned towards the agent.

I'd also recommend consulting the literature on steering behaviors (or reviewing it, if you've already covered that material). These behaviors are all pretty well defined, and you can find example implementations in libraries such as OpenSteer, UnitySteer etc. By looking at how it's done elsewhere (or just reading the description in the 'canonical' paper on the subject) and comparing it to what you're doing, you should be able to figure out what's causing the problem.

Sorry to be a little vague, but to offer a specific suggestion I'd probably have to dig into the code myself. In the meantime though, perhaps the above suggestions will be of some help.

What if you put the 'move' stuff in Update() and the 'find' stuff in LateUpdate()?