Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Polar Coordinates and NaN errors

edited September 2017 Posts: 35

Hey all,

I am trying to use polar coordinates to make a guided missile, the concept is that the code works out the vector between the rocket and its target and works out the angle difference between this and the rockets velocity vector and then tries to slowly correct for this angle.

The code seems to work best to my knowledge, but then suddenly all my vector values become NaN and I don't know why, I have tried to check for reasons why such as a divide by 0 but no luck.

If anyone could share some light on this that would be greatly appreciated, Thanks!

I've posted the code for the missile logic below and have commented it all, if anyone wants to read it.

Ps I have also attached some pictures below to show the error

Rocket = class() function Rocket:init(x,y) -- you can accept and set parameters here -- initial position self.pos = vec2(x,y) -- inital velocity self.vel = vec2(0,1) -- vector that links rocket position to its target self.aim = target.pos - self.pos self.speed = math.pow(((math.pow(self.vel.x,2))+ (math.pow(self.vel.y,2))),0.5) -- the rockets angle, a vector pointing directly up has an angle of 0 self.angle = 0 end function Rocket:draw() pushMatrix() pushStyle() ellipse(self.pos.x + 5,self.pos.y + 15,10) -- the translation is used so that the rotate function rotates the rectangle from the centre translate(self.pos.x + w/2 ,self.pos.y + h/2) rotate(-self.angle) fill(255, 0, 229, 255) stroke(255, 255, 255, 255) rect(-w/2,-h/2,w,h) popStyle() popMatrix() end function Rocket:update(target) -- update position self.pos = self.pos + self.vel print(self.pos) print(self.vel) print(self.aim) -- update vector connecting ship and target position self.aim = target.pos - self.pos -- magnitude of the aim vector self.aimMag = math.pow(((self.aim.x)*(self.aim.x)+ (self.aim.y)*(self.aim.y)),0.5) -- angle between the ships velocity and vector between the ship to its target self.angleRelToTarget = math.acos((self.vel.x*self.aim.x + self.vel.y*self.aim.y)/self.aimMag) self.out = math.deg(self.angleRelToTarget) -- print(self.angleRelToTarget) text(self.out , self.pos.x + 50, self.pos.y + 50) pushStyle() strokeWidth(2) stroke(0, 0, 0, 255) -- this line shows the vector connecting the rocket to its target line(self.pos.x + w/2,self.pos.y + h/2,target.pos.x,target.pos.y) popStyle() -- this changes the ships velocity angle self.angle = self.angle + self.angleRelToTarget/2 -- print(math.deg(self.angle)) -- updates velocity with this new angle self.vel = vec2(math.sin(self.angle),math.cos(self.angle))*self.speed end
Tagged:

• Posts: 7,811

@rydergaz Having an example with workable code would help a lot. Include minimum code for the setup, draw, and touched functions so your code can be run. That way anyone who wants to help doesn't have to figure out the other functions just to explain your problem.

• Posts: 35

Sorry

• Posts: 35

Here we go

• Posts: 35

@dave1707 here's the whole programme

