I am having trouble getting my digital servo and LED to work properly with an Arduino sketch. I have a servo with an initial position of 74 which rotates to a position of 133 and stops with a touch and release of button #1. The servo will rotate back to the initial position of 74 only when the input from button #2 is being held high. This setup alone behaves as intended, but when I add an LED to the sketch it does not.
I have an LED that will power on when button#1 is pressed, and then power off after a predetermined amount of time. But when I try to have the LED power on after button #2 is pressed, but before the servo starts its execution, and then power off after the servo completes its execution, nothing will execute (Neither the servo nor LED will respond to either button and remain stationary.). Below is the latest version of the sketch I am working with.
#include <Servo.h>
Servo myservo;
int pos;
const int buttonPin = 2;
const int buttonPin2 = 3;
int buttonState = 0;
int buttonState2 = 0;
const int outputPin1 = 10;
void setup()
{
Serial.begin(9600);
myservo.attach(9);
pinMode(buttonPin, INPUT);
pinMode(buttonPin2,INPUT);
pinMode(outputPin1,OUTPUT);
}
void loop()
{
buttonState = digitalRead(buttonPin);
buttonState2 = digitalRead(buttonPin2);
if (buttonState == HIGH) {
pos=133;
myservo.write(pos);
delay(5);
}
if ((buttonState2 == HIGH)&&(pos>74)) {
digitalWrite(outputPin1, HIGH);
pos-=1;
myservo.write(pos);
delay(5);
digitalWrite(outputPin1, LOW);
}
if (buttonState == HIGH) {
digitalWrite(outputPin1, HIGH);
delay(1000);
digitalWrite(outputPin1, LOW);
}
}
I suspect this sketch may need an interrupt or millis but I have had no success when trying to integrate them into the code.
Any help would be much appreciated.
some time ago I wrote a library to assist in this type of problem. It serves to "Sweep" the servo toward its intended destination in a non-blocking fashion (i.e. no use of delay()). It also allow you to set up a function to call when the servo either starts or stops moving. That is also in the example. Just try your servo on each of the 2 Servo instances (separately).
Here is example .ino
#include "Sweep.h"
void startMoving(int value);
void stoppedMoving(int value);
Sweep servo1(startMoving, stoppedMoving); //callback functions to execute when the servo starts or stops moving.
Sweep servo2; // callback functions not required
void setup()
{
Serial.begin(9600);
servo1.begin(4);
servo2.begin(5);
pinMode(13, OUTPUT);
Serial.print("Total Attached Servos:\t");
Serial.println(Sweep::getServoCount());
}
void loop()
{
Sweep::update(); // this is necessary
static unsigned long lastMillis = 0;
static bool toggle = true;
if(millis() - lastMillis > 5000)
{
Serial.print(F("Moving servo1 to:\t"));
Serial.println(toggle? 180:0);
servo1.moveTo(toggle? 180:0);
toggle = !toggle;
lastMillis = millis();
}
if (Serial.available())
{
int target = constrain(Serial.parseInt(), 0, 180);
Serial.print(F("Moving servo2 to:\t"));
Serial.println(target);
servo2.moveTo(target);
}
}
void startMoving(int value)
{
Serial.print(F("servo1 motion started: "));
Serial.println(value);
digitalWrite(13, HIGH);
}
void stoppedMoving(int value)
{
Serial.print(F("servo1 motion completed: "));
Serial.println(value);
digitalWrite(13, LOW);
}
the .h file:
#ifndef SWEEP_H
#define SWEEP_H
#include <Servo.h>
#include "Arduino.h"
#define MOTION_SPEED_INTERVAL 20 // milliseconds
#define MAX_SERVO_INSTANCES 8
class Sweep : public Servo {
public:
Sweep(void(*_startCallback)(int), void(*_endCallback)(int));
Sweep();
void begin(int servo);
void moveTo(uint32_t newPosition);
static void moveAllTo(uint32_t angle);
static void update();
static void update(uint32_t now);
static int getServoCount();
int getPosition (void) const;
private:
enum MotionState{
ARM_STANDBY,
ARM_MOVING,
};
void(*startCallback)(int);
void(*endCallback)(int);
static Sweep* instanceAddress;
static int instanceCount;
int servoPin;
MotionState motionState = ARM_MOVING;
uint32_t lastMotionMillis = 0;
int currentPosition;
int targetPosition;
uint32_t sensedChangedMillis;
static void setTargetPosition(Sweep* instance, int position);
};
#endif
and the .cpp:
#include "Sweep.h"
#include "Arduino.h"
int Sweep::instanceCount = 0;
Sweep* instances[MAX_SERVO_INSTANCES] = {nullptr};
Sweep::Sweep()
{
instances[instanceCount++] = this;
}
Sweep::Sweep(void(*_startCallback)(int), void(*_endCallback)(int))
{
instances[instanceCount++] = this;
startCallback = _startCallback;
endCallback = _endCallback;
}
int Sweep::getServoCount()
{
return instanceCount;
}
void Sweep::begin(int servo)
{
servoPin = servo;
pinMode(servoPin, OUTPUT);
attach(servoPin);
moveTo(0);
delay(1000);
detach();
}
void Sweep::setTargetPosition(Sweep* instance, int position) //flip-flop for the right vs. levt hands.
{
instance->targetPosition = position;
}
void Sweep::moveTo(uint32_t newPosition)
{
setTargetPosition(this, newPosition);
}
void Sweep::moveAllTo(uint32_t angle)
{
for(auto i : instances)
{
setTargetPosition(i, angle);
}
}
void Sweep::update()
{
update(millis());
}
void Sweep::update(uint32_t now)
{
for(auto srv : instances)
{
switch (srv->motionState)
{
case ARM_MOVING:
if(now - srv->lastMotionMillis > MOTION_SPEED_INTERVAL)
{
if(srv->targetPosition == srv->currentPosition)
{
if(srv->attached())
{
srv->detach();
srv->motionState = ARM_STANDBY;
srv->endCallback(srv->getPosition());
}
}
else
{
if(!srv->attached())
{
srv->attach(srv->servoPin);
}
if(srv->targetPosition > srv->currentPosition)
{
srv->currentPosition++;
srv->write(srv->currentPosition);
}
else
{
srv->currentPosition--;
srv->write(srv->currentPosition);
}
}
srv->lastMotionMillis = now;
}
break;
case ARM_STANDBY:
if(srv->targetPosition != srv->currentPosition)
{
srv->motionState = ARM_MOVING;
srv->startCallback(srv->getPosition());
}
break;
}
}
}
int Sweep::getPosition(void) const
{
return currentPosition;
}
I'm trying to adapt my sketch to what you have done, but my servo does not want to operate between the positions of 133 and 74, but more like 133 and 90. I have little experience working with millis and below is what the code currently looks like.
#include <Sweep.h>
#include <Servo.h>
Servo myservo;
int pos;
const int buttonPin = 2;
const int buttonPin2 = 3;
int buttonState = 0;
int buttonState2 = 0;
const int outputPin2 = 8;
const int outputPin1 = 10;
void startMoving(int value);
void stoppedMoving(int value);
Sweep servo1(startMoving,stoppedMoving);
Sweep servo2; // callback functions not required
void setup()
{
Serial.begin(9600);
myservo.attach(9);
pinMode(buttonPin, INPUT);
pinMode(buttonPin2,INPUT);
pinMode(outputPin1,OUTPUT);
pinMode(outputPin2,OUTPUT);
servo1.begin(9);
servo2.begin(5);
}
void loop()
{
Sweep::update(); // this is necessary
buttonState = digitalRead(buttonPin);
buttonState2 = digitalRead(buttonPin2);
static unsigned long lastMillis = 0;
static bool toggle = true;
if(buttonState == HIGH)
{
servo1.moveTo(toggle? 133:74);
toggle = !toggle;
lastMillis = millis();
}
if ((buttonState2 == HIGH)/*&&(pos>74)*/)
{
servo1.moveTo(toggle? 74:133);
toggle = !toggle;
lastMillis = millis();
}
}
void startMoving(int value)
{
digitalWrite(outputPin1, HIGH);
delay(1000);
digitalWrite(outputPin1, LOW);
}
void stoppedMoving(int value)
{
digitalWrite(outputPin1, HIGH);
delay(1000);
digitalWrite(outputPin1, LOW);
}
Could my "servo1.moveTo(toggle? :)" arguments be causing this?
wickedhurricane:
Could my "servo1.moveTo(toggle? :)" arguments be causing this?
can you (in english) define what happens for each event:
(example)
Event: Press Button A
result: Servo moves to position 150
Event: Press Button B
result: Servo Moves to position 0
etc....