Skip to content


Arduino Pointers and the Ping for Automated High Five

highfive2Charles Stutzman submitted this article about using C pointers in Arduino code. He combines an Arduino, a ultrasonic range sensor and a servo in this article. Pointers are used to move data around. Much of the code here is intended to show the use of pointers. The Parallax Ping sensors and general servo interfacing is also covered.

Charles submitted this article as part of the uCHobby giveaway program. Read Charles’s article after the jump and leave a comment.

Charles Writes:

Pointers, pointers to pointers, and reading information at the memory address pointed to by the pointers. These are topics that I haven’t seen addressed in the Arduino environment yet.

I was having a problem getting a variable to pass globally from one function to another. I declared the variables that I wanted to use in multiple functions globally outside all the functions and setup(). I tried declaring the variable in every function, and passing it using the return function, and putting the variable to be passed in the function call, i.e. function(variable). No success, I kept getting errors about scope, or the program will compile and upload, but the variable will be empty in the other function where I am trying to read the value.

I talked to David at uCHobby about the problem, and he pointed me to an article about using the volatile modifier on variables. It is a modifier that is rarely taught in depth but can make a difference in the programming especially when there is an optimizer in use (the Arduino uses an optimizer to make the code more efficient or take up less memory, I am not sure which, David could tell you). [David: the volatile modifier tells the compiler not to keep a local copy of a variable in a register. Its important when an interrupt could update the value making a saved copy invalid.]

I built a set of code from a few examples to try and quickly make something work. I was trying to use a PING sensor, some servos, some LEDs, and the serial monitor. I built the system I was working with one piece at a time, starting with the PING. Compile example, upload and voila. Simple. I can put my hand in front of the sensor and the serial monitor reads the distance my hand is from the sensor. pingsensor servo

Next lets make the LEDs dim and brighten based on how far away the PING is from an object. Something like:

analogWrite(dimLED, inches);

where dimLED is a LED on a PWM pin that is dimming as the variable inches gets smaller. Success. I can make a sensor affect the LED.

Now let’s make the servo move. The Servo knob example works great for this. It lets us use an analog input to move a servo through its range. You will note that later in the actual example I put together, I did not use the servo library, or this example, but rather used an example from Robotgrrl.

Now lets make the ping sensor talk to the servo. Should be simple but the first attempt I had of this made things very jittery. The refresh rate on the servo and the PING sensor made it necessary for these to be set up as separate functions. Separate functions ended up meaning that we needed a timer to call them at timed intervals so that the refresh rates did not make the servo jittery. Separate functions and library calls eventually made it difficult to have the variables working correctly. The inches variable from the PING example was not passing to the servo function. Leaving me with a servo that did not move, but the PING was getting data. I moved the variable to make it global, and that didn’t fix the problem.

Scope errors, and undefined in this type messages drove me nuts. I consulted C++ tutorials on passing variables and global variables, and then tried the volatile modifier David at uC Hobby suggested. I talked to a computer programmer and he suggested I use pointers. Here is a good reference that helped me realize how to use pointers. I vaguely remember using pointers in my C programming class, but that was 8 years ago. I then set up the variable globalInches and a pointer to it *getInches:

int globalInches;

int* getInches=&globalInches;

To read the variables in and write the variables, as they are needed you have to reference them:

int inches1 = *getInches;

*getInches = inches;

The article about pointers goes into pointers to pointers, to pointers… and how to point to a memory address of a variable as opposed to a variable. The reason for pointing to the memory address instead of trying to pass the variable is that likely the program will try making a new variable rather than checking for the existence of a variable already. Whereas pointing to the memory address will get you the data that is in that position always. The last example they use is like this one:

int main()
{
    int instruments(12);
    int* p_instruments = &instruments;
    int** p_p_instruments(&p_instruments);
    int*** p_p_p_instruments = &p_p_instruments;
    ***p_p_p_instruments = 6;
}

Table for current information from above code

Variable Name Variable Type Memory Address Stored Value
instruments int 1279 6
p_instruments int* 1377 1279
p_p_instruments int** 1477 1377
p_p_p_instruments int*** 1000 1477

I put the last memory address lower than the first to show that a computer doesn’t care when a variable is declared, it will put it into memory at the first available location and during a program run, memory addresses can and will be emptied at any moment.

This makes instruments = 12, then points p_instruments to the address of instruments, then points p_p_instruments to the address of p_instruments, then points p_p_p_instruments to the address of p_p_instruments, then lastly dereferences p_p_p_instruments to put 6 in the instruments variable. Each * is a “dereference operator”, and takes the location that the variable has stored and uses it to look at the data in the memory location. The & symbol is “the address of operator”. It points the variable to the address of the variable it modifies. Reading the operators like they are called makes the line of code make more sense.

int* p_instruments = &instruments;

Reads like “int* p_instruments equals the address of instruments”.

*p_instruments = 6;

Reads like “dereferenced p_instruments equals 6”, meaning that the memory location that p_instruments is pointing to will now have 6 as it’s value. It just so happens that that memory location is the variable instruments, so now instruments = 6.

After getting it all working and tweaking the values I have a program that can make the servo with a flag on it move closer to the sensor till the servo is at or almost at the sensor, and then move it away as soon as it gets to an inch or so away. The action to start the servo to the sensor will be initiated by a button push. pushbutton

Note to programmers on keeping track of problem versions of code. In doing this example, and making it work from multiple source code parts and pieces, I ended up with many versions of the same file that all work in different fashions, or not at all. I apparently never saved any of the ones that had numerous errors in them, and I should have made a separate sketch folder for failed code, so that I could go back and see what didn’t work in doing this example. As it is I have only the memory of variable failures, and not the code to show and repeat the errors for this article. I wish I had a library of the bad code to be able to give the exact errors that came up.

