Best way to implement the hydraulics and hydraulic stabilizers on a mobile crane

Hi all,
I’m trying to implement hydraulics and hydraulic stabilizers / outriggers in Unity using the physics engine. This would be like the feet that come down on a mobile crane to keep it from tipping over. The way this works in real life is the outrigger feet go down, make contact with the ground and by exerting force on the ground there’s a responsive force (Newton’s 3rd Law) that lifts the chassis up… I’ve been messing around with this for a few days now… first tried just having a piston press against the ground, but apparently no responsive force is modeled into the engine. So, I tried adding a scripted responsive upward force applied to the horizontal portion of the stabilizer which kicked in when a collision between the outrigger pad and the ground (or a ground pad) occurred. This sort-of works, but getting the chassis back down and modelling when the pads should come up is now a concern. Plus, the code is getting a little convoluted because then there has to be a downward force applied when the stabilizer is raised, to take the upward pressure off the chassis. Is there’s a more elegant solution that I’m overlooking? I’ve dug around on the forums and Answers, but there doesn’t seem to be anything fitting this situation.

The other part of this would be implementing the actual crane portion. I have part of that working except when the crane is elevated, or extended, the center of mass changes and thus the force required to manipulate the crane changes. I’ve looked at the various construction posts, but I didn’t see anyone who’s actually tried to model hydraulics. Any ideas on this as well?

In the included picture, pretty much all of the primitives are rigidbodies. The cyilinder (chassis), stabilizer pad and the plate on the ground have box colliders. The horizontal is fixed-jointed to the chassis (eventually this would slide into the chassis), the vertical is connected to the horizontal by a configurable joint which only allows movement on the Y axis.

A quick way to do this would to mess with the joints that come with the engine (perhaps spring?)

The best way to do this would be to code it in. Is your current solution taking fluid dynamics into account or just relying on classical mechanics? You might want to calculate the actual pressure and forces with code and apply them to your objects. Depends on how accurate you want your simulation to be :stuck_out_tongue:

I guess when I said “modeled hydraulics” what I really meant was the behavior that an object having a force applied to it in a specific direction will “push away” from an unmovable object. Example, stand next to a wall, extend your arms toward the wall. You are exerting force on your arms in the direction of the wall, but when they reach the wall, you start pushing yourself away from the wall. That’s what I mean, not fluid dynamics, etc…

I realize it will need to be coded… and as I stated in my original post I have written code for it, but it’s getting very convoluted. To the point to where I’m beginning to wonder, am I going about this all wrong. Let me try to be a little more specific about this. I’m not looking to go crazy with hydraulic pressure calculations, etc. The focus is on the crane movement itself. But, I want to use the built-in physics engine primarily because it would be a heck of a lot easier than re-inventing the wheel and coming up with algorithms to realistically mimic the movements the physics engine should already be able to provide.

Imagine a crane with it’s main arm structure connected to a pivot pin, which connects to a turntable. The sections of the crane arm are extendable (a telescoping boom). So here’s a picture so there’s no confusion as to what I’m talking about…

At this point, I’m not worried about having visible hydraulic or cable actuators. The turntable can spin 360 degrees, the pivot pin allows the boom to elevate from 0 degrees to 75 or 80 degrees. Then you have two boom sections which can extend outward.

Then there are the 4 outriggers/stabilizers which extend outward from the chassis. There is a separate piston that moves downward to make contact with the ground and apply force to the ground (which results in an upward force on the lateral arm).

This video shows the movement of a single stabilizer

