Joints and object control

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Tasaq
Posts: 13
Joined: Mon Mar 26, 2012 4:25 pm

Joints and object control

Post by Tasaq »

Hi:)
I've been trying to work out to do something like that:
Image
I would like to to rotate gray part around red vector and green vector. Also I would like to make gray object to stay in static relation with orange object( simply to make gray follow orange and maintaining equal orientation, or vice versa), like a wheel of a car or propeler in a plane. I know how to use single, simple joints, but when it comes to more advanced ones I am kinda lost.
Also I would like to make steering like shown on wikipedia, which is depicted with this image:
Image
For this my idea is to create a point that doesn't receive collisions and rotate wheels using it's position. But when it comes to make the wheels spin around the X axis crazy stuff happenes. My main question would be how to combine simple joints and motors to make them work correctly :)
Thanks in advance :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Joints and object control

Post by Norbo »

I would recommend checking out the BEPUphysicsDemos project in the main source download; there's a variety of joint-based samples in. In particular, the SuspensionCarDemo seems closely related.

The suspension car demo doesn't use a turning circle or steering bar, but the separate rotations could be simulated by motor targets (or if you really want fidelity, an actual rigid entity representing the bar- but this would require more solving effort to keep stable).

Vehicles built out of joints and constraints are generally more expensive for the same level of stability compared to the Vehicle class, which uses ray casts to approximate wheels. It might be a good idea to just use the Vehicle class if you don't need the full simulation.
Tasaq
Posts: 13
Joined: Mon Mar 26, 2012 4:25 pm

Re: Joints and object control

Post by Tasaq »

Norbo wrote:In particular, the SuspensionCarDemo seems closely related.
Is car creted with this class the same as the one used in executable demo? Or is it made with Vehicle class? Because I want to avoid Vehicle class because I want to have physical wheels and more control. I want to this that because I want to learn using bepu as much as i can. You see, game physics is my Achilles' heel and I want to change it ;) I won't use what I will do for any project :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Joints and object control

Post by Norbo »

The Vehicle class is the one used when 'V' is pressed in the demos application. The SuspensionCarDemo is a separate example car created from a bunch of entities and constraints. Downloading the demo source and playing around with the demos is probably the best way to get acquainted with the joints and constraints :)
Tasaq
Posts: 13
Joined: Mon Mar 26, 2012 4:25 pm

Re: Joints and object control

Post by Tasaq »

Norbo wrote:The SuspensionCarDemo is a separate example car created from a bunch of entities and constraints
Sorry for very late response, I had a lot of work on my uni :) I played with the demo and i really like it ;) Also i run into some problems when I wanted to make car accelerate and go faster. First thing is that my car gets bouncy when I accelerate. Another is that when I want to make donut or just simple slide rear wheels are rotating(as in attached picture, I put the wheels in yellow square because in my proxy model it's hard to say where is back or front :) ). I tought that it's the matter of friction but i made it very low(1 for ground and 0.01f for wheels). I also have gravity with -10 and masses for car 140 and wheel 100 ( I wanted to input real world values but i read on the forum that too much difference in weight makes simulation go crazy). I don't think that I have changed anything else in the demo besides masses, friction, maximumForce, stiffness and damping for suspensionSpring. How can I force the wheels to slide perfectly and orient with the car? :)
Attachments
carwheel.jpg
carwheel.jpg (29.09 KiB) Viewed 6013 times
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Joints and object control

Post by Norbo »

That is caused in large part by the time step duration being too long relative to the motion. The integrator has a hard time keeping things accurate. This is one of those factors that makes fully physical vehicles 'generally more expensive for the same level of stability compared to the Vehicle class.'

For example, setting the Space.TimeStepSettings.TimeStepDuration to 1/600f (defaults to 1/60f) and then calling Space.Update() 10 times or using Space.Update(dt) should almost entirely mitigate the effect. That is unreasonably expensive though.

A SwivelHingeAngularJoint or RevoluteLimit, being 1DOF angular constraints can be used to control the steering angle of the wheels as well. They work slightly differently compared to RevoluteMotors; the wheels will steer towards the final direction faster, but they tend to torque out of alignment a little bit while doing so. Reducing the time step duration a little (1/120f or 1/180f) helps a lot. The misalignment might also be mitigable by incrementally changing the goal state rather than jumping directly to it, but the odd behavior will still exist on a large time step duration.

For the back wheels in particular, using a RevoluteAngularJoint instead of a SwivelHingeAngularJoint+RevoluteMotor to control their steering will work better. The RevoluteAngularJoint works on two degrees of freedom simultaneously, making it better suited for the job. It can't, however, be used for steering the driving wheels because it will fight against any rolling motion present prior to changing the steering direction- in effect, the car would fully brake every time the wheels turned.

Here's an example implementation of an unsteerable wheel using the RevoluteAngularJoint, similar in design to the SuspensionCarDemo:

Code: Select all

        void AddBackWheel(Vector3 wheelOffset, Entity body)
        {
            var wheel = new Cylinder(body.Position + wheelOffset, .2f, .5f, 5f);
            wheel.Material.KineticFriction = 4.5f;
            wheel.Material.StaticFriction = 4.5f;
            wheel.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);

            //Preventing the occasional pointless collision pair can speed things up.
            CollisionRules.AddRule(wheel, body, CollisionRule.NoBroadPhase);

            //Connect the wheel to the body.
            var pointOnLineJoint = new PointOnLineJoint(body, wheel, wheel.Position, Vector3.Down, wheel.Position);
            var suspensionLimit = new LinearAxisLimit(body, wheel, wheel.Position, wheel.Position, Vector3.Down, -1, 0);
            //This linear axis motor will give the suspension its springiness by pushing the wheels outward.
            var suspensionSpring = new LinearAxisMotor(body, wheel, wheel.Position, wheel.Position, Vector3.Down);
            suspensionSpring.Settings.Mode = MotorMode.Servomechanism;
            suspensionSpring.Settings.Servo.Goal = 0;
            suspensionSpring.Settings.Servo.SpringSettings.StiffnessConstant = 300;
            suspensionSpring.Settings.Servo.SpringSettings.DampingConstant = 70;

            var revoluteAngularJoint = new RevoluteAngularJoint(body, wheel, Vector3.Right);

            //Add the wheel and connection to the space.
            Space.Add(wheel);
            Space.Add(pointOnLineJoint);
            Space.Add(suspensionLimit);
            Space.Add(suspensionSpring);
            Space.Add(revoluteAngularJoint);
        }
