Haptic Feedback Example Applications: Joystick Crane Interface


These examples are provided as guides to using the Haptic Feedback Evaluation Kit for potential real-world applications. As discussed at the end, these are not full real-world solutions, but a useful starting step!

They outline the approach taken to solve the problem. They are not a guide to programming on the Arduino, therefore some prior knowledge of the Arduino language will be useful. Try the Arduino Learning or Reference pages for help with specific functions.


Joystick Crane Interface Example

Joystick Crane Interface Example

Joysticks are often used as a method for remotely controlling movement of an object. For example, a crane controller may use a joystick for the operator to control the crane’s position.

In this scenario, it may be difficult for the operator to get a good overall view, especially as the crane and its load are likely to be very large. The scale can be hard to judge and there may be a strict area where it is considered safe to work.

Haptic feedback can easily be used to warn the operator that they are getting close to the edge of, or even beyond, the safe operating area.

The methods for defining and measuring the crane’s position within this safe area may be complex. For this example, we will show how the Haptic Feedback Evaluation Kit can be used to play different haptic effects depending on the user’s position in a square, with the input controlled by a joystick.

Definition And Scope

To provide haptic feedback to an operator depending on their position within a square of 200 x 200 as they move within it, controlled by a joystick.

  • Create an imaginary area of 200 x 200 representing a real-life area of land
  • Measure input from the user via an electronic joystick
  • Use the joystick measurements to move the user within the square
  • Warn the user they are approaching the edge of the square


  • 1 x Haptic Feedback Evaluation Kit

We’ll be using the spare pins on the Arduino to accept the input from the joystick. To access these pins you can either solder connection wires to the top of the Haptic Shield (not recommended) or remove the shield and use simple jumpers to the required pins.

  • 1 x Analogue Joystick
An analogue joystick

An analogue joystick

We’ve used a simple 5V joystick, these are inexpensive and widely available from prototyping stores. The operation principle is fairly simple too - it’s simply two variable resistors (one for each axis) that change in value as the user moves the stick off centre. The output is two analogue voltages for the stick position and a digital signal for the switch (closed by pressing down on the stick - we don’t use it in this application).

  • 1 x Breadboard

Always good to have around, in this case, we need it to give both the Haptic Shield and the analogue joystick access to the 5V pin on the Arduino.

  • 1 x C10-100 Linear Resonant Actuator (optional)

In this example, we used an external C10-100 instead of the one in the Haptic Grip. This enables us to install haptic feedback directly on the joystick, which is typically where the user would expect it to be. This, of course, would be optional and the process of using an external actuator makes very little difference on the design, see a quick tutorial on how to use one here.


This software is built from the Development Mode. You can download the code used in this example here or in the top right of the page.


Note: Before starting and putting effort into making the required wiring, we will be playing haptic effects to the user to warn them of proximity to the edge. If you want to experience specific effects and compare them to others, the easiest way to do this is to use the Engineering Mode. You may wish to select what effect would be a good warning before disconnecting the Haptic Shield.

Let’s start with defining our safe area and when we will play haptic effects to warn the user. With a square of 200 x 200, the user does not need any distraction if they are working in the middle, i.e. no effect. We could consider a light early warning to appear as the user moves too far from the safe centre, say at ± 60, on either axis. A stronger warning could appear at ± 85, encouraging the user to move closer to the centre. At ± 100 we can send an urgent vibration warning.

We selected to use effects 9 (Soft Bump 30%), 12 (Triple Click 100 %), and 92 (Transition Ramp Up Short Sharp 1 0-100%) respectively.

Our chosen limits for the 'safe area'

Our chosen limits for the 'safe area'

The process can be split into 3 repeatable steps; measuring the input, adjusting the coordinates, play haptic effects (if required). We will split these three steps into their own functions for clarity, but first, we need to start with a setup!


It is best to remove the Haptic Shield from the Arduino and connect to the pins using jumper cables.