--# Main -- Rocket displayMode(FULLSCREEN) w = 10 h = 30 TURN_ANGLE = 0.09 -- Use this function to perform your initial setup function setup() target = Target(WIDTH/2, HEIGHT/2,WIDTH*0.05) rocket = Rocket(200,HEIGHT*0.1) end -- This function gets called once every frame function draw() background(200, 201, 212, 255) target:draw() rocket:draw() rocket:update(target) end function touch() target.touched(touch) end --# Rocket Rocket = class() function Rocket:init(x,y) -- you can accept and set parameters here -- initial position self.pos = vec2(x,y) -- inital velocity self.vel = vec2(0,1) -- vector that links rocket position to its target self.aim = target.pos - self.pos self.speed = math.pow(((math.pow(self.vel.x,2))+ (math.pow(self.vel.y,2))),0.5) -- the rockets angle, a vector pointing directly up has an angle of 0 self.angle = 0 end function Rocket:draw() pushMatrix() pushStyle() ellipse(self.pos.x + 5,self.pos.y + 15,10) -- the translation is used so that the rotate function rotates the rectangle from the centre translate(self.pos.x + w/2 ,self.pos.y + h/2) rotate(-self.angle) fill(255, 0, 229, 255) stroke(255, 255, 255, 255) rect(-w/2,-h/2,w,h) popStyle() popMatrix() end function Rocket:update(target) -- update position self.pos = self.pos + self.vel print(self.pos) print(self.vel) print(self.aim) -- update vector connecting ship and target position self.aim = target.pos - self.pos -- magnitude of the aim vector self.aimMag = math.pow(((self.aim.x)*(self.aim.x)+ (self.aim.y)*(self.aim.y)),0.5) -- angle between the ships velocity and vector between the ship to its target self.angleRelToTarget = math.acos((self.vel.x*self.aim.x + self.vel.y*self.aim.y)/self.aimMag) self.out = math.deg(self.angleRelToTarget) -- print(self.angleRelToTarget) text(self.out , self.pos.x + 50, self.pos.y + 50) pushStyle() strokeWidth(2) stroke(0, 0, 0, 255) -- this line shows the vector connecting the rocket to its target line(self.pos.x + w/2,self.pos.y + h/2,target.pos.x,target.pos.y) popStyle() -- this changes the ships velocity angle self.angle = self.angle + self.angleRelToTarget/2 -- print(math.deg(self.angle)) -- updates velocity with this new angle self.vel = vec2(math.sin(self.angle),math.cos(self.angle))*self.speed end --# Target Target = class() function Target:init(x,y,radius) -- you can accept and set parameters here self.pos = vec2(x,y) self.radius = radius end function Target:draw() pushStyle() fill(0, 0, 0, 255) ellipse(self.pos.x,self.pos.y,self.radius) -- Codea does not automatically call this method popStyle() end function Target:touched(touch) -- Codea does not automatically call this method self.x = CurrentTouch.x self.y = CurrentTouch.y end
• Posts: 7,811

You have a problem with math.acos() in rocket:update in the line

self.angleRelToTarget = math.acos((self.vel.x*self.aim.x + self.vel.y*self.aim.y)/self.aimMag)

the result of the calculation

(self.vel.x*self.aim.x + self.vel.y*self.aim.y)/self.aimMag

is greater than 1.0 which results in a nan when doing math.acos.

One way to fix this is to do something like

val=(self.vel.x*self.aim.x + self.vel.y*self.aim.y)/self.aimMag)
if val>1 then
val=1
end
self.angleRelToTarget = math.acos(val)

• Posts: 35

The result shouldn't be over 1.0 since I'm taking the dot product right?

• Posts: 35

I've sorted the Nan error now, the issue was that when relative angle between the missiles velocity vector and the vector connecting it to its target become nearly 180 degrees (i.e the rocket is flying away from target.) the code gets stuck at 180 and the rocket doesn't turn

• Posts: 35

The new code is

