Rotate 2D turret toward target heading (LerpAngle)

I’m trying to write a script to rotate an object toward a specified heading using LerpAngle().
So far, it rotates, but it never stops rotating. The targetHeading acts more like a speed than a target.

Any idea how to get the object to hit that target heading and stick?

        public class Turret : MonoBehaviour {
        
        	public float TargetHeading; //0deg - 359deg
        	public float RotateSpeed;
        
        	// Use this for initialization
        	void Start () {
        		TargetHeading = 0;
        	}
        	
        	// Update is called once per frame
        	void Update () {
        		//Map 0deg heading to a global rotation angle
        		float zeroDeg = 0;
        		float targetHTG = HeadingToGlobal (TargetHeading, zeroDeg);
        		if (targetHTG != transform.rotation.z) {
        			float angle = Mathf.LerpAngle (transform.rotation.z, targetHTG, Time.time);
        			transform.Rotate(0,0,angle);
        		}
        	}
        
                //Convert a Heading value (deg) to a global rotation value (deg)
        	float HeadingToGlobal (float headingDeg, float zeroDeg) {
        		float result = zeroDeg - headingDeg;
        
        		if (result < 0)
        			result += 360;
        		else if (result >= 360)
        			result -= 360;
        
        		return result;
        	}
        }

I spot one serious issue. Transform.rotation is a Quaternion. They are non-intuitive, 4D constructs in which the individual values range from 0.0 to 1.0. When you refer to ‘transform.rotation.z’, you are not getting an angle rotation. What you may be able to use is ‘transform.eulerAngle.z’. I say ‘may’ because eulerAngles has its own set of issues, but I think you can get away with using them here.

But it seems like you are may be going the long way around in this code. Here is an alternate solution that uses Vector3.right as the zero heading angle:

    public class Turret : MonoBehaviour {
    
    	public float targetHeading; //0deg - 359deg
    	public float rotateSpeed;
    
            	void Start () {
    		TargetHeading = 0;
    	}
    	
            void Update () {
                Quaternion q = Quaternion.AngleAxis(targetHeading, Vector3.forward);
                transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * rotateSpeed);
            }
    }

If you want a different angle as your zero heading, you need to add a constant to targetHeading in the AngleAxis() call.

public Transform target;
public float initialForwardAngle = 0; // initial angle of your “gun barrel”
public float maxRotationSpeed = 60;
public float threshold = 4;

void Update() {
	RotateGradually2D ();
}

public void RotateGradually2D()
{
	angleToTarget = Mathf.Atan2 (target.position.y - transform.position.y, target.position.x - transform.position.x) * Mathf.Rad2Deg;
	signToTarget = Mathf.Sign (angleToTarget - _currentAngle);

	if (Mathf.Abs(angleToTarget - _currentAngle) > threshold) {
		_currentAngle += signToTarget * maxRotationSpeed * Time.deltaTime;
	} else {
		_currentAngle = angleToTarget;
	}

	transform.eulerAngles = new Vector3(0, 0, _currentAngle - initialForwardAngle);
}
private float angleToTarget; // Destination angle
private float _currentAngle = 0; // Current angle
private float signToTarget;