As for the front steering wheels, to stop turning outside of the desired range, you may want to add a RevoluteLimit. The RevoluteLimit tends to be stronger than the RevoluteMotor in this kind of difficult situation. So, for example, you could add this to the front wheels:

Code: Select all

            var steeringConstraint = new RevoluteLimit(body, wheel, Vector3.Up, Vector3.Right, -maximumTurnAngle,
                                                       maximumTurnAngle);
            Space.Add(steeringConstraint);
I think I'll spend a little while checking the RevoluteMotor to see if I can make it handle this situation better, since it's really the most intuitive option for handling steering. No promises at this point, though :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Joints and object control

Post by Norbo »

I forgot to mention one of the easiest options: don't make it spin so fast :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Joints and object control

Post by Norbo »

Alright, I've fiddled around a bit more. The RevoluteMotor is doing all it can in the circumstances, but the RevoluteMotor's correction power can be boosted such that it mostly overcomes the issue. For example:

Code: Select all

            steeringMotor.Settings.Servo.SpringSettings.Advanced.UseAdvancedSettings = true;
            steeringMotor.Settings.Servo.SpringSettings.Advanced.Softness = 0;
            steeringMotor.Settings.Servo.SpringSettings.Advanced.ErrorReductionFactor = 0f;
            steeringMotor.Settings.Servo.BaseCorrectiveSpeed = 10;
You may find that it is better to use a lower base corrective speed and scale it up when the wheels are moving faster. Something like this in the update:

Code: Select all

            steeringMotor1.Settings.Servo.BaseCorrectiveSpeed = 3 + 7 * Math.Min(steeringMotor1.ConnectionB.AngularVelocity.Length() / 100, 1);
            steeringMotor2.Settings.Servo.BaseCorrectiveSpeed = 3 + 7 * Math.Min(steeringMotor2.ConnectionB.AngularVelocity.Length() / 100, 1);
The faster the update rate, the less needed these compensations are.

Due to the strong corrective impulses, strengthening the main angular joint is a good idea to prevent excessive torquing:

Code: Select all

            swivelHingeAngularJoint.SpringSettings.DampingConstant *= 1000;
            swivelHingeAngularJoint.SpringSettings.StiffnessConstant *= 1000;
Also, instead of letting the wheels rotate individually, it is helpful to bind them together with a RevoluteAngularJoint:

Code: Select all

RevoluteAngularJoint steeringStabilizer = new RevoluteAngularJoint(wheel1, wheel2, Vector3.Right);
I've uploaded a new version to the development fork that includes these changes all together. It's pretty drivable at very high speeds, though it still benefits from a faster time step in general.
Tasaq
Posts: 13
Joined: Mon Mar 26, 2012 4:25 pm

Re: Joints and object control

Post by Tasaq »

Wow this looks promising, I am going to throw it into my project to see how it goes, or rather rides :) Also decreasing time step is truly an overkill :)
Norbo, You are truly a definition of perfect help ;) Never have I seen a better help section on any forum before :)
Post Reply