Hello,
I am trying to learn how to work with adafruit 16 channel 12 bit PWM servo driver. I can now control the servo from a pot but what I would like to know is that is it possible to control the speed of the servo ? is it controlled by setting the frequency ?
Hi,
The frequency of the PWM has nothing to do with response of the servo.
The fastest the servo will move can be found by commanding a 0deg position, then when it gets there, send a 180deg command.
To slow the response down you can send incremental commands and if needed delays between them.
Say 0 to 180 in two commands will be the fastest.
But
servo.write(0)
servo.write(10)
servo.write (20)
etc will be slower.
You can write a for loop to do this more efficiently.
TomGeorge:
Hi,
The frequency of the PWM has nothing to do with response of the servo.
The fastest the servo will move can be found by commanding a 0deg position, then when it gets there, send a 180deg command.
To slow the response down you can send incremental commands and if needed delays between them.
Say 0 to 180 in two commands will be the fastest.
But
servo.write(0)
servo.write(10)
servo.write (20)
etc will be slower.
You can write a for loop to do this more efficiently.
Tom...
thanks Tom for your reply, but I am using the adafruit library for this PWM driver not servo library
is it possible to use servo library ? I am controlling the servo by a pot like the below
Servo go as fast as they can to the set point you give them, so you don't control how fast they get there. but you can control timing by taking smaller steps as explained above.
if you want to move from angle A to angle B (>A) you have B-A degrees to turn. if you want to take those steps in N seconds, then (assuming moving 1° is almost instantaneous) you can make 1° steps and pause for 1000UL* N / (B-A-1) (ms) in between steps
eg for going from 10° to 61° you have 51° to move and say you want to get there in ~10 seconds.
You take 50 steps of 1° and pause for 1000*10/50 = 200ms in between steps
Servo pulse timing varies so you need to find the minimum and maximum for your specific servo (at 0° and 180° — carefully adjust as hitting the physical limits of travel can damage your servo / the gears)
Once you have that, then to go to a specific angle in degrees between 0 and 180, you can use
J-M-L:
Servo go as fast as they can to the set point you give them, so you don't control how fast they get there. but you can control timing by taking smaller steps as explained above.
if you want to move from angle A to angle B (>A) you have B-A degrees to turn. if you want to take those steps in N seconds, then (assuming moving 1° is almost instantaneous) you can make 1° steps and pause for 1000UL* N / (B-A-1) (ms) in between steps
eg for going from 10° to 61° you have 51° to move and say you want to get there in ~10 seconds.
You take 50 steps of 1° and pause for 1000*10/50 = 200ms in between steps
Servo pulse timing varies so you need to find the minimum and maximum for your specific servo (at 0° and 180° — carefully adjust as hitting the physical limits of travel can damage your servo / the gears)
Once you have that, then to go to a specific angle in degrees between 0 and 180, you can use
J-M-L,
I would like from you please to explain if possible how to get the degree angle here as a variable ?
I read the adafruit tutorial or their example doesn't explain this part about the angles
firashelou:
J-M-L,
I would like from you please to explain if possible how to get the degree angle here as a variable ?
your potentiometer is what gives you an angle, isn't it ?
int newAngle = map(analogRead(potPin), 0, 1024, 0, 181); // as we don't reach 1024, we won't get 181 and will stop at 180
if you keep the previous angle in a previousAngle variable then you know you have to travel from there to newAngle
if (newAngle > previousAngle) { // rotate up
for (int angle = previousAngle; angle < newAngle; angle+=1) {
// **move to angle**
// **pause for a bit**
}
} else { // rotate down
for (int angle = previousAngle; angle > newAngle; angle-=1) {
// **move to angle**
// **pause for a bit**
}
}
//**finally move to newAngle**
J-M-L:
your potentiometer is what gives you an angle, isn't it ?
int newAngle = map(analogRead(potPin), 0, 1024, 0, 181); // as we don't reach 1024, we won't get 181 and will stop at 180
if you keep the previous angle in a previousAngle variable then you know you have to travel from there to newAngle
if (newAngle > previousAngle) { // rotate up
for (int angle = previousAngle; angle < newAngle; angle+=1) {
// move to angle
// pause for a bit
}
} else { // rotate down
for (int angle = previousAngle; angle > newAngle; angle-=1) {
// move to angle
// pause for a bit
}
}
//finally move to newAngle
thank you J-M-L, I was watching a tutorial on youtube by robojax about this module i understood a bit then I checked your reply and I made this sketch, the thing is that my servo seems to be a 0 to 90 degrees but the sketch is not working when i rotate the potentiometer but before that i uploaded a sketch for test and all is working well
void loop() {
int throttlePotValue = analogRead(throttlePin);
//int throttlePotValue = analogRead(throttlePin);
Serial.println(throttlePotValue);
delay(500);
//throttlePotValue = map(throttlePotValue, 0, 1022, 200, 600);
int newAngle = map(throttlePotValue, 0, 1024, 0, 91); // as we don't reach 1024, we won't get 181 and will stop at 180
int previousAngle = 0;
if (newAngle > previousAngle) { // rotate up
for (int angle = previousAngle; angle < newAngle; angle+=1) {
// **move to angle**
// **pause for a bit**
pwm.setPWM(0, 0, angle);
}
} else { // rotate down
for (int angle = previousAngle; angle > newAngle; angle-=1) {
// **move to angle**
// **pause for a bit**
pwm.setPWM(0, 0, angle);
}
}
}
you can't do pwm.setPWM(0, 0, angle);the function does not take an angle, that's where you map to a pulselength with
map(angle, 0, 90, SERVOMIN, SERVOMAX); // 90 if you have only 90°
aha now i understand but I had to change to code to this and now it is working very smooth next I must integrate the timing to make it go faster or slower
when i tried the newAngle and previousAngle the transition was bad it was making like go forward then backword without me changing the pot rotation
void loop() {
int throttlePotValue = analogRead(throttlePin);
//int throttlePotValue = analogRead(throttlePin);
Serial.println(throttlePotValue);
//delay(500);
//throttlePotValue = map(throttlePotValue, 0, 1022, 200, 600);
int newAngle = map(throttlePotValue, 0, 1024, 0, 91); // as we don't reach 1024, we won't get 181 and will stop at 180
int previousAngle = 0;
int pulse = map(newAngle, 0, 90, SERVOMIN, SERVOMAX);
pwm.setPWM(0, 0, pulse);
}
I am trying to integrate the time to make the servo go fast or slow but i don't want that to be dependent on how fast I rotate the potentiometer but it is increasing the response time from where I turn the pot to servo angle rotating
int newAngle = map(throttlePotValue, 0, 1024, 0, 91); // as we don't reach 1024, we won't get 181 and will stop at 180
int previousAngle = 0;
int pulse = map(newAngle, 0, 90, SERVOMIN, SERVOMAX);
for (int i=0; i<91; i++) {
int timeDelay = 1000*1/89;
pwm.setPWM(0, 0, pulse);
delay(timeDelay);
}
yes to go fast or slow you need to change how long the delay is but you won't be able to go faster that what the Servo can do. --> can it turn 90° in 1 second ?
J-M-L:
yes to go fast or slow you need to change how long the delay is but you won't be able to go faster that what the Servo can do. --> can it turn 90° in 1 second ?
I think yes it can but that depends on how fast I tun the potentiometer
J-M-L:
OK - could work then (although there is always some inertia to work against if you do small steps)
J-M-L:
OK - could work then (although there is always some inertia to work against if you do small steps)
ok what I am trying to do here is having many maps for the servo for example if I turn the potentiometer a little bit, I want the servo to turn more than the pot position so I tried this but it is not giving the desired result
int throttlePotValue = analogRead(throttlePin);
//int throttlePotValue = analogRead(throttlePin);
//Serial.println(throttlePotValue);
//delay(500);
//throttlePotValue = map(throttlePotValue, 0, 1022, 200, 600);
int newAngle = map(throttlePotValue, 0, 1024, 0, 91); // as we don't reach 1024, we won't get 181 and will stop at 180
int previousAngle = 0;
int pulse = map(newAngle, 0, 90, SERVOMIN, SERVOMAX);
int previousPulse;
int currentPulse;
Serial.println(pulse);
if(currentPulse == 600 && previousPulse == 200) {
currentPulse = 200;
pulse = 600;
if(pulse > 600) {
pulse = 600;
}
previousPulse = 600;
} else if (currentPulse == 200 && previousPulse == 600) {
currentPulse = 600;
pulse = 200;
previousPulse = 200;
}
Serial.println(pulse);
//delay(500);
/*if(pulse > 200 && pulse < 601) {
pulse = pulse + 200;
if(pulse > 600) {
pulse = 600;
}
} else if (pulse > 601) {
pulse = pulse - 200;
}
Serial.println(pulse);
//delay(500);*/
pwm.setPWM(0, 0, pulse);
ok what I am trying to do here is having many maps for the servo for example if I turn the potentiometer a little bit, I want the servo to turn more than the pot position so I tried this but it is not giving the desired result
you define your transfer function from a value between 0 and 1023 to your angle (or SERVOMIN, SERVOMAX directly). with map() you have an affine function "y = ax + b" passing by the 2 points (well and converted to integers, so you get steps, not a line).
what you are saying now is that if you move "just a bit' (meaning the difference between newAngle and oldAngle is small) you want to actually go further ? in that case you are loosing the mapping and need to think exactly what that mean when the pot value increases... --> you might be better off using a rotary encoder