I have code using the physics engine written which moves the outriggers in and out and the vertical piston up and down. (using AddForce()). If you watch the video, when the stabilizer pad makes contact with the ground, the force is then transferred upward to the lateral arm which lifts the lateral stabilizer and the truck chassis. That has been the tricky part. I’m new to the unity physics engine so I’m not real sure on the best way to code/model the reactive force which results when the pad contacts the ground. In effect the outrigger is still exerting a downward force, but since the ground is immobile, the result is the outrigger pushing itself away from the ground. That is what I’m having trouble coding. Because when the reverse happens, all of the weight has to be off of that stabilizer before it begins to retract off the ground. I’ve been experimenting with using collision detection to determine when the pad is in contact with the ground, but it doesn’t seem to work very well. So I guess in this instance the real question is, if you want to simplify it, is can AddForce be used in such a way that when the object having the force applied to it will push away from an unmovable object. Or does AddForce essentially work only as a “thruster”?

I’m afraid that AddForce is essentially a “thruster”.
If the masses of the bodies aren’t to scale the simulation may act strangely too, perhaps you would want to check them out. The built-in physics engine is quite powerful and should be able to cope with such simulations with relative ease: I’ve used Unity for fluid simulations before :sunglasses:

If you can post your code and the setup/components of one of the stabilizers, I can take a look and give some suggestions.

The weights aren’t to scale, and I’m still playing with them. I think everything is set to 1 for mass. The set-up is pretty simple. Box in the middle (which is the body/chassis) is a rigidbody.

Horizontal beam is a rigidbody, configurable joint permitting only X movement, connected to chassis.

Vertical Beam is a rigidbody, configurable joint permitting only Y movement. Connected to the horizontal beam.

There is a small plate which is unseen on the underside, outer part of the horizontal beam, just used to mark where to apply the upward force when the pad contacts the ground plate.
outrigger pad, fixed joint to the vertical beam, also has the script attached because it’s the object which is checked for collision with the ground plate.
Then there’s the ground plate which is just there to trigger the collision. I added that because I was getting sporadic detection with the terrain.

Gravity is off for all rigidbodies.

    private bool padGrounded = false;
    private int modifier = 1;


    // Use this for initialization
    void Start () {
            if (!leftSide) {
                modifier = -1;
                }
    }
    void OnCollisionEnter (Collision other) {
        Debug.Log ("Pad Contact");
        padGrounded = true;
        
        }

    

    void OnCollisionExit (Collision other) {
        Debug.Log ("No Ground Contact");

        padGrounded = false;
        }



    void FixedUpdate () {

        if (!padGrounded) {
                        if (Input.GetKey (KeyCode.F)) {
                                horizontalPiston.rigidbody.AddForce (Vector3.left * Time.fixedDeltaTime * 100 * modifier);
                        } else if (Input.GetKey (KeyCode.G)) {
                                horizontalPiston.rigidbody.AddForce (Vector3.right * Time.fixedDeltaTime * 100 * modifier);
                        }
                        if (Input.GetKey (KeyCode.T)) {
                                verticalPiston.rigidbody.AddForce (Vector3.up);
                        } else if (Input.GetKey (KeyCode.B)) {
                                verticalPiston.rigidbody.AddForce (Vector3.down);

                        }
                } else {

            if (Input.GetKey (KeyCode.T)) {
                // T raises the stabilizer, but if the pad is in contact with the ground, force should be transferred to the
                // horizontal stabilizer to push the chassis upward (for levelling).
            
            
                horizontalPiston.rigidbody.AddForceAtPosition (Vector3.down * Time.fixedDeltaTime * 100, forcePlate.transform.position);
            
            
            
            } else if (Input.GetKey (KeyCode.B)) {
                horizontalPiston.rigidbody.AddForceAtPosition (Vector3.up * Time.fixedDeltaTime * 100, forcePlate.transform.position);
            }

                }

    }
}

I’ve made a quick attempt at modelling a bunch of stabilizers using joints, gravity and some sort of scale in terms of mass. It seems to work fine on my side, you can download it here. All you need to do is implement some side-ways movement, your collision detection (which works fine from the looks of it) and some fine-tuning like dynamic adjustment to terrain height (if you wish but this solution seems to work fine when tested on moderately bumpy surfaces).

Code

using UnityEngine;
using System.Collections;

