Create a Crane Training App in AR – Part 1

Before this tutorial, it is recommended that you do the AR Butterfly Lifecycle one first, as it get you familiar with the concepts covered in this more advanced tutorial.

In this tutorial, we will be creating a crane training app in augmented reality (AR). A basic control scheme and mechanics to show how a tower crane can pick up objects and put them down. The app will have 4 main components.

  • the crane will be able to turn, raise/lower its hook and move it forwards and backwards. The hook is able to pickup…
  • the container which can then be placed in the back of…
  • the truck which is the end goal.
  • the crane is controlled by the dashboard which will have physical buttons that you need to tap on in order to control the crane.

ezgif 4 30afcc9d3bd6

Each of these 4 components will be an image target. An image target is way to project models in AR. These are specific images that the app can identify through your camera. It calculates the position and angle of the image and then projects a model or whatever you want on top of it. We will be having one for each component, so you will be able to place them wherever you want, having a different arrangement each time you use the app.

The best types of targets are ones with lots of “points” that the app can identify and lock on to. This involves creating high contrast targets, with many edges and patterns that stand out. A good type of target for example would be a QR code, which is similar to the ones we’ll be using in this tutorial.

Untitled

Project Files

You can download the project files here. It contains the scripts, models and target images you will need. The EasyAR SDK isn’t installed though. You can learn how to do that here.

You can print out the targets here. Just print out the image and cut the targets out.

Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.

Creating the Scene

First, we need to create a new 3D Unity project. Once that’s all set up, delete the “Main Camera” as EasyAR will take care of that. You should just have the directional light remaining.

easyar deletecamera

Now you need to drag the “EasyAR_Startup” prefab (EasyAR > Prefabs) into the scene. Once that’s done, click on it and enter in your SDK licence key from EasyAR into the “key” field.

easyar keyinput 2

Creating the Image Targets

Now we need to create our 4 image targets (crane, container, truck, dashboard). Drag the “ImageTarget” prefab (EasyAR > Prefabs > Primitives) into the scene. Click on it as we need to change a few properties.

Set “Path” to “CraneMarker.jpg”. We have our image targets stored in the “StreamingAssets” folder and “Path” is the path to that image from the folder. Since we don’t have the images in any sub-folders, we can just directly link it. For “Name”, we just write down the image name (without file extension). Set “Size” to 5 for X and Y. This can really be any number, as it’s just used as a reference for us to resize the models to how they will appear in the app. Lastly, change “Storage” from App to Assets.

crane imagetargetsettings

Now we need to link the image tracker into the “Loader” property. This is found as a child of the “EasyAR_Startup” object in the scene.

crane imagetargettracker

Now copy and paste the image target 3 times so we have a total of 4. I arranged them into a row as seen below and changed the names so they’ll be easier to work on later.

crane multipleimagetargets

Finally, we need to tell EasyAR that we’re using 4 image targets. To do this, go to the “EasyAR_Startup” prefab in the scene and find the “ImageTracker” object as its child. There is a script on it with a property called “Simultaneous Target Number”. Change this from 1 to 4.

Creating the Crane

Now it’s time to create the crane. Adding in the model as well as script functionality. Create an empty GameObject as a child of the crane image target object. Now drag both the “Base” and “Top” models (in the Models folder) into the scene, as children of the empty object.

crane crane1

You should see that the models are a bit big upon dragging them in. Don’t worry, we can fix that.

crane cranetoobig

Scale and re-position the two models so they look like the ones below. Make sure that the “Top” model has its pivot point in the center of the tower. In the image below, I also flipped the top so it is mirroring it’s direction. You can do this by setting the X axis of its scale value to negative whatever it is right now.

crane craneresized

Now it’s time to add the hook. Go to the “Models” folder and drag in the “Hook” prefab as a child of the “Top” model of the crane. Re-position it so it’s at the end of the crane top. For me, I set it to: X: -13, Y: 0, Z: 0.

crane hookcreation

Now click on the hook object and add a “LineRenderer” component to it. Set the material to “Dashboard” as it’s dark and looks like a cable. Make sure the 2 size values are all 0 and finally set the width (little input field under the “Width” label) to 0.20.

crane linerenderer

Next, create a new empty GameObject and make it a child of the top of the crane (not the hook). This is going to be what the LineRenderer will connect to from the hook. Position it just above the hook (same X and Z position as hook, but different Y).

crane hookanchorcreation

Finally, create another empty GameObject called “ConatinerHoldPosition” and make it a child of the hook object. This is the position relative to the hook where the container will attach to. So set it just a bit below the hook.

crane containerholdpos

Now we can begin to create the script for the crane. In the “Scripts” folder, create a new C# script called “Crane”. Drag the script onto the “Crane” object that holds all the models and hook. Once that is done, we can open up the script and begin with creating some variables.

// speeds
    public float turnSpeed;             // rate at which the crane can rotate on the Y axis
    public float hookVerticalSpeed;     // rate at which the hook can be raised and lowered
    public float hookHorizontalSpeed;   // rate at which the hook can be moved horizontally along the crane

    // hook
    public float hookRaiseLimit;        // the highest the hook can be raised
    public float hookLowerLimit;        // the lowest the hook can be lowered
    public float hookForwardsLimit;     // the furthest forward the hook can be moved
    public float hookBackwardsLimit;    // the furthest backwards the hook can be moved

    // components
    public GameObject craneTop;         // top of the crane which rotates
    public GameObject hook;             // the hook object

We’re adding in the ability to rotate the top of the crane, raise and lower the hook and move it forward and backwards along the top of the crane.

All of the limit variables like “hookRaiseLimit” and “hookForwardsLimit” are values along their axis in local position of the hook.

