Using the trajectory equations provided on hyperphysics, I have developed some code to plot the trajectory of an object. I now need to work out the x and y forces to apply to make the object follow said path.
I know that F=MA but I can't seem to reverse this to find the x and y force values to cause an object of given mass to follow the trajectory curve plotted by general ballistic code.
Sorry for the lengthy question but I can provide code and more of my equations if necessary. Sorry if this if the wrong forum.
EDIT:
The equations I am working with are:
velocity = Impulse / mass
velocity = Distance / time
Velocity = speed / time
Force = mass * acceleration
Momentum = mass * velocity
Impulse = avg force * time
[2ND EDIT:]
The code follows – lua language, using the Corona SDK…
Matt
main.lua
local trajlibapi = require("trajectorylib")
local mathlibapi = require("mathlib")
local physics = require("physics")
physics.start()
physics.setGravity(0,10)
--[[ environment setup ]]--
local start, sling = nil, nil
local offsetX, offsetY = 50, 300
local iteration = 0.1 -- gap between increments of trajectory points
--local velocity = 40 -- launch velocity v/ms
--local angle = 60 -- launch angle (theta) degrees
--[[ trajectory plotting ]]--
function trajectory( velocity, angle, iteration )
local points, r, h, f = trajlibapi.calcTrajectoryPoints( 0, 0, velocity, angle, iteration )
print( 'angle: ', angle )
print( 'velocity: ', velocity )
print( 'range: ', r )
print( 'height: ', h )
print( 'flight time: ', f )
for i=1, #points do
--print( math.round( points[i].x ), math.round( points[i].y ) )
display.newCircle( start.x + points[i].x, start.y - points[i].y, (points[i].velocityx + points[i].velocityy) * 0.1 )
end
return points
end
--[[ throwing the ball ]]--
function throw( points, sling, start, distance, angle )
local radius = 50
local ball = display.newCircle( start.x, start.y, radius )
ball.alpha = .7
ball:setFillColor( 90,90,200 )
physics.addBody( ball, "dynamic", {friction=.1, bounce=.1, density=1, radius=radius } )
local point = points[2]
local area = trajlibapi.calcAreaOfCircle( radius )
local gm = 1 * area
local g = 2.1
print('area: '..area)
print('gm: '..gm)
print('dist: '.. distance)
--ball:applyLinearImpulse( start.x-sling.x, start.y-sling.y, ball.x, ball.y )
--ball:applyForce( (start.x-sling.x)*gm, (start.y-sling.y)*gm, ball.x, ball.y )
local vx, vy = trajlibapi.calcInitialVelocity( start.x, start.y, angle, distance )
print('velocity: '..vx,vy)
ball:setLinearVelocity( vx, vy )
--print('applied: ', point.x, -point.y )
function ball:timer(event)
timer.cancel( ball.t )
Runtime:removeEventListener("enterFrame", ball)
ball:removeSelf()
end
ball.t = timer.performWithDelay(2000, ball, 1)
function ball:enterFrame(event)
local c = display.newCircle(ball.x,ball.y,2)
c:setFillColor(255,0,0)
end
Runtime:addEventListener("enterFrame", ball)
end
--[[ initial point capture ]]--
function touch(event)
if (not start) then
start = event
display.newCircle( event.x, event.y, 2 )
elseif (not sling) then
sling = event
display.newCircle( event.x, event.y, 2 )
local c = display.newCircle( start.x, start.y, mathlibapi.lengthOf( start, sling ) )
c:setStrokeColor( 0,0,255 )
c:setFillColor( 0,0,0,0 )
c.strokeWidth = 2
local angle = math.abs( mathlibapi.angleOf( sling, start ) )
local distance = mathlibapi.lengthOf( sling, start )
local points = trajectory( distance, angle, iteration )
throw( points, sling, start, distance, angle )
end
end
Runtime:addEventListener("tap", touch)
trajlib.lua:
module(..., package.seeall)
--[[ references ]]--
-- The code in this listing was derived from this first URL:
-- http://hyperphysics.phy-astr.gsu.edu/hbase/traj.html
-- http://en.wikipedia.org/wiki/Trajectory_of_a_projectile
--[[ support functions ]]--
local function vxf( velocity, acceleration )
return velocity * math.cos( acceleration * math.pi / 180 )
end
local function vyt( velocity, acceleration, time )
return velocity * math.sin( acceleration * math.pi / 180 ) - 9.8 * time
end
local function yt( velocity, acceleration, time )
return velocity * math.sin( acceleration * math.pi / 180 ) * time - 0.5 * 9.8 * time * time
end
--[[ worker functions ]]--
function totalRangeHeightFlightTime( v, ag )
local h = vyt(v, ag, 0) * vyt(v, ag, 0) / (2 * 9.8)
local t = 2 * vyt(v, ag, 0) / 9.8
local r = v * v * math.sin( 2 * ag * math.pi / 180 ) / 9.8
return r, h, t
end
function positionAtTime(v, ag, t)
local vx = vxf(v,ag) -- horizontal velocity
local x = vxf(v,ag) * t -- horizontal distance
local vy = vyt(v, ag, t) -- vertical velocity
local y = yt(v, ag, t) -- height at time 't'
return x, y, vx, vy
end
--[[ calculate trajectories ]]--
-- returns a collection of points determined as the trajectory of the object
function calcTrajectoryPoints( startX, startY, velocity, angle, iteration )
if (not iteration) then
iteration = 0.1
end
local r, h, f = totalRangeHeightFlightTime(velocity, angle) -- total range, height and flight time
local points = {}
for t=0, f, iteration do
local x, y, vx, vy = positionAtTime(velocity, angle, t)
points[ #points+1 ] = { x=x, y=y, time=t, velocityx=vx, velocityy=vy }
end
return points, r, h, f
end
-- http://answers.yahoo.com/question/index?qid=20080617223556AA8DD8M
function calcInitialVelocity( startX, startY, angle, force )
return force * math.cos(angle), force * math.sin(angle)
end
--[[ area functions ]]--
function calcAreaOfCircle( radius )
return math.pi * radius * radius
end
mathlib.lua:
module(..., package.seeall)
-- returns the distance between points a and b
function lengthOf( a, b )
local width, height = b.x-a.x, b.y-a.y
return math.sqrt(width*width + height*height)
end
-- converts degree value to radian value, useful for angle calculations
function convertDegreesToRadians( degrees )
-- return (math.pi * degrees) / 180
return math.rad(degrees)
end
function convertRadiansToDegrees( radians )
return math.deg(radians)
end
-- rotates a point around the (0,0) point by degrees
-- returns new point object
function rotatePoint( point, degrees )
local x, y = point.x, point.y
local theta = convertDegreesToRadians( degrees )
local pt = {
x = x * math.cos(theta) - y * math.sin(theta),
y = x * math.sin(theta) + y * math.cos(theta)
}
return pt
end
-- rotates point around the centre by degrees
-- rounds the returned coordinates using math.round() if round == true
-- returns new coordinates object
function rotateAboutPoint( point, centre, degrees, round )
local pt = { x=point.x - centre.x, y=point.y - centre.y }
pt = rotatePoint( pt, degrees )
pt.x, pt.y = pt.x + centre.x, pt.y + centre.y
if (round) then
pt.x = math.round(pt.x)
pt.y = math.round(pt.y)
end
return pt
end
-- returns the degrees between (0,0) and pt
-- note: 0 degrees is 'east'
function angleOfPoint( pt )
local x, y = pt.x, pt.y
local radian = math.atan2(y,x)
--print('radian: '..radian)
local angle = radian*180/math.pi
--print('angle: '..angle)
if angle < 0 then angle = 360 + angle end
--print('final angle: '..angle)
return angle
end
-- returns the degrees between two points
-- note: 0 degrees is 'east'
function angleBetweenPoints( a, b )
local x, y = b.x - a.x, b.y - a.y
return angleOfPoint( { x=x, y=y } )
end
function angleOf( a, b )
return math.atan2( b.y - a.y, b.x - a.x ) * 180 / math.pi
end
-- Takes a centre point, internal point and radius of a circle and returns the location of the extruded point on the circumference
-- In other words: Gives you the intersection between a line and a circle, if the line starts from the centre of the circle
function calcCirclePoint( centre, point, radius )
local distance = lengthOf( centre, point )
local fraction = distance / radius
local remainder = 1 - fraction
local width, height = point.x - centre.x, point.y - centre.y
local x, y = centre.x + width / fraction, centre.y + height / fraction
local px, py = x - point.x, y - point.y
return px, py
end
-- returns the smallest angle between the two angles
-- ie: the difference between the two angles via the shortest distance
function smallestAngleDiff( target, source )
local a = target - source
if (a > 180) then
a = a - 360
elseif (a < -180) then
a = a + 360
end
return a
end
-- is clockwise is false this returns the shortest angle between the points
--[[
function AngleDiff( pointA, pointB, clockwise )
local angleA, angleB = AngleOfPoint( pointA ), AngleOfPoint( pointB )
if angleA == angleB then
return 0
end
if clockwise then
if angleA > angleB then
return angleA - angleB
else
return 360 - (angleB - angleA)
end
else
if angleA > angleB then
return angleB + (360 - angleA)
else
return angleB - angleA
end
end
end
]]--
-- test code...
--[[
local pointA = { x=10, y=-10 } -- anticlockwise 45 deg from east
local pointB = { x=-10, y=-10 } -- clockwise 45 deg from east
print('Angle of point A: '..tostring(AngleOfPoint( pointA )))
print('Angle of point B: '..tostring(AngleOfPoint( pointB )))
print('Clockwise: '..tostring(AngleDiff(pointA,pointB,true)))
print('Anti-Clockwise: '..tostring(AngleDiff(pointA,pointB,false)))
]]--
Best Answer
This can be analyzed easily using differential equations. Given that you refer to x and y coordinates, I'll restrict my answer to trajectories which can be modeled as $(x(t),y(t))$, $t$ representing time, for some continuous functions $x(t),y(t)$. I will use $\vec{F}(t) = (f_x(t),f_y(t))$ to denote the force applied to the object at time $t$. Your problem can then be written as the system of differential equations $$x''(t) = Mf_x(t)$$ $$y''(t) = Mf_y(t)$$ so the desired force vector is simply $\vec{F}(t) = \begin{pmatrix}x''(t)/M \\ y''(t)/M\end{pmatrix}$.
Also, is the trajectory is given by a function $y = h(x)$, then set $t = x$ to get $\vec{F}(x) = \begin{pmatrix}0 \\ h''(x)/M\end{pmatrix}$.