--# Main -- Rocket displayMode(FULLSCREEN) w = 10 h = 30 TURN_ANGLE = 0.09 -- Use this function to perform your initial setup function setup() target = Target(WIDTH/2, HEIGHT/2,WIDTH*0.05) rocket = Rocket(200,HEIGHT*0.1) end -- This function gets called once every frame function draw() background(200, 201, 212, 255) target:draw() rocket:draw() rocket:update(target) end function touched(t) target.pos.x = CurrentTouch.x target.pos.y = CurrentTouch.y end --# Rocket Rocket = class() function Rocket:init(x,y) -- you can accept and set parameters here -- initial position self.pos = vec2(x,y) -- inital velocity self.vel = vec2(0,1) -- vector that links rocket position to its target self.aim = target.pos - self.pos -- self.speed = math.pow(((math.pow(self.vel.x,2))+ (math.pow(self.vel.y,2))),0.5) self.speed = 1 parameter.integer("speed",2,10) -- the rockets angle, a vector pointing directly up has an angle of 0 self.angle = 0 end function Rocket:draw() pushMatrix() pushStyle() ellipse(self.pos.x + 5,self.pos.y + 15,10) -- the translation is used so that the rotate function rotates the rectangle from the centre translate(self.pos.x + w/2 ,self.pos.y + h/2) rotate(-self.angle) fill(255, 0, 229, 255) stroke(255, 255, 255, 255) rect(-w/2,-h/2,w,h) popStyle() popMatrix() end function Rocket:update(target) -- print("----start----") -- print(self.vel) -- print(self.speed) --print(self.aim) -- update position self.pos = self.pos + self.vel*speed -- print(self.pos) -- print(self.vel) -- print(self.aim) -- update vector connecting ship and target position self.aim = target.pos - self.pos -- magnitude of the aim vector self.aimMag = math.pow(((self.aim.x)*(self.aim.x)+ (self.aim.y)*(self.aim.y)),0.5) self.velMag = math.pow(((math.pow(self.vel.x,2))+ (math.pow(self.vel.y,2))),0.5) val=((self.vel.x*self.aim.x + self.vel.y*self.aim.y)/(self.aimMag*self.velMag)) -- angle between the ships velocity and vector between the ship to its target self.angleRelToTarget = math.acos((self.vel.x*self.aim.x + self.vel.y*self.aim.y)/self.aimMag) relAngle = self.angleRelToTarget -- angle of direction rocket wants to head in self.aimAngle = math.atan(self.aim.x/self.aim.y) -- angle of velocity of rocket self.aimVel = math.atan(self.vel.x/self.vel.y) self.out = math.deg(self.angleRelToTarget) -- print(self.angleRelToTarget) text(self.out , self.pos.x + 50, self.pos.y + 50) pushStyle() strokeWidth(2) stroke(0, 0, 0, 78) -- this line shows the vector connecting the rocket to its target line(self.pos.x + w/2,self.pos.y + h/2,target.pos.x,target.pos.y) popStyle() if self.aimVel > self.aimAngle then print("left") self.turn = -5 if math.abs(self.out) < 1 then self.turn = 1 end elseif self.aimVel < self.aimAngle then self.turn = 5 print("right") if math.abs(self.out) < 1 then self.turn = 1 end end -- this changes the ships velocity angle self.angle = self.angle + self.turn -- print(math.deg(self.angle)) -- updates velocity with this new angle self.vel = vec2(math.sin(math.rad(self.angle)),math.cos(math.rad(self.angle))) print(self.out) end --# Target Target = class() function Target:init(x,y,radius) -- you can accept and set parameters here self.pos = vec2(x,y) self.radius = radius end function Target:draw() pushStyle() fill(0, 0, 0, 255) ellipse(self.pos.x,self.pos.y,self.radius) -- Codea does not automatically call this method popStyle() end function Target:touched(touch) -- Codea does not automatically call this method self.pos.x = CurrentTouch.x self.pos.y = CurrentTouch.y end
• edited September 2017 Posts: 7,811

@rydergaz Here's an image from the guided missile program that I completed yesterday. The missile starts in the lower left corner and goes at a 45 degree angle to the right leaving a white trail. I'm using backingmode(RETAINED) to keep all the plotted point on the screen as the missile moves. When I tap the screen, a target point is created in red and a blue missile point is created where the missile was when the target point was created. After the missile passes thru a red target point, I tap the screen again creating another red target point and a blue missile position point. I did it several times to show the path of the missile as it seeked out each target point as I created them.

PS. I ran this in portrait mode.

IMG_1125.PNG 301.2K
• Posts: 35

Ah nice yours looks like it's working really smoothly, this is the latest update on mine it's almost there but for some reason the rocket chooses to turn away from the target sometimes. This screenshot shows you my rocket path, the orange dot is where I placed the target. You can see on the last target the rocket goes in the wrong direction.

• Posts: 35

Here is my rocket path

IMG_0141.PNG 145.9K
• Posts: 35

How are you guiding your rocket ?

• Posts: 35

@dave1707 this is the code for my latest rocket programme

• Posts: 35

Update: managed to get it fully functioning runs like a dream now.

• Posts: 35

@dave1707 I'm still interested to see how you went about designing your homing missile. I took the bearings from the velocity vector and the vector connecting the rocket position to the target position and changed the velocity vectors angle till it's at the same angle as the position vector. If that makes sense

• edited September 2017 Posts: 7,811

@rydergaz Here's my version. I removed the blue dot since it isn't necessary. I left the backingMode in here. You can comment it out and uncomment background. The value of speed can be changed.

