Thursday, November 17, 2011

Sparkfun Inventor's Kit Circuit-08: Potentiometer








Today we look at the use of Potentiometers, a.k.a "variable resistors".  Whats fun about these is that they are provide a window into more natural robotics, in other words, a way to start thinking of sensors that mimic the way we sense the world -- not in binary black and white on off terms, but on a continuum. To mimic analog behavior (where "shades of grey" or "values between 0 and 1" can be interpreted) the Arduino has not just the 14 digital pins (on the left side of the board when the power connector  is facing you) but 6 analog pins (on the right side, top).  They are inputs and they take voltages from 0 to 5V and convert them into digital numbers from 0 to 1024 (the manual says this is 10 bits of resolution). 

When the potentiometer is connected to one of these inputs via its middle lead, and the outer leads are connected to ground and 5 Volts on the board, you can dial it from 0 on one side to 5 Volts on the other, with 2.5 V being the voltage when the arrow is in the center, and use the returned values as variables in the program.

The code from http://ardx.org/CIRC08 is here:

/*
  Analog Input
Demonstrates analog input by reading an analog sensor on analog pin 0 and
turning on and off a light emitting diode(LED)  connected to digital pin 13.
The amount of time the LED will be on and off depends on
the value obtained by analogRead().

The circuit:
* Potentiometer attached to analog input 0
* center pin of the potentiometer to the analog pin
* one side pin (either one) to ground
* the other side pin to +5V
* LED anode (long leg) attached to digital output 13
* LED cathode (short leg) attached to ground

* Note: because most Arduinos have a built-in LED attached
to pin 13 on the board, the LED is optional.

Created by David Cuartielles
Modified 16 Jun 2009
By Tom Igoe

http://arduino.cc/en/Tutorial/AnalogInput

*/

int sensorPin = 0;    // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int sensorValue = 0;  // variable to store the value coming from the sensor

void setup() {
  // declare the ledPin as an OUTPUT:
  pinMode(ledPin, OUTPUT); 
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);   
  // turn the ledPin on
  digitalWrite(ledPin, HIGH); 
  // stop the program for milliseconds:
  delay(sensorValue);         
  // turn the ledPin off:       
  digitalWrite(ledPin, LOW); 
  // stop the program for for milliseconds:
  delay(sensorValue);                 
}


What this program does is simply set the delay between turning the LED on and off to whatever the potentiometer is putting out. When you turn it hard left the delay is zero, when you the delay appears to be 1024 or about 1 second (since 1000 milliseconds  is 1 second).


The manual provides a way to make the LED start flashing only when the voltage reaches a certain threshold.  They provide this code to start the flashing when it reaches 512 ms (i.e. half way):

void loop() {
int threshold = 512;
if(analogRead(sensorPin) > threshold) {
digitalWrite(ledPin, HIGH); }
else{digitalWrite(ledPin, LOW);}
}

(I highlight the old void loop() code and comment it out, then paste the above code underneath it).
When you upload this the LED will remain off when the potentiometer arrow angle is anywhere between 0 and the middle and then it turns on when it is in the middle or below.  As they say, "you can adjust the sensitivity by changing the threshold value."

You can also make it fade, controlling the brightness of the LED directly from the potentiometer (you are familiar with this effect from volume knobs on guitars and stereos and amplifiers -- these are examples of potentiometers used to fade sound). To make the LED fade we change the Digital pin connecting the LED to the board from 13 to 9, i.e. int ledPin = 9;      // select the pin for the LED

The manual says to use the following for your void loop():

void loop() {
int value = analogRead(potPin) / 4;
analogWrite(ledPin, value);
}

When you try to compile this, of course, you'll get the error "potPin was not declared in this scope" This is obviously a typo (or a way to test how well we are now understanding programming at this point!).

Change it to sensorPin and you are golden! (int value = analogRead(sensorPin) / 4;)

void loop() {
int value = analogRead(sensorPin) / 4;
analogWrite(ledPin, value);
}
Why divide by 4? The manual says, "the analogRead() function returns a value from 0 to 1024 (10 bits) while the analogWrite() takes a value from 0 to 255 (8 bits)." So a lot of what one does to get one thing talking to another is to do conversion math so the scales match up.  As Einstein pointed out, everything is relative!

Now that we can control the brightness of an LED, the implication is that we can control a lot of variable elements. The book suggests combining lessons and control a servo with a potentiometer.

What I did, for fun, was to add the servo to CIRC-08 by putting my three-pin header down on the breadboard at holes 22, 23 and 24. Then I connected my servo and used a white wire to connect the Servo's white signal wire  to the hole  next to the positive pin of the LED on the board. Then I connected a red wire next to the Servo's red wire to the positive +5 V rail of my breadboard, and a black wire next to the Servo's black wire and then to the negative (gnd) rail of the breadboard. Then, without uploading any additional code, keeping the void loop() above,  I was able to use the potentiometer to control both the brightness of the LED and the position of the Servo.

The manual says to wire up the servo as we did in CIRC-04, and use the code from the example program in Arduino called "Knob" (File>Examples>Servo>Knob) and change one line of code:
int potpin = 0; ---> int potpin = 2; (be careful, potpin has all small p's, while  the usual convention is that the second work gets a cap! Misspelling can cause an error!)
Now your Servo should turn as you turn the potentiometer!

So I went ahead and uploaded the Example Knob file:

// Controlling a servo position using a potentiometer (variable resistor)
// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop()
{
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180)
  myservo.write(val);                  // sets the servo position according to the scaled value
  delay(15);                           // waits for the servo to get there
}


and then changed int potpin  = 0;  to int potpin =2; .

But nothing happened.  So I looked at the code and looked at my board and realized there was no need to change int potpin = 0; to intpotpin = 2; because the center lead of my potentiometer was already connected to analog input 0, not 2.  So there are some discrepancies in the manual. The schematic for CIRC-08 shows the potentiometer connecting to Arduino analog pin 0 and the code says int sensorPin = 0;  but then in the "Not Working" section they say "make sure you haven't accidentally connected the potentiometer's wiper to digital pin 2 rather than analog pin 2 (the row of pins beneath the power pins).  So from then they seem to be assuming you are hooked up to pin 2. Just be consistent and everything should work out fine!

The thing is, you don't really need this example sketch, which calls a library called "Servo.h" since you can use the potentiometer sketch above as well. But it is great to play with all this.









No comments:

Post a Comment