PDA

View Full Version : Controlling servo speed with Arduino



SXRguyinMA
10-14-2010, 10:33 AM
Ok for the Tempest SXR mod, I had a comment on one of the sites it was featured on (Engadget IIRC) that it'd be neat if the vents opened and closed slower to give a more dramatic effect. I took a look at Arduino's website on servo control, but can't find anything on how to set servo speed. Anyone know how? :think:

crenn
10-14-2010, 02:41 PM
You can only set position, however you can make it take steps down to the final position with a small delay (a few ms) in between each step. This should give the desired results.

EDIT: If you post the code you're currently running, I can quickly modify it.

SXRguyinMA
10-14-2010, 03:08 PM
here's what I'm running currently:



// Controlling a servo position using a temperature sensor
// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
// edited 5-12-2010 by Will Lyon to include base setting for servo if voltage not detected on pin 7
// edited again 7-4-2010 by crenn to simplify the code a little
// edited yet again 7-5-2010 by crenn to add features
// edited again 7-21-2010 by Will Lyon - recalibrated servo positions

#include <Servo.h>

Servo myservo; // create servo object to control a servo

//Constants
const unsigned char CONTROL = 7; // digital pin used to detect if the system is on or off
const unsigned char temps = 0; // analog pin used to connect the temp sensor
const unsigned char MAX_VAL = 10;

//Main global varibles
char trigger = 0; // varible used to store the control pin value
unsigned int val; // variable to read the value from the analog pin

unsigned int updateAvgtemp(){
static int history[MAX_VAL]={0};
static unsigned char lastHist=0;
static unsigned char numHist=0;
unsigned int temp=0;
unsigned char counter=0;
unsigned char arcount=0;
history[lastHist] = analogRead(temps);
if(numHist<MAX_VAL)
++numHist;
arcount=lastHist;
++lastHist;
if(lastHist>=MAX_VAL)
lastHist=0;
temp=0;
counter=0;
do{
temp+=history[arcount];
arcount--;
if(arcount>MAX_VAL)
arcount=(MAX_VAL-1);
counter++;
}while(counter < numHist);
return (temp/numHist);
}

void setup()
{
pinMode (CONTROL, INPUT); // sets the control pin to input
myservo.attach(9); // attaches the servo on pin 9 to the servo object
digitalWrite(CONTROL, LOW); // ensure internal pullup resistor is disabled.
}
void loop()
{
trigger = digitalRead(CONTROL); // read input of pin CONTROL and store it
if (trigger == HIGH){ // reads if pin CONTROL, if true, do this:
val = updateAvgtemp(); // read the value of the temp sensor (value with range of 1024)
val = map(val, 350, 700, 160, 80); // scale it to use it with the servo (value between 160 and 80)
myservo.write(val); // sets the servo position according to the scaled value
}
else {
myservo.write(180); // sets servo position to 180 if above statment is false
}
delay(125); // wait 25ms for the servo to move to it's new position and also 100ms until it gets the new value
}

crenn
10-14-2010, 03:31 PM
// Controlling a servo position using a temperature sensor
// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
// edited 5-12-2010 by Will Lyon to include base setting for servo if voltage not detected on pin 7
// edited again 7-4-2010 by crenn to simplify the code a little
// edited yet again 7-5-2010 by crenn to add features
// edited again 7-21-2010 by Will Lyon - recalibrated servo positions
// edited again 10-15-2010 by crenn - slow down servo when computer is off

#include <Servo.h>

Servo myservo; // create servo object to control a servo

//Constants
const unsigned char CONTROL = 7; // digital pin used to detect if the system is on or off
const unsigned char TEMP_SENSOR = 0; // analog pin used to connect the temp sensor
const unsigned char MAX_SAMPLES = 10;
const unsigned char OFF_POSITION = 180;
const unsigned char LOW_POSITION = 160;
const unsigned char HIGH_POSITION = 80;

//Main global varibles
char trigger = 0; // varible used to store the control pin value
unsigned int val = OFF_POSITION; // variable to read the value from the analog pin

