Hello forum members,
I am actually a beginner in arduino. I do not have a lot of idea about programming but we have a school project of launching a rocket and we have to measure the initial velocity , maximum height and distance travelled by the rocket with the help of arduino program. The rocket will be placed on a ramp. When the rocket( coke bottle filled with vinegar and baking soda) is placed on the lamp it will be touching the first switch in its on state (i.e 1 ) and when the rocket is fired , then it will release the first switch(i.e 0) and will go through ramp touching the second switch placed at certain distance making it first in on state and then off state. So my idea was to calculate the time using interrupts on those two switch as sensors and from the time calculated we can measure initial velocity.
Problems: I got the code but it keeps measuring the initial velocity all the time. I want the code to measure the initial velocity only at the time when the rocket is fired. Please help me and Thank you very very much for your time and consideration.
Sorry my english is not so good. I will post my code and circuit diagram here.Thanks
Thank you Robin2 . I don't know how to post my code so i post it as an attachment. How can i post my code so that everybody should not have to download the code. Thanks.
The variables for the time should be unsigned long.
You need another boolean variable that is normally false and is set to true in your second_Interrupt(). Then your code in loop() will not do anything unless it knows the second interrupt has been triggered.
Also, you need to pause interrupts while reading the values in loop() in case another interrupt changes the values - probably unlikely in this case, but it is good practice. Something like this
#include<TimerOne.h>
#define switch1 2
#define switch2 3
int deg=45;
volatile unsigned long first_time=0;
volatile unsigned long second_time=0;
volatile boolean secondInterruptTriggered = false;
unsigned long copyOfFirstTime;
unsigned long copyOfSecondTime;
unsigned long elapsed_time;
float speed;
float height;
float range;
void setup() {
pinMode(switch1,INPUT);
pinMode(switch2,INPUT);
Serial.begin(9600);
Serial.println("waiting for projectile");
Serial.println(" Speed(Mps):\tHeight tRange:");
Timer1.initialize(500000);
// NOTE HIGH and LOW is wrong here, it should be RISING or FALLING,
// but I'm not sure which is appropriate for each case
attachInterrupt(digitalPinToInterrupt(2),first_Interrupt,HIGH);
attachInterrupt(digitalPinToInterrupt(3),second_Interrupt,LOW);
Timer1.attachInterrupt( isr_timer );
}
void loop() {
if (secondInterruptTriggered == true) {
noInterrupts();
copyOfFirstTime = first_time;
copyOfSedondTime = second_time;
secondInterruptTriggered =false;
interrupts();
elapsed_time = copyOfSecondTime-copyOfFirstTime; //elapses_time being calculated in millis
speed = (0.9*pow(10,3))/elapsed_time; //0.9 m is the distance between two switch
height = (pow(speed,2)*sin(deg*0.017))/19.6; //0.017 is the value when degree is converted into radian and 19.6 is two times gravity
range = (pow(speed,2)*sin(deg*0.034))/9.8;
Serial.print("\t");
Serial.print(speed);
Serial.print("\t");
Serial.print(height);
Serial.print("\t");
Serial.print(range);
Serial.println();
delay(10000);
}
}
void isr_timer()
{
}
void first_Interrupt()
{
first_time=millis();
}
void second_Interrupt()
{
second_time=millis();
seconInterruptTriggered = true;
}
Thanks for the suggestion Chuckyx . Here is the code for my post . Thanks for your consideration.
#include<TimerOne.h>
#define switch1 2
#define switch2 3
int deg=45;
volatile long first_time=0;
volatile long second_time=0;;/'
long elapsed_time;++,,,,,,,,/.
float speed;
float height;
float range;
void setup() {
pinMode(switch1,INPUT);
pinMode(switch2,INPUT);
Serial.begin(9600);
Serial.println("waiting for projectile");
Serial.println(" Speed(Mps):\tHeight tRange:");
Timer1.initialize(500000);
attachInterrupt(digitalPinToInterrupt(2),first_Interrupt,HIGH);
attachInterrupt(digitalPinToInterrupt(3),second_Interrupt,LOW);
Timer1.attachInterrupt( isr_timer );
}
void loop() {
elapsed_time=second_time-first_time; //elapses_time being calculated in millis
speed = (0.9*pow(10,3))/elapsed_time; //0.9 m is the distance between two switch
height = (pow(speed,2)*sin(deg*0.017))/19.6; //0.017 is the value when degree is converted into radian and 19.6 is two times gravity
range = (pow(speed,2)*sin(deg*0.034))/9.8;
Serial.print("\t");
Serial.print(speed);
Serial.print("\t");
Serial.print(height);
Serial.print("\t");
Serial.print(range);
Serial.println();
delay(10000);
}
void isr_timer()
{
}
void first_Interrupt()
{
first_time=millis();
}
void second_Interrupt()
{
second_time=millis();
}
Thanks again Robin2 . I am right now implementing your suggestion to my code but meanwhile would you please have a look at this mathematical part of my code because they were not giving the right value. Perhaps I didn't put the mathematical relation right through arduino code. These are the simple formulas for the projectile motion. Thanks for your time.
void loop() {
elapsed_time=second_time-first_time; //elapses_time being calculated in millis
speed = (0.9*pow(10,3))/elapsed_time; //0.9 m is the distance between two switch
height = (pow(speed,2)*sin(deg*0.017))/19.6; //0.017 is the value when degree is converted into radian and 19.6 is two times gravity
range = (pow(speed,2)*sin(deg*0.034))/9.8;
Serial.print("\t");
Serial.print(speed);
Serial.print("\t");
Serial.print(height);
Serial.print("\t");
Serial.print(range);
Serial.println();
delay(10000);
}
As I understand the switch wiring and ramp arrangement, the bottle is sitting on the first switch(connecting it to ground) and it will open when the bottle is leaves the position, so that interrupt should be RISING.
The second switch will be initially open and close when the bottle gets reaches it, so that interrupt can be "FALLING". In this case, you will need to subtract the length of the bottle from the distance between the two switches.
Are your switches mechanical? If so, there are some interrupt issues related to unintended triggers due to switch "bounce". You may need to write the software so only the initial interrupt is recorded (and not any of the secondary "bounce" transitions. It's possible that the time between the two switch is long in relation to the bounce times, and any the overall effect of multiple triggers may not be meaningful.
You may have some other interrupt issues to deal with, in that the program start up and bottle placement may trigger the interrupts before the actual launch, so you may need to clear any pending interrupt flags.
@cattledog - Hello, Cattledog . I am actually having all the problems that u mentioned in ur reply. I was aware of all those facts but the problems is I don't know how to solve all the switch bounces effect and the false trigger . Yes my switches are mechanical and whatever you mentioned in ur reply those all apply in my case. I don't wanna sound annoying but I would be very grateful if you help me out.
@Robin2 - I implemented your correction to my Program but I still gets a lot of outputs in my serial monitor. My goal is that I want only one output and that also when the rocket leaves the ramp. I want the program to stop when the rocket is done taking off.
Please help me out. I have my project to test tomorrow. Thank you.
RESULTS: I get too many outputs even though I do not touch the switch. Here is the pic of my serial monitor outputs.
Please post a complete version of your most recent code.
Have you independently confirmed the switch wiring with digitalRead() and can see the transitions from HIGH to LOW when the switch closes and from LOW to HIGH when the switch opens?
cattledog:
Please post a complete version of your most recent code.
Have you independently confirmed the switch wiring with digitalRead() and can see the transitions from HIGH to LOW when the switch closes and from LOW to HIGH when the switch opens?
@cattledog - hello ,this one is my latest version of the code improvised by Mr.Robin2.
There is no problems with HIGH and FALL , I used RISING for the first switch and FALLING for the second switch.
I basically want to cancel the switch bounce and also I want to the code to give me output once and only when the rocket is fired.
#include<TimerOne.h>
#define switch1 2
#define switch2 3
int deg=45;
volatile unsigned long first_time=0;
volatile unsigned long second_time=0;
volatile boolean secondInterruptTriggered = false;
unsigned long copyOfFirstTime;
unsigned long copyOfSecondTime;
unsigned long elapsed_time;
float speed;
float height;
float range;
void setup() {
pinMode(switch1,INPUT);
pinMode(switch2,INPUT);
Serial.begin(9600);
Serial.println("waiting for projectile");
Serial.println(" Speed(Mps):\tHeight tRange:");
Timer1.initialize(500000);
// NOTE HIGH and LOW is wrong here, it should be RISING or FALLING,
// but I'm not sure which is appropriate for each case
attachInterrupt(digitalPinToInterrupt(2),first_Interrupt,FALLING);
attachInterrupt(digitalPinToInterrupt(3),second_Interrupt,RISING);
Timer1.attachInterrupt( isr_timer );
}
void loop() {
if (secondInterruptTriggered == true) {
noInterrupts();
copyOfFirstTime = first_time;
copyOfSecondTime = second_time;
secondInterruptTriggered =false;
interrupts();
elapsed_time = copyOfSecondTime-copyOfFirstTime; //elapses_time being calculated in millis
speed = (0.9*pow(10,3))/elapsed_time; //0.9 m is the distance between two switch
height = (pow(speed,2)*sin(deg*0.017))/19.6; //0.017 is the value when degree is converted into radian and 19.6 is two times gravity
range = (pow(speed,2)*sin(deg*0.034))/9.8;
Serial.print("\t");
Serial.print(speed);
Serial.print("\t");
Serial.print(height);
Serial.print("\t");
Serial.print(range);
Serial.println();
delay(10000);
}
}
void isr_timer()
{
}
void first_Interrupt()
{
first_time=millis();
}
void second_Interrupt()
{
second_time=millis();
secondInterruptTriggered = true;
}
basically want to cancel the switch bounce and also I want to the code to give me output once and only when the rocket is fired
I'm not certain if your FALLING and RISING triggers are correct, or if you are getting the proper signals from your switches. However, with that said --
To clear any pending interrupt flags created with the attachInterrupt() add this line of code as follows
attachInterrupt(digitalPinToInterrupt(2),first_Interrupt,FALLING);
attachInterrupt(digitalPinToInterrupt(3),second_Interrupt,RISING);
EIFR = B00000011;//clear flags by writing 1 to External Interrupt Flag Register locations INTF1/INTF0
A google search on "clear pending interrupt flags Arduino" will give you some information.
A simple way to only get one set of readings is to detach the external interrupts after the first set of readings.
Try placing the detachInterrupt() statements into the corresponding ISRs.
This approach may not work because the interrupts are actually triggered and the timing of the flag clearing and the isr execution is not clear to me. In that case, try move the detach statements to the reading section. There may be multiple triggers with switch bounce, but I don't think the time scale of the bounce is large compared to the spacing between the switches.
With the interrupts detached, You may not need the copy variables, but can work directly with first_time and second_time variables.
If you just want the code to show one message then add a variable to check that has happened. Perhaps call it outputDisplayed and start with it false. Then change this line
if (secondInterruptTriggered == true) {
to
if (secondInterruptTriggered == true and outputDisplayed == false) {
outputDisplayed = true;
However I suspect you need to experiment to check that your switches are working the way you want. Interrupts have a life of their own so they can be difficult to debug. You may need to write a program that allows you to capture several triggers of both interrupts.
Approximately how long should the rocket require to pass from the base switch to the top switch?
Maybe the interrupt for the top switch should only be attached AFTER the rocket has left the base? And maybe the time interval should be the gap between the time of the last base interrupt and the first top interrupt?
Why are you using interrups at all?
Don't worry about debouncing.
Before the rocket has launched everything is stable nothing is changing.
As soon as the state of the SW1 changes you know the rocket has launched and you note the time.
It does not matter if SW1 then bounces on and off.
Your program then monitors SW2 and as soon as it changes state you note the time.
It does not matter if SW2 then bounces on and off.
You now have the time between the rocket activating SW1 and SW2.
As well as the millis() function there is a micros() function.
Both functions will overflow so if your rocket is going to sit on the launch pad for more than 50 days in the case of millis() or 70 minutes in the case of micros() you would need to cater for that.
It takes time to process an interrupt so if you don't use them you actually get a slightly more accurate reading.
speed = (0.9*pow(10,3))/elapsed_time; //0.9 m is the distance between two switch
It hardly seems necessary to use the pow function to approximate 10 * 10 * 10. It hardly seems necessary to perform 4 multiplications to calculate a constant.
To follow up on Ardly's suggestion to not use interrupts, there is a very simple way of making a one shot timer with two while() loops.
while(digitalRead(switch1) == LOW){} //wait until switch1 goes HIGH on opening when rocket leaves
startTime = micros();
while (digitalRead(switch2) == HIGH){}//wait until switch2 goes LOW on closure when rocket arrives
endTime = micros();
duration = endTime-startTime
This can be made faster with use of direct port readings instead of digitalRead() and more precise with the use of hardware timer counts instead of micros().
If the while() loops and the calculation were all in setup() it would only run once.
I know it is great fun to dive into programming but there is a big payoff to sitting back with pencil and paper and analysing a problem carefully before you come up with solutions.
Here are a couple of things to think about;
I take my Porsche 918 Spyder onto a race track and drive 3 miles in 1 minute. Was my ‘speed’ 180mph or could I use more precise language?
What are the differences between a cannon ball being fired from a cannon and a rocket being launched from a pad?