Rocket Simulation

Hi,



I’m stuck on some physics calculations for a rocket simulation I’m building. Specifically, I’m getting confused with a few aspects on how to use the jme-physics library.



Firstly, I’m doing some calculations to work out the Newtonian force required to launch a projectile (of a specified mass) over a specific X distance whilst using a specific angle. If I know the X distance, angle and mass, I can work backwards to get the required velocity, acceleration and Newtonian Force for a direct hit. For your reference; http://hyperphysics.phy-astr.gsu.edu/hbase/traj.html#tra12



However, I’m lost when attempting to apply these calculations to jME-physics, and now I’m half tempted (due to time constraints) to revert to using position calculations and setting the local translation in order to simulate the force… though I really want to work this out using jME-physics.



At the moment I’m applying a constant force (using an InputHandler) with a Vector specifying the direction I want to head towards. I have a couple of problems where the constant acceleration launches my Node way past my target location and off the screen, and secondly the direction is a bit off. I’ve adapted the code from Lesson5 which attaches a custom InputAction to a physics specific InputListener which gets updated as a callback.


direction.set(target.getWorldTranslation());
appliedForce.set(direction).multLocal(evt.getTime());
node.addForce(direction);



My questions are thus:
1. How does the jme-physics ODE addForce relate to a Newtonian force? The force in the API is a vector whereas a Newtonian force is kilograms per metre per second square.

2. After I calculate the required initial velocity, I need to apply this to my DynamicPhysicsNode. At the moment, the only way I can see how this could be done in the API is to re-apply a force over a series of timesteps. Is this the only way?

3. If I re-apply a force over a series of timesteps, how long (how many timesteps) should I apply the force in order to simulate an initial velocity?

Thanks heaps in advance!

  1. A good question, I never investigated this. I think it even depends on the timestep size. Maybe you can find this out from ODE doc/mailinglist and report back here. I would like to make it timestep-size independent in jME Physics 2. I think we should make the forces in jME Physics 2 newtonian and compute them physics engine specific internally.


  2. Yes. What would be better? Something like myPhysicsObject.setConstantForce( xy )?


  3. That really depends on the other forces applied to the body, if you want to achieve this by adding forces. An actual initial velocity could be set directly, I'd say.
  1. Ok, I havn't found anything yet but I'll keep looking. Yes, being able to apply a timestep-size independant force would be really helpful for me.

    Anyone else?


  2. Yes, setting a directional vector with myPhysicsObject.setConstantForce( xyz ) would be great.


  3. Of course another alternative to appling a Newtonian force for a specific time is to just set an initial velocity. This may not look realistic for a rocket but the simulation may still work out the same.



    Does setLinearVelocity take a directional vector and apply a force in that direction forever? I remember reading somewhere that the linear velocity has a directional and size component… But I'm not sure where I read that… any ideas?



    thanks heaps for your time. really appreciated.  :slight_smile:

Ok, I've worked this out. It was easier than I thought by just using the formula, a = F/M.



Basically, if I want to apply a Newtonian force of say 1000 kg/m/s^ then I can firstly get the total acceleration required to move an object of a specified Mass and Force using a=F/M.



During each update I can get the total force applied to the node using node.getForce() and then divide this force with the mass to get the acceleration applied during each timestep. Then I keep a tally of the acceleration applied over all timesteps and continue to apply the force until the total acceleration reaches the required acceleration.



I'm pretty happy now because my manual calculations correlate with the simulation behaviour of the rocket.



package org.chrismills.stuntrobot.physics;

import java.util.logging.Logger;

import com.jme.input.InputHandler;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
import com.jme.util.LoggingSystem;
import com.jmex.physics.DynamicPhysicsNode;

/**
 * This class applies a physics force according to a Newtonian force.
 * The force is applied to a physcics node in a specified direction towards
 * a target spatial. This class uses the formula:
 * Acceleration = Force / Mass to determine the number of timesteps that
 * the physics force is applied to the physics node.
 *
 * @author Chris Mills
 */
public class ForceInputAction extends InputAction {

   // the physics object to apply the force
   private DynamicPhysicsNode node;

   // the target object to point the force towards.
   private Spatial target;

   // the force to apply in Newtons i.e. kilograms per metre per second squared
   private float newtonianForce;

   //the direction of the force
   private final Vector3f direction = new Vector3f();

   // the required acceleration in order to apply the Newtonian force to this node
   private float requiredAcceleration;

   // the total acceleration applied so far to this node
   private final Vector3f totalAcceleration = new Vector3f();

   private InputHandler inputHandler;
   
