misi89
August 5, 2018, 1:43pm
#1
Hi.
I have a project where I have a servo which should change its position from 80° to 140° and back to 80° 4times. What is important I can not use delay in the code.
I tried in many ways, and all worked for continuous ‘sweep’ but I can not count the cycles.
Basically I have an RTC that provides time and in a certain time it calls the servo function that should do 4 sweeps from 80° → 140° → 80°.
I tried with a for loop then do…while cycle with no success. Coud you give me few tips? Thank you.
Code only for the servo:
#include <Servo.h>
Servo myservo;
int myservo_pin = 17;
long myservo_movetime = 50;
int pos = 80;
int cPos;
int gPos;
int tDelay = 10;
void setup() {
myservo.attach(myservo_pin);
}
void loop() {
cPos = myservo.read();
if (cPos == 80) gPos = 140;
if (cPos == 140) gPos = 80;
if (cPos != gPos && millis() >= myservo_movetime) moveServo();
}
void moveServo() {
if (cPos < gPos) myservo.write(cPos+1);
if (cPos > gPos) myservo.write(cPos-1);
myservo_movetime = millis() + tDelay;
}
Something to experiment with
#include <Servo.h>
Servo theServo;
byte sweepCount;
const byte servoPin = A5;
int servoIncrement = 1;
byte servoPos = 80;
boolean moving = false;
unsigned long waitStartTime;
unsigned long currentTime;
unsigned long stepPeriod = 10;
const byte buttonPin = A1; //for testing purposes
void setup()
{
Serial.begin(115200);
theServo.attach(servoPin);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop()
{
currentTime = millis();
if (moving == false)
{
if (digitalRead(buttonPin) == LOW)
{
moving = true;
}
}
else
{
if (currentTime - waitStartTime >= stepPeriod) //time to move
{
theServo.write(servoPos);
servoPos += servoIncrement;
if (servoPos < 80 || servoPos > 140)
{
servoIncrement *= -1;
sweepCount++;
if (sweepCount == 8)
{
moving = false;
sweepCount = 0;
}
}
waitStartTime = currentTime;
}
}
//other non blocking code can be put in loop()
}
In this program the servo sweeps are started with a button press but you could start them with any other required trigger.
misi89
August 5, 2018, 7:08pm
#3
Thank you. Exactly this is what I was looking for, In the meantime I figured out a workaround, but your solution looks better.
Thank you.
What would be even better would be a state machine controlled by switch/case with 3 states. It would be more obvious what was happening
misi89
August 6, 2018, 6:48am
#5
Thank you very much. I will look forward to it and implement in the next variant.
A state machine version
#include <Servo.h>
Servo theServo;
byte sweepCount;
const byte servoPin = A5;
int servoIncrement = 1;
unsigned long stepStartTime;
unsigned long currentTime;
unsigned long stepPeriod = 10;
const byte lowerLimit = 80;
const byte upperLimit = 140;
byte servoPos = lowerLimit;
const byte triggerPin = A1; //for testing purposes
enum states
{
WAITING_FOR_TRIGGER,
INCREASE_ANGLE,
DECREASE_ANGLE
};
byte currentState = WAITING_FOR_TRIGGER;
void setup()
{
Serial.begin(115200);
theServo.attach(servoPin);
theServo.write(servoPos);
pinMode(triggerPin, INPUT_PULLUP);
}
void loop()
{
currentTime = millis();
switch (currentState)
{
case WAITING_FOR_TRIGGER:
if (digitalRead(triggerPin) == LOW)
{
servoPos = lowerLimit;
theServo.write(servoPos);
stepStartTime = currentTime;
currentState = INCREASE_ANGLE;
sweepCount = 0;
}
break;
//--------------------------------------------
case INCREASE_ANGLE:
if (currentTime - stepStartTime >= stepPeriod)
{
servoPos += servoIncrement;
if (servoPos > upperLimit)
{
servoPos = upperLimit;
stepStartTime = currentTime;
currentState = DECREASE_ANGLE;
}
else
{
theServo.write(servoPos);
stepStartTime = currentTime;
}
break;
//--------------------------------------------
case DECREASE_ANGLE:
if (currentTime - stepStartTime >= stepPeriod)
{
servoPos -= servoIncrement;
if (servoPos < lowerLimit)
{
sweepCount++;
if (sweepCount == 4)
{
currentState = WAITING_FOR_TRIGGER;
}
else
{
servoPos = lowerLimit;
stepStartTime = currentTime;
currentState = INCREASE_ANGLE;
}
}
theServo.write(servoPos);
stepStartTime = currentTime;
}
break;
}
}
//other non blocking code can be put in loop()
}