Servo control via 2 buttons (w/ Pololu controller)

Hello all,

I have been playing around with servo controllers lately, and have run into a roadblock. Currently I have been able to get servos working reliably with a Pololu 8-channel servo controller (http://www.pololu.com/catalog/product/207) via joystick control. I then wanted to achieve similar control with some simple push buttons, as seen on the Sparkfun joystick shield (http://www.sparkfun.com/commerce/product_info.php?products_id=9760), which I am using here.

My problem is that I can't seem to get the servos to respond. I've made several attempts at if statements and switch cases that read the button states, simplifying my approach each time in the attempt to weed out what I'm doing wrong, but I'm completely stumped.

Basically, my setup is this: I have the joystick shield mounted atop the Arduino. The arduino is connected to the Pololu controller via the TX port for communication, currently at a baud rate of 38400. The Arduino is also communicating with an LCD panel (http://www.sparkfun.com/commerce/product_info.php?products_id=9052), which is connected via digital pins 13, 12, 11, 10, 9 and 8 (and is working perfectly).

Mounted on the joystick shield is a joystick communicating via analog pins 0 and 1. I have also set up a second, external joystick attached to analog pins 2 and 3. Both joysticks work fine. Also mounted on the shield are four large push buttons, connected to digital pins 3 (right), 4 (up), 5 (down), and 6 (left). Each joystick also has a push button, and these are connected to digital pins 2 (on-shield stick) and 7 (off-shield stick) respectively.

It should be noted that the current purpose of the LCD is to display the outputs for all of these controls.

What's maddening is that I know the buttons are responding properly, since I can monitor their output in realtime via the LCD panel, but the servos will not respond to those inputs. They just stay locked in the rest position. The joystick controlled ones continue to work perfectly, and the LCD updates fine.

My last attempt was to try and apply the same output scheme the joysticks are using, since nothing else seemed to work. This involved a three-state IF statement and a map function as seen below:

  if (digitalRead(PIN_BUTTON_UP) == LOW) 
  {
    statusUD = 0;
  }
  else if (digitalRead(PIN_BUTTON_DOWN) == LOW) 
  {
    statusUD = 2;
  }
  else
  {
    statusUD = 1;
  }

  int outputUD = map(statusUD, 0, 2, 500, SERVO_LIMIT);
  
  put(7,outputUD);

...where pressing one button turns the servo one way, pressing another button turns the servo the opposite way, and leaving both unpressed turns the servo back to the rest position. "put(servo#, position)" is used to communicate with the servo controller. Note that on the Sparkfun joystick shield, button feedback is inversed; pressing a button gives a LOW state, releasing it gives a HIGH state. Again, the LCD reflects that this statement is working; but the servos do not move.

This if statement obviously lacks decent safety constraints (2 buttons pressed at once, for example), but that's just because I was trying to make it as simple as possible in the hope that it'd work, and then improve it from there.

I've no clue what I'm missing.

EDIT: I should note that I've also tried using FOR statements with the buttons in an attempt to make the servo update its position incrementally, based on how long either of the two buttons is held down. This doesn't really work, though, since the FOR statement locks up the Arduino's processor until it finishes, meaning the joystick signals are ignored during that time. For the moment I'm content to just have the servo respond to one of three absolute states based on the status of a button pair.

I've also used && operators in the if statements to try and make them more compact and robust, but eventually removed them in my quest to simplify my solution until it actually worked.

Thanks again for any help.

Here’s my code (couldn’t fit it all in one post):

I hope you’ll forgive the messy comments; I’ve been cobbling this together from numerous sources, each with their own notes…

/*
  Manage 6 servo motors with Pololu Servo controller
 
 Read two analog input pins from a joystick (vertical and
 horizotal axis) and set servo position (from 500 to 5500)
 in according with the joystick position (from 0 to 1023)
 
 The circuit:
 Check www.fabiobiondi.com/blog for video and images.
 
 created 04 december 2009
 by Fabio Biondi - http:www.fabiobiondi.com
 
 */

/* ------------------------------------------------------------
 LiquidCrystal Library - Hello World
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
 The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 
 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 8 Feb 2010
 by Tom Igoe
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 -----------------------------------*/

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);


// JOYSTICK VARIABLES

const int joyH1 = 0;
const int joyV1 = 1;
const int joyH2 = 2;
const int joyV2 = 3;

  int statusUD = 1;
  int statusLR = 1;


int SERVO_LIMIT = 4500;


// Store the Arduino pin associated with each input [SPARKFUN STATUS MONITOR] ----------------
const int PIN_BUTTON_A_SELECT = 2; // Select button is triggered when joystick is pressed
const int PIN_BUTTON_B_SELECT = 7; // Select button is triggered when joystick is pressed

const int PIN_BUTTON_RIGHT = 3;
const int PIN_BUTTON_UP = 4;
const int PIN_BUTTON_DOWN = 5;
const int PIN_BUTTON_LEFT = 6;

const int PIN_ANALOG_A_X = 0;
const int PIN_ANALOG_A_Y = 1;
const int PIN_ANALOG_B_X = 2;
const int PIN_ANALOG_B_Y = 3;

//---------------



void setup()// run once, when the sketch starts
{

  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  //lcd.print("hello, world!");
  //lcd.print(Serial.read());


  //begin serial for servos
  Serial.begin(38400);


  //SPARKFUN LCD STATUS MONITOR TEST ---------------------------


  // Specify each pin connected to a pushbutton as an input.
  // Also enable the Arduino's internal "pull-up" resistors
  // for each pushbutton we want to read--this means the shield
  // doesn't need to have resistors on it.
  // Note that when a pull-up resistor is used on a pin the
  // meaning of the values read are reversed compared to their
  // usual meanings:
  //    * HIGH = the button is not pressed
  //    * LOW = the button is pressed  
  pinMode(PIN_BUTTON_RIGHT, INPUT);  
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);

  pinMode(PIN_BUTTON_LEFT, INPUT);  
  digitalWrite(PIN_BUTTON_LEFT, HIGH);

  pinMode(PIN_BUTTON_UP, INPUT);  
  digitalWrite(PIN_BUTTON_UP, HIGH);

  pinMode(PIN_BUTTON_DOWN, INPUT);  
  digitalWrite(PIN_BUTTON_DOWN, HIGH);

  pinMode(PIN_BUTTON_B_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_B_SELECT, HIGH);  

  pinMode(PIN_BUTTON_B_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_A_SELECT, HIGH); 

}

