Revolute Joints not being drawn and also jitters

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Psykocyber
Posts: 8
Joined: Thu Mar 15, 2012 11:40 am

Revolute Joints not being drawn and also jitters

Post by Psykocyber »

I'm currently working on a simulation software, where we need to constantly need to insert and clear "creatures" consisting of boxes and joints.
For this we use BallSocketJoints and RevoluteJoints. Whenever we display the simulation in realtime, the BEPUDrawer (for some reason) only wants to display BallSocketJoints, but not RevoluteJoints. Actually it doeas display it from time to time, but it's rare, and we've not been able to fix this. It should be noted we are using the development branch, we cannot test it on the release branch because of the multithreading bug.

The architecture of the program is this:
One BEPU (single-threaded) space is created for each core on the PC. Here we run the simulations in parallel, and replace the spaces when they're done simulating.

Neither the joint nor the limits can be displayed.

We are using a velocity motor in an attempt to make it behave like a joint. Could there be a better way?

EDIT:

A second issue of higher importance is that when we create these "creatures", do so randomly

Creation:

Code: Select all

foreach (var jointGene in dna.Joints)
            {
                var box1 = parts.Find(delegate(Entity entity) { return entity.PartNumber == jointGene.p1; });
                Debug.Assert(box1 != null);
                var box2 = parts.Find(delegate(Entity entity) { return entity.PartNumber == jointGene.p2; });
                Debug.Assert(box2 != null);
                CollisionRules.AddRule(box1,box2,CollisionRule.NoBroadPhase);
                if (jointGene.type == "b")
                {
                    var socket = new BallSocketJoint(box1, box2, (box1.Position + box2.Position)/2f);
                    
                    joints.Add(socket);
                }
                else if (jointGene.type == "r")
                {
                    var revolute = new RevoluteJoint(box1, box2, box1.Position, Vector3.Forward);
                    revolute.Limit.MinimumAngle = -MathHelper.Pi;
                    revolute.Limit.MaximumAngle = MathHelper.Pi;
                    revolute.AngularJoint.SpringSettings.StiffnessConstant = 1f;
                    revolute.AngularJoint.SpringSettings.DampingConstant = 100f;
                    
                    if (true)
                    {
                            revolute.Motor.Settings.Mode = MotorMode.VelocityMotor;
                        revolute.Motor.Settings.MaximumForce = 1000;
                    }
                    else
                    {
                        revolute.Motor.Settings.Mode = MotorMode.Servomechanism;
                        revolute.Motor.Settings.MaximumForce = 200;
                    }
                    revolute.Limit.IsActive = true;
                    revolute.Motor.IsActive = true;
                    
                    joints.Add(revolute);
                }
            }
Part & joint creation description:

Code: Select all

PartGene part = new PartGene();
            part.id = dna.Parts.Max(p => p.id)+1;
            part.type = type;
            part.kfr = Math.Max(RandomFloat(), 0.1f);
            part.sfr = Math.Max(RandomFloat(), 0.1f);
            part.sx = RandomFloat(0.5f,6);
            part.sy = RandomFloat(0.5f, 6);
            part.sz = RandomFloat(0.5f, 6);
            part.x = parent.x + MinOrMax(-part.sx, part.sx) * 2f;
            part.y = parent.y + MinOrMax(-part.sy, part.sy) * 2;
            part.z = parent.z + MinOrMax(-part.sz, part.sz) * 2;
            if (part.y - part.sy < -35)
                part.y += 5;
            part.ox = 0;
            part.oy = 0;
            part.oz = 0;
            part.m = Math.Max(RandomFloat(), 0.2f);

            JointGene joint = new JointGene();
            int maxJointID = 0;
            if (dna.Joints.Count > 0)
                maxJointID = dna.Joints.Max(j => j.id) + 1;
            joint.id = maxJointID;
            joint.p2 = part.id;
            joint.p1 = parent.id;
            joint.type = "r";
            //Must not be the same position or the all joints will connect
            //todo: The position should be between the two parts
            /*joint.jx = (parent.x + part.x)/2;
            joint.jy = (parent.y + part.y)/2;
            joint.jz = (parent.z + part.z)/2;*/
            joint.rx = 0;
            joint.ry = 0;
            joint.rz = 0;
            joint.fmin = -2;
            joint.fmax = 2;

            dna.Parts.Add(part);
            dna.Joints.Add(joint);
The code is perfectly able to create the parts and connect them with joints, but during simulation, most creatures will end out starting to jitter uncontrollably and fly off. This is kinda ruining our simulations. We've tried changing some damping and softness values, but have not found anything that will kill this issue.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Revolute Joints not being drawn and also jitters

Post by Norbo »

Whenever we display the simulation in realtime, the BEPUDrawer (for some reason) only wants to display BallSocketJoints, but not RevoluteJoints. Actually it doeas display it from time to time, but it's rare, and we've not been able to fix this.
Unfortunately, I don't have any good explanations for this. If the physics simulations were free running such that there was some asynchronous access going on, there might be a problem, but it doesn't sound like that's how it's configured. Could you reproduce the issue in a BEPUphysicsDemos demo for me to look at?
The code is perfectly able to create the parts and connect them with joints, but during simulation, most creatures will end out starting to jitter uncontrollably and fly off. This is kinda ruining our simulations. We've tried changing some damping and softness values, but have not found anything that will kill this issue.
Some general advice:
1) Ensure distances to connections aren't too far away. Having a very long lever arm makes the system harder to solve.
2) Ensure mass ratios aren't too extreme. If something really heavy depends on something really light, things will get unstable without a ton of iterations. The definition of "extreme" here varies, but as an example, 1:10 can cause problems in many cases.
3) When tuning an object, change only one thing at a time. Avoid using MaximumForce if you can, opting instead for non-clampy tuning like adjusting stiffness and damping.
4) Ensure there's a sufficient number of iterations in the solver for the simulation. Extremely complicated contraptions can require more iterations to get right. (Note that increasing the number of iterations can also improve the quality of poorly configured systems, though it typically requires a lot more iterations than a well-configured system.)
5) If the masses of objects are particularly huge or particularly tiny, the SolverSettings.DefaultMinimumImpulse may need to be adjusted to ensure the simulation does/doesn't early out. There's also a DefaultMinimumIterations which can be used to tune when constraints can early out.
6) Ensure the Space.TimeStepSettings.TimeStepDuration is low enough. It defaults to 1/60f. Some particularly complicated simulations benefit from a faster time step (however, while decreasing the time step duration almost always helps, it is rarely required).

