The below code generates a pseudo-random angle every three seconds and then the servo rotates to it. At most angles, large and small, the servo jitters noticeably around its target angle, instead of coming to a standstill. Are there errors in my code that cause this problem?
When I set target angles via serial, no jitter occurs, and also not with other people's random angle servo codes, such as this one. I also made a short 45MB 720p video of the issue.
What am I doing wrong?
#include <Servo.h>
const int timeServoInterval = 7;
const int timeSimUserInterval = 3000;
unsigned long timeNowServo = 0;
unsigned long timeNowUser = 0;
int angleCurrent;
int angleTarget;
Servo ovres;
void setup() {
//Serial.begin(115200);
randomSeed(analogRead(0));
ovres.attach(3);
ovres.write(0);
angleCurrent = ovres.read(); // Seed with initial value to start
angleTarget = random(10, 140); // Seed with initial value to start
}
void loop() {
simulateUserInput();
rotateServo();
}
void rotateServo()
{
if (millis() - timeNowServo >= timeServoInterval)
{
timeNowServo = millis();
if (angleCurrent <= angleTarget)
{
angleCurrent ++;
ovres.write(angleCurrent);
}
else
{
if (angleCurrent >= angleTarget)
{
angleCurrent --;
ovres.write(angleCurrent);
}
}
}
}
void simulateUserInput() // Set angle programmatically (later by user input)
{
if (millis() - timeNowUser > timeSimUserInterval)
{
timeNowUser = millis();
angleTarget = random(10, 170);
}
}
You never seem to recognise that the servo is on target and stop writing to it. You keep adding or subtracting one and writing a new value. Why not a simple "If it's on target do nothing"?
Thanks, Steve, you were right of course; it jitters because it's looping on, changing "angleCurrent" when the target is already reached before three seconds are over. I added an if statement and now it works as intended. Random angle and two millis() functions running nicely independently.
#include <Servo.h>
const byte timeServoInterval = 6;
int timeSimUserInterval; // Set "do something" interval programmatically
unsigned long timeNowServo = 0;
unsigned long timeNowUser = 0;
int angleCurrent;
int angleTarget;
Servo ovres;
void setup()
{
randomSeed(analogRead(0));
ovres.attach(3);
ovres.write(0);
angleCurrent = ovres.read(); // Seed with initial value to start
angleTarget = random(0, 180); // Seed with initial value to start
}
void loop()
{
simulateUserInput(); // Values (°) randomly generated within a range
rotateServo();
}
void rotateServo()
{
if (millis() - timeNowServo >= timeServoInterval) // Check if it is time to rotate
{
timeNowServo = millis(); // Record the current time
if (angleCurrent != angleTarget) // Don't write to servo if target angle is reached
{
if (angleCurrent <= angleTarget)
{
angleCurrent ++;
ovres.write(angleCurrent);
}
else
{
if (angleCurrent >= angleTarget)
{
angleCurrent --;
ovres.write(angleCurrent);
}
}
}
}
}
void simulateUserInput() // Set target angle programmatically (later through user input)
{
if (millis() - timeNowUser > timeSimUserInterval)
{
timeNowUser = millis();
timeSimUserInterval = random(1000, 8000);
angleTarget = random(0, 180);
}
}