Having issues tracking an object with a RigidBody

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By jarlowrey
:warning: Old Version Published before Godot 3 was released.

I want my bullets (RigidBody2D) to be able to track other nodes like a homing missile. Having lots of issues setting up this system. I read over the recommendations here and here and tried to go with a PID controller. Unfortunately it’s not working, and I’m not sure where to go next.

var Kp = 1000
var Ki = 1000
var Kd = 100
var prevError = 0
var P =0 
var I =0 
var D =0
func _get_PID_output(currentError, delta):
	P = currentError;
	I += P * delta;
	D = (P - prevError) / delta;
	prevError = currentError;
	   
	return P*Kp + I*Ki + D*Kd;
func _track_target(delta):
	var angle_btw = get_global_pos().angle_to(target.get_global_pos())
	var angle_diff = get_global_rot() - angle_btw
	var torque = _get_PID_output(angle_diff,delta)
	prevError = angle_diff
	set_applied_torque(torque)
	_set_vel_from_angle(get_global_rot())
	get_node("Sprite 2").set_global_rot(angle_btw) #debugging, show desired angle

Blue is the rigid body bullet, red is “Sprite 2” that is supposed to be pointing the the angle_btw direction. It looks like the angle_to is not even the right direction!

enter image description here

Project

Yay it works! That took forever, thanks @mollusca

var Kp = 1000.0
var Ki = 100.0
var Kd = 1000.0
var _prev_error = 0
var _P =0 
var _I =0 
var _D =0
func _get_PID_output(currentError, delta):
	_P = currentError;
	_I += _P * delta;
	_D = (_P - _prev_error) / delta;
	_prev_error = currentError;
	   
	return _P*Kp + _I*Ki + _D*Kd;
func _track_target(delta):
	var angle_btw = get_global_pos().angle_to_point(target.get_global_pos()) + PI/2
	var error = get_global_rot() - angle_btw
	#deal with angle discontinuity
	#https://stackoverflow.com/questions/10697844/how-to-deal-with-the-discontinuity-of-yaw-angle-at-180-degree
	if(error > PI): 
	   error = error - PI * 2
	elif(error < -PI):
	   error = error + PI * 2
	
	var torque = _get_PID_output(error,delta)
	set_applied_torque(torque)
	_set_vel_from_angle(get_global_rot())
:bust_in_silhouette: Reply From: mollusca

Use angle_to_point instead of angle_to. You’ll also have to do something about the discontinuity of the angle error.

Hmmm unfortunately that didn’t do the trick. Why is angle_to_point better? I’ve tried both before, they seem very similar in the docs. Still seems like they are trying to shoot off in the wrong direction.

func _track_target(delta):
	var angle_btw = get_global_pos().angle_to_point(target.get_global_pos())
	var error = get_global_rot() - angle_btw
	if(error > PI):
	   error = error - PI * 2
	elif(error < -PI/2):
	   error = error + PI * 2
	
	var torque = _get_PID_output(error,delta)
	prevError = error
	set_applied_torque(torque)
	_set_vel_from_angle(get_global_rot())
	get_node("Sprite 2").set_global_rot(angle_btw)

enter image description here

jarlowrey | 2017-05-11 11:16

It seems if I add PI/2 to the angle_btw, it is now pointing in the right direction! Bullets still are orbiting nothing, but it’s a step in the right direction. Any idea why this value is off by 90 deg?

jarlowrey | 2017-05-11 11:35

I changed my gain values to 1k, 100, 1k and it’s working! Good call on the angle discontinuity!

jarlowrey | 2017-05-11 11:48