void loop() //Main program loop, executes forever after setup()
{

  // Move servo motors connected to Servo Controllers pins: 0
  // in according with the analog joystick value
  int outputJV1 = map(analogRead(joyV1), 0, 1023, 500, 5200);

  // Avoid to set servo position > 4500 (but you can modify this condition to fix your needs)
  if (outputJV1>SERVO_LIMIT)
    outputJV1 = SERVO_LIMIT;

  put(0,outputJV1);

  // Wait 1 ms
  delay(3);


  // Using Joystick 1, Move servo motors connected to Servo Controllers pins: 1
  // in according with the analog joystick value
  int outputJH1 = map(analogRead(joyH1), 0, 1023, 500, 5200);

  // Avoid to set servo position &gt; 4500 (but you can modify this condition to fix your needs)
  if (outputJH1>SERVO_LIMIT)
    outputJH1 = SERVO_LIMIT;

  put(1,outputJH1);

  // Wait 1 ms
  delay(3);

  //   ------------------------

  // Using Joystick 2, move servo motors connected to Servo Controllers pins: 2
  // in according with the analog joystick value
  int outputJV2 = map(analogRead(joyV2), 0, 1023, 500, 5200);

  // Avoid to set servo position > 4500 (but you can modify this condition to fix your needs)
  if (outputJV2>SERVO_LIMIT)
    outputJV2 = SERVO_LIMIT;

  put(2,outputJV2);

  // Wait 1 ms
  delay(3);

  // Move servo motors connected to Servo Controllers pins: 3
  // in according with the analog joystick value
  int outputJH2 = map(analogRead(joyH2), 0, 1023, 500, 5200);

  // Avoid to set servo position &gt; 4500 (but you can modify this condition to fix your needs)
  if (outputJH2>SERVO_LIMIT)
    outputJH2 = SERVO_LIMIT;

  put(3,outputJH2);

  // Wait 1 ms
  delay(3);


  //----------------------------------


  // Using buttons Right and Left, move servo motors connected to Servo Controllers pins: 4
  // in according with the analog joystick value  [C = CENTER, R = 5200, L = 500]


    // Decide whether I want the servo to rotate clockwise or counterclockwise based on which button is being pressed

  if (digitalRead(PIN_BUTTON_RIGHT) == 0) 
  {
    statusLR = 0;
  }
  else if (digitalRead(PIN_BUTTON_LEFT) == 0) 
  {
    statusLR = 2;
  }
  else
  {
    statusLR = 1;
  }

  int outputLR = map(statusLR, 0, 2, 500, SERVO_LIMIT);
  
  put(6,outputLR);





  //---------------------------------------------

  // Using buttons Up and Down, move servo motors connected to Servo Controllers pins: 5
  // in according with the analog joystick value [C = CENTER, R = 5200, L = 500]


    // Decide whether I want the servo to rotate clockwise or counterclockwise based on which button is being pressed

  if (digitalRead(PIN_BUTTON_UP) == LOW) 
  {
    statusUD = 0;
  }
  else if (digitalRead(PIN_BUTTON_DOWN) == LOW) 
  {
    statusUD = 2;
  }
  else
  {
    statusUD = 1;
  }

  int outputUD = map(statusUD, 0, 2, 500, SERVO_LIMIT);
  
  put(7,outputUD);





  // LCD TEST BRANCH -----------------------------------

  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);
  // print the number of seconds since reset:
  //lcd.print(Serial.read());

  //SPARKFUN TEST LCD READOUT---------------------

  // Print the current values of the inputs (joystick and
  // buttons) to the console.
  lcd.print("L");
  lcd.print(digitalRead(PIN_BUTTON_LEFT));
  //lcd.print(" ");

  lcd.print("R");
  lcd.print(digitalRead(PIN_BUTTON_RIGHT));
  //lcd.print(" ");

  lcd.print("U");
  lcd.print(digitalRead(PIN_BUTTON_UP));
  //lcd.print(" ");

  lcd.print("D");
  lcd.print(digitalRead(PIN_BUTTON_DOWN));
  //lcd.print(" ");

  lcd.print("AS");
  lcd.print(digitalRead(PIN_BUTTON_A_SELECT));
  //lcd.print(" ");

  //lcd.print("BS");
  //lcd.print(digitalRead(PIN_BUTTON_B_SELECT));
  //lcd.print(" ");