unsigned int updateAvgtemp(){
static int history[MAX_SAMPLES]={0};
static unsigned char lastHist=0;
static unsigned char numHist=0;
unsigned int temp=0;
unsigned char counter=0;
unsigned char arcount=0;
history[lastHist] = analogRead(TEMP_SENSOR);
if(numHist<MAX_SAMPLES)
++numHist;
arcount=lastHist;
++lastHist;
if(lastHist>=MAX_SAMPLES)
lastHist=0;
temp=0;
counter=0;
do{
temp+=history[arcount];
arcount--;
if(arcount>MAX_SAMPLES)
arcount=(MAX_SAMPLES-1);
counter++;
}while(counter < numHist);
return (temp/numHist);
}

void setup()
{
pinMode (CONTROL, INPUT); // sets the control pin to input
myservo.attach(9); // attaches the servo on pin 9 to the servo object
digitalWrite(CONTROL, LOW); // ensure internal pullup resistor is disabled.
}
void loop()
{
trigger = digitalRead(CONTROL); // read input of pin CONTROL and store it
if (trigger == HIGH){ // reads if pin CONTROL, if true, do this:
val = updateAvgtemp(); // read the value of the temp sensor (value with range of 1024)
val = map(val, 350, 700, LOW_POSITION, HIGH_POSITION); // scale it to use it with the servo (value between 160 and 80)
myservo.write(val); // sets the servo position according to the scaled value
}
else {
while(val<OFF_POSITION){
val++;
myservo.write(val);
delay(100);
}
myservo.write(OFF_POSITION); // sets servo position to 180 if above statment is false
}
delay(125); // wait 25ms for the servo to move to it's new position and also 100ms until it gets the new value
}
Here you go!

SXRguyinMA
10-14-2010, 03:40 PM
thanks! I'll try it out tonight :D

I'm thinking I mgiht also add in a line to blink an LED (4 actually), and set some amber ones up so as it's closing (when the computer get shut down) the LEDs will blink slowly, like warning lights almost. we'll see though. I don't want it to get too corny :think:

crenn
10-14-2010, 04:57 PM
Easy enough to do.

x88x
10-14-2010, 07:27 PM
IDK if this would work, but would work, but would it be possible to either reduce the voltage to the servo to slow it down? I think crenn's way is simpler, I'm just wondering if that'll make the movement jerky at all?

SXRguyinMA
10-14-2010, 07:32 PM
well it slowed it down a tad, but not much at all. how could I alter it to slow it more?

and no jitter :D

x88x
10-14-2010, 07:33 PM
well it slowed it down a tad, but not much at all. how could I alter it to slow it more?

and no jitter :D

You should be able to increase the pause time between movements to slow it down. Good to hear it's smooth.

SXRguyinMA
10-14-2010, 07:44 PM
would I increase the 100ms delay after the "myservo.write" or the 125ms delay at the end? :?

SXRguyinMA
10-14-2010, 07:51 PM
tried both, neither worked lol

SXRguyinMA
10-14-2010, 08:20 PM
this is what I need! :D

http://www.01mech.com/supermodified

http://www.01mech.com/supermodified_arduino

x88x
10-14-2010, 08:27 PM
You want to change the 'delay(100)' in the 'while' loop. What did you change it to? Try upping it to a few hundred and see if you see a difference...this is milliseconds we're dealing with here, you're not gonna notice any difference if you only change it by a few.

SXRguyinMA
10-14-2010, 09:58 PM
I changed it to 500 and it didn't change a thing, I'll try higher

SXRguyinMA
10-14-2010, 10:08 PM
tried it @ 1000 and 5000, nothing changed lol

SXRguyinMA
10-14-2010, 10:13 PM
found this over on the Arduino forum:


const int angleIncrement = 1;
const int incrementDelay = 10;
for (int angle = 0; angle < 180; angle += angleIncrement) { // single "degree" increments
myServo.write (angle);
delay (incrementDelay); // so we'll take 10 * 180 milliseconds = 1.8 seconds for the traverse.
}



now how would I work it into my sketch?

crenn
10-15-2010, 02:09 AM
What that's doing is pretty much what I'm doing with my code. Are you sure the code is uploading?

EDIT: Just a note. When you want to increase the delay, update the lines with

myservo.write(val);
delay(100);

Increasing the delay at the end won't slow down the servo much.

