Hello.
I am trying to make a little sketch that are supposed to to this.
Make a 360 servo spin to a random angle every (random minute from 1-50)
Also i have a button that when pressed bypasses the random minute time and execute the random servo angle.
The thing is that the servo only moves when i press the button, it is not moving at a random time.
Below is the code. and a diagram I have read "read this before posting" and searched the forum without luck i am pretty good with electronics but my coding skill is no good.
I tried to comment the code with help from a friend.
I am thinking that it is my "Delays" that ruin the code.
Would appreciate any help.
Using a arduino duemilanova and a 360 servo and a simple microswitch.
#include<Servo.h>
Servo myservo; //create object from servo
volatile int Sposition = 0; // Declare varable in volatile mode. Because we wish to use interrupts. Otherwise CPU missed main routine varibale data
const int button =2; // input from momentary button
volatile long randNo,randSer; // varible for store random angle and random time
volatile int turn,rest; // varible for store number of half count and rest angle
volatile int i,j; // varible for "for"loops
void setup() {
Serial.begin (9600);
pinMode(button, INPUT); //momentary button input configures as input
myservo.attach(10); // Servo attached into pin No 10
attachInterrupt(0,servoPosition,LOW); //Interrupt initilized with high to low trigger, It will call servoPosition function whne butoon pressed
}
void loop() { // main loop
Serial.println ("Button 2 pressed.");
randNo=random(0,50); // Generate random number in between 0 and 50. Becuase we need upto 50 minutes delay
delayloop(); // Delay loop function for tak e the delay
servoPosition(); // After button pressed or time is exceed from 50 minutes. This function will be called
}
void delayloop(void) // Delay loop function
{
for(i=0;i<randNo;i++) // Loop for take our time according to random number. We have create single 1 minute delay and loop in upto random nuber
{
delay(1000*60); //single 1 minute delay.
}
}
void servoPosition() // Servo will run according to this function
{
Sposition=random(0,500); // Generate random number from 0 to 500. It's for angle
if(Sposition>180) //If random angle is more than 180,we should divide it into half rotations and rest for small angles
{ //Normally servo library support upto 180 degree abgle. So we have to know about how many half rotation has in random angle
turn=Sposition/180; //Extract number of half rotations
rest=Sposition%180; // Estract how much angle it has after half rotations
for(j=0;j<turn;j++) // Loop for get the half rotations.Ex-if random angle is 400, we have 2 half rotations (400=180*2+40)
{
myservo.write(180);
delay(15); // Servo need small delay for set the angle
}
myservo.write(rest); // Rest angle after half rotations. According to above example. It is 40 degree
delay(15); // Servo need small delay for set the angle
}
else // If random angle is less than 180'. We just place that into servo. Because library can handle that angle
{
myservo.write(Sposition); // Set servo into specific location
delay(15);
}
}
attachInterrupt(0,servoPosition,LOW); //Interrupt initilized with high to low trigger, It will call servoPosition function whne butoon pressed
Your comment is WRONG.
There is NO reason to be using an interrupt to read a switch. Get rid of the stupid delayloop() call and function. Read, understand, and embrace the blink without delay example's philosophy, and write the code correctly.
Quit abusing global variables. Learn to pass arguments to functions.
delay() has absolutely NO place in an interrupt service routine.
Try to understand what's happening and you will see the benefit of getting rid of that blocking code.
you can work on getting the delays out of the servoPosition() function too...
something close to this may work:
#include<Servo.h>
Servo myservo; //create object from servo
volatile int Sposition = 0; // Declare varable in volatile mode. Because we wish to use interrupts. Otherwise CPU missed main routine varibale data
const int button =2; // input from momentary button
volatile long randSer; // varible for store random angle and random time
int randNo=random(0,50);
volatile int turn,rest; // varible for store number of half count and rest angle
volatile int i,j; // varible for "for"loops
unsigned long timerStart;
unsigned long oneMinute = 60000UL;
boolean trigger, pressed;
int lastButtonState;
void setup()
{
Serial.begin (9600);
pinMode(button, INPUT_PULLUP); //momentary button input configures as input
myservo.attach(10); // Servo attached into pin No 10
}
//
void loop()
{
int buttonState = digitalRead(button);
if (buttonState == LOW)
{
if (lastButtonState == HIGH)
{
pressed = true;
Serial.println(F("Button 2 pressed."));
}
}
lastButtonState = buttonState;
randomTrigger(randNo);
if ((trigger) || (pressed))
{
servoPosition(); // After button pressed or time is exceed from 50 minutes. This function will be called
pressed = false;
trigger = false;
}
}
//
void servoPosition()
{
Sposition=random(0,500);
if(Sposition>180)
{
turn=Sposition/180; //Extract number of half rotations
rest=Sposition%180; // Estract how much angle it has after half rotations
for(j=0;j<turn;j++) // Loop for get the half rotations.Ex-if random angle is 400, we have 2 half rotations (400=180*2+40)
{
myservo.write(180);
delay(15); // Servo need small delay for set the angle
}
myservo.write(rest); // Rest angle after half rotations. According to above example. It is 40 degree
delay(15); // Servo need small delay for set the angle
}
else // If random angle is less than 180'. We just place that into servo. Because library can handle that angle
{
myservo.write(Sposition); // Set servo into specific location
delay(15);
}
}
void randomTrigger(int myDelay)
{
if (millis() - timerStart >= myDelay * 60000UL)
{
trigger = false;//
}
else
{
trigger = true;
randNo = random(0,50);// next random
timerStart = millis();
}
}
PaulS:
There is NO reason to be using an interrupt to read a switch. Get rid of the stupid delayloop() call and function. Read, understand, and embrace the blink without delay example's philosophy, and write the code correctly.
Quit abusing global variables. Learn to pass arguments to functions.
delay() has absolutely NO place in an interrupt service routine.
Thanks for the input (abit harsh though)
Reading the "blink without delay" now
Why is global variables bad for such a small sketch?
Hard to get rid of the delay function when you have learned it, but will try. Har to wrap my head around the passing of arguments to functions, but i will try.
Why is global variables bad for such a small sketch?
Lets take a look at one example:
void delayloop(void) // Delay loop function
{
for(i=0;i<randNo;i++) // Loop for take our time according to random number. We have create single 1 minute delay and loop in upto random nuber
{
delay(1000*60); //single 1 minute delay.
}
}
Now, where the hell did randNo come from? Is it the correct type? Does it contain a meaning value?
Compare that to:
void delayloop(long cnt) // Delay loop function
{
for(i=0; i<cnt; i++) // Loop for take our time according to input value.
{
delay(1000*60); //single 1 minute delay.
}
}
Now, its obvious where the loop limit value came from, what its type is, and the comment now has nothing to do with HOW cnt got a value (which is as it should be).
Why is global variables bad for such a small sketch?
Lets take a look at one example:
void delayloop(void) // Delay loop function
{
for(i=0;i<randNo;i++) // Loop for take our time according to random number. We have create single 1 minute delay and loop in upto random nuber
{
delay(1000*60); //single 1 minute delay.
}
}
Now, where the hell did randNo come from? Is it the correct type? Does it contain a meaning value?
the randNO is stated on line 21: randNo=random(0,50);
Compare that to:
void delayloop(long cnt) // Delay loop function
{
for(i=0; i<cnt; i++) // Loop for take our time according to input value.
{
delay(1000*60); //single 1 minute delay.
}
}
Now, its obvious where the loop limit value came from, what its type is, and the comment now has nothing to do with HOW cnt got a value (which is as it should be).
Lioncour:
Any reason why you are using the internal pulldown resistor in the arduino? I was told it was better do use a resistor to ground to pulldown buttons.
-A
I did it only so the logic (HIGH's and LOW's) reflect the expected behaviour of the sketch...
freestyle as you see fit!
(I can't argue the pro's and con's of pull-up versus pull-downs)
PS you may have to debounce your pushbutton, but that just leaves more fun to be had!
Any reason why you are using the internal pulldown resistor in the arduino?
It's not a pulldown resistor. It's a pullup resistor. The reasons for using them are many. The internal pullup resistor has never been forgotten, soldered incorrectly, or shorted to anything else. And, you've paid for it already. External resistors can be forgotten, soldered incorrectly, shorted, and need to be sourced and paid for.
I was told it was better do use a resistor to ground to pulldown buttons.
You were told something that was wrong. Pullup OR pulldown resistors doesn't really matter, as long as you write the code to match the way the resistor is wired. But, since the Arduino comes with pullup resistors, it makes sense to use them.
PS you may have to debounce your pushbutton, but that just leaves more fun to be had!
[/quote]
Yes. tested your code, and the bouncing of the button made the servo move like cracy.
earlier i would have debounced it with a delay, but not anymore.
-A
The internal resistors on the Arduino lines are pull-up resistors, not pull-downs. You're going to confuse people using the wrong term.
There's no reason not to use it. It inverts the logic of switches, but that's easy to adjust for. It eliminates the need for an external resistor, which makes for one less component in your circuit.
What reason have you read for not using INPUT_PULLUP?
Lioncour:
#include<Servo.h>
pinMode(button, INPUT_PULLUP); //momentary button input configures as input
}
Any reason why you are using the internal pulldown resistor in the arduino? I was told it was better do use a resistor to ground to pulldown buttons.
Lioncour:
Yes. tested your code, and the bouncing of the button made the servo move like cracy.
earlier i would have debounced it with a delay, but not anymore.
-A
yes! now you are a fierce programmer determined to learn how to debounce a button!!
earlier i would have debounced it with a delay, but not anymore.
Now that we've beaten you up for using delay(), debouncing is a case where a delay() IS acceptable. Think about how long a switch might bounce. A decent quality switch will settle in less than 10 milliseconds. A delay(10); only when the switch state changes to pressed (to avoid bouncing) is not that bad.
A delay(10); on every pass through loop() would be.
PaulS:
A delay(10); on every pass through loop() would be.
Could not figure out where to place the delay, Tried instead with
long lastDebounceTime = 0;
long debounceDelay = 50; and the rest of the http://arduino.cc/en/Tutorial/Debounce
Not understanding where i am supposed to bake this into the code.
btw, have ditched almost all my original code and are using the one from BulldogLowell.
But i am not getting any wiser. Need a pointer i think,
but my blink without delay is going great.
Lioncour:
Not understanding where i am supposed to bake this into the code.
-A
try here... at the moment of the state change of the button pin:
void loop()
{
int buttonState = digitalRead(button);
if (buttonState == LOW)
{
if (lastButtonState == HIGH)
{
pressed = true;
Serial.println(F("Button 2 pressed."));
delay(20);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Here, but you may have to tweak your number
}
}
lastButtonState = buttonState;
randomTrigger(randNo);
if ((trigger) || (pressed))
{
servoPosition();
pressed = false;
trigger = false;
}
}
try here... at the moment of the state change of the button pin:
[/quote]
Now the button works like a charm,
But my servo is spinning like crazy.
i did a Serial.println(Sposition); (still using the code you whacked out)
And it looks like the arduino is giving the servo new angles continuesly, like it is skipping the whole waiting for random time part of the code.
Anyone knows why?
#include<Servo.h>
Servo myservo; //create object from servo
volatile int Sposition = 0; // Declare varable in volatile mode. Because we wish to use interrupts. Otherwise CPU missed main routine varibale data
const int button =2; // input from momentary button
volatile long randSer; // varible for store random angle and random time
int randNo=random(0,50);
volatile int turn,rest; // varible for store number of half count and rest angle
volatile int i,j; // varible for "for"loops
unsigned long timerStart;
unsigned long oneMinute = 60000UL;
boolean trigger, pressed;
int lastButtonState;
void setup()
{
Serial.begin (9600);
pinMode(button, INPUT_PULLUP); //momentary button input configures as input
myservo.attach(10); // Servo attached into pin No 10
}
//
void loop()
{
int buttonState = digitalRead(button);
if (buttonState == LOW)
{
if (lastButtonState == HIGH)
{
pressed = true;
Serial.println(F("Button 2 pressed."));
delay(200);
}
}
lastButtonState = buttonState;
randomTrigger(randNo);
if ((trigger) || (pressed))
{
servoPosition(); // After button pressed or time is exceed from 50 minutes. This function will be called
pressed = false;
trigger = false;
}
}
//
void servoPosition()
{
Sposition=random(0,500);
if(Sposition>180)
{
turn=Sposition/180; //Extract number of half rotations
rest=Sposition%180; // Estract how much angle it has after half rotations
for(j=0;j<turn;j++) // Loop for get the half rotations.Ex-if random angle is 400, we have 2 half rotations (400=180*2+40)
{
myservo.write(180);
delay(15); // Servo need small delay for set the angle
}
myservo.write(rest); // Rest angle after half rotations. According to above example. It is 40 degree
delay(15); // Servo need small delay for set the angle
}
else // If random angle is less than 180'. We just place that into servo. Because library can handle that angle
{
myservo.write(Sposition); // Set servo into specific location
delay(15);
}
}
void randomTrigger(int myDelay)
{
if (millis() - timerStart >= myDelay * 60000UL)
{
trigger = false;//
}
else
{
trigger = true;
randNo = random(1,50);// next random
timerStart = millis();
Serial.println(Sposition);
}
}