Incorporating button into Servo Loop - arduino

I am extremely new so please bare with me. I am attempting to control a servo by both the internal timer and by button. Essentially the servo will open a door for 6 seconds every 24 hours or so OR if you press the button enter image description here
The loop for the timer works but the button doesn't. However if i just upload the button code it works fine. Help please! Even better if the servo could go to 180 when the button is held down and return to 0 when released would be ideal.
Here is my code. Tell me where I messed up please!
#include <Servo.h>
Servo myservo;
const int BUTTON_PIN = 8;
const int SERVO_PIN = 9;
int angle = 0; // the current angle of servo motor
int lastButtonState; // the previous state of button
int currentButtonState; // the current state of button
void setup(){
myservo.attach(SERVO_PIN);
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
myservo.write(angle);
currentButtonState = digitalRead(BUTTON_PIN);
}
void loop(){
myservo.write(0);// move servos to center position -> 90°
delay(18000);
myservo.write(180);// move servos to center position -> 120°
delay (6000);
lastButtonState = currentButtonState; // save the last state
currentButtonState = digitalRead(BUTTON_PIN); // read new state
if(lastButtonState == HIGH && currentButtonState == LOW) {
Serial.println("The button is pressed");
// change angle of servo motor
if(angle == 180)
angle = 0;
else
if(angle == 0)
angle = 180;
// control servo motor arccoding to the angle
myservo.write(angle);
}
}

Based on your picture your pins should be 7 and 9. Basically, the only issue with your code is that you can not use delay if you also want to be monitoring something (your button). So instead you use what is called a watchdog timer, where you basically make something happen ever so often based on the system clock, but then also remain available to do other things when that is not happening.
Comparing the blink and blink without delay examples in the arduino example sketch folder may help explain this concept further.
#include <Servo.h>
Servo myservo;
const int BUTTON_PIN = 7;
const int SERVO_PIN = 9;
unsigned long dayTimer_ms = 0;
unsigned long autoOpenDelay_ms = 86400000;
int angle = 0;
void setup(){
myservo.attach(SERVO_PIN);
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
myservo.write(0);
}
void loop() {
if(millis() - dayTimer_ms > autoOpenDelay_ms )
{
dayTimer_ms = millis();
myservo.write(180); //(open?)
delay(6000);
myservo.write(0);
}
if(millis()<dayTimer_ms)//overflow handling (in case this runs for more than 50 days straight)
{
dayTimer_ms = millis();
}
if (!digitalRead(BUTTON_PIN) && angle != 180)
{
angle = 180;
myservo.write(angle);
}
if (digitalRead(BUTTON_PIN) && angle != 0)
{
angle = 0;
myservo.write(angle);
}
}

Related

Servo Speed Control

How can i make my servo do this but slower?
if(angle == 140)
angle = 159;
else
if(angle == 159)
angle = 140;
This is the whole code:
#include <Servo.h>
const int TOUCH_SENSOR_PIN = 6; // Arduino pin connected to touch sensor's pin
const int TOUCH_SENSOR_PIN2 = 7 ;
const int SERVO_PIN = 9; // Arduino pin connected to servo motor's pin
Servo servo; // create servo object to control a servo
// variables will change:
int angle = 140; // the current angle of servo motor
int lastTouchState; // the previous state of touch sensor
int currentTouchState; // the current state of touch sensor
int lastTouchState2; // the previous state of touch sensor 2
int currentTouchState2; // the current state of touch sensor 2
void setup() {
Serial.begin(9600); // initialize serial
pinMode(TOUCH_SENSOR_PIN, INPUT);
pinMode(TOUCH_SENSOR_PIN2, INPUT);
servo.attach(SERVO_PIN); // attaches the servo on pin 9 to the servo object
servo.write(angle);
currentTouchState = digitalRead(TOUCH_SENSOR_PIN);
currentTouchState2 = digitalRead(TOUCH_SENSOR_PIN2);
}
void loop() {
lastTouchState = currentTouchState; // save the last state
currentTouchState = digitalRead(TOUCH_SENSOR_PIN); //read new state
lastTouchState2 = currentTouchState2; // save the last state
currentTouchState2 = digitalRead(TOUCH_SENSOR_PIN2); //read new state
if((lastTouchState == LOW && currentTouchState == HIGH) || (lastTouchState2 == LOW && currentTouchState2 == HIGH)) {
if(angle == 140)
angle = 159;
else
if(angle == 159)
angle = 140;
// control servo motor arccoding to the angle
servo.write(angle);
} }
you can control the speed of the servo by making it rotating several little steps instead of giving it the final demand angle, something like this.
if(angle <= 140){
for (; angle<= 150; angle += 1) {
myservo.write(angle);
delay(15);
}
}
else if(angle >= 150){
for (; angle >= 140; angle -= 1) {
myservo.write(angle);
delay(15);
}
}
you can adjust the speed by changing the delay value in both for-loops.
A full working example can be found in the examples provided by the Arduino IDE under Servo -> Sweep I guess.