Use the Pin Mapping resource to easily see which pins are required. For this example, we’ll need connections for the DRV2605 (red), and if you are using the Haptic Grip (blue) you'll need those too. If you're using an external actuator, like us in this example, you don't need to connect the pins required by the Haptic Grip, freeing up two additional analogue pins.

We connected pins 3V3, GND, A4, A5, 4, 6, 7, and 9 straight from the Arduino to the Haptic Shield. We connected the other GND and 5V to the breadboard, as the analogue joystick also needs power. Note the DRV2605 also relies on the 5V connection so be sure to connect the Haptic Shield 5V pin to the breadboard too.

The two outputs from our joystick were connected to A2 and A3.

Don't forget the external LRA connection too! Simply unplug the Haptic Grip from the Haptic Shield, then connect the LRA leads to the SMD test points OUT- and OUT+.

Attach an external connector by detaching the grip and using the SMD test points

Attach an external connector by detaching the grip and using the SMD test points

Initial Setup

The Development Mode handles all the initialisation for you to start using the Haptic Feedback Evaluation Kit, so most of the work here is done for you!

However it doesn’t know your exact application, so there are always a couple of things to add. Similarly, there may be functionality in the code that you are not using - so consider streamlining it at a later date.

Lines 41 - 50 include a range of global variables that support the functions below, as their existence requires an explanation of their function we’ll cover these later!

Instead, we will highlight that we have changed line 64 to use the C10-100 LRA:

motor.selectMotor( 3 );. Remember the DRV2605 needs to be calibrated! Line 65 is important!

We also need to set the pins that are connected to the analogue outputs from the joystick. In line 60 we can see that the pin setup has been included in its own separate function, this starts at line 91.

Two lines (98 and 99) show that we have set two pins to be inputs, XPIN and YPIN. These names have been defined using #define, for the sake of neatness, this is included with all the other pre-existing in#defines the defs.h file (see lines 35 and 36).

We also noticed the reading from the joystick at rest was often changing on different power-ups. Line 73 calls a function to initialise the joystick (line 110), simply reading the resting value of the joystick and assigning the values to two variables initX and initY. These are then used to offset the readings when we measure the input.


This function handles the input from the analogue joystick by editing two variables, Xread and Yread. We use these later to adjust our position in the square. analogRead() is the critical function here, we also use our initX and initY values from the initialisejoystick() function to make sure our reading is accurate.

By default, our joystick seemed to invert the Y axis, so we multiply the Yread value by -1 to correct it. You may wish to delete this line.


Adjust the speed of movement by measuring the joysticks position

Adjust the speed of movement by measuring the joystick's position

The table headings and coordinates are printed on the serial monitor

The table headings and coordinates are printed on the serial monitor

We keep track of our position in the 200 x 200 square using two variables representing the x coordinate and the y coordinate, Xco and Yco. Our starting point is right in the middle, as these variables were created with values of 0.

This function takes our current coordinate and adjusts it according to results from measure();. However, there is a little twist, it is common for joystick-based control to change speed depending upon the strength of the input. For example, slightly moving the joystick to the right will cause a much slower movement than moving the joystick all the way to the right-hand side.

To implement this we’ve used two arrays; limits[] determines at what values of Xread and Yread the speed will change (input sensitivity) and adj[] determines the speed for each limits[] group (output speed).

For example, if the joystick is at rest and Xread is equal to 0, then the integer i will equal 3, leading to adj[i] = adj [3] = 0, and a movement of 0 is applied. Similarly the joystick is pushed all the way down and Yread is -500, then integer i will equal 0, so adj[i] = adj[0] = -10. Now our position moves down the Y-axis at a speed of -10, much faster than the -5 or -1!

To slow down the speed, reduce the values in adj[]. To increase the sensitivity of the joystick, reduce the values in limits[]. You could also increase the resolution of the joystick by adding more groupings to the two arrays - but remember to increase the exit condition of the for() loops!

The movement speed in the X direction and Y direction are assigned to variables moveX and moveY. The coordinates Xco and Yco are then adjusted by this value. If you wish, you could remove this step and directly edit the coordinates in the for() loops with Xco = Xco + adj[i].

