Knobs for Arduino Controls


A very useful control is the simple knob. On an Arduino, the way to do this is to use a potentiometer, a device with three electrical contacts (a rheostat is similar, but has only two contacts; don’t use one of those by mistake).

These are available in several types: a “linear taper” version is preferable if you need a simple adjustment, because the numbers read by the Arduino will be proportional to the distance the control is turned. If you were using one to actually drive a train, you might want to use a “log taper” (aka “audio taper”) model, as these produce less change in the returned value for degree of rotation at lower throttles, and more at higher, giving more precise low-speed control (see this excellent explanation of how they work).

While there are many different maximum resistance ratings, a 10 K ohm one is a good choice for use on an Arduino (the data sheet for the Arduino supposedly says “10K or less”, although I can’t find that statement, and higher ones may work acceptably; it’s likely the intent is to keep the pot resistance well below the 20K ohm internal resistance of the analog pin, to limit current). Values above 1K ohm will be more efficient of the Arduino’s limited power supply than lower values. If you use one rated 100 ohms, 50 mA will go through the pot, which isn’t a huge problem as the +5V pin is limited to the board’s limit of 500 mA (in some cases it can handle more). But it’s never a good idea to waste power if you don’t need to; you may need it for something else. I’m using a 10K ohm pot; they’re easy to find (Radio Shack 271-1715 or equivalent) and the best match for the Arduino’s requirements.

A potentiometer, or “pot” for short, is one of the simplest Arduino controls to use. The outer two of its contacts are connected to the Arduino’s +5 and Ground pins to create a voltage across a resistor, and the middle pin, which is internally connected to a “slider” that moves along the resistor when the shaft is turned, is connected to an analog pin (I’ll use A0 in my example). When the analog pin is read, it will report a voltage between zero (if the slider is at the ground end) to +5V (if the slider is at the far end), expressed as a value from 0 to 1023.

If what you want to use it for isn’t 0-1024, you will need to scale the result. For example, a throttle with a range of 0-255 could be derived from the number read by dividing the value by four. There’s a more general solution, which will be covered below.

Also, you can use a separate power supply for the +5 (it should be a regulated 5 volt supply however), but if you do you will need to connect its ground to the Arduino’s ground. It’s simpler just to use a high-resistance pot with the Arduino +5V pin; a 10K ohm pot will only draw half a milliamp of current.

ard-pot

Here’s the essential Arduino code to read one and scale it to a 0-255 range:

const int MAX_POT = 1023;
const int MIN_POT = 0;
const int MAX_SCALE = 255;
const int MIN_SCALE = 0;
const int potPin = A0;

int readThrottle()
{
int th = constrain ( analogRead(potPin), MIN_POT, MAX_POT );

return( map( th, MIN_POT, MAX_POT, MIN_SCALE, MAX_SCALE) );
}

This defines a function which when read returns a number from 0 to 255 corresponding to how far the knob on the potentiometer has been turned. The MIN_POT and MAX_POT values can be changed if the pot you are using does not go all the way to 0 or 1023 (e.g., if you test it and it only goes to 1012, set MAX to that value and readThrottle will output 255 when the pot returns 1012).

And if you want to scale to some range other than 0 to 255, you can change MIN_SCALE and MAX_SCALE (for example, you could use the POT to select a number from 18 to 96; there’s no reason one end of the scale needs to be zero). Note, however, that if the range from MIN_SCALE to MAX_SCALE is larger than the range returned by the pot (MIN_POT to MAX_POT), scaling will skip some of the values. E.g., for MAX_SCALE of 2048 (all others the same), readThrottle is going to return 0, 2, 4... (although it might not be that simple, and it might not return even numbers only, but at best it’s going to return roughly every other number).

While it might seem more efficient of SRAM to get rid of “th” and just put the constrain function in the middle of the map function, it’s more readable this way. And a good compiler will realize that th is only being used in one place, and get rid of it anyway, producing identical code to what you’d have if you’d removed it yourself.

If you use a POT for a throttle with a motor shield, be aware that a train isn’t going to move for throttle setting 1 (out of 255). You need to put it up above 50% (I found my test loco needed 161 out of 255 to move at all).