public class Stabalizer : MonoBehaviour {



        //The controls

        public KeyCode Up = KeyCode.T;
        public KeyCode Down = KeyCode.B;
        public KeyCode Left = KeyCode.F;
        public KeyCode Right = KeyCode.G;


    public int maximumHeight = 30; //Maximum height for the horizontal piston
    public float heightIncrements = 1.0f; //Increments in height
    public float damping = 10.0f; // Damping in height increments

    public Rigidbody hPiston;  // Horizontal Piston


    private ConfigurableJoint vPiston;  //Vertical Piston but we can get this from our horizontal piston
    private float height;

    // Use this for initialization
    void Start () {
  
    }
  
    // Update is called once per frame
    void Update () {
  
        if (Input.GetKeyDown (Up) && height < maximumHeight) {

            vPiston = hPiston.GetComponent <ConfigurableJoint>();
          
            JointDrive d = new JointDrive();
            height += heightIncrements;
            d.positionSpring = height;
            d.mode = JointDriveMode.Position;
            d.positionDamper = 10;
            d.maximumForce = 3.402823e+38f;
          
          
            vPiston.yDrive = d; //so basically this uses the physics engine's built in joints!

        }

        else if (Input.GetKeyDown (Down) && height > 0)

        {

            vPiston = hPiston.GetComponent <ConfigurableJoint>();
          
            JointDrive d = new JointDrive();
            height -= heightIncrements;
            d.positionSpring = height;
            d.mode = JointDriveMode.Position;
            d.positionDamper = 10;
            d.maximumForce = 3.402823e+38f;
          
          
            vPiston.yDrive = d;

        }

        else if (Input.GetKeyDown (Left)){

            //TODO: ADD SOME SIDEWAYS MOVEMENT

        }

        else if (Input.GetKeyDown (Right)){

            //TODO: ADD SOME SIDEWAYS MOVEMENT

        }


    }
}

Hope this helps :slight_smile:

Hmmm… somethings not right because when the scene starts, the body and the stabilizers drop to the ground. Once there the stabilizers don’t move at all. Is d.positionDamper supposed to resist gravity to keep the stabilizers up unless the spring force is acting on them?
Oh, I see… it’s a per tap increment.

That’s an interesting implementation… It does provide a nice even lift. However, the stabilizers will eventually be operated independently (or a couple at a time). So, when the one side goes up it actually produces a rotational force on the body. In effect if there’s enough available lift on the one side you could actually tip the truck over. That isn’t really possible here because the stabilizers float.

I appreciate the assistance. I still don’t fully understand joint drives, but this is helpful.

You can achieve something like this (below) if you modify the stabilizer script (which would be friendlier than using multiple controls from a user POV). You may also want to add some joints to the pads to make them behave more natural.


(the weird lines on the gif are from a horrible gif encoding algorithm, not the engine :p)

public bool selected;

   
    void Start () {
 
        selected = false;

    }
 
    // Update is called once per frame
    void Update () {
 
        if (selected) {

            renderer.material.color = Color.red;

      //DO CRANEY STUFF


        }

        else

        {

            renderer.material.color = Color.white;

        }
 

    }

    void OnMouseDown (){

        selected = !selected;

    }

Full Code

using UnityEngine;
using System.Collections;

public class Stabalizer : MonoBehaviour {

    public bool selected;

        //The controls

        public KeyCode Up = KeyCode.T;
        public KeyCode Down = KeyCode.B;
        public KeyCode Left = KeyCode.F;
        public KeyCode Right = KeyCode.G;


    public int maximumHeight = 30; //Maximum height for the horizontal piston
    public float heightIncrements = 1.0f; //Increments in height
    public float damping = 10.0f; // Damping in height increments

    public Rigidbody hPiston;  // Horizontal Piston


    private ConfigurableJoint vPiston;  //Vertical Piston but we can get this from our horizontal piston
    private float height;