Control 2 servo motors with 2 buttons Arduino

I'm working on another school project where I'm trying to make an obstacle course (model size). For this project I'm using 2 servo motors, which I want to control with 2 different buttons. So 1 button is connected to 1 servo motor and the other one is connected to the other servo. I'm actually struggling to get both buttons to work with the servo motors.
When I attach 1 button and 1 servo motor everything works exactly the way I want. I press the button, the servo motor moves 90 degrees and after 5 seconds it moves back.
The code:
#include <Servo.h>
Servo myservo;
const int servoPin = D8; // Servo pin
const int buttonPin = D7; // Pushbutton pin
void setup() {
myservo.attach(servoPin);
pinMode(buttonPin, INPUT);
}//setup
void loop() {
if (digitalRead(buttonPin) == HIGH) {
myservo.write(180);
delay(50); // waits 50ms to reach the position
delay(15000);//15 seconden wachten
myservo.write(0);
delay(50); // waits 50ms to reach the position
}
}//loop
However I read on a forum that when you want to use more then one servo motor, you have to write the code differently. You have to include servo motors like this:
#include <Servo.h>
Servo myservoa, myservob;
When I changed the code everything stopped working and I don't really understand what I'm doing wrong here. I want the servo motors to work AT THE SAME TIME, with 2 different buttons.
The new code:
#include <Servo.h>
Servo myservoa, myservob;
const int servoPin1 = D8; // Servo pin
const int servoPin2 = D6; // Servo pin
const int buttonPin1 = D7; // Pushbutton pin
const int buttonPin2 = D5; // Pushbutton pin
void setup() {
myservoa.attach(servoPin1);
myservob.attach(servoPin2);
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);
}//setup
void loop() {
if (digitalRead(buttonPin1) == HIGH) {
myservoa.write(90);
delay(50); // waits 50ms to reach the position
delay(5000);// 5 seconden wachten
myservoa.write(0);
delay(50); // waits 50ms to reach the position
}
if (digitalRead(buttonPin2) == HIGH) {
myservob.write(90);
delay(50); // waits 50ms to reach the position
delay(5000);// 5 seconden wachten
myservob.write(0);
delay(50); // waits 50ms to reach the position
}
}//loop
I hope somebody can help me out!
EDIT:
So i found out that 2 servo motors actually was to much for my NodeMCU. The code in the comments worked fine tho! Now I'm trying to combine the servo motor with a small vibration motor. The 2 sensors work well together but I can't get the vibration motor to work properly.
I want the vibration motor to vibrate for 5 seconds after I pressed the button. After 5 seconds it has to stop automatically. With the code the vibration motor only vibrates when I press the button. When the button isn't pressed, the vibration motor stops directly.
Code:
#include <Servo.h>
Servo myservo;
const int servoPin = D8; // Servo pin
const int vibratiePin = D3; // Servo pin
const int buttonPin1 = D6; // Pushbutton pin
const int buttonPin2 = D5; // Pushbutton Pin
unsigned long stopA = 0;
unsigned long stopB = 0;
bool controlA = false;
bool controlB = false;
void setup() {
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);
myservo.attach(servoPin);
pinMode(vibratiePin, OUTPUT);
}//setup
void loop() {
unsigned long now = millis();
if(controlA && stopA < now) {
myservo.write(0);
controlA = false;
} else if (!controlA && digitalRead(buttonPin1) == HIGH) {
controlA = true;
myservo.write(90);
stopA = millis() + 5000;
}
if(controlB && stopB < now) {
digitalWrite(vibratiePin, LOW);
controlB = false;
stopB = millis() + 5000;
} else if (!controlB && digitalRead(buttonPin2) == HIGH) {
controlB = true;
digitalWrite(vibratiePin, HIGH);
}
stopB = now;
}
I hope somebody can see the problem here because I don't understand what I'm doing wrong.
Your problem is that you are sleeping the code at each on if statement:
if (digitalRead(buttonPin1) == HIGH) {
...
delay(5000);// the code is blocked for 5 seconds here
...
}
So if the buttonPin1 is HIGH the code after that block will run just after 5100 milliseconds after (at least).
Indeed you shouldn't use longs delays like that inside the loop. The reason is what you see: while the code is stopped the motors are still running and it is a real dangerous scenario for real applications.
The solution is: don't sleep! There are several ways to do it. One of them is use a program variable to control the state of each of motors and another one to set the time limit to run the motor:
unsigned long stopA = 0;
unsigned long stopB = 0;
bool controlA = false;
bool controlB = false;
void loop() {
unsigned long now = mills();
if(controlA && stopA < now) {
myservoa.write(0);
controlA = false;
} else if (!controlA && digitalRead(buttonPin1) == HIGH) {
controlA = true;
myservoa.write(90);
stopA = mills() + 5050;
}
//similar to motor b
//...
}
This way the code never be blocked into a sleeping command and loop can perform other actions while each motor is running.

