Simple servo control module - nano

Hey, having an issue getting smooth control of servos from a nano, using an input from another board. The servos need to turn opposite so the code needs to take the reading from a pin on the Ramps controller and convert it and write the appropriate position to each servo.

Externally powered servos, signals connected to pins D5 and D6, and pin A1 is connected to pwm pin on Ramps 1.4.

The servos jitter and don't move like I want them to. What am I missing?

int inputPin = A1; //pin from ramps with target position
int inputvalue; 
int posvalue;
int servo1pos;
int servo2pos;

#include <Servo.h>
 Servo servo1;
 Servo servo2;
 

void setup() {

servo1.attach(5);
servo2.attach(6);
servo1.write(90);
servo2.write(90);

inputvalue = 500;
pinMode(A1,INPUT);

}

void loop() {

inputvalue = analogRead(inputPin);                //read the state of pin from ramps
posvalue = map(inputvalue, 0, 1023, 0, 180);      //convert to angle
servo1pos = posvalue;
servo2pos = 180-posvalue;

servo1.write(servo1pos);                         //write servo 1 angle
servo2.write(servo2pos);                     //write servo 2 complimentary angle


}

A1 is connected to pwm pin on Ramps 1.4.

PWM is not analog (0 to 5V), it is digital (0 or 5V).

Maybe this will help.

Is the PWM form the Ramps board a servo PWM signal? That is different from the analogWrite PWM signal. See here for more info.

Ok that makes sense, so I'm not reading the signal from the pwm pin correctly. Using your references, this should be more like how to do it, but still doesn't seem to read the input right. Just programming a value with "servo.Write" works fine, so I just need to translate the pwm input to a value between 0 and 180 for that to work.

I'm using this m-code via ramps to change the pins state.:

int anglevalue;
int servo1pos;
int servo2pos;

byte PWM_PIN = A1;
int pwm_value;

#include <Servo.h>
Servo servo1;
Servo servo2;
 
void setup() {
pinMode(PWM_PIN, INPUT);
Serial.begin(115200);

servo1.attach(5);
servo2.attach(6);
servo1.write(90);
servo2.write(90);
}

void loop() {
pwm_value = pulseIn(PWM_PIN, HIGH);
Serial.println(pwm_value);

anglevalue = map(pwm_value, 0, 100, 0, 180);      //convert to angle value
servo1pos = anglevalue;
servo2pos = 180-anglevalue;

servo1.write(servo1pos);                         //write servo 1 angle
servo2.write(servo2pos);                         //write servo 2 complimentary angle
}

Are you seeing values of 0 - 100 for pwm_value? And is it predictable when the values change? Because the code looks fine if those are the real input values.

Steve

pwm_value = pulseIn(PWM_PIN, HIGH);

The puilseIn() function returns the number of microseconds the signal is HIGH not the percent high (duty cycle). A servo signal should be 1000us to 2000us, nominally.

Serial.println(pwm_value);

What range of values does that print return? That range should be in the map() statement.

Ok thanks, I almost have it. The output tops out at 1023-ish when pin is set to 255. It works pretty smooth but the readings fluctuate a little here and there, but with the delay its not too bad, but is there anyway to average them or smooth it somehow? The serial output looks like this:

686
686
680
680
680
680
680
686
686
686
665
680
680
680
680
686
686
680
680
680

*Problem 1 - The servos move just a little here and there. Anyway to smooth it or average them?

*Problem 2 - The two servos move one just after the other instead of at the same time. Any way to make them move in sync?

Here is the code that is working so far.

int anglevalue;
int servo1pos;
int servo2pos;

byte PWM_PIN = A1;
int pwm_value;

#include <Servo.h>
Servo servo1;
Servo servo2;
 
void setup() {
pinMode(PWM_PIN, INPUT);
Serial.begin(115200);

servo1.attach(5);
servo2.attach(6);
servo1.write(90);
servo2.write(90);
}

void loop() {
pwm_value = pulseIn(PWM_PIN, HIGH, 10000);
Serial.println(pwm_value);

anglevalue = map(pwm_value, 0, 1023, 0, 180);      //convert to angle value
servo1pos = anglevalue;
servo2pos = 180-anglevalue;

servo1.write(servo1pos);                         //write servo 1 angle
servo2.write(servo2pos);                         //write servo 2 complimentary angle

delay(200);
}

This is the project, the code controls the gripper for a robotic arm. Final project for school. There is a control pendant to do everything or a pc, or run saved programs from an sd card


OK, my mistake in thinking that the ramps board is sending servo PWM (1000 to 2000 us pulse every 20ms). The M42 command sends analogWrite type PWM (0 to 100% duty cycle at 490Hz or 980Hz).

You are currently reading only the HIGH pulse width, but you need to measure duty cycle. This thread discusses measuring duty cycle.

And you would use 0 and 100 in the map function.

anglevalue = map(pwm_value, 0, 100, 0, 180);

groundFungus:
You are currently reading only the HIGH pulse width, but you need to measure duty cycle. This thread discusses measuring duty cycle.

I can't get a good idea from this article how to code in the full duty cycle. And I can't get options two or three, from the "three ways to read pwm" mentioned above, to work.
Would you be able to show an example of how to add the full duty cycle into my code?
Thanks

Here is code using pulseIn like in the forum thread that I linked. Tested with my Uno.

#include <Servo.h>

Servo servo;

const byte inPin = 4;
const byte servoPin = 7;

void setup()
{
   Serial.begin(115200);
   servo.attach(servoPin);
}

void loop()
{
   static unsigned long timer = 0;
   unsigned long interval = 100;
   if (millis() - timer >= interval)
   {
      timer = millis();
      unsigned long ontime = pulseIn(inPin, HIGH);      
      unsigned long offtime = pulseIn(inPin, LOW);      
      float period = ontime + offtime;
      float duty = (ontime / period) * 100.00;
      Serial.println(duty, 1);      
      servo.write(map(int(duty), 0, 100, 10, 170));
   }
}

That works well, thanks.
I still have the same problem, though, with a slightly varying output. Should I add some kind of averaging code to smooth it out? Or what is the best way to get a more static output? Otherwise the servo jumps here and there, sometime 4 percent all of the sudden.

39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
40.5
percent
74
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
40.3
percent
74
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
40.6
percent
74
degree
38.2
percent
70
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
40.3
percent
74
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.9
percent
72
degree
38.8
percent
70
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
40.3
percent
74
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1
percent
72
degree
39.7
percent
72
degree
39.1

You could average several readings, or keep a running or moving average.

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