continuous rotation servo (arduino) responding to button press - arduino

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

Related

Incorporating button into Servo Loop

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);
}
}

Arduino Automatic Clothes Line : How can I make my meet the different criteria?

So I'm a novice in programming and is helping my friend with coding an automatic clothes line for a project.
Each component works fine individually but when I put all the code together the motors are confused in which direction to go. can anyone take a look at it and give us feedback?
We have a rain sensor, light sensor, 2 switches , and a motor.
When it rains OR when it is dark the motors pulls the clothes in and when the the clothes reaches the end it touches switch 1 and stops the motors.
When it stop rains/sunny AND/OR when there light it pulls the clothes out in the open.
Here is the code I was provided:
**
#include <Stepper.h>
//motors
const int stepsPerRevolution = 400;
//motor speeds
Stepper myStepper = Stepper(stepsPerRevolution, 2,4, 3, 5);//clockwise
Stepper myStepper2 = Stepper(stepsPerRevolution, 5, 3, 4, 2);//counterclockwise
//rain sensor
const int capture_D =4;
const int capture_A = A0;
int val_analogique;
int led = 8;
//switches
const int switch1 = A3;
const int switch2 =A4;
void setup() {
// put your setup code here, to run once:
// motors
myStepper.setSpeed(60);
myStepper2.setSpeed(60);
//rain sensor
pinMode(capture_D, INPUT);
pinMode(capture_A, INPUT);
pinMode(led, OUTPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
//light sensors
unsigned int AnalogValueL;
AnalogValueL = analogRead(A5);
Serial.println(AnalogValueL);
delay(2000);
//rainsensor
if((digitalRead(capture_A) && digitalRead(capture_D)) ==LOW)
{
digitalWrite(led, HIGH);
myStepper2.step(stepsPerRevolution); // bringclothesout
Serial.println("DRY");
delay(1000);
}
else
{
//when it rains the clolthes re brought in
digitalWrite(led, LOW);
Serial.println("WET");
myStepper.step(stepsPerRevolution);//bring clothes in
delay(1000);
}
if(AnalogValueL < 1010)
{
digitalWrite(led, HIGH);
Serial.println("SUNNY");
myStepper2.step(stepsPerRevolution);
delay(1000);
}
else
{
digitalWrite(led, LOW);
Serial.println("Dark");
myStepper.step(stepsPerRevolution);
delay(1000);
}
//switches
unsigned int AnalogValueS;
AnalogValueS = analogRead(switch1);
Serial.println(AnalogValueS);
delay(2000);
if(AnalogValueS <= 1000)
{
digitalWrite(led, HIGH);
Serial.println("Off");
myStepper.setSpeed(0);
}
else
{
digitalWrite(led, LOW);
Serial.println("on");
}
unsigned int AnalogValueSS;
AnalogValueSS = analogRead(switch2);
Serial.println(AnalogValueSS);
delay(2000);
if(AnalogValueSS <= 1000)
{
digitalWrite(led, HIGH);
Serial.println("ON");
}
else
{
digitalWrite(led, LOW);
Serial.println("Off");
}
*/
}//end of program
**
Feedback?
Here's my feedback:
Your code needs a little bit of tidying up for the sake of clarity and readability.
It is always recommended to declare your Serial.begin(); at the beginning of the setup() function.
You forgot to declare the switches pins as inputs:
pinMode(switchX, INPUT); // where X = 1, 2
Why are you using analog pins as switch inputs? (const int switch1 = A3). If you are connecting ON/OFF switches here you should rather use digital pins. In case your switches are the light sensors, then they are fine (read comment 9 below). Otherwise, this:
AnalogValueS = analogRead(switch1);
is wrong as you cannot read a digital switch with an analogRead()
Additionally, you don't say if your switches are active HIGH or active LOW, namely, if they pulse LOW when pressed and HIGH when released or viceversa.
One important mistake is that you are assigning pin 4 twice for different functions. First as a motor pin, then as capture_D:
Stepper myStepper = Stepper(stepsPerRevolution, 2, 4, 3, 5);
Stepper myStepper2 = Stepper(stepsPerRevolution, 5, 3, 4, 2);
const int capture_D = 4;
You read the analog value in a variable declared inside the main() loop while you previously declared int val_analogique without using it. This is poor consistency.
Similarly, you read from analog pin A5 without previously declaring it as an INPUT:
AnalogValueL = analogRead(A5);
The flow of your loop could be affected by that many delay() throughout the code.
You expressed having three sensors:
We have a rain sensor, light sensor, 2 switches, and a motor.
It is good practice to label the pins from these sensors with a representative name from the sensor in question: e.g.:
const int lightSensor1 = 4;
In the C++ mindset is common practice to use enums to define states from a specific event or scenario. For instance:
typedef enum {
RAINING,
DARK,
NOT_RAINING,
SUNNY
}WEATHER_CONDITIONS;
WEATHER_CONDITIONS currentCondition = SUNNY;
where the typedef means that you are creating your own data type WEATHER_CONDITIONS and their assigned values are 0,1, 2,... according to their order.
With regards to the Stepper.h library you are declaring two Stepper instances expecting that in that way you will reverse the direction of the motor. That is NOT how it works. According to the library (Stepper.cpp) to reverse the motor, you need to send a negative value as an argument to reverse its direction. Please read line 184 from this file from the library.
On this line:
if((digitalRead(capture_A) && digitalRead(capture_D)) ==LOW)
you are attempting to read a digital value from an analog pin. While it might work if the voltage on that pin is at a logic level, this is not recommended.
Finally, you SHOULD connect the switches for stopping the motor to INTERRUPT pins. This is a more effective way to detect when the switch has been pressed and take immediate action by changing a state. You would have to use pins 2 and 3 (INT0 and INT1).
This is my take on this code. Compiled correctly but UNTESTED!
#include <Arduino.h>
#include <Stepper.h>
/*Constants*/
//motor speeds
const int stepsPerRevolution = 400;
/*Pinout declarations*/
// Motor pins
const int motorPins[4] = {2, 3, 4, 5};
//rain sensor
const int capture_D = 4; // capture_D
const int capture_A = A0; // A0
const int lightSensor = A5;
//switches
const int switch1 = 9; // Previously: A3 So this is an analog switch?
const int switch2 = 10; // Previously: A4 You should assing this to other two digital pins
//Led
const int led = 8;
/*Custom variables*/
typedef enum {
DARK,
SUNNY
} LIGHT_CONDITIONS;
LIGHT_CONDITIONS lightState = SUNNY;
const char* lightLabels[] = {"DARK",
"SUNNY"};
typedef enum {
DRY,
WET
} HUMIDITY_CONDITIONS;
HUMIDITY_CONDITIONS humidityState = DRY;
const char* humidityLabels[] = {"DRY",
"WET"};
typedef enum {
CW, // Let's assume that this is bring them in
CCW, // this is take them out
STOP
} MOTOR_DIRECTION;
MOTOR_DIRECTION currentDirection = STOP; // This declares a default state
const char* directionLabels[] = {"Clothes In",
"Clothes Out"};
/*General variables*/
int rawLightValue;
// Objects declaration
Stepper myStepper = Stepper(stepsPerRevolution,
motorPins[0],
motorPins[1],
motorPins[2],
motorPins[3]);
void activateMotor(int direction) {
switch (direction) {
case MOTOR_DIRECTION::CW:
myStepper.step(-stepsPerRevolution);
currentDirection = CW;
break;
case MOTOR_DIRECTION::CCW:
myStepper.step(stepsPerRevolution);
currentDirection = CCW;
break;
case MOTOR_DIRECTION::STOP:
currentDirection = STOP;
myStepper.step(0);
break;
default:
// so much empty
break;
}
}
void setup() {
Serial.begin(9600);
// motors
myStepper.setSpeed(60);
//rain sensor
pinMode(capture_D, INPUT);
pinMode(capture_A, INPUT);
pinMode(switch1, INPUT);
pinMode(switch2, INPUT);
pinMode(lightSensor, INPUT);
pinMode(led, OUTPUT);
}
void loop() {
// First, read light sensor
rawLightValue = analogRead(lightSensor);
Serial.println(rawLightValue);
if (rawLightValue < 1010) {
digitalWrite(led, HIGH);
lightState = SUNNY;
Serial.println(lightLabels[lightState]);
} else {
digitalWrite(led, LOW);
lightState = DARK;
Serial.println(lightLabels[lightState]);
}
// Then read rain sensor --> digital portion only, granted that you have calibrated
// its pulsing voltage corectly. I am assuming that you are using one of these sensors:
// https://circuitdigest.com/microcontroller-projects/rain-detector-using-arduino
if (digitalRead(capture_D) == LOW) {
digitalWrite(led, HIGH);
humidityState = DRY;
Serial.println(humidityLabels[humidityState]);
}
else {
//when it rains the clolthes re brought in
digitalWrite(led, LOW);
humidityState = WET;
Serial.println(humidityLabels[humidityState]);
}
// Based on these conditions, activate the motor accordingly
/* When it rains OR when it is dark the motors pulls the clothes in and when
the the clothes reaches the end it touches switch 1 and stops the motors.
*/
if ((humidityState == WET) || (lightState == DARK)) {
// While the switch is released, meaning that the switch has NOT been pressed:
while (digitalRead(switch1) == HIGH) {
activateMotor(CCW);
Serial.println(directionLabels[currentDirection]);
}
// Finally, let the motors go until the swithces tell the system to stop the motor
activateMotor(STOP);
}
if ((humidityState == DRY) && (lightState == SUNNY)) {
// While the switch is released, meaning that the switch has NOT been pressed:
while (digitalRead(switch2) == HIGH) {
activateMotor(CW);
Serial.println(directionLabels[currentDirection]);
}
// Finally, let the motors go until the swithces tell the system to stop the motor
activateMotor(STOP);
}
}

Arduino: Why doesn't my stepper move in reverse direction?

I have verified that its not a wiring problem by using some non library example code, so it seems the problem is not with the circuit.
I'm expecting the following code to run the motor in one direction 200 steps then run 200 steps in the opposite direction. It seems to run the initial 200 steps but then stops, why?
In the setup function:
stepper.setCurrentPosition(0);
// Set the maximum speed in steps per second:
stepper.setMaxSpeed(1000);
In the loop function:
while(stepper.currentPosition() < 300){
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.run();
if (stepper.distanceToGo() == 0) {
stepper.moveTo(-stepper.currentPosition());
stepper.setSpeed(200);
stepper.run();
}
}
Here's my entire code. The if/else at the bottom is where I want to run the motor. I've put in some non working example code in this block as an example:
#include <deprecated.h>
#include <MFRC522.h>
#include <MFRC522Extended.h>
#include <require_cpp11.h>
// Include the AccelStepper library:
#include <AccelStepper.h>
// constants won't change. They're used here to set pin numbers:
const int BUTTON_PIN = 2; // the number of the pushbutton pin
#define BLUE 7
#define GREEN 6
#define RED 3
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 53 // Configurable, see typical pin layout above
#define dirPin 10
#define stepPin 11
#define motorInterfaceType 1
// Variables will change:
String authKeyFob = "123456789";
String card_ID="";
int ledState = 0; // remember current led state
int buttonState = 0;
int oldButtonState = 0;
bool toggle = false;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
// initialize the pushbutton pin as an pull-up input
// the pull-up input pin will be HIGH when the switch is open and LOW when the switch is closed.
pinMode(BUTTON_PIN, INPUT);
pinMode(GREEN, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(BLUE, OUTPUT);
stepper.setCurrentPosition(0);
stepper.setMaxSpeed(1000);
stepper.setAcceleration(50);
// stepper.setSpeed(200);
// stepper.moveTo(200);
}
void loop() {
/*
// Change direction once the motor reaches target position
if (stepper.distanceToGo() == 0) {
stepper.moveTo(-stepper.currentPosition());
}
// Move the motor one step
stepper.run();
*/
buttonState = digitalRead(BUTTON_PIN);
// read the state of the switch/button:
oldButtonState = LOW; // NEED TO ADD A DECLARATION FOR THIS BEFORE SETUP
buttonState = digitalRead(BUTTON_PIN);
// Look for new cards, and select one if present
if (!mfrc522.PICC_IsNewCardPresent() ) {
}
if(mfrc522.PICC_ReadCardSerial() ){
card_ID="";
for (byte i = 0; i < mfrc522.uid.size; i++) {
card_ID += mfrc522.uid.uidByte[i];
}
if(card_ID == authKeyFob){
toggle = !toggle;
delay(200);
}
}
// if the button just became pressed...
if(buttonState == HIGH && oldButtonState==LOW){
toggle = !toggle; // same thing, toggle our variable.
delay(200);
}
if (toggle) {
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.run();
} else {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.run();
}
oldButtonState = buttonState; // save the button state for next time
}
The run method doesn't block. It just takes one step if it is time. So let's step through your code. First we enter the while loop and tell it to step to 200 and set the speed and call run. We keep repeating that over and over. If we get to a point where we have 0 to go then you say moveTo the negative position, set the speed, call run once and then the while loop exits and repeats. On that repeat we say move to 200 and start calling run on that. So you're only calling run once with the moveTo set to the negative number.
You need to rethink the logic on this. I don't know what else is in your loop, so it's hard to say what exactly you want. If you really insist on it being blocking in the while loop then:
stepper.moveTo(200);
stepper.setSpeed(200);
while(stepper.distanceToGo() != 0){
stepper.run();
}
stepper.moveTo(-200);
while(stepper.distanceToGo != 0){
stepper.run();
}
This code moves the stepper in each direction.
if (toggle) {
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
while(stepper.currentPosition() <= 200){
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.runSpeedToPosition();
if(stepper.currentPosition()==200){
break;
}
}
} else {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
while(stepper.currentPosition() >= -200){
stepper.moveTo(-200);
stepper.setSpeed(200);
stepper.runSpeedToPosition();
if(stepper.currentPosition()==-200){
break;
}
}
}

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.

Continuous servo rotation Arduino

I have a continuous rotation servo that I need to go clockwise and counterclockwise. I have found the mid point being at 100, and the clockwise and counterclockwise speeds I've found to be the most appropriate are 110 and 85, respectively. The servo rotates clockwise when button A is pushed, and counterclockwise when B is pushed.
I want a way to slow down the servo, once the button is released, at an exponential rate, so that it would say go from 110 to 100, or 85 to 100 in t (user definable) seconds. Is there a function anyone knows of that might help me accomplish this? or a way of doing this. Detailed answers appreciated as I am an Arduino noob.
#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 ledPinB = 4; // sets pin 10 as LED
const int ledPinG = 5; // sets pin 10 as LED
const int ledPinR = 6; // sets pin 10 as LED
// SERVO PROPERTIES
const int crSpeedDefault = 100; // is the stay still position, motor should not turn
const int crSpeedCW = 110; // turns the motor full speed clockwise
const int crSpeedCC = 85; // turns the motor full speed counter-clockwise
// 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 (ledPinB, OUTPUT); // sets led as output
pinMode (ledPinG, OUTPUT); // sets led as output
pinMode (ledPinR, OUTPUT); // sets led as output
myservo.write(crSpeedDefault); // default servo to crSpeedDefault
startup();
}
int startup() {
blinker(2, ledPinB);
blinker(1, ledPinG);
blinker(1, ledPinR);
}
void blinker(int count, int pin) {
for ( int x = 0; x < count; x++ )
{
digitalWrite(pin, HIGH);
delay(1000);
digitalWrite(pin, LOW);
delay(1000);
}
}
void loop()
{
buttonStateCW = digitalRead(buttonPinCW);
buttonStateCC = digitalRead(buttonPinCC);
// clockwise rotation
if (buttonStateCW == HIGH) {
digitalWrite(ledPinR, HIGH);
myservo.write(crSpeedCW);
// counterclockwise rotation
}
else if (buttonStateCC == HIGH) {
digitalWrite(ledPinG, HIGH);
myservo.write(crSpeedCC);
}
else {
myservo.write(crSpeedDefault);
digitalWrite(ledPinR, LOW);
digitalWrite(ledPinG, LOW); // turn the LED off by making the voltage LOW
}
}
Updated with RMI's answer
#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 ledPinB = 4; // sets pin 10 as LED
const int ledPinG = 5; // sets pin 10 as LED
const int ledPinR = 6; // sets pin 10 as LED
const int t = 1; // slow down
// SERVO PROPERTIES
const int crSpeedDefault = 100; // is the stay still position, motor should not turn
const int crSpeedCW = 107; // turns the motor full speed clockwise
const int crSpeedCC = 87; // turns the motor full speed counter-clockwise
// 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 (ledPinB, OUTPUT); // sets led as output
pinMode (ledPinG, OUTPUT); // sets led as output
pinMode (ledPinR, OUTPUT); // sets led as output
myservo.write(crSpeedDefault); // default servo to crSpeedDefault
startup();
}
int startup() {
//blinker(2, ledPinB);
//blinker(1, ledPinG);
//blinker(1, ledPinR);
}
void blinker(int count, int pin) {
for (int x = 0; x < count; x++)
{
digitalWrite(pin, HIGH);
delay(1000);
digitalWrite(pin, LOW);
delay(1000);
}
}
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
}
}
Try This.
void loop()
{
...
// clockwise rotation
if (buttonStateCW == HIGH) {
digitalWrite(ledPinR, HIGH);
float speed = crSpeedCW;
for (int i = 0; i < t * 5; i++) {
speed -= (speed - (float)crSpeedDefault) / 10;
myservo.write((int)speed);
delay(200);
}
myservo.write(crSpeedCW);
}
else if (buttonStateCC == HIGH) {
digitalWrite(ledPinG, HIGH);
// Do the same here in reverse
myservo.write(crSpeedCC);
}
else {
...
}
}
This will slow down the speed exponentially. You have to adjust hard coded numbers to suit your the ranges.

Resources