//-------------
  lcd.print("Q");
  lcd.print(outputUD);
  //lcd.print(" ");
//-------------

  lcd.setCursor(0, 1);

  lcd.print("E");
  lcd.print(analogRead(PIN_ANALOG_A_X));
  //lcd.print(" ");

  lcd.print("F");
  lcd.print(analogRead(PIN_ANALOG_A_Y));
  //lcd.print(" ");  

  lcd.print("G");
  lcd.print(analogRead(PIN_ANALOG_B_X));
  //lcd.print(" ");

  lcd.print("H");
  lcd.print(analogRead(PIN_ANALOG_B_Y));
  //lcd.print(" ");  



  //lcd.println();  

  // END LCD TEST BRANCH -----------------------------------


  // Wait 100 ms
  //delay(50);


}

/*
 Move Servo
 */
void put(int servo, int angle){

  //servo is the servo number (typically 0-7)
  //angle is the absolute position from 500 to 5500

  unsigned char buff[6];

  unsigned int temp;
  unsigned char pos_hi,pos_low;

  //Convert the angle data into two 7-bit bytes
  temp=angle&0x1f80;
  pos_hi=temp>>7;
  pos_low=angle & 0x7f;

  //Construct a Pololu Protocol command sentence
  buff[0]=0x80; //start byte
  buff[1]=0x01; //device id
  buff[2]=0x04; //command number
  buff[3]=servo; //servo number
  buff[4]=pos_hi; //data1
  buff[5]=pos_low; //data2

  //Send the command to the servo controller
  for(int i=0;i<6;i++){
    Serial.print(buff[i],BYTE);
  }

}

/*
* Set Servo Speed (not used in this sketch)
 */
void servoSetSpeed(int servo, int speed){
  //servo is the servo number (typically 0-7)
  //speed is servo speed (1=fastest, 127=slowest)
  //set speed to zero to turn off speed limiting

  unsigned char buff[5];
  unsigned char speedcmd;

  speedcmd=speed&0x7f;//take only lower 7 bits of speed

  buff[0]=0x80;//start byte
  buff[1]=0x01;//device id
  buff[2]=0x01;//command number
  buff[3]=servo;//servo number
  buff[4]=speed;//data1

  for(int i=0;i<5;i++){
    Serial.print(buff[i],BYTE);
  }

}

EDIT: I suppose I should also mention that the current end goal for this project is basically to construct a human-controllable robot arm with a status display.

Debug hint: Cut your code down to the bare minimum required to show up your problem. Your LCD code simply confuses things

Read this bit, then read it again:

 pinMode(PIN_BUTTON_B_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_B_SELECT, HIGH);  

  pinMode(PIN_BUTTON_B_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_A_SELECT, HIGH);
statusUD = 0;
  }
  else if (digitalRead(PIN_BUTTON_DOWN) == LOW)
  {
    statusUD = 2;
  }
  else
  {
    statusUD = 1;
  }

  int outputUD = map(statusUD, 0, 2, 500, SERVO_LIMIT);