    // Use this for initialization
    void Start () {
  
        selected = false;

    }
  
    // Update is called once per frame
    void Update () {
  
        if (selected) {

            renderer.material.color = Color.red;

            if (Input.GetKeyDown (Up) && height < maximumHeight) {
              
                vPiston = hPiston.GetComponent <ConfigurableJoint>();
              
                JointDrive d = new JointDrive();
                height += heightIncrements;
                d.positionSpring = height;
                d.mode = JointDriveMode.Position;
                d.positionDamper = 10;
                d.maximumForce = 3.402823e+38f;
              
              
                vPiston.yDrive = d; //so basically this uses the physics engine's built in joints!
              
            }
          
            else if (Input.GetKeyDown (Down) && height > 0)
              
            {
              
                vPiston = hPiston.GetComponent <ConfigurableJoint>();
              
                JointDrive d = new JointDrive();
                height -= heightIncrements;
                d.positionSpring = height;
                d.mode = JointDriveMode.Position;
                d.positionDamper = 10;
                d.maximumForce = 3.402823e+38f;
              
              
                vPiston.yDrive = d;
              
            }
          
            else if (Input.GetKeyDown (Left)){
              
                //TODO: ADD SOME SIDEWAYS MOVEMENT
              
            }
          
            else if (Input.GetKeyDown (Right)){
              
                //TODO: ADD SOME SIDEWAYS MOVEMENT
              
            }


        }

        else

        {

            renderer.material.color = Color.white;

        }
  

    }

    void OnMouseDown (){

        selected = !selected;

    }



}

The gifs aren’t showing up for me so I’m not sure what you’re describing here. What I gather from the code is that when a stabilizer is selected the parts are tinted red… that’s a good idea.

The keyboard control is just temporary. In the end it’ll probably be something like you go to one side of the crane and one analog stick controls one stabilizer, the other controls the second. Then you can switch to the other side… once they’re set you go up in the cab, etc… I’m more concerned with getting the actual operations to work because all of this will have to be integrated into a 3D model which will be built later (by someone else because I don’t have much 3D experience).

Firstly, here’s the gif! https://drive.google.com/file/d/0B3rZeKUDjp8iUjFDa1V5QW1MS28/view?usp=sharing It worked earlier, something must be up with Unity’s servers :frowning:

So you’re trying to make something more like this?

For the horizontal movement, I’d allow movement on the x-axis for a configurable joint (between the body and stabilizers) by setting it to limited or even free. Then just add some x movement code to the stabilizer script and all should be fine.
When you get a proper model, be sure to get it modular (ie. each part separately) otherwise it would be very difficult to work with.

No, no, no… I said crane… not train. :slight_smile: Yes, I was thinking about about doing the look-to-select a control because this will be Rift enabled. Once the control was selected, the analog sticks would do the actual movement which means I also have to factor in the analog axis position and have that affect the speed of the stabilizer movement.

Yes in your GIFs, that is what it’s supposed to do as far as rolling the body. Now, using your implementation, how do you start with the stabilizers off the ground? What I was trying to do earlier was increase the Y scale of the body so it would be in contact with the ground (in reality the wheels would be in contact), but I can’t seem to get the outriggers to come up off the ground.

I’m trying to make an outrigger setup that can be used on cranes, fire trucks, etc…

This is pretty much the end-result I’m looking for…
Here’s a couple of crane outriggers:

Well, from the top of my head, you should be able to simply change the connection points of the stabilizer-to-body joints, raising and lowering the stabilizers. For the inward/outward movement you could mess with the joints’ x-movement, otherwise just scale the horizontal beam and move the vertical beam accordingly (I’m on my phone so code WILL NOT WORK :hushed:).

In regards to the rear-wheel pickup, the script in my last post already allows such behaviour, just select the back stabilizers.