displayMode(FULLSCREEN)

function setup()
mx,my=0,0
x,y=0,0
vx,vy=1,1
speed=2
backingMode(RETAINED)
end

function draw()
--background(0)
fill(255)
ellipse(x,y,5)
if px~=nil then
fill(255,0,0)
ellipse(px,py,10)
dx=px-x
dy=py-y
if not hit then
move()
if math.abs(dx)<3 and math.abs(dy)<3 then
hit=true
end
end
end
x=x+vx*speed
y=y+vy*speed
end

function move()
v1=vec2(dx,dy)
v1=v1:normalize()
if vx<v1.x then
vx=vx+speed*.005
else
vx=vx-speed*.005
end
if vy<v1.y then
vy=vy+speed*.005
else
vy=vy-speed*.005
end
end

function touched(t)
if t.state==BEGAN then
px=t.x
py=t.y
hit=false
end
end

• Posts: 35

Thanks! Your programme works so well and it's very fluid. The move() function is so smart, would it be okay if I used this same concept in a bigger project of mine?

• Posts: 7,811

@rydergaz Anything that's posted in the forum is free to use by anyone unless it says that it's not. So go ahead and use it wherever you want.

• Posts: 7,811

@rydergaz I'm not sure how you're going to use the code, but here's another version. I removed things not used. Try holding the iPad in portrait and landscape position. This is just a missile targeting another missile.

displayMode(FULLSCREEN)

function setup()
x,y,vx,vy=0,0,0,0
speed=5
px=WIDTH
py=HEIGHT*.8
backingMode(RETAINED)
end

function draw()
fill(255)
dx=px-x
dy=py-y
if not hit then
ellipse(x,y,5)
px=px-3.1
py=py+.3
move()
if math.abs(dx)<3 and math.abs(dy)<3 then
hit=true
end
end
fill(255,0,0)
ellipse(px,py,10)
x=x+vx*speed
y=y+vy*speed
end

function move()
v1=vec2(dx,dy)
v1=v1:normalize()
if vx<v1.x then
vx=vx+(v1.x-vx)/4
else
vx=vx-(vx-v1.x)/4
end
if vy<v1.y then
vy=vy+(v1.y-vy)/4
else
vy=vy-(vy-v1.y)/4
end
end

• edited September 2017 Posts: 35
@dave1707 thanks! I'll post an image of your rocket in use in the game I'm making. Here are the changes I made to your code so that it suits the style of my game, I'm very happy with how it's turned out.

~~~

--# Main
-- Rocket V3

displayMode(FULLSCREEN)

function setup()
mx,my=0,0
x,y=WIDTH/2,0
vx,vy=0,1
speed=4
gas = {}
--backingMode(RETAINED)
end

function draw()
aim = vec2(vx,vy)

angle = angleMachine(aim)

background(0)

fumes(x,y)

fill(255)

pushMatrix()

translate(x,y)

rotate(-angle)

rect(-5,-15,10,30)
popMatrix()

if px~=nil then
fill(255,0,0)
ellipse(px,py,10)
dx=px-x
dy=py-y
if not hit then
move()
if math.abs(dx) 0 then

angle = 360 + angle

end

return angle
end

function fumes(xx,yy)

randomNum = math.random(1,10)

if randomNum > 5 then

table.insert(gas,Smoke(xx,yy))

end

for a,b in pairs(gas) do

b:draw()

if b.status == "delete" then

table.remove(gas)

end

end

end

--# Smoke
Smoke = class()

function Smoke:init(xx,yy)

-- you can accept and set parameters here
self.startPos = vec2(xx,yy)

self.alpha = 255
self.angle = angle
self.timer = 0
self.status = "alive"

pushMatrix()

translate(x,y)

rotate(-angle)

fill(255,0,228,255)

popMatrix()

end

function Smoke:draw()
self.r = math.random(1,255)
self.g = math.random(1,255)
self.b = math.random(1,255)

pushMatrix()

translate(self.startPos.x,self.startPos.y)

rotate(-self.angle)

self.alpha = self.alpha*0.97
fill(self.r, self.g,self.b, self.alpha)