   private static Logger log = LoggingSystem.getLogger();

   /**
    * The force action to apply to a specific physics node.
    * The target spatial indicate the relative direction to the physics node
    * in which to direct the apply force.
    * The value of the newtonian force allows us to calculate the
    * required acceleration for the specified mass; using the formula a = F/m.
    *
    * @param node the physics node to apply the force to
    * @param target  the target object in which to move towards
    * @param newtonianForce the amount of Force to apply in Newtons.
    *                   i.e. kgs per metre per second squared
    * @param inputHandler the parent input handler
    */
   public ForceInputAction(DynamicPhysicsNode node,
                     Spatial target,
                     float newtonianForce,
                     InputHandler inputHandler) {

      // simply remember in member variables
      this.node = node;
      this.target = target;
      this.newtonianForce = newtonianForce;
      this.inputHandler = inputHandler;
      
      // the direction shall be the same forever based on the
      // starting positions of the physics node and the target object.
      this.direction.set(target.getWorldTranslation().subtract(node.getWorldTranslation()));

      // Acceleration = Force / Mass
      this.requiredAcceleration = newtonianForce / node.getMass();

      // apply force imediately.
      node.addForce(direction);
   }

   /**
    * This method will apply a Newtonian force on a physics node.
    * The acceleration is calculated when applying each physics force using
    * a = F/m which is then added to a tally. 
    * If the total acceleration is less than the required acceleration, then
         * continue to apply the force in the target direction.
         *
    * @param evt the action event
    */
   public void performAction(InputActionEvent evt) {

      // swap to check if we are above the required acceleration
      if(totalAcceleration.length() > requiredAcceleration) {
         log.info("NO force as acceleration is " + totalAcceleration
               + " (" + totalAcceleration.length()
               + ") which is more than " + requiredAcceleration);
         // clear this force input action from the input handler, IS THIS THE BEST WAY?
         inputHandler.removeAction(this);

      } else {
         log.info("Adding force as acceleration is " + totalAcceleration
               + " (" + totalAcceleration.length()
               + ") is less than " + requiredAcceleration);
         node.addForce(direction);
      }

      Vector3f combinedForce = node.getForce(new Vector3f());
      Vector3f acceleration = combinedForce.divide(node.getMass());
      totalAcceleration.set(totalAcceleration.add(acceleration));

   }
}



This is currently designed as an InputAction attached to a specific InputHandler for physics, however there may be a better way.
BTW, I would love for an InputAction to have a pointer to its parent input handler, therefore allowing the input action to disable itself after it has completed it's purpose.

Irrisor - is this what you were thinking?

Suggestions and comments are very welcome.  :lol:

Thanks to all, jME rocks!!

Ok, I've refactored this class so it can be subclassed for specific game objects… in my case a Rocket.  :wink:

It maybe useful for someone else so here's the code.




import java.util.logging.Logger;

import com.jme.input.InputHandler;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
import com.jme.util.LoggingSystem;
import com.jmex.physics.DynamicPhysicsNode;

/**
 * This class applies a physics force according to a Newtonian force.
 * The force is applied to a physcics node in a specified direction towards
 * a target spatial. This class uses the formula:
 * Acceleration = Force / Mass to determine the number of timesteps that
 * the physics force is applied to the physics node.
 *
 * @author Chris Mills
 */
public abstract class ForceInputAction extends InputAction {

   // the physics object to apply the force
   protected DynamicPhysicsNode node;

   // the target object to point the force towards.
   protected Spatial target;

   // the force to apply in Newtons i.e. kilograms per metre per second squared
   protected float newtonianForce;

   //the direction of the force
   protected final Vector3f direction = new Vector3f();

   // the required acceleration in order to apply the Newtonian force to this node
   protected float requiredAcceleration;

   // the total acceleration applied so far to this node
   protected final Vector3f totalAcceleration = new Vector3f();

   protected InputHandler inputHandler;
   
   protected static Logger log = LoggingSystem.getLogger();

   /**
    * The force action to apply to a specific physics node.
    * The target spatial indicate the relative direction to the physics node
    * in which to direct the apply force.
    * The value of the newtonian force allows us to calculate the
    * required acceleration for the specified mass; using the formula a = F/m.
    *
    * @param node the physics node to apply the force to
    * @param target  the target object in which to move towards
    * @param newtonianForce the amount of Force to apply in Newtons.
    *                   i.e. kgs per metre per second squared
    * @param inputHandler
    */
   public ForceInputAction(DynamicPhysicsNode node,
                     Spatial target,
                     float newtonianForce,
                     InputHandler inputHandler) {

      // simply remember in member variables
      this.node = node;
      this.target = target;
      this.newtonianForce = newtonianForce;
      this.inputHandler = inputHandler;
      
      // the direction shall be the same forever based on the
      // starting positions of the physics node and the target object.
      this.direction.set(target.getWorldTranslation().subtract(node.getWorldTranslation()));

      // Acceleration = Force / Mass
      this.requiredAcceleration = newtonianForce / node.getMass();

      // apply force imediately.
      node.addForce(direction);
   }