Why "map"?

Thank you for your speedy response, AWOL:

I’m using ‘map’ there because that’s the same setup my joysticks are relying on, and they’re working. Nothing I’ve tried has worked so far, so I figured it was worth trying to implement the buttons in a similar way. I agree it’s a little odd, though.

This horrible kludge was my original attempt, once I decided to focus on a 3-state button-based switch (it’s broken as hell, but the core approach may have been better):

//----------------------------------


   // Using buttons Right and Left, move servo motors connected to Servo Controllers pins: 4
   // in according with the analog joystick value  [C = CENTER, R = 5200, L = 500]
   int outputLR = 2500;
   const char* sumstatusLR = "C";
   int STATUS_RIGHT = digitalRead(PIN_BUTTON_RIGHT);
   int STATUS_LEFT = digitalRead(PIN_BUTTON_LEFT);

   
   // Decide whether I want the servo to rotate clockwise or counterclockwise based on which button is being pressed
   
   if (STATUS_RIGHT == HIGH && STATUS_LEFT == HIGH) {
     sumstatusLR = "C";
   }
   else if (STATUS_RIGHT == LOW && STATUS_LEFT == HIGH)
   {
     sumstatusLR = "R";
   }
   else if (STATUS_LEFT == LOW && STATUS_RIGHT == HIGH)
   {
     sumstatusLR = "L";
   }
   
   // Regulate the rate at which the instructions are updated based on how long one of the buttons is pressed
   
   if (sumstatusLR = "C")
   {   
    outputLR = 2500;
    put(4,outputLR);
   }
   
      if (sumstatusLR = "R")
   {
          for(int upshift=outputLR; upshift<5500; upshift++)
     {
       outputLR = upshift;
        // Avoid to set servo position > 4500 (but you can modify this condition to fix your needs)
       if (outputLR>SERVO_LIMIT)
        {
         outputLR = SERVO_LIMIT;
        }
       put(4,outputLR);
       // Wait 1 ms
       delay(3);
     }  
     
   }
   
      if (sumstatusLR = "L")
   {
          for(int downshift=outputLR; downshift>500; downshift--)
     {
       outputLR = downshift;
        // Avoid to set servo position > 4500 (but you can modify this condition to fix your needs)
       if (outputLR>SERVO_LIMIT)
        {
         outputLR = SERVO_LIMIT;
        }
       put(4,outputLR);
       // Wait 1 ms
       delay(3);
     }  
     
   }

//---------------------------------------------

   // Using buttons Up and Down, move servo motors connected to Servo Controllers pins: 5
   // in according with the analog joystick value [C = CENTER, R = 5200, L = 500]
   int outputUD = 2500;
   const char* sumstatusUD = "C";
   int STATUS_UP = digitalRead(PIN_BUTTON_UP);
   int STATUS_DOWN = digitalRead(PIN_BUTTON_DOWN);

   
   // Decide whether I want the servo to rotate clockwise or counterclockwise based on which button is being pressed
   
   if (STATUS_UP == HIGH && STATUS_DOWN == HIGH)
   {
     sumstatusUD = "C";
   }
   else if (STATUS_UP == LOW && STATUS_DOWN == HIGH)
   {
     sumstatusUD = "R";
   }
   else if (STATUS_DOWN == LOW && STATUS_UP == HIGH)
   {
     sumstatusUD = "L";
   }
   
   // Regulate the rate at which the instructions are updated based on how long one of the buttons is pressed
   
   while (sumstatusUD = "C")
   {   
    outputUD = 2500;
    put(5,outputUD);
   }
   
      if (sumstatusUD = "R")
   {
          for(int upshift=outputUD; upshift<5500; upshift++)
     {
       outputUD = upshift;
        // Avoid to set servo position > 4500 (but you can modify this condition to fix your needs)
       if (outputUD>SERVO_LIMIT)
        {
         outputUD = SERVO_LIMIT;
        }
       put(5,outputUD);
       // Wait 1 ms
       delay(3);
     }  
     
   }
   
      if (sumstatusUD = "L")
   {
          for(int downshift=outputUD; downshift>500; downshift--)
     {
       outputUD = downshift;
        // Avoid to set servo position > 4500 (but you can modify this condition to fix your needs)
       if (outputUD>SERVO_LIMIT)
        {
         outputUD = SERVO_LIMIT;
        }
       put(5,outputUD);
       // Wait 1 ms
       delay(3);
     }  
     
   }