SXRguyinMA
10-15-2010, 07:48 AM
yes it's uploading, the board it resetting and everything. I'm changing the control pin from 7 to 5 to test it so I don't actually have to shut down the computer, and it doesn't seem to be slowing at all. I've changed that value to 500, 1000 and 5000 with no change in speed

x88x
10-15-2010, 01:59 PM
Hmmm, there's definitely something wrong here...at 5000 it should take it 15 minutes to close all the way (180 degrees)....

EDIT:
Just to make sure, this is the place where you're changing the delay time right?

else {
while(val<OFF_POSITION){
val++;
myservo.write(val);
delay(100);
}
myservo.write(OFF_POSITION); // sets servo position to 180 if above statment is false
}

SXRguyinMA
10-15-2010, 02:07 PM
that's the one. FYI from full open to full close it's only moving ~70º or so, but still, it's just as snappy, takes .5 sec or less, just like in the vid

a guy over on the Arduino forums said he's adding something to the servo library and to look for it later today. I just looked and nothing yet.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1276899740

x88x
10-15-2010, 02:23 PM
Even only moving 70 degrees, it should take it almost 6 minutes with a 5000ms delay...hmmm. You said it slowed it down a little...where did it slow down? If the actual movement isn't happening any slower, I would wonder if it's even entering the while loop. I know my teensy has a USB console output feature, does the arduino you're using have something similar? If we could get some debugging output from it in one way shape or form that would be very helpful in pinpointing the problem. My first thought is the value of 'val'. Of there's no debug console, maybe throw together a quick morse code number library (or maybe one exists already) and have an LED blink you the value?

Ooh, one thing I just thought of..idk what the syntax requirements are in the arduino language, but I know some other languages can get really picky about it...try this for the while loop line instead, out of curiosity.