highfive1The physical pin outs for the example is as follows using a Bare Bones Board kit:

Bare Bones Board Arduino in the breadboard

4 pin momentary on push-button with one pin at pin 2, one on the opposite side to 5+, and one to

ground with a pull down resistor

Servo with power and ground to the respective power lines, and the signal to pin 6

PING sensor with power and ground to the respective power lines, and the signal to pin 7

LED to pin 13 and ground

Here is the breadboard and Bare Bones Board with the sensor, servo, pushbutton and LED hooked up ready to go for this example.

/*
||
|| @file highfivePINGaervo.pde
|| @version 1.0
|| @author Charles Stutzman
|| @contact charlesd.stutzmansr@gmail.com
||
|| @description
|| | This sketch takes a button push and initiates a high five style motion from a servo to a PING 
|| | sensor.
|| | based off of the TimedAction example ThreeExamplesAtOnce.pde by Alexander Brevig 
|| | alexanderbrevig@gmail.com
|| | has three TimedActions, that interact and initiate a high five motion, and one that is a 
|| | heartbeat to show activity on the board
|| | May contain parts and pieces from Ardiuno Examples Library (PING, Blink LED, Button 
|| | digital Input, and http://robotics.learnhub.com/lesson/1766-arduino-and-servos
|| #
||
*/

#include 
//TimedAction initialization of the circuits heartbeat
TimedAction heartbeatAction = TimedAction(1000,heartbeat);

//TimedAction initialization of the Servo position function
TimedAction servoAction = TimedAction(20,servo);

//TimedAction initialization of the PING sensor read function
TimedAction pingAction = TimedAction(200,ping);

//TimedAction initialization of the button push for the start of a "high five" between the servo flag //and the PING sensor
TimedAction buttonAction = TimedAction(50,button);

// globalvariables for ping and servo functions
int globalInches;
int* getInches=&globalInches;

//heartbeat variables and pins
const int ledPin = 13;
boolean ledState = false;

//servo variables and pins
const int servo1 = 6;
int servoAngle1;
int pulseWidth1;

//ping variables and pins
const int pingPin = 7;

//button pins and variables
const int buttonPin= 2;
int buttonState = 0;

//set up for servo position setting
void servoPulse1 (int servo1, int servoAngle1) {
  pulseWidth1 = (servoAngle1 * 11) + 500; // Converts angle to microseconds
  digitalWrite(servo1, HIGH); // Set servo high (turns it on)
  delayMicroseconds(pulseWidth1); // Wait a very very small amount
  digitalWrite(servo1, LOW); // Set servo low (turns it off)
  // Typical Refresh cycle of servo (20 ms) normally a delay would be here, but the delay is in the //TimedAction calls
}

void setup() {
  pinMode(ledPin,OUTPUT);
  digitalWrite(ledPin,ledState);
  Serial.begin(9600);// there for debugging and watching the sensor values
  pinMode(servo1, OUTPUT); 
  pinMode(buttonPin, INPUT);
}

void loop() {
  heartbeatAction.check(); //trigger every second
  servoAction.check(); //trigger every 20 millisecond
  pingAction.check();//trigger every 200 millieconds
  buttonAction.check();//trigger every 50 milliseconds
}

//checks for a button push to initiate the "high five"
void button() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH){
    *getInches = 6;// makes globalInches go to a value that the servo will move when the servo checks //the value
  }
}

//beats the LED at pin 13 at 1 beat per second as a heartbeat
void heartbeat() {
  ledState ? ledState=false : ledState=true;
  digitalWrite(ledPin,ledState);
}

//moves the servo according to data in *getInches
void servo() {
  int inches1 = *getInches;
  if (inches1 > 2) {
    if (inches1 < 7) {
      servoAngle1 = inches1*3;
    } 
  }
  else {
    servoAngle1 = 60;
  }
  servoPulse1(servo1, servoAngle1);
  Serial.print(inches1);
  Serial.println(" inches from sensor."); //datalogging for debugging
}

//gets data from the ping sensor
void ping() {
  // establish variables for duration of the ping, 
  // and the distance result in inches and centimeters:
  long duration, inches;

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);

  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);
  Serial.print(inches);
  Serial.print(" inches is what the sensor just read.");//there to help identify the number
  Serial.println();

  *getInches = inches;
}

long microsecondsToInches(long microseconds) {
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second). This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf

  return microseconds / 74 / 2;
}

Here is the sequenced pictures of the action:

highfive

Have fun and enjoy making the Arduino interact with others and its environment.

Charles Stutzman

Posted in Arduino, Ideas, Microcontroller, Projects.


One Response

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. signal7 says

    While this is a good introduction to pointers, it doesn’t mention the best feature of using pointers: arithmetic.

    If you declare an array of type int, what you are really doing is creating a pointer to a location in memory that consists of a sequence of 4 byte blocks (because int’s are typically 4 bytes to most* compilers). You can then reference the elements of the array using simple addition and subtraction. array[3] is the same as *(array + 3). I know that might seem confusing, but the compiler knows the type of the array and also knows that each element is 4 bytes so when you add some number to the pointer, the compiler internally computes array + (3 * 4) to arrive at the correct address.

    This might not seem useful – I’ll grant you that. However, when you start using arrays of structs or other more complicated data structures, this will be holy grail of understanding the usefulness of pointers. Maybe it’s overkill for the arduino environment, but with these AVR parts coming with more and more memory, I’m sure more data processing applications will be coming.

    * I say most compilers because there is no guarantee that an int is 4 bytes and you can’t really depend on it being 4 bytes if you want to write reliable code. If you really need a 4 byte int, use int32 instead.