…I completely missed that error. XP It’s corrected now, but it shouldn’t be affecting anything important, even so; I’m not using those buttons for anything right now.

You’re right about the LCD complicating things…I imagine the core problem is probably very simple (once I find it, at any rate), but I think I’ve been pretty careful. Considering I missed a mistake as obvious as that, though, I guess I really shouldn’t be one to talk. I’ll cut the LCD out of my software for now and attempt to debug the remainder (and clean up all the junk comments!)…

I went through and cleaned up the program; sadly, though, my problem still remains. I’m now going to go through and cull the LCD-related bits in order to try and isolate the key issue, but at least the original code is all shiny now. =P

//-------------------------------------------------------------------------
  // - CONSTANTS AND INITIAL VARIABLES -
//-------------------------------------------------------------------------

// Included libraries
#include <LiquidCrystal.h> 

// Initialize LCD library with the numbers of the interface pins
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);

// JOYSTICK ANALOG PINS
const int PIN_ANALOG_A_X      = 0;
const int PIN_ANALOG_A_Y      = 1;
const int PIN_ANALOG_B_X      = 2;
const int PIN_ANALOG_B_Y      = 3;

// BUTTON DIGITAL PINS
const int PIN_BUTTON_A_SELECT = 2; // Select button is triggered when joystick is pressed
const int PIN_BUTTON_B_SELECT = 7; // Select button is triggered when joystick is pressed
const int PIN_BUTTON_RIGHT    = 3;
const int PIN_BUTTON_UP       = 4;
const int PIN_BUTTON_DOWN     = 5;
const int PIN_BUTTON_LEFT     = 6;

// BUTTON-PAIR STATUS VARIABLES
int statusUD = 1;
int statusLR = 1;

//SERVO_MAX and SERVO_MIN variables
int SERVO_MAX = 4500;
int SERVO_MIN = 500;

//#########################################################################

void setup()
{
  // Set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  //lcd.print("System engaged~");

  //Create serial channel for Pololu controller instructions
  Serial.begin(38400);

  // Specify each pin connected to a pushbutton as an input.
  // Also enable the Arduino's internal "pull-up" resistors
  // for each pushbutton we want to read--this means the shield
  // doesn't need to have resistors on it.
  // Note that when a pull-up resistor is used on a pin the
  // meaning of the values read are reversed compared to their
  // usual meanings:
  //    * HIGH = the button is not pressed
  //    * LOW = the button is pressed  
  
  pinMode(PIN_BUTTON_RIGHT, INPUT);  
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);

  pinMode(PIN_BUTTON_LEFT, INPUT);  
  digitalWrite(PIN_BUTTON_LEFT, HIGH);

  pinMode(PIN_BUTTON_UP, INPUT);  
  digitalWrite(PIN_BUTTON_UP, HIGH);

  pinMode(PIN_BUTTON_DOWN, INPUT);  
  digitalWrite(PIN_BUTTON_DOWN, HIGH);

  pinMode(PIN_BUTTON_B_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_B_SELECT, HIGH);  

  pinMode(PIN_BUTTON_A_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_A_SELECT, HIGH); 
}

//#########################################################################