As a final step, we need to confine our user to a 200 x 200 square. A couple of if() statements check to see if Xco and Yco are beyond the boundary and sets them to ± 100 if needed.


This is the simplest part as we’ve already done the hard work of measuring the input and adjusting the position. Simply check the values of our coordinates to see if we need to play a haptic effect.

Interfacing with the DRV2605 is made simple by files included with the Development Mode, simply use the;playFullHaptic() function to play a haptic effect. We have a DRV2605 Arduino Library reference document in the Downloads and Resources section for help.

Mount the LRA to the back of the joystick for localised haptic feedback

If the Xco or Yco is equal to ±100 then we play effect 92, twice for extra impact. Note that as we are using a C10-100 LRA, we must set the library value to 6. Libraries 1 - 5 are for ERMs.

Final Steps and Tips

If you’ve downloaded the code and not made any changes (using the same pin connectors for the analogue inputs) you should be able to load the code into the kit, start moving the joystick and feeling the vibrations on the grip (or joystick if you have the external actuator).

Also built into the code (you may have noticed) is a load of text sent up the serial port using;Serial.print(). Open the serial monitor in the Arduino IDE (ctrl + shift + M) to see your current coordinates printed on the scrolling screen. This should make it easier for debugging.

We also used an external C10-100 actuator instead of the one inside the grip. This way we could mount it to the back of the joystick to get haptic feedback directly on the input device! Remember, to connect an external actuator you need to disconnect the grip from the Haptic Shield and still need to call the;autoCalibrate() function.

Future Work

How does this relate to the ‘real world’? Whilst this demonstrates one approach to the application, it obviously has several limitations that could easily be improved on.

For further revisions, consider the following points and how you might go about solving them:

  • The world is 3D!

We’re only measuring two axes, with crane operation it’s likely that the third Z axis will be of concern as the operator winches up and lowers different loads. Also, 2 joysticks = 4 analogue pins. The Arduino Uno R3 only has 6 analogue pins, and 2 are required by the I2C bus.

  • Will the confined workspace be a square or rectangle?

Likely not! Worksites can be all types of shapes - although they may be able to be reduced into (fairly) square ‘safe’ areas. What about other heavy machinery, equipment, or buildings? These could be islands of ‘dangerous area’ within the workspace and would need to be catered for.

  • An effect is played every cycle

This means every measurement has an effect played, is that best? A great way to increase the sense of urgency is to reduce the time between effects. The early warning could play an effect, say, every 4th or 5th measurement. How would you go about doing that? Have a look at our vehicle distance sensor application for clues!

  • Measuring the crane’s actual position

This method is based on measuring the input, in reality, it’s much better to measure the position of the crane and not the input to movement. What would happen if the crane actually moved much faster than you anticipated? When the coordinates above get to ±100, they stop. Is there something to stop the crane in place?

  • Reduce speed at extremities?

When you’re close to the edge of the safe zone, you probably want the operator to have refined control. This would mean varying the speed of the output depending on the crane's proximity to the edge.

  • How will you mount the vibration motor in the joystick?

Our Application Bulletin 014: Mechanical Layout of Vibration Motors for Typical User-Interfaces and Controls and 015: Mechanical Mounting for Vibration Motors: Moulded and Machined Enclosures will help you with this.

  • Other types of feedback

The operator may not be able to process all the information from haptic feedback alone. For example, if the crane was close to any of the corners, haptic feedback could be played as a warning for the x axis, y-axis, or both. Even a simple 3 x 3 LED array would be helpful, maybe the outer 8 would be coloured red and the inner one green?

Contact Us

1.07 Canterbury Court
1-3 Brixton Road, London, SW9-6DE
[email protected]
+44 (0) 1932 252 482
(English / FR / DE / ES / IT)
+44 (0) 1932 325 353
Precision Microdrives
Mon. – Fri. 9:00 – 18:00 (BST / UTC)
* Charges vary depending on service provider and country