vBeam is what needs to move up and down, not the BeamH… so changing the stabilizer to body point won’t produce the desired effect. The Horizontal Beam’s connection point on the body is fixed… the Vertical Beam has to move up and down when the outriggers aren’t in contact with the ground. In my initial diagram I may have oversimplified a bit… because the horizontal bars aren’t climbing the verticals. When the pads are in contact with the ground, the relative effect of the horizontals climbing the vertical beams may be fine.

Ah, yes :smile: I’ve modified the script a bit to just add a “locked” feature (a bool that’s true as the stabilizers are being deployed). It should work fine… All that’s needed is some horizontal deployment :stuck_out_tongue:

Here’s a package: “Crane 2” and here’s a [gif](https://drive.google.com/file/d/0B3rZeKUDjp8iUHhnMDlkUmozNjQ/view?usp=sharing deployed).) (it takes some time to load)
(Press z to deploy the stabilizers)

TL;DR Code

//  declarations and blah
private bool locked; //Locks the joints in position

// Use this for initialization
void Start () {
   
    locked = true;
   
}

// Update is called once per frame
void Update () {
   
   
    if (selected) {
       
       
        if (Input.GetKeyDown (Unlock)){
           
            locked = !locked;
           
        }

       
       
    }
   
    else
       
    {
       
        renderer.material.color = Color.white;
       
    }
   
    if (locked)
       
    {
       
       
       
        rigidbody.AddForce (Vector3.up * 10);
       
        vPiston = hPiston.GetComponent <ConfigurableJoint>();
       
        JointDrive d = new JointDrive();
        height = 0;
        d.positionSpring = height;
        d.mode = JointDriveMode.Position;
        d.positionDamper = 0;
        d.maximumForce = 3.402823e+38f;
       
       
        vPiston.yDrive = d;
       
    }
   
   
}

void OnMouseDown (){
   
    selected = !selected;
   
}



}

Full Code

using UnityEngine;
using System.Collections;

public class Stabalizer : MonoBehaviour {

    public bool selected;

        //The controls

        public KeyCode Up = KeyCode.T;
        public KeyCode Down = KeyCode.B;
        public KeyCode Left = KeyCode.F;
        public KeyCode Right = KeyCode.G;
        public KeyCode Unlock = KeyCode.Z;



    public int maximumHeight = 30; //Maximum height for the horizontal piston
    public float heightIncrements = 1.0f; //Increments in height
    public float damping = 10.0f; // Damping in height increments

    public Rigidbody hPiston;  // Horizontal Piston


    private ConfigurableJoint vPiston;  //Vertical Piston but we can get this from our horizontal piston
    private float height;
    private bool locked; //Locks the joints in position

    // Use this for initialization
    void Start () {
   
        selected = false;
        locked = true;

    }
   
    // Update is called once per frame
    void Update () {
   

        if (selected) {

            renderer.material.color = Color.red;

            if (Input.GetKeyDown (Unlock)){

                locked = !locked;

            }



            if (Input.GetKeyDown (Up) && height < maximumHeight) {
               
                vPiston = hPiston.GetComponent <ConfigurableJoint>();
               
                JointDrive d = new JointDrive();
                height += heightIncrements;
                d.positionSpring = height;
                d.mode = JointDriveMode.Position;
                d.positionDamper = 10;
                d.maximumForce = 3.402823e+38f;
               
               
                vPiston.yDrive = d; //so basically this uses the physics engine's built in joints!
               
            }
           
            else if (Input.GetKeyDown (Down) && height > 0)
               
            {
               
                vPiston = hPiston.GetComponent <ConfigurableJoint>();
               
                JointDrive d = new JointDrive();
                height -= heightIncrements;
                d.positionSpring = height;
                d.mode = JointDriveMode.Position;
                d.positionDamper = 10;
                d.maximumForce = 3.402823e+38f;
               
               
                vPiston.yDrive = d;
               
            }
           
            else if (Input.GetKeyDown (Left)){
               
                //TODO: ADD SOME SIDEWAYS MOVEMENT
               
            }
           
            else if (Input.GetKeyDown (Right)){
               
                //TODO: ADD SOME SIDEWAYS MOVEMENT
               
            }



       

            }

        else

        {

                renderer.material.color = Color.white;

        }

        if (locked)

        {

       
   
            rigidbody.AddForce (Vector3.up * 10);

            vPiston = hPiston.GetComponent <ConfigurableJoint>();
           
            JointDrive d = new JointDrive();
            height = 0;
            d.positionSpring = height;
            d.mode = JointDriveMode.Position;
            d.positionDamper = 0;
            d.maximumForce = 3.402823e+38f;
           
           
            vPiston.yDrive = d;

        }


    }

