This project lets me plug all the servos from a robot arm into an Adafruit PWM Servo driver. Then I can adjust the angle of a servo, click a button to go to the next one, adjust it, move back to the previous one if necessary, etc until the arm is in a good position. Then I can click through the servos and see the settings on an OLED and record it in a spreadsheet. Later I can use the settings in a function. Repeat for the next robot arm position.
I have this nearly done - the servo angles are stored in an array, the encoder adjusts the servo angle and shows it on the OLED. But there is one thing that's keeping it from being done - the buttons are blocked. I can't switch to another servo.
An earlier version of this code used a potentiometer, and I could flip through the servos, but that wasn't good because the servos always went to the position that the pot was in, so I swapped in the encoder. Somehow doing the encoder blocks the buttons from being recognized.
The pot code is still there but commented out. Any suggestions are appreciated!
/***************************************************
Potentiometer or Encoder + Adafruit PWM Servo Driver + OLED + Buttons
****************************************************/
#include <Wire.h>
// Encoder library setup
#include <Encoder.h>
Encoder myEnc(2, 3); // Pins for encoder
long oldPosition = -999;
// JC Button library
#include <JC_Button.h>
// JC Button pin assignments
const byte
DN_PIN(7),
UP_PIN(8); // connect a button from these pins to ground
Button btnUP(UP_PIN), btnDN(DN_PIN); // define the buttons
const unsigned long
REPEAT_FIRST(500), // ms required before repeating on long press
REPEAT_INCR(100); // repeat interval for long press
const int
MIN_COUNT(0),
MAX_COUNT(16);
// OLED - U8g2 library
#include <Arduino.h>
#include <U8x8lib.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
// Adafruit PWM Servo Driver
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN 150 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 600 // this is the 'maximum' pulse length count (out of 4096)
// Servos
const int potPin1 = A0; // potentiometer1 pin
const int totalServos = 16; // Total channels on Adafruit PWM board
int servoArray[totalServos]; // Array to track servo values
int servonum = 0; // Select the specific servo in the array
const int neutral = 365; // Neutral position for servo startup
// variables
int val;
int pulseLength;
///////////////////////
void setup() {
btnUP.begin();
btnDN.begin();
u8x8.begin();
u8x8.setPowerSave(0);
pwm.begin();
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
for (int servonum = 0; servonum < totalServos; servonum++) { // Set servo neutral position in array.
servoArray[servonum] = neutral;
}
for (int servonum = 0; servonum < totalServos; servonum++) { // Copy array value to servos
pwm.setPWM(servonum, 0, servoArray[servonum]);
}
yield();
}
///////////////////////
void loop() {
// Serial.begin(9600);
static int
selectedServoPosition, // the number that is adjusted
lastselectedServoPosition(-1); // previous value of count (initialized to ensure it's different when the sketch starts)
static unsigned long
rpt(REPEAT_FIRST); // a variable time that is used to drive the repeats for long presses
enum states_t {WAIT, INCR, DECR}; // states for the state machine
static states_t STATE; // current state machine state
btnUP.read(); // read the buttons
btnDN.read();
if (selectedServoPosition != lastselectedServoPosition) // print the count if it has changed
{
lastselectedServoPosition = selectedServoPosition;
Serial.println(selectedServoPosition, DEC);
}
switch (STATE)
{
case WAIT: // wait for a button event
if (btnUP.wasPressed())
STATE = INCR;
else if (btnDN.wasPressed())
STATE = DECR;
else if (btnUP.wasReleased()) // reset the long press interval
rpt = REPEAT_FIRST;
else if (btnDN.wasReleased())
rpt = REPEAT_FIRST;
else if (btnUP.pressedFor(rpt)) // check for long press
{
rpt += REPEAT_INCR; // increment the long press interval
STATE = INCR;
}
else if (btnDN.pressedFor(rpt))
{
rpt += REPEAT_INCR;
STATE = DECR;
}
//////////////////
// Potentiometer code - sends pot value directly to servo, does not store it.
// val = analogRead(potPin1); // reads the value of the potentiometer (value between 0 and 1023)
// pulseLength = map(val, 0, 1023, SERVOMIN, SERVOMAX); //map potentiometer to SERVOMIN and SERVOMAX
// pwm.setPWM(servonum, 0, pulseLength);
// Encoder code - updates current servo array value and servo
val = (servoArray[servonum]); // get current setting for this servo
long newPosition = myEnc.read(); // read encoder
if (newPosition > oldPosition) {
oldPosition = newPosition;
val = (val + 10);
if (val > 600){
(val = 600);
}
(servoArray[servonum]) = val;
} else if (newPosition < oldPosition) {
oldPosition = newPosition;
val = (val - 10);
if (val < 150){
(val = 150);
}
(servoArray[servonum]) = val;
}
else {
// Do nothing
}
// Send current array value to servo
// pulseLength = (servoArray[servonum]);
// pwm.setPWM(servonum, 0, pulseLength);
pwm.setPWM(servonum, 0, (servoArray[servonum])); // See if this is all you need instead of above two lines <<<<<<<<<<<<
//u8x8.setFont(u8x8_font_courB18_2x3_f); // This is good, fits single-digit servo
u8x8.setFont(u8x8_font_inr21_2x4_f); // Good one!
// Display selected servo
u8x8.setCursor(0, 0);
u8x8.print("Servo:");
if (servonum < 10) {
u8x8.setCursor(14, 0);
u8x8.print(" "); // Need this to get rid of flickering & stray pixels from numbers over 10
u8x8.setCursor(12, 0);
u8x8.print(servonum);
}
else { // Handle longer numbers, no need to add the space
u8x8.setCursor(12, 0);
u8x8.print(servonum);
}
// Display Pulse Length of servo position
u8x8.setCursor(0, 4);
u8x8.print("Pul:");
u8x8.setCursor(8, 4);
//u8x8.print(pulseLength); // display value of pot
u8x8.print (servoArray[servonum]); // read the current setting from the array
break;
case INCR:
++servonum; // increment the counter
servonum = min(servonum, MAX_COUNT); // but not more than the specified maximum
STATE = WAIT;
break;
case DECR:
--servonum; // decrement the counter
servonum = max(servonum, MIN_COUNT); // but not less than the specified minimum
STATE = WAIT;
break;
}
}