Some more specific advice:
1) That revolute limit won't do much as-is. The restricted zone has zero angle which will be easily bypassed.
2) Those stiffness/damping constants are really low. If the masses are really low, that might be okay, but beware of #5 above.
3) Changing the stiffness/damping of the revolute motor is probably better to start with than using the maximum force, unless you desire the specific behavior offered by maximum force. #3 above applies.
4) The RevoluteJoint is constructed with an anchor at the position of one of the boxes instead of between the boxes somewhere. That would imply longer connection distances. #1 above applies.

If you can reproduce some instability in a BEPUphysicsDemo demo, I could take a closer look at the configuration.
Psykocyber
Posts: 8
Joined: Thu Mar 15, 2012 11:40 am

Re: Revolute Joints not being drawn and also jitters

Post by Psykocyber »

We have tried setting dampness and stiffness to 100 each. Mass is now 40 pr part, no matter the size.
All the parts are positioned next to each other. Now with

Another thing the revolute free axis, does that have to be aligned with a world axis?

Do you have a idea of what a good velocity would be for the velocity motor? I cannot find any usage of it in the demos.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Revolute Joints not being drawn and also jitters

Post by Norbo »

Another thing the revolute free axis, does that have to be aligned with a world axis?
Nope, any axis works.

If you see some weird results, take a closer look at the configuration, especially if any group joints are being used like the RevoluteJoint. The RevoluteJoint constructor guesses about how it's supposed to be configured based on the provided input. This may not match what you intend in every case, so the configuration may need to be adjusted. For descriptions and explanations of this configuration process, check out the last two pages in this thread: viewtopic.php?f=4&t=1615&start=45
Do you have a idea of what a good velocity would be for the velocity motor? I cannot find any usage of it in the demos.
What the velocity should be depends on how you want it to behave, but if it's an angular joint, it uses radians. A velocity of 2*Pi will perform one full revolution per time unit.
Psykocyber
Posts: 8
Joined: Thu Mar 15, 2012 11:40 am

Re: Revolute Joints not being drawn and also jitters

Post by Psykocyber »

Thanks, I will look into it in detail later.
After looking more into the robot arm thingamajic, I reallise that I should have been using Servo motor as I want an elbow behavior, not rotation.
I will experiment with that later also.
Psykocyber
Posts: 8
Joined: Thu Mar 15, 2012 11:40 am

Re: Revolute Joints not being drawn and also jitters

Post by Psykocyber »

I don't really understand that thread :/

So, back to scratch. I want to create an elbow joint between two boxes, so that the bending is like a normal elbow.
The placement of these boxes are dynamic, so I can't hardcode anything.
So my question is more, am I doing this correctly and how can I calculate the free axis?
And to make matters worse, I still can't see the joints (most of the time), so it's really hard to know whats going on.

Code: Select all

var revolute = new RevoluteJoint(box1, box2, pos,??????); //Right now Vector3.Forward, but this behaves really weird
revolute.Limit.MinimumAngle = 0;
revolute.Limit.MaximumAngle = MathHelper.PiOver2;
revolute.AngularJoint.SpringSettings.StiffnessConstant = 50f;
revolute.AngularJoint.SpringSettings.DampingConstant = 100;

revolute.Motor.Settings.Mode = MotorMode.Servomechanism;
revolute.Motor.Settings.MaximumForce = 1000;

revolute.Motor.IsActive = true;
and the usage:

Code: Select all

//The same joint as above
inputAngle = Math.Acos(Vector3.Dot(Vector3.Normalize(revolute.BallSocketJoint.OffsetA), Vector3.Normalize(revolute.BallSocketJoint.OffsetB)));

//Do some neural network stuff
/*...*/

r = n1 - n2;
if (r < 0) //Where r is the output from two neurons n1 and n2 
{
    revolute.Motor.Settings.Servo.Goal = Math.Min(revolute.Motor.Settings.Servo.Goal + r * dt, revolute.Limit.MinimumAngle);
}
else
{
    revolute.Motor.Settings.Servo.Goal = Math.Max(revolute.Motor.Settings.Servo.Goal - r*dt, revolute.Limit.MaximumAngle);
}
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Revolute Joints not being drawn and also jitters

Post by Norbo »

So, back to scratch. I want to create an elbow joint between two boxes, so that the bending is like a normal elbow.
The placement of these boxes are dynamic, so I can't hardcode anything.
So my question is more, am I doing this correctly and how can I calculate the free axis?
There is no one correct way to do it; it depends entirely on what you want.

The two big things to remember are that the axis is in world space (but it does not have to be aligned with any particular axis) and that the RevoluteJoint guesses at a configuration for the joint which you can modify after the fact if you wish.
Post Reply