Servo control issue

Hello,

Looking for some help in finding where I've gone wrong in controlling a mechanical eye project.

I'm following the "Compact Eye" animatronic from Will Cogley and I'm not sure if my issues lies with wiring or something else.

Issue - When I have everything wired up, except power for the motors the code constantly reports "329" in the serial monitor as the received input without any input from me. When I supply motor power I can move the connected joystick to affect the input from the X axis only but it means the servos are always fighting to move from whatever is forcing the "329" input. The only time I can get this input to stop is when I disconnect the "VCC" connection of the servo driver from the 5 volt rail on the breadboard I have it connected to but then I cannot test further since the servo driver is disconnected.

Any guidance is appreciated and the hardware, code and wiring diagram is below. Thanks!

Hardware

  • Arduino Uno R3
  • Adafruit PCA9685 16 Channel Servo driver
  • HiLetgo Game Joystick
  • potentiometer
  • momentary tactile button

Wiring

Code

//  Nilheim Mechatronics Simplified Eye Mechanism Code
//  Make sure you have the Adafruit servo driver library installed >>>>> https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
//  X-axis joystick pin: A1
//  Y-axis joystick pin: A0
//  Trim potentiometer pin: A2
//  Button pin: 2

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>


Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define SERVOMIN  140 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  520 // this is the 'maximum' pulse length count (out of 4096)

uint8_t servonum = 0;

int xval;
int yval;

int lexpulse;
int rexpulse;

int leypulse;
int reypulse;

int uplidpulse;
int lolidpulse;

int trimval;

const int analogInPin = A0;
int sensorValue = 0;
int outputValue = 0;
int switchval = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("8 channel Servo test!");
  pinMode(analogInPin, INPUT);
  pinMode(2, INPUT);

  pwm.begin();

  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  delay(10);
}

// you can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;

  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= 60;   // 60 Hz
  Serial.print(pulselength); Serial.println(" us per period");
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit");
  pulse *= 1000000;  // convert to us
  pulse /= pulselength;
  Serial.println(pulse);
  // pwm.setPWM(n, 0, pulse);
}

void loop() {

  xval = analogRead(A1);
  lexpulse = map(xval, 0, 1023, 270, 390);
  rexpulse = lexpulse;

  switchval = digitalRead(2);


  yval = analogRead(A0);
  leypulse = map(yval, 0, 1023, 280, 400);
  reypulse = map(yval, 0, 1023, 400, 280);

  trimval = analogRead(A2);
  trimval = map(trimval, 320, 580, -40, 40);
  uplidpulse = map(yval, 0, 1023, 280, 420);
  uplidpulse += (trimval - 40);
  uplidpulse = constrain(uplidpulse, 280, 400);
  lolidpulse = map(yval, 0, 1023, 410, 280);
  lolidpulse += (trimval / 2);
  lolidpulse = constrain(lolidpulse, 280, 400);


  pwm.setPWM(0, 0, lexpulse);
  pwm.setPWM(1, 0, leypulse);
  pwm.setPWM(2, 0, rexpulse);
  pwm.setPWM(3, 0, reypulse);

  if (switchval == HIGH) {
    pwm.setPWM(4, 0, 240);
    pwm.setPWM(5, 0, 240);
  }
  else if (switchval == LOW) {
    pwm.setPWM(4, 0, uplidpulse);
    pwm.setPWM(5, 0, lolidpulse);
  }



  Serial.println(lexpulse);

  delay(5);


}

If you boil your code down to just the lexpulse variable, it is this

void loop() {

  xval = analogRead(A1);
  lexpulse = map(xval, 0, 1023, 270, 390);
  pwm.setPWM(0, 0, lexpulse);
  Serial.println(lexpulse);
  delay(5);
}

So every 5 ms, you read A1, map it and the result is 329. If you were to print out xval you would see it is a constant around the middle of the range, ~512. The map() function uses integer math so things get truncated.

Without moving your joystick, it reports the middle position, ~511. What were you expecting to happen?

Thanks for the reply!

Without moving the joystick I was expecting for it to report the middle position and no movement to come from the servos. But sadly even with no input from me the motors dart to the fixed position as soon as the arduino program starts up.

That is exactly what it is doing. xval is 512, lexpulse is 329. No joystick movement required.

Ah apologies, so are you saying the "329" is the middle position? Is that the integer math the map() function uses that you were referring to?

If so my issue still persists that when the program starts the servos still move and point the "eyes" they are attached to to a spot that is not the middle and when I move the joystick I do not get the movements I expect.

My guess is either I have something mis-wired or that maybe I need to learn more about servos and set them at a 0 position?

You are mapping 0-1023 to the range 270-390 using your map() function. What is halfway between 270 and 390?

https://docs.arduino.cc/language-reference/en/functions/math/map/

It sounds like you need to calibrate your "eyes". Start by moving the servo to 0. Slowly increase that number. When the "eyes" are in the proper lower spot, that is the minimum value you want for your map() function. Continue moving the servo until the eyes are in the proper upper spot. That is your max value. I'm guessing those values won't be 270 and 390 like your current code dictate.

Thanks so much for helping with this one @blh64!

Your input helped me troubleshoot and realize the actual issue. My pull down resistor was not wired properly; What I thought was bad input code making my servos move rapidly/without input was actually servo jitter due to bad grounding/wiring on my part. I also found out putting the ground connections closer together on my breadboard made a huge difference in the jitter as well.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.