“craneTop” is the top model that we created just before, and “hook” is the hook model that we also added in.

Now we’re going to be creating a function for the following things the crane can do.

  • Turn clockwise
  • Turn anti-clockwise
  • Raise hook
  • Lower hook
  • Move hook forwards
  • Move hook backwards

Create the function “TurnClockwise”. As long as this is being called, the crane top will rotate clockwise. Do the same for “TurnAntiClockwise” but make sure that the turn speed is negative as we want to rotate in the other direction.

// rotates the crane clockwise along the Y axis
public void TurnClockwise ()
{
    craneTop.transform.Rotate(Vector3.up, turnSpeed * Time.deltaTime);
}

// rotates the crane anti-clockwise along the Y axiss
public void TurnAntiClockwise ()
{
    craneTop.transform.Rotate(Vector3.up, -turnSpeed * Time.deltaTime);
}

Now make a function to lower the hook. This checks if the local Y position of the hook is greater than the lower limit. If so, then the hook can rise. This prevents the hook from going down forever. Then the same for “RaiseHook”, but checking if the local Y position is less than the raise limit. Also make sure to move the hook in the right direction. Vector3.down for going down and Vector3.up for going up.

// moves the hook down
public void LowerHook ()
{
    if(hook.transform.localPosition.y > hookLowerLimit)
    {
        hook.transform.localPosition += Vector3.down * hookVerticalSpeed * Time.deltaTime;
    }
}

// moves the hook up
public void RaiseHook ()
{
    if(hook.transform.localPosition.y < hookRaiseLimit)
    {
        hook.transform.localPosition += Vector3.up * hookVerticalSpeed * Time.deltaTime;
    }
}

Finally, we need to make a function to move the hook forward. This is much like moving the hook up and down, but it’s now on a horizontal axis. Then of course, make a function to move backwards.

// moves the hook forwards horizontally along the crane
public void MoveHookForward ()
{
    if(hook.transform.localPosition.x > hookForwardsLimit)
    {
        hook.transform.localPosition += Vector3.left * hookHorizontalSpeed * Time.deltaTime;
    }
}

// moves the hook backwards horizontally along the crane
public void MoveHookBackwards ()
{
    if(hook.transform.localPosition.x < hookBackwardsLimit)
    {
        hook.transform.localPosition += Vector3.right * hookHorizontalSpeed * Time.deltaTime;
    }
}

If you want to test out the crane movement before making a build, you can add in this piece of code which will allow for the keyboard to control the crane.

void Update ()
{
    if (Input.GetKey(KeyCode.E))
        TurnClockwise();
    if (Input.GetKey(KeyCode.Q))
        TurnAntiClockwise();
    if (Input.GetKey(KeyCode.W))
        RaiseHook();
    if (Input.GetKey(KeyCode.S))
        LowerHook();
    if (Input.GetKey(KeyCode.D))
        MoveHookForward();
    if (Input.GetKey(KeyCode.A))
        MoveHookBackwards();
}

If you do want to test in the editor before building the app, do the following:

  • Add a camera to the scene.
  • De-activate the “EasyAR_Startup” GameObject.
  • Disable the “Image Target Behaviour” script on each of the image targets.

It should look like the image below.

crane testsettings

If you were to test the crane now, you’d notice that it doesn’t really move or anything. This is because we need to enter in the speeds and limits. Click on the “Crane” where we attached the recently made script and enter in the values as seen below. You will also need to drag in the top of the crane and the hook to their corresponding variables.

crane cranesettings

Now if you press play, you should be able to control the crane with the keyboard.

crane testgof

But you might notice that there’s no cable connecting the hook to the crane, even after we set up the LineRenderer. That’s because each frame, we need to update the position of both ends of the cable. To do this, we need to create a new script called “Hook”. Make sure you attach the script to the “Hook” object.

We start with our variables. “lineRenderer” is the LineRenderer component we made on the hook earlier. “cableAnchorPosition” is the GameObject we made earlier that was just above the hook.

public LineRenderer lineRenderer;
public GameObject cableAnchorPosition;

Now in the Update function, we’re going to do 2 things. First, we’re going to make the cable anchor follow the hook along its X axis. This is because we want the cable to connect vertically from the hook to the crane and follow when it moves. Secondly, we’re going to connect the LineRenderer from the hook to the cable anchor. Here’s how…

“newPos” is a Vector3 that we set to be the same as the cable anchor’s position. We then change the X axis on it to match that of the hook. Then we set the cable anchor’s position to be the new pos, thus making it follow the hook along the X axis.

To connect the LineRenderer, we use the SetPositon() function. This gets a point in the line and sets it’s position. Since out line only has 2 points, we just need to set the line element of 0, to the hooks position, and the line element of 1 to the cable anchor’s position.

void Update ()
{
    // make the cable anchor follow us along the crane
    Vector3 newPos = cableAnchorPosition.transform.localPosition;
    newPos.x = transform.localPosition.x;
    cableAnchorPosition.transform.localPosition = newPos;

    // connect the line renderer from the cable anchor to us
    lineRenderer.SetPosition(0, transform.position);
    lineRenderer.SetPosition(1, cableAnchorPosition.transform.position);
}

Now going back to the editor and clicking on the “Hook” object, we can drag in our LineRender and “HookAnchorPosition” object to the script.

crane hooksettings

Then, we can press play and watch as the cable follows the hook.

crane hookrope

That’s it for part 1 of the tutorial! So far we have a working crane that can rotate and move the hook around. In part 2, we will be setting it up so the crane can pickup a container and place it in a truck, all with in-game touch controls – see you then!