I am trying to figure out how to write the code so that when a toggle switch is on the servo moves once and stops. Then when I turn to toggle switch to off it moves back to the default position, or zero position. What I have working so far is when the toggle switch is on the for loop starts, but it will just keep going. I am guessing I don't need the for loop has that will keep running.
I am also trying to figure out how to have it run slower since the way it currently works it goes from Zero to 120 real quick and then slowly goes back to the resting position. I have the code about halfway to wait I am intending to do
#include <Servo.h>
int pos = 0; // variable to store the servo position
const int toggleSwitch = 2; // The switch will be on Pin 2
int switchState = 0;
Servo myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created
void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
pinMode(toggleSwitch, INPUT_PULLUP); //turn on pullup resistors
}
void loop()
{
switchState = digitalRead(toggleSwitch);
if (switchState == LOW)
{
for (pos = 0; pos <= 120; pos += 1) // goes from 0 degrees to 120 degrees
// in steps of 1 degree
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(60); // waits 60ms for the servo to reach the position
}
}
}
What you want to do is move your servo when the toggle switch changes state, not based on its current state. Have a look at the StateChangeExample in the IDE (File->examples->02 Digital->StateChangeDetection).
It will show you have to detect when the switch has changed. Then, depending on the change (ON->OFF or OFF->On) you can either move the servo one way or the other.
Quick question regarding that particular Example. When I loaded it up it was constantly showing the state as off except for when I switch it to on. Is that normal for it to do that. Also, if I would use something like that to control a servo. Would it constantly make an effort to bring the servo back to the rest position, or would run once and stop.
You may need your button to be INPUT_PULLUP rather than INPUT depending on how it is wired up. A typical wiring is to connect one side of the button to ground and the other side to the input pin. Then, you declare the input pin as INPUT_PULLUP. This inverts the logic such that a LOW reading means it is pressed (connected to ground) and a HIGH reading means not pressed (connected to Vcc through the internal pull-up resistor)
That example should not report multiple readings of the same value, but it depends on the button wiring.
I will have to double check when I get home, but I believe the One side of the Toggle switch is connected to ground and the other end is connected to Pin 2. So I would need to change to example program/sketch to have the switch as INPUT_PULLUP. I will have to double check that when I get a chance after work.
You need to throw away that for() loop. You probably copied that from the sweep example. That example only demonstrated that you plugged it in properly.
Think about the switch providing a "target" position. The loop() function can loop thousands of times per second, checking the position of the switch and updating the target.
Every 60 milliseconds (or whatever you pick) look at the current position and move it closer to the target by 1. Send that current position to the servo.
For that "every x milliseconds" open up the example called 02. Digital BlinkWithoutDelay and study it closely.
Okay I got the code working basically how I want it to work see code below
/*
* Program to control door with servo on model train layout
* Tony Cochran
*/
#include <Servo.h>
int pos =0; //set position for Servo
const int toggleSwitch = 2; //Switch Pin
int switchState = 0; //Set Switch State
int lastSwitchState = 0; //previous state of the button
Servo shedDoor1; //servo for one side of opening door
// maxium of eight can be created
void setup()
{
// put your setup code here, to run once:
shedDoor1.attach(9);
pinMode (toggleSwitch, INPUT_PULLUP); //turn on pullup resistors
//intialize serial communication
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
switchState = digitalRead(toggleSwitch);
if (switchState != lastSwitchState) //Look at switch State
{
if (switchState == LOW) //set to have toggle switch off to correspond to starting position of the servo
{
Serial.println("on");
pos = 0; pos <=90; pos += 1; //goes from 0 to 90 degrees
//in steps of 1 degree
shedDoor1.write(pos); //move servo
delay(300); //delay
}
else
{
Serial.println("off");
pos =90; pos <=0; pos -= 1; //goes from 90 to 0 degrees
//in steps of 1 degree
shedDoor1.write(pos); //move servo
delay(300); //delay
}
lastSwitchState = switchState;
}
}
What I am trying to determine now is how to have it move at a slower rate, if possible.
Eventually I want to try to have a second servo move after the first one moved. Which I think will primarily mean copying the code that currently moves it after some kind of delay. If I am thinking correctly.
I am not entirely sure what was meant with setting the millisecond. I opened it up and had the Built-in Led Blinking steadily. I am not entirely sure where it should be placed it in my code I have written.
It shows you how to track elapsed time rather than using delay(). This allows loop() to basically run continuously and whenever the elapsed time is great enough, you increment/decrement your pos and send it to the servo. You then record that time and start tracking elapsed time again, etc.
I got it to delay for the movement of the servo after the switch is triggered it has a 500 millisecond delay between the changing of the switch and the movement of the servo. What I am really trying to do is have the actual movement of the servo be controlled by the time. So I am not entirely sure where in my code it should be located to actually control how fast the servo moves.
See code I have.
/*
* Program to control door with servo on train layout
* Tony Cochran
*/
#include <Servo.h>
int door1pos =1; //set position for servo
const int toggleSwitch =2; //Switch Pin
int switchState = 0; //set Switch State
int lastSwitchState =0; //previous state of button;
Servo shedDoor1; //servo for one door
//maxium of eight created
unsigned long previousMillis = 0; //Last time servo moved
const long interval = 500;
void setup() {
// put your setup code here, to run once:
shedDoor1.attach(9);
pinMode (toggleSwitch, INPUT_PULLUP); //turn on pullup resistors
Serial.begin(9600);
}
void loop()
{
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
switchState = digitalRead(toggleSwitch);
if (currentMillis - previousMillis >= interval) //set interval
{
previousMillis = currentMillis;
if (switchState != lastSwitchState) //Look at switch State
{
if (switchState == LOW) // set toggle switch to on for opening door
{
Serial.println("Switch is on, open Door");
door1pos = 1; door1pos <=90; door1pos += 1; //goes from 0 to 90 degrees
//in steps of 1 degree
shedDoor1.write(door1pos);
}
else
{
Serial.println("Switch is off, close door");
door1pos = 90; door1pos >= 1; door1pos -= 1; //goes from 90 to 0 degrees
shedDoor1.write(door1pos);
}
lastSwitchState = switchState;
previousMillis = currentMillis;
}
}
}
You took out the "for()" but you left this bit behind...
door1pos = 1; door1pos <=90; door1pos += 1; //goes from 0 to 90 degrees
//in steps of 1 degree
Do you know what that part does? It doesn't do what the comment says. Let's analyze this a bit more...
First, the semicolons ( ; ) split up statements in C code. Usually we only write one statement per line because it is easier for humans to read that way. The compiler doesn't care. You could write the entire program on one line and it would run just fine except it would be difficult to edit without a really wide screen.
So let's put it on separate lines...
door1pos = 1;
door1pos <=90;
door1pos += 1;
The first line assigns the value of 1 to door1Pos.
The second line compares the value of 90 with door1Pos. But it doesn't do anything with that comparison. The result is ignored.
The last line is a compound addition and assignment. It increments door1Pos by 1.
So those 3 lines could be replaced with:
door1Pos = 2;
Now do you see why the "steps of 1" doesn't work?
Think about the switch as a command. It commands either 0 or 90. But you do not want to instantly slam the servo from one to the other. So you should take a step towards that goal every 50 milliseconds or so. If you are at the goal then you don't need to take a step. Keep checking the switch. It may have moved while the door was in transit.
It still confuses me a bit. How can I set it up so that when the switch is off, the servo moves back toward position zero or 1. Then when the switch is on the servo moves from zero or 1 to 89 or 90.
If I am an understanding it I only really need the position argument and then somehow in the if statement tell the servo to go to 90, and have the millis statement in there as well. I have looked at the Blink Without Delay example, but I seem to be unable to grasp the concept behind it.
Thousands of times per second the Arduino looks to see if it is time to do something. In the original BWoD sketch, it only needs to flip the light on or off every 1000 milliseconds.
A millisecond might seem fast to you but the slow Arduinos can do 16000 things in a millisecond. Every time you do delay(10) it is like asking you to close your eyes and do nothing for a week.
For your sketch, shorten the BWoD interval and instead of blinking a light, move your servo one step closer to its destination.
I think my problem even after reading the tutorial, is that it doesn't go into how it works. I may be able to figure it out if I could understand how it works. All I see is it saying open up the arduino IDE and copy this code and it will work. It doesn't go into how it works, at least not in my read through.
Is the code included below even heading the write direction.
/*
Program to control door with servo on train layout
Tony Cochran
*/
#include <Servo.h>
int door1pos = 1; //set position for servo
const int toggleSwitch = 2; //Switch Pin
int switchState = 0; //set Switch State
int lastSwitchState = 0; //previous state of button;
Servo shedDoor1; //servo for one door
//maxium of eight created
unsigned long previousMillis = 0; //Last time servo moved
//constant's won't change
const long interval = 500; //interval at which to move servo
void setup() {
// put your setup code here, to run once:
shedDoor1.attach(9);
pinMode (toggleSwitch, INPUT_PULLUP); //turn on pullup resistors
Serial.begin(9600);
}
void loop()
{
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
switchState = digitalRead(toggleSwitch);
if (currentMillis - previousMillis >= interval)
{
//save the last time the servo moved
previousMillis = currentMillis;
//Check Switch state
if (switchState == LOW) // set toggle switch to on for opening door
{
Serial.println("Switch is on, open Door");
door1pos = 1;
shedDoor1.write(door1pos);
}
else
{
Serial.println("Switch is off, close Door");
door1pos = -1;
shedDoor1.write(door1pos);
}
lastSwitchState = switchState;
}
}
I think I got everything figured out. I have it moving at a slower right and then I think having it stop at a certain position. I am just looking to see if there is any improvements that can be done, or if there is a more efficient way of doing what I think it is doing. It looks like it using a virtual arduino and servo on tinkercad.
See code below
/*
Program to control door with servo on train layout
Tony Cochran
*/
#include <Servo.h>
int door1pos = 1; //set position for servo
const int toggleSwitch = 2; //Switch Pin
int switchState = 0; //set Switch State
int lastSwitchState = 0; //previous state of button;
Servo shedDoor1; //servo for one door
//maxium of eight created
unsigned long previousMillis = 0; //Last time servo moved
unsigned long currentMillis = 0; //set millis at start of loop
//constant's won't change
const long interval = 80; //interval at which to move servo
void setup() {
// put your setup code here, to run once:
shedDoor1.attach(9);
pinMode (toggleSwitch, INPUT_PULLUP); //turn on pullup resistors
Serial.begin(9600);
}
void loop()
{
// put your main code here, to run repeatedly:
currentMillis = millis();
switchState = digitalRead(toggleSwitch);
if (currentMillis - previousMillis >= interval)
{
//save the last time the servo moved
previousMillis = currentMillis;
//Check Switch state
if (switchState == LOW) // set toggle switch to on for opening door
{
Serial.println("Switch is on, open Door"); //Serial print out to check switch state
if (door1pos != 90) //move servo to 90 degrees and stop
{
door1pos += 1; //move position up one degree
shedDoor1.write(door1pos); //write servo position
}
}
else
{
Serial.println("Switch is off, close Door"); //Serial print out to check switch state
if (door1pos != 0) //move servo to 0 degrees and stop
{
door1pos -= 1; //move position back one degree
shedDoor1.write(door1pos); //write servo position
}
}
lastSwitchState = switchState; //load last know switch position
}
}
if (door1pos != 90) //move servo to 90 degrees and stop
Get into the habit of using greater-than or less-than instead of equals. You might change the code later to work in steps of 4 and then it will never exactly equal 90 and will break the motor trying to drive past the stops.
if (door1pos < 90) //move servo to 90 degrees and stop
This also lets it "recover" if something sets the position outside the valid range. Up or down will eventually bring it back to the valid range instead of stopping just outside the valid range.
You are printing a LOT. On a real Arduino, this will slow down your door significantly. Once you've validated that open and close are the right way around, remove those Serial.println() statements.
You are testing the state of the switch inside the 80-millisecond interval. That's OK for a switch but for a button it might be possible for a rapid "slap" of the button to last less than 80ms. Usually you would check the state of the input buttons at the highest possible speed. Then use that as an input to the slower parts of the program.
I plan on removing the print statements when I have things working as I intend them too. I designed it to use a switch, due to how I plan on using it. So, I didn't think of it how it would function if I used a button instead of a switch.
That being mentioned what would be recommended if using a button instead of a switch.