void loop()
{
//-------------------------------------------------------------------------
  // - SERVO CONTROL INTERFACE -
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 0
  // Controlled by Joystick_A_Y
  int output_J_A_Y = map(analogRead(PIN_ANALOG_A_Y), 0, 1023, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(0,output_J_A_Y);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 1
  // Controlled by Joystick_A_X
  int output_J_A_X = map(analogRead(PIN_ANALOG_A_X), 0, 1023, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(1,output_J_A_X);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 2
  // Controlled by Joystick_B_Y
  int output_J_B_Y = map(analogRead(PIN_ANALOG_B_Y), 0, 1023, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(2,output_J_B_Y);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 3
  // Controlled by Joystick_B_X
  int output_J_B_X = map(analogRead(PIN_ANALOG_B_X), 0, 1023, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(3,output_J_B_X);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 4
  // Controlled by button pair (LEFT,RIGHT)
  // IF statement checks whether servo moves to MAX, MIN, or CENTER value
  if (digitalRead(PIN_BUTTON_RIGHT) == LOW) 
  {
    statusLR = 0;
  }
  else if (digitalRead(PIN_BUTTON_LEFT) == LOW) 
  {
    statusLR = 2;
  }
  else
  {
    statusLR = 1;
  }
  // The three states are mapped to the servo's signal range
  int outputLR = map(statusLR, 0, 2, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(4,outputLR);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 5
  // Controlled by button pair (UP,DOWN)
  // IF statement checks whether servo moves to MAX, MIN, or CENTER value
  if (digitalRead(PIN_BUTTON_UP) == LOW) 
  {
    statusUD = 0;
  }
  else if (digitalRead(PIN_BUTTON_DOWN) == LOW) 
  {
    statusUD = 2;
  }
  else
  {
    statusUD = 1;
  }
  // The three states are mapped to the servo's signal range
  int outputUD = map(statusUD, 0, 2, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(5,outputUD);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------
  // - LCD DISPLAY INTERFACE -
//-------------------------------------------------------------------------
  // Set cursor to column 0, line 0
  // NOTE: Line 1 = second row, counting begins with 0):
  lcd.setCursor(0, 0);
//-------------------------------------------------------------------------
  // Print the current values of the control inputs to the LCD
//-------------------------------------------------------------------------
  // BUTTON_LEFT
  lcd.print("L");
  lcd.print(digitalRead(PIN_BUTTON_LEFT));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  // BUTTON_RIGHT
  lcd.print("R");
  lcd.print(digitalRead(PIN_BUTTON_RIGHT));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  //BUTTON_UP
  lcd.print("U");
  lcd.print(digitalRead(PIN_BUTTON_UP));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  //BUTTON_DOWN
  lcd.print("D");
  lcd.print(digitalRead(PIN_BUTTON_DOWN));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  //BUTTON_A_SELECT
  lcd.print("AS");
  lcd.print(digitalRead(PIN_BUTTON_A_SELECT));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  //BUTTON_B_SELECT
  lcd.print("BS");
  lcd.print(digitalRead(PIN_BUTTON_B_SELECT));
  lcd.print(" ");
//-------------------------------------------------------------------------
  // Set cursor to column 0, line 2
  // NOTE: Line 1 = second row, counting begins with 0):
  lcd.setCursor(0, 1);
//-------------------------------------------------------------------------
  //JOYSTICK_A_X
  lcd.print("E");
  lcd.print(analogRead(PIN_ANALOG_A_X));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  //JOYSTICK_A_Y
  lcd.print("F");
  lcd.print(analogRead(PIN_ANALOG_A_Y));
  //lcd.print(" ");  
//-------------------------------------------------------------------------
  //JOYSTICK_B_X
  lcd.print("G");
  lcd.print(analogRead(PIN_ANALOG_B_X));
  //lcd.print(" ");
//-------------------------------------------------------------------------
  //JOYSTICK_B_Y
  lcd.print("H");
  lcd.print(analogRead(PIN_ANALOG_B_Y));
  //lcd.print(" ");  
//-------------------------------------------------------------------------
}

//#########################################################################

//-------------------------------------------------------------------------
  // - CUSTOM FUNCTIONS AND LIBRARIES -
//-------------------------------------------------------------------------
// Signal Pololu controller; set a given servo to a given position
void servoMove(int servo, int angle)
{
  // 'Servo' is the servo number (typically 0-7)
  // 'Angle' is the absolute position from 500 to 5500
  unsigned char buff[6];
  unsigned int temp;
  unsigned char pos_hi,pos_low;
  // Convert the angle data into two 7-bit bytes
  temp=angle&0x1f80;
  pos_hi=temp>>7;
  pos_low=angle & 0x7f;
  // Construct a Pololu protocol command sentence
  buff[0]=0x80; //start byte
  buff[1]=0x01; //device id
  buff[2]=0x04; //command number
  buff[3]=servo; //servo number
  buff[4]=pos_hi; //data1
  buff[5]=pos_low; //data2
  // Send the command to the servo controller
  for(int i=0;i<6;i++){
    Serial.print(buff[i],BYTE);
  }
}
//-------------------------------------------------------------------------
// END PROGRAM
//#########################################################################

Alright…AWOL, if you’re still there, here is the refactored code without the joysticks or the LCD implemented. I’ve tested this and it still doesn’t work, which leaves me very confused. What should be happening, as far as I can tell, is that for each button-pair - UP and DOWN, for example - pressing one button should send a signal of 0 or 2 to “statusUD”, which then results in “outputUD” being given a mapped value of 500 or 5500, respectively, which is then sent to the servo controller. When neither button in the pair is pressed, outputUD should give a value of 3000 instead. These values should remain constant so long as I hold down either button in the pair, meaning the servo should move to either its maximum or minimum position and stay there until I release one button, at which point it snaps back to the rest position.

I verified that “outputUD” and “statusUD” are both behaving properly via the LCD panel. But even in this new, simplified sketch, the servos will not move.

I should mention that while I’ve cut out the LCD and joysticks in software, I’ve not changed my hardware around any, so it could be a hardware problem, I suppose. But that seems very unlikely, considering that everything else seems to work perfectly.

This must be something really, really obvious for me to be this stuck. Any ideas? I’ll try and play with it some more in the meantime. u)o.=)o_[@[}

Thanks again.

// BUTTON DIGITAL PINS
const int PIN_BUTTON_A_SELECT = 2; // Select button is triggered when joystick is pressed
const int PIN_BUTTON_B_SELECT = 7; // Select button is triggered when joystick is pressed
const int PIN_BUTTON_RIGHT    = 3;
const int PIN_BUTTON_UP       = 4;
const int PIN_BUTTON_DOWN     = 5;
const int PIN_BUTTON_LEFT     = 6;

// BUTTON-PAIR STATUS VARIABLES
int statusUD = 1;
int statusLR = 1;

// SERVO_MAX and SERVO_MIN variables
int SERVO_MAX                 = 5500;
int SERVO_MIN                 = 500;

int DELAY                     = 0;

void setup()
{
    // Create serial channel for Pololu controller instructions
  Serial.begin(38400);

  // Specify each pin connected to a pushbutton as an input.
  // Also enable the Arduino's internal "pull-up" resistors
  // for each pushbutton we want to read--this means the shield
  // doesn't need to have resistors on it.
  // Note that when a pull-up resistor is used on a pin the
  // meaning of the values read are reversed compared to their
  // usual meanings:
  //    * HIGH = the button is not pressed
  //    * LOW = the button is pressed  
  
  pinMode(PIN_BUTTON_RIGHT, INPUT);  
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);

  pinMode(PIN_BUTTON_LEFT, INPUT);  
  digitalWrite(PIN_BUTTON_LEFT, HIGH);

  pinMode(PIN_BUTTON_UP, INPUT);  
  digitalWrite(PIN_BUTTON_UP, HIGH);

  pinMode(PIN_BUTTON_DOWN, INPUT);  
  digitalWrite(PIN_BUTTON_DOWN, HIGH);

  pinMode(PIN_BUTTON_B_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_B_SELECT, HIGH);  

  pinMode(PIN_BUTTON_A_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_A_SELECT, HIGH); 
}


void loop()
{
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 4
  // Controlled by button pair (LEFT,RIGHT)
  // IF statement checks whether servo moves to MAX, MIN, or CENTER value
  if (digitalRead(PIN_BUTTON_RIGHT) == LOW) 
  {
    statusLR = 0;
  }
  else if (digitalRead(PIN_BUTTON_LEFT) == LOW) 
  {
    statusLR = 2;
  }
  else
  {
    statusLR = 1;
  }
  // The three states are mapped to the servo's signal range
  int outputLR = map(statusLR, 0, 2, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(4,outputLR);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(DELAY);
//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 5
  // Controlled by button pair (UP,DOWN)
  // IF statement checks whether servo moves to MAX, MIN, or CENTER value
  if (digitalRead(PIN_BUTTON_UP) == LOW) 
  {
    statusUD = 0;
  }
  else if (digitalRead(PIN_BUTTON_DOWN) == LOW) 
  {
    statusUD = 2;
  }
  else
  {
    statusUD = 1;
  }
  // The three states are mapped to the servo's signal range
  int outputUD = map(statusUD, 0, 2, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(5,outputUD);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(DELAY); 
}

//-------------------------------------------------------------------------
  // - CUSTOM FUNCTIONS AND LIBRARIES -
//-------------------------------------------------------------------------
// Signal Pololu controller; set a given servo to a given position
void servoMove(int servo, int angle)
{
  // 'Servo' is the servo number (typically 0-7)
  // 'Angle' is the absolute position from 500 to 5500
  unsigned char buff[6];
  unsigned int temp;
  unsigned char pos_hi,pos_low;
  // Convert the angle data into two 7-bit bytes
  temp=angle&0x1f80;
  pos_hi=temp>>7;
  pos_low=angle & 0x7f;
  // Construct a Pololu protocol command sentence
  buff[0]=0x80;    // Start byte
  buff[1]=0x01;    // Device id
  buff[2]=0x04;    // Command number
  buff[3]=servo;   // Servo number
  buff[4]=pos_hi;  // Data1
  buff[5]=pos_low; // Data2
  // Send the command to the servo controller
  for(int i=0;i<6;i++){
    Serial.print(buff[i],BYTE);
  }
}

Your not using a 9v battery for power are you?

No, zoomkat; I'm using a 9-volt power adapter, the one sold by Adafruit Industries. The Pololu controller has two power circuits, one for the servos and one for the control circuitry itself. I've hooked up the raw 9 volts (pin Vin) to the processing circuitry, and the 5v pin to the servos. For some reason, this arrangement only seems to work properly when I also connect the Arduino to the computer USB cable, at the same time; perhaps there's not enough amperage without it? I've been meaning to investigate this as well and see what I'd need to do to run it without the PC connection, but haven't got that far yet.

If it isn't already quite apparent, I'm fairly new to both programming and electronic hardware, so there is still much that I'm unfamiliar with...

Why would the use of a battery be important? Were you thinking the battery might be dying, were I using one?

…and the servos are powered by the 5v pin power out.

That is going to be a big problem. The power system on the arduino is not made to power electric motors. You need an external power supply for the servos if you expect them to actually operate. I’m supprised you haven’t caused a power overload on your computer USB port.

Actually, I'm surprised to hear that, as the servos work just fine when controlled via joystick. I can operate at least 6 at a time, although I'll admit the servo controller tends to give me an error and stop working after a little while if I try to send it too many signals at once (resetting it fixes this). I've assumed this is either because it's too much for the controller to interpret at once or that it's due to a lack of an ideal power supply. 2 servos at once seems to be fairly stable. I've been using it this way for at least a few weeks, as well.

Hum. Still, I've been meaning to try and figure out a better power system anyway, so if my setup is really as risky as you say, I'll start looking into that before I go much further with it. I'd still love to know why the pushbuttons don't work when the joysticks do, though...

Do you notice how this:

//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 1
  // Controlled by Joystick_A_X
  int output_J_A_X = map(analogRead(PIN_ANALOG_A_X), 0, 1023, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(1,output_J_A_X);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);

looks very much like this:

//-------------------------------------------------------------------------
  // Engage servo connected to Pololu pin 2
  // Controlled by Joystick_B_Y
  int output_J_B_Y = map(analogRead(PIN_ANALOG_B_Y), 0, 1023, SERVO_MIN, SERVO_MAX);
  // Signal Pololu controller
  servoMove(2,output_J_B_Y);
  // Signal delay (attempts to keep Pololu controller from panicing)
  delay(3);
//-------------------------------------------------------------------------

?

A few simple arrays and "for" loops would cut down on the amount of code you need to write, and reduce the potential for errors.

Thanks Groove,

Could I trouble you for some sort of example? I’m aware that what I have is probably not the most elegant way of solving the problem, but most of my attempts at using FOR loops have resulted in the Arduino ‘locking out’ my control signals until a given FOR loop completes. For example, initially I was using the Arduino servo library directly, and wound up with something like this:

void loop() {
for (myAngle1=0; myAngle1<=180; myAngle1++) {
myAngle1 = 100;
myAngle2 = 90;
servoPulse1(servo1, myAngle1);
servoPulse2(servo2, myAngle2);
}
}

…and once the Arduino hits this portion of the code, nothing else gets done until it’s finished the loop, which is unacceptable to me. I’m not a savvy enough programmer yet to see clearly how I might make better use of the FOR loop without introducing that problem; there’s much more for me to learn. =P

EDIT: Oh, and regarding arrays, I’ll look into that. I know enough about them to see you’re probably right, and that I can likely compress my joystick command code segments into a single array, which would likely be cleaner…I’ll give it a try.

Resetting the index of a for loop inside the loop is a sure way to ensure that the loop doesn’t behave properly.

If you want a for loop to terminate prematurely, you need a (conditional) break in the loop.

The conditional part can be an if statement. That if statement can include a call to a function, like digitalRead().

So, you could have code like this:

unsigned long timeToMove = 500; // Allow 1/2 second to get to new positions
for(byte ang1=0; ang1<=180; ang1++)
{
   byte ang2 = ang1 + 10;
   if(ang2 > 180) ang2 = 180;
   servo1.write(ang1);
   servo2.write(ang2);
   unsigned long servoMove = millis();
   unsigned long currentTime = millis();
   bool buttonPushed = false;
   while(currentTime - servoTime > timeToMove)
   {
      if(digitalRead(buttonPin) == HIGH)
      {
         buttonPushed = true;
         break; // Don't wait for the time to elapse
      }
   }
   if(buttonPushed) break; // Will break out of the for loop if the button was pushed
}
for (myAngle1=0; myAngle1<=180; myAngle1++) {
myAngle1 = 100;
myAngle2 = 90;
servoPulse1(servo1, myAngle1);
servoPulse2(servo2, myAngle2);
}

You’re changing the loop control variable “myAngle1” inside the loop.
Unless you know what you’re doing, this is not a good idea, and will result in hair loss.