arduino interrupts with servo motor

currently am working on project to open a door with access code using arduino UNO and a servo motor. Normal operation requires entering access code using keypad which is working fine. Another option requires pressing a button that causes an interrupt to rotate the servo motor. My problem is my interrupt only works once and never works again. Plus how do i put the for-loop to rotate the servo motor inside the interrupt function with a delay. I know that is not possible but am calling another function that has the delayMicroseconds but all this is not working. Below is my implementation please help
#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Servo.h>
Servo servo;
const int openButtonPin = 2;
void setup() {
// put your setup code here, to run once:
servo.attach(5);
pinMode(openButtonPin, INPUT); //Pin 2 is input
attachInterrupt(0, enforceOpenAccess, HIGH); // PIN 2
}
void(* resetFunc)(void) = 0;
void loop()
{
//My other keypad implementations go here
}
void myDelay(int x) // function to cause delay in the interrupt
{
for(int i = 0; i<x; i++)
{
delayMicroseconds(1000);
}
}
void enforceOpenAccess() // ISR
{
for(int k =0; k<=180; k+=2)
{
servo.write(k); //rotate the servo
myDelay(30); //delay the rotation of the servo
}
}
The code above is run on arduino UNO being simulated in proteus and the interrupt button is a push button. Please if there is other ways of implementing that but with the same behaviour as I have described above help out. Thanks a lot
There are a couple of problems in the slice of code you posted. Just for completeness, you should post the loop function, since we can't guess what you wrote inside.
Just one comment: did you put a pullup? Otherwise use INPUT_PULLUP instead of INPUT for the button pinmode.
The main one is that you attached the interrupt for the HIGH mode, which will trigger the interrupt any time the pin is up, not on the rising edge. And please use the macro digitalPinToInterrupt to map to the correct pin:
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
Then.. Let's improve the code. You really should use the interrupts only when strictly necessary when you have to respond IMMEDIATELY (= less than a couple of milliseconds) to an input. Here you don't have to, so it's MUCH better to check for the button in the loop (more on turning the motor following)
uint8_t lastState;
void setup()
{
...
lastState = LOW;
}
void loop()
{
uint8_t currentState = digitalRead(openButtonPin);
if ((currentState != lastState) && (currentState == HIGH))
{
// Start turning the motor
}
lastState = currentState;
...
}
This will enable you to properly debounce the button too:
#include <Bounce2.h>
Bounce debouncer = Bounce();
void setup()
{
...
pinMode(openButtonPin, INPUT); //Pin 2 is input
debouncer.attach(openButtonPin);
debouncer.interval(5); // interval in ms
}
void loop()
{
debouncer.update();
if (debouncer.rose())
{
// Start turning the motor
}
...
}
If, on the other way, you REALLY want to use the interrupts (because waiting for a couple of milliseconds is too much for you), you should do something like this:
#include <Bounce2.h>
Bounce debouncer = Bounce();
void setup()
{
...
pinMode(openButtonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
}
void loop()
{
...
}
void enforceOpenAccess() // ISR
{
// Start turning the motor
}
It looks like your code? No, because now we'll speak about turning the motor
You should NOT use delays to make steps, because otherwise you will wait for 30ms * 180 steps = 5.4s before being able to do anything else.
You can, however, make a sort of reduced state machine. You want your servo to move from 0 to 180 in steps of 1. So let's code the "don't move" state with any value greater than 180, and consequently we can do something like this in the loop:
unsigned long lastServoTime;
uint8_t servoPosition = 255;
const int timeBetweenSteps_in_ms = 30;
void loop()
{
...
if (servoPosition <= 180)
{ // servo should move
if ((millis() - lastServoTime) >= timeBetweenSteps_in_ms)
{
lastServoTime += timeBetweenSteps_in_ms;
servoPosition++;
if (servoPosition <= 180)
servo.write(servoPosition);
}
}
}
Then, using any of the previous examples, instead of // Start turning the motor write
lastServoTime = millis();
servoPosition = 0;
servo.write(servoPosition);
This way you won't block the main loop even when the button is pressed
This is what is in my loop()
char key = keypad.getKey();
if(key)
{
if(j < 10)
{
studentNumber[j] = key;
//holdMaskedNumber[j] = '*';
lcd.setCursor(0,2);
lcd.print(String(studentNumber));
if(j == 9)
{
studentNumber[9] = '\0';
//holdMaskedNumber[9] = 0;
lcd.clear();
//String number = String(studentNumber);
//lcd.print(number);
//delay(1000);
//lcd.clear();
lcd.print("Access Code");
}
j++;
}
else
{
if(i < 5)
{
accessCode[i] = key;
holdMaskedCode[i] = '*';
lcd.setCursor(1,2);
lcd.print(String(holdMaskedCode));
if(i == 4)
{
holdMaskedCode[5] = '\0';
accessCode[5] = '\0';
//lcd.clear();
//lcd.setCursor(0,0);
//accessCodeString = String(accessCode);
//lcd.print(accessCodeString);
//delay(1000);
lcd.clear();
for(int i =0; i<6; i++)
{
lcd.print("Please wait.");
delay(500);
lcd.clear();
lcd.print("Please wait..");
delay(500);
lcd.clear();
lcd.print("Please wait...");
delay(500);
lcd.clear();
}
digitalWrite(4, HIGH);
lcd.print("Access Granted");
for(int k =0; k<=180; k+=2)
{
servo.write(k);
delay(30);
}
resetFunc();
}
i++;
}
}
}

Arduino - combine sketches

New to programming and Arduino..
I'm currently making a project for my son's Gold Rush diorama with added electronics. From my understanding, it does not like reading delay() codes.
Please, any suggestions are appreciated. Thank you.
I'm trying to combine two sketches;
One that has random fluctuating LEDS (acts as the lanterns in the mine shafts)
The other, a servo that pulls a string up and down (acts as an elevator pulley)
Each sketch alone works properly. I'm not sure the proper way to combine the two without using "delay()"
Leds sketch below;
/*random fluctuating leds*/
void setup() {
// put your setup code here, to run once:
pinMode(12,LOW);
pinMode(11,LOW);
pinMode(10,LOW);
}
void loop() {
// put your main code here, to run repeatedly:
analogWrite(12, random(120)+135);
analogWrite(11, random(120)+135);
analogWrite(10, random(120)+135);
delay(random(100));
}
Servo Sweep Sketch below;
/* Sweep
by BARRAGAN <http://barraganstudio.com>
This example code is in the public domain.
modified 8 Nov 2013
by Scott Fitzgerald
http://arduino.cc/en/Tutorial/Sweep
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop()
{
for(pos = 0; pos <= 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for(pos = 180; pos>=0; pos-=1) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}
In general you can replace delay(1000) with the following code:
unsigned long interval=1000; // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.
void setup() {
//...
}
void loop() {
if ((unsigned long)(millis() - previousMillis) >= interval) {
previousMillis = millis();
// ...
}
}
So you need something like the following code, that I have not tested, but hopefully gives you a starting point:
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
int pos_direction=0; // motor direction
unsigned long interval=1000; // the time we need to wait (analogwrite)
unsigned long previousMillis=0; // millis() returns an unsigned long.
unsigned long interval1=15; // the time we need to wait (servo)
unsigned long previousMillis1=0; // millis() returns an unsigned long.
void setup() {
interval = random(100);
pinMode(12,LOW);
pinMode(11,LOW);
pinMode(10,LOW);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
if ((unsigned long)(millis() - previousMillis) >= interval) {
previousMillis = millis();
analogWrite(12, random(120)+135);
analogWrite(11, random(120)+135);
analogWrite(10, random(120)+135);
interval = random(100);
}
if ((unsigned long)(millis() - previousMillis1) >= interval1) {
previousMillis1 = millis();
if(pos_direction==0){
if(pos==180) pos_direction=1;
else pos++;
}
else if(pos_direction==1){
if(pos==0) pos_direction=0;
else pos--;
}
myservo.write(pos);
// ...
}
}

continuous rotation servo (arduino) responding to button press

I am trying to make a continous rotation servo move clockwise if button on pin2 is pressed, and counterclockwise if button on pin3 is pressed. I want the servo to keep moving in the direction set according to the button until the button is released. This is the code I have so far (I am new to arduino):
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// CONSTANTS
// PINS
const int crServo = 12; // sets pin 12 as servo
const int buttonPinCW = 2; // sets pin 2 as button; CW => clockwise => FOCUS FAR
const int buttonPinCC = 3; // sets pin 3 as button; CC => counterclockwise => FOCUS NEAR
const int ledPin = 10; // sets pin 10 as LED
// SERVO PROPERTIES
const int crSpeedDefault = 1500; // 1500 is the stay still position, motor should not turn
const int crSpeedCW = 1300; // 1300 turns the motor full speed clockwise
const int crSpeedCC = 1700; // 1700 turns the motor full speed counter-clockwise
const int crStepDefault = 2;
// SET BUTTON STATES
int buttonStateCW = 0; //sets button 1 as off
int buttonStateCC = 0; // sets button 2 as off
void setup()
{
myservo.attach(crServo); // attaches the servo on pin 12 to the servo object
pinMode (buttonPinCW, INPUT); // sets button as input
pinMode (buttonPinCC, INPUT); // sets button as input
pinMode (ledPin, OUTPUT); // sets led as output
myservo.write(crSpeedDefault); // default servo to crSpeedDefault
}
int slowFocusPull(int x){
int result;
result = abs(x - crSpeedDefault) / crStepDefault;
return result;
}
void loop()
{
buttonStateCW = digitalRead(buttonPinCW);
buttonStateCC = digitalRead(buttonPinCC);
// clockwise rotation
if (buttonStateCW == HIGH) {
digitalWrite(ledPin, HIGH);
myservo.write(slowFocusPull(crSpeedCW));
// counterclockwise rotation
} else if (buttonStateCC == HIGH) {
digitalWrite(ledPin, HIGH);
myservo.write(slowFocusPull(crSpeedCC));
} else {
digitalWrite(ledPin, LOW);
}
}
The issue lies in the function slowFocusPull. Basically I just want to be able to adjust the speed with just modifying the constant. Without this function everything works fine.
UPDATE: final loop for reference
void loop()
{
buttonStateCW = digitalRead(buttonPinCW);
buttonStateCC = digitalRead(buttonPinCC);
// clockwise rotation
if (buttonStateCW == HIGH) {
digitalWrite(ledPinR, HIGH);
float speed = crSpeedCW;
Serial.print("CLOCKWISE-ROTATION \n");
for (int i = 0; i < t * 5; i++) {
speed += ((float)crSpeedDefault - speed)/ 10;
Serial.print(speed);
Serial.print("\n");
myservo.write((int)speed);
delay(100);
}
myservo.write(crSpeedCW);
}
else if (buttonStateCC == HIGH) {
digitalWrite(ledPinG, HIGH);
float speed = crSpeedCC;
Serial.print("COUNTER-CLOCKWISE-ROTATION \n");
for (int i = 0; i < t * 5; i++) {
speed += ((float)crSpeedDefault - speed) / 10;
Serial.print(speed);
Serial.print("\n");
myservo.write((int)speed);
delay(100);
}
myservo.write(crSpeedCC);
}
else {
myservo.write(crSpeedDefault);
digitalWrite(ledPinR, LOW);
digitalWrite(ledPinG, LOW); // turn the LED off by making the voltage LOW
}
}
Looks like your project would benefit from using Hardware Interrupts, which asynchronously call functions when events (like button presses) occur (these are perfect for controllers, and remove the overhead of polling).
Try wiring up the two pins and wiring up the buttons to pins 2 and 3 as is shown in this diagram:
Hardware interrupts literally interrupt the code, the uno has two such pins: digital pin 2 and digital pin 3 (this is really useful for robotics, also the mega has 6 such pins!)
here's a skeleton for how your code might want to look
void setup() {
attachInterrupt(0, goClockwise, RISING); //the "0" places arduino uno's interrupt pin 2 (for uno r3)
attachInterrupt(1, goCounterClockwise, RISING); //the "1" places interrupt for arduino uno's pin 3
}
void loop() {
delay(1000); dummy delay, code is handled in interrupt functions
}
void goClockwise () {
//runs when pin 2's button is pressed
//code for making servo go clockwise
}
void goCounterClockwise () {
//code triggered when pin 3's button is pressed
//code for ccw goes here
}
If you have any questions on I'd be happy to work through them with you.
Here's a link to the Arduino ref page for hardware interrupts:
click here to learn more about arduino hardware interrupts

Resources