while(val < OFF_POSITION){

SXRguyinMA
10-15-2010, 02:30 PM
just throw those spaces in there? I'll try it when I go home for lunch in a few

oh and those mouse glides came in today. thanks!

x88x
10-15-2010, 02:35 PM
Yup, just add spaces. Most languages don't care, but sometimes you'll run into one that's just picky (BASH is horrible with the strictness of its syntax).

Glad to hear the glides got there fine. They're a few days later than I intended, but I could not for the life of me find my stamps...and then they ended up being in the box with the envelopes...you know, so I wouldn't lose them? :facepalm:

SXRguyinMA
10-15-2010, 02:37 PM
I've done the same, I feel your pain :facepalm: lol

crenn
10-15-2010, 06:55 PM
I'll test the code on my arduino and see how I go.

SXRguyinMA
10-15-2010, 08:37 PM
from Arduino forums:


Here's (http://rapidshare.com/files/425318464/VarSpeedServo.zip) the VarSpeedServo library. It's a clone of the Servo Library with one additional function slowmove which is a replacement of write with an additional speed parameter.

Speed=0: Write is used, full speed
Speed=1: Slowest
Speed=255: Fastest. With the servos I have, above 127 I couldn't see any difference to write because the mechanical speed was the limiting factor.

Everything that works with Servo works with VarSpeedServo too. Important: Don't use Servo.h and VarSpeedServo.h at the same time, it will create conflicts.

Example:


#include <VarSpeedServo.h>
VarSpeedServo myServo;
...
myServo.attach (mainPin, ServoMin, ServoMax);
...
myServo.slowmove (newpos, speed);
...




Let me know how it works out.

Korman

testing it now...

SXRguyinMA
10-15-2010, 08:55 PM
alright here's the current code:


// Controlling a servo position using a temperature sensor
// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
// edited 5-12-2010 by Will Lyon to include base setting for servo if voltage not detected on pin 7
// edited again 7-4-2010 by crenn to simplify the code a little
// edited yet again 7-5-2010 by crenn to add features
// edited again 7-21-2010 by Will Lyon - recalibrated servo positions
// edited again 10-15-2010 by crenn - slow down servo when computer is off
// edited again 10-15-10 by Will Lyon, with new VarSpeedServo library to slow servo movement
// VarSpeedServo library from Korman on Arduino.cc forums

#include <VarSpeedServo.h>

VarSpeedServo myservo; // create variable speed servo object to control a servo

//Constants
const unsigned char CONTROL = 5; // digital pin used to detect if the system is on or off
const unsigned char TEMP_SENSOR = 0; // analog pin used to connect the temp sensor
const unsigned char MAX_SAMPLES = 10; // number of temp sensor samples to average
const unsigned char OFF_POSITION = 180; // position of servo when no voltage is detected on pin 5
const unsigned char LOW_POSITION = 155; // lowest servo position for lowest temp
const unsigned char HIGH_POSITION = 120; // highest servo position for highest temp

//Main global varibles
char trigger = 0; // varible used to store the control pin value
unsigned int val = OFF_POSITION; // variable to read the value from the analog pin

unsigned int updateAvgtemp(){
static int history[MAX_SAMPLES]={0};
static unsigned char lastHist=0;
static unsigned char numHist=0;
unsigned int temp=0;
unsigned char counter=0;
unsigned char arcount=0;
history[lastHist] = analogRead(TEMP_SENSOR);
if(numHist<MAX_SAMPLES)
++numHist;
arcount=lastHist;
++lastHist;
if(lastHist>=MAX_SAMPLES)
lastHist=0;
temp=0;
counter=0;
do{
temp+=history[arcount];
arcount--;
if(arcount>MAX_SAMPLES)
arcount=(MAX_SAMPLES-1);
counter++;
}while(counter < numHist);
return (temp/numHist);
}

void setup()
{
pinMode (CONTROL, INPUT); // sets the control pin to input
myservo.attach(9, HIGH_POSITION, LOW_POSITION); // attaches the servo on pin 9 to the servo object
digitalWrite(CONTROL, LOW); // ensure internal pullup resistor is disabled.
}
void loop()
{
trigger = digitalRead(CONTROL); // read input of pin CONTROL and store it
if (trigger == HIGH){ // reads if pin CONTROL, if true, do this:
val = updateAvgtemp(); // read the value of the temp sensor (value with range of 1024)
val = map(val, 350, 700, LOW_POSITION, HIGH_POSITION); // scale it to use it with the servo (value between 160 and 120)
myservo.slowmove(val, 255); // sets the servo position according to the scaled value
}
else {
while(val<OFF_POSITION){
val++;
myservo.slowmove(val, 255);
delay(100);
}
myservo.slowmove(OFF_POSITION, 1); // sets servo position to 180 if above statment is false, at slowest speed
}
delay(125); // wait 25ms for the servo to move to it's new position and also 100ms until it gets the new value
}

it works great, I just need to lube my hinges etc, they're a little sticky.

I also had to change the high position to 120 from 90, otherwise it wanted to open the vents too far and actually popped the pins out of the first 2 flaps lol.

I'll see tomorrow morning (when the room and computer have cooled off) about the general operation, but it definitely closes slower!

SXRguyinMA
10-16-2010, 07:59 AM
alright so after some recalibration (still not sure why it was needed)

this:


const unsigned char OFF_POSITION = 180; // position of servo when no voltage is detected on pin 5
const unsigned char LOW_POSITION = 155; // servo position for lowest temp
const unsigned char HIGH_POSITION = 120; // servo position for highest temp


is now this:


const unsigned char OFF_POSITION = 180; // position of servo when no voltage is detected on pin 5
const unsigned char LOW_POSITION = 160; // servo position for lowest temp
const unsigned char HIGH_POSITION = 135; // servo position for highest temp


but originally (before the "VarSpeedServo" library) it was this:



const unsigned char OFF_POSITION = 180; // position of servo when no voltage is detected on pin 5
const unsigned char LOW_POSITION = 160; // servo position for lowest temp
const unsigned char HIGH_POSITION = 90; // servo position for highest temp


:? :think:

crenn
10-16-2010, 10:07 AM
Because you're changing the length of the pulses.

Change:

myservo.attach(9, HIGH_POSITION, LOW_POSITION);
to this:

myservo.attach(9);

billygoat333
10-16-2010, 11:19 PM
I can has new video?

SXRguyinMA
10-17-2010, 12:04 AM
in time, young Jedi :D

Joey1558
10-21-2010, 08:34 PM
update update etadpu

SXRguyinMA
10-21-2010, 08:57 PM
look @ my tempest SXR thread, should be last page or 2nd to last :D