   /**
    * This method will apply a Newtonian force on a physics node.
    * The acceleration of each physics force application is calculated using
    * a = F/m and add to a tally. 
    * If the total acceleration is less than the required acceleration, then
     * continue to apply the force in the target direction.
     *
    * @param evt more data about the event
    */
   public void performAction(InputActionEvent evt) {

      // swap to check if we are above the required acceleration
      if(totalAcceleration.length() > requiredAcceleration) {
         // do custom handling when total force has been applied
         removeForce();

      } else {      
         node.addForce(direction);
         // do custom handling when applying the force
         addForce();
      }

      Vector3f combinedForce = node.getForce(new Vector3f());
      Vector3f acceleration = combinedForce.divide(node.getMass());
      totalAcceleration.addLocal(acceleration);
   }
   
   /**
    * Do custom logic in subclass when we apply the force
    */
   public abstract void addForce();

   /**
    * Do custom logic in subclass when we finish applying the force
    */
   public abstract void removeForce();

}




One Question though: What's the best way to remove an InputAction from it's parent InputHandler??

inputHandler.remove(this);

didn't work even when inputHandler is a pointer to the parent InputHandler.
Basically, I'd like to remove this ForceInputAction once it's done it's job.. thus removing it from chewing up cycles.

Cheers!  :D
FuzzyDuck said:

One Question though: What's the best way to remove an InputAction from it's parent InputHandler??

inputHandler.remove(this);

didn't work even when inputHandler is a pointer to the parent InputHandler.

inputHandler.removeAction( yourAction ) should work. Where inputHandler is the same (not the parent) InputHandler you subscribed the action to.

And to answer your request to have a reference to the InputHandler from the action: that's not possible as an InputAction may be subscribed to multiple InputHandlers. But you can subclass InputAction and provide such a reference there, if you know that your actions are subscribed to a single InputHandler.

I'm glad you figured out a way to match the simulation with your own calculations. If I find the time I'm going to have a look if I can improve the jME Physics 2 API with your findings.

Thanks for your reply Irrisor. Sorry that was a typo on my behalf.  ://

I did try

inputHandler.removeAction(this)

(as opposed to "remove") where the inputHandler was the one the action was subscribed to.

By reading the source, I expected this to work, but alas something is amiss.

I stepped through the code, and it appears that the ActionTrigger is being removed from the list of allTriggers and not from the list of activeTriggers.

I'll have another look at this…

Cheers.  :slight_smile:


Before removing itself a triggers also deactivates itself, which should remove it from the activeTriggers also… but probably you have found a bug with the remove?

Yes… that's what I think this is… But i spotted it first! hehe  :smiley:

I've made a note of it… in preparation for challenge nr 2.  5 more sleeps…  :stuck_out_tongue:

No sense in throwing away good points!  :wink:

hehe

BTW, thanks to all for the great work on the physics engine (and jME for that matter). It's a nice piece of software and I'm having a lot of fun with it.

are you sure that your method works?

I still don't know what you want to achieve.

However I have problems with lesson 5… the movement is not smooth at all, I think that it is all fault of the multiplication of the force for the number step which is not the same thing of applying a constant force at every step… if I'm not wrong final velocity or position would be wrong



In your case to obtain the required accelleration on an object you can simply get the direction of target and normalize it and the multiply for accelleration required and mass…

I'm wrong?

Yep. this method worked fine for me. I've manually checked against a few different formula for trajectories.

Note that my code works back from the Newtonian force (kgs/m/s^) and calculate the acceleration required based upon the current object mass.

A force in the physics API is different to a Newtonian force thus the acceleration required is decremented during each physics time step until no more acceleration is required. During each time step, a force (as per the API) is applied to the object.



What you are trying to achieve?

I'm working on a multi-joint robot arm…

I'm not sure on how to apply forces and torques…

I've found this thread on force and timestep…

http://q12.org/pipermail/ode/2005-August/016667.html



However I've seen that the problem could be in the clear forces at every time step…

if one uses PhysicsUpdateCallback.beforeStep

than the force must not be pre-multiplied for the timestep… I think…