    void OnMouseDown (){

        selected = !selected;

    }



}

I had an epiphany last night so I actually have it working pretty well. I had to go back to using AddForce because i just couldn’t get the joint drive method to work. I added in a hydraulic lock as well, I will have to see if it functions like yours. I also made a separate script for the pads which handles the collision detection. When the collider is hit, as before it applies an upward force… But, now, each hydraulic assembly is a two part system… a piston and a hydraulic cylinder. So now the upward force is applied to the cylinder, not the horizontal. I’m also trying to make the the class itself as generic as I can… So instead of having a single class that controls both horizontal and vertical, each stabilizer gets its own script attached and the public parameters are changed appropriately. The other sticking point was figuring out when to switch back to moving the piston instead of applying force to the cylinder. So in order to get the pad to come off the ground I had to store the local position of the vertical piston when it first makes contact with the collider. When you are lowering the chassis the piston passes that location by just enough to trigger a detection conditional.

Sounds good! In terms of collision, you may want to take a look using raycasts: storing the local position and then waiting for a collision would be very risky and open to all sorts of glitches.
I still think that simulating the fluid as a spring is more realistic: it has a nice and more natural bounce to it which isn’t really achievable with AddForce. The script I wrote works on a per-stabilizer basis and moves the vertical piston (in the last post I was referring to the inny-outy movement moving the horizontal ones, not the up-down movement).

I’m still struggling with the understanding and implementation of the spring method… that’s what’s keeping me from using it, not that I think AddForce is better. I will probably end up switching to the joint drive as soon as I have a better understanding of how it works. Conceptually I think I understand it. The hydraulic lock I was using used the freeze position which of course locks up everything, so it doesn’t work if you try to do independent stabilizer movement. So what I think I’m going to try is using the joint drive to hold the piston in place and see if working on that furthers my understanding of joint drive to the point to where I can switch the main movement over from AddForce. No offense, but I don’t really like to cut-and-paste code if I don’t have a pretty good understanding of what’s going on. Then I’ll take a look at raycasts… I haven’t done anything with them before either. Unity is after-all new to me. Again, thanks for all the input and assistance.

Have you checked the documentation?

I like to think of the spring method like this


I agree with the no cut-and-paste ethos; Unity is very easy to pick up so don’t worry :slight_smile:

Yes, I looked at the docs for joint drive… as I said, conceptually I understand it. What is throwing me is that you aren’t using targetPosition in your code. In that case, where does targetPosition default to? Your code changes the positionSpring to achieve movement. I think that’s the part I’m not getting.

In order for this to be usable as a hydraulic lock, I would have to set the targetPositon to the piston/cylinder’s location when the lock comes on and set the positionSpring to a very high number to overcome gravity exerted on the piston as well as the weight of any attached rigidbodies… allowing virtually no pull on the rubber band. Then to unlock it, just set JointDriveMode to none. Or am I mistaken as to how jointdrive works?

TargetPosition is, as a default, set to where the joints start at.
I wasn’t using it and was just relying on the springs to keep stuff in place. When activating the hydraulic lock the springs become redundant (they’re set to 0) allowing the joint to slide freely. Then, AddForce is used to keep the pistons in place until the hydraulic lock is turned off and the springs are reactivated.