I'm just beginning to get into the basics of scripting, but I think I need a little help with this. With my current script, the servo follows the potentiometer to the tee, which in my case can be damaging to the servo because it is rather strong and is actually being used to move around a lot of weight. I'd rather have the movement of the servo smoothed out so it doesn't whip around as much and potentially cause damage to itself.
The potentiometer isn't going to be moved around a lot, so complex movement doesn't really have to be smoothed out. So for that I was thinking have it fetch the potentiometer input every couple of seconds or so and ease to that position before checking the potentiometer again. Once again like I said I'm rather new to programming in general, so do correct me if I am wrong with anything.
I doodled this up to present more accurately what I'm looking for, it is fine if the servo has a small delay to it.
And the Frankenstein script I pieced together from various examples I found around:
#include <Servo.h>
const int analogPin = A0;
Servo myservo;
void setup()
{
myservo.attach (9);
int analogValue = analogRead(analogPin);
}
void loop() {
int analogValue = analogRead(analogPin);
myservo.writeMicroseconds(analogValue*2+300);
delay(1);
}
Thank you in advance for anyone willing to help me or guide me to where I need to go, I'm really excited about learning more ways to use the Arduino I have.
Maybe this is not the best solution but it is worthed to try : http://arduino.cc/en/Tutorial/Smoothing#.UydU7ah5Pak . I'm using this to smooth readings from analog sensors. Play with value of numReadings - make it 40..60.. or higher - whatever works best for you .
It's not tested but should work :
#include <Servo.h>
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
const int analogPin = A0;
Servo myservo;
void setup()
{
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
myservo.attach (9);
}
void loop() {
total= total - readings[index];
readings[index] = analogRead(analogPin);
total= total + readings[index];
index = index + 1;
if (index >= numReadings)
index = 0;
average = total / numReadings;
myservo.writeMicroseconds(average*2+300);
delay(1);
}
As far as I can tell, the script works up to a point. I set the numReadings constant to 40, but it simply made the servo spaz out and swing stuff around. I added a Serial.printin of the everage to see what was going on, and it was showing negative numbers jumping around. I plugged 10 back in and tested again, and the numbers went back to normal and the servo returned to it's passive state. I played around with the numReading constant, and found out the servo began to receive negative numbers at the const int numReadings = 33; mark, where putting 32 in would be fine, and 33 would cause it to spaz.
Could it be possible that it is hitting it's memory capacity? Or is it just a coincidence that it stops working past 32, the number of kB my Arduino Uno happens to have?
Thank you for your help anyway!
Nevermind, I did some tweaking and instead of trying to set the number of readings higher than it would allow, I set the number to the maximum I could, and instead changed the delay between loops to 25 instead of 1. This drew out the smoothing to compensate for the small amount of numreadings.
My final script, for anyone that may stumble across this in the future looking for something similar:
// Define the number of samples to keep track of. The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input. Using a constant rather than a normal variable lets
// use this value to determine the size of the readings array.
#include <Servo.h>
const int numReadings = 32;
Servo myservo;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int inputPin = A0;
void setup()
{
// initialize serial communication with computer:
Serial.begin(9600);
myservo.attach (9);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
void loop() {
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
average = average*1.85+450; // line can be removed or altered to fit the max and min of different model servos
// send it to the computer as ASCII digits
myservo.writeMicroseconds(average);
Serial.println(average);
delay(25); // delay in between reads for stability
}
If all you want is some smoothing rather than an exact average, you can achieve that without needing an array just by using a decaying average. Conceptually it works like this:
average = (weight * average) + ((1-weight) * newValue);
The bigger the value of weight, the slower it will be to respond.
Averaging or smoothing isn't the real answer here - what is desired is slew-rate-limiting to
avoid overloading the servo. That's not the same thing.
#define DELAY 1000ul // or whatever value limits the rate enough
unsigned long ts = micros () ;
#define MAX_DEGREES 180 // or whatever
#define MIN_DEGREES 0 // or whatever
int current = 90 ; // response variable
int input = 90 ; // command variable
void loop ()
{
if (micros () - ts >= DELAY) // execute this every DELAY us
{
ts += DELAY ; // bump up timestamp for next time
// adjust response by one degree only if its not in agreement, respecting limits
if (input > current && current < MAX_DEGREES)
current ++ ;
else if (input < current && current > MIN_DEGREES)
current -- ;
servo.write (current) ;
}
..
}