Help!!!

Hello All,

I’m doing a project for school involving bottle rockets.
I need to measure the altitude that it goes to, as well as release a parachute.
The RF transmitter/receiver set I got didn’t work that great, so I opted to have the Arduino log the altitude to an SD card.
The basics of what I want the sketch to do is: detect if a button is pressed, and set the button count to 1, which tells the loop to start the launch sequence. Three seconds after, the parachute is released by a servo. All the while, the Arduino reads the BMP085 altimeter and logs the results to the SD card.
My code is attached, but I just cannot get it to work. I’m starting to tear my hair out. I’m only 18, but I’ll look 3 times that if I don’t solve this!!! :confused:

Many thanks in advance!

Warwick

bottlerocketcode.zip (1.4 KB)

Don’t use a zip file.
Just attach the ino file.
OR
If the sketch is small enough, you can use code tags.

Attach your code using the </> icon on the left side of the posting menu.
Put your sketch between the code tags [code][/code]

.

^the sketch is small enough to use code tags.

you never said what the actual problem is but I suspect you need to look this: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Hi Warwickshaw,

So... what does it do and what fails?

Pat.

After you post your code using code tags, explain what the program should do, and what it does instead.

What sensor are you using to measure altitude? I might be able to use it on my Arduino RC plane.

Hello,

I’ve attached the code, below.
As I said before, it is supposed to detect when the button is pressed and count how many times it is pressed. I should have mentioned that I want the button press count to reset when it gets to three, and that if button press is one, to run the main code (read altitude, release parachute, etc, etc)
It refuses to run the main code when buttonPress is 1, and won’t reset the # of times it has been pressed.

Warwick

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <SPI.h>
#include <SD.h>
#include <Servo.h>

Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);

Servo servo;

const int chipSelect = 10;
int rledPin = 2;
int gledPin = 3;
int buttonPin = 4;
int buttonState = 0;
int buttonPress = 0;


//display the BMP085 details
void displaySensorDetails(void){
  sensor_t sensor;
  bmp.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" hPa");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" hPa");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" hPa");  
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}

void setup(void){
  Serial.begin(9600);
  if(!bmp.begin()){
    Serial.print(No BMP085 detected.");
    while(1);
  }
  displaySensorDetails();

  while(!Serial){
    ;
  }
  Serial.print("Initializing SD card...");

  if(!SD.begin(chipSelect)){
    Serial.println("Card failed, or not present.");
    return;
  }
  Serial.println("Card initialized.");
  pinMode(rledPin, OUTPUT);
  pinMode(gledPin, OUTPUT);
  
  //flash the green led to show that the system is ready
  pinMode(buttonPin, INPUT);
  for(int c = 0; c < 5; c++){
    digitalWrite(gledPin, HIGH);
    delay(400);
    digitalWrite(gledPin, LOW);
    delay(400);
  }
  servo.attach(8);                     //attach the servo
  servo.write(180);                   //put it to the ready position
  digitalWrite(gledPin, HIGH);    //steady green light to say that it is ready to launch
}

void loop(){
  buttonState = digitalRead(buttonPin);     //This counts 
  if(buttonState == LOW){                       //the number
    buttonPress++;                                  // of button
    Serial.print(buttonPress);                    //presses
    delay(300);
  }else{
    if(buttonPress == 3){                         //resets the buttonPress
      buttonPress == 0;                            // variable to 0
    }
    return;
  }

  if(buttonPress == 1){                           //main code
    return;
  }else if(buttonPress == 1){
    for(int f = 1; f < 11; f++){
      digitalWrite(rledPin, HIGH);
      delay(500);
      digitalWrite(rledPin, LOW);
      delay(500);
    }
    digitalWrite(rledPin, HIGH);                //steady red light to indicate launch (this is when I pull the pin!)
    sensors_event_t event;
    bmp.getEvent(&event);
    if (event.pressure){
      Serial.print("Pressure:    ");
      Serial.print(event.pressure);
      Serial.println(" hPa");
    
      /* First we get the current temperature from the BMP085 */
      float temperature;
      bmp.getTemperature(&temperature);
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" C");
    
      /* Then convert the atmospheric pressure, and SLP to altitude         */
      /* Update this next line with the current SLP for better results      */
      float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
      Serial.print("Altitude:    "); 
      Serial.print(bmp.pressureToAltitude(seaLevelPressure, event.pressure)); 
      Serial.println(" m");
      Serial.println("");
    
      File dataFile = SD.open("datalog.txt", FILE_WRITE);

     // if the data file is available, write to it:
      if (dataFile){
        dataFile.println((bmp.pressureToAltitude(seaLevelPressure, event.pressure)));
        delay(500);
        dataFile.close();
        // print to the serial port too:
        Serial.println((bmp.pressureToAltitude(seaLevelPressure, event.pressure)));
      }
      // if the file isn't there:
      else {
        Serial.println("error opening datalog.txt");
      }
      delay(500);
    }else{
      Serial.println("Sensor error");
    }
    delay(1000);
    buttonPress == 2;                                      //make sure that the loop doesn't repeat
  }
}

void parachute(){
  if(buttonPress == 1){                                   //when button is pressed
    delay(3000);                                              //wait three seconds
    servo.write(75);                                         //release the parachute
    delay(1000);                                              //wait a bit
    servo.write(180);                                        //return to normal position
  }else{
    return;
  }
}

Cool project! :-)

Basically you want to use the arduino as a timer, to release the parachute? That should be easy enough.

From your sourcecode i see, however, that the "parachute()" function is never called, but as it is now with that delay() inside, you can not call it and expect to log data at the same time.

Also you could mount an acceleration sensor and store data from it. :-)

What are all those keypresses about, by the way? You only really need to detect when the rocket is launched. Cleaning up a bit, using functions, your program could look like this:

const int parachuteDelay = 3000;  // three seconds after launch

unsigned long startTime;
boolean parachuteDeployed=false;

void setup() {
    // sd-card and sensors
    ...

    // wait until launching before returning from setup()
    while (!hasLaunched()) ; // just wait
    startTime=millis();
}

// here you do the check for whether rocket is launched or not
boolean hasLaunched() {
    // return true or false depending on whether rocket
    // has launched or not

    // (insert your code here)
}


void loop() {
    // read sensors and log to sd-card
    logData();

    // if parachute has not already been deployed, and it is time to do so, then deploy parachute
    if (!parachuteDeployed && millis()-startTime > parachuteDelay) {
        parachute();
        parachuteDeployed=true;
    }
}


void logData() {
    // (insert your code here)
}

void parachute() {
    servo.write(75);                                         //release the parachute
    delay(1000);                                              //wait a bit
    servo.write(180); 
}

Power_Broker: What sensor are you using to measure altitude? I might be able to use it on my Arduino RC plane.

The Bosch BMP180 barometric sensor has a resolution of as little as 25 cm height difference (0.03 hpa), according to the data-sheet. I have one. This must be tested!! :-)

https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf

Hi warwickShaw,

For starters

buttonPress == 0;

Should only have 1 equal sign. This does not reset the buttonPress value, it compares it to zero and ignores the result.

Fix this first, then see what happens.

You also have an == 2 in there too.

These are correct in if statements, but not assignments.

Pat.

Hi Warwickshaw,

Students at our school do something similar, so I took a quick look at your code. There are some errors.

First thing I noticed is that in your button press detector, you have used "buttonpress == 0" and "buttonpress == 2". Notice that a double equal sign is a test of equality, not an assignment. I believe you want to change the instances of "buttonpress ==" to "buttonpress =", except where you are actually testing the value of the variable, as in "if (buttonpress == 3) {...".

Make sense? The rule is that a single equals sign means check the variable, but a double equals sign sets the variable. (Also think about the logic of looking to see if the variable is exactly 3. What if it missed one, and the variable is 4? Do you want to ignore that, or treat it the same as if it was 3? It's often better to test if a variable is greater than or equal rather than strictly equal.)

The second thing to tackle is to remove all of the timing statements that use delay. This will only make your program run sluggishly, and miss button presses, and generally not work like you want. The flash delay in setup is ok, but you shouldn't use delay indiscriminately in loop!

Have a look at the "blink without delay" code in the Examples menu of the Arduino IDE. Then go study the post called "Demonstration code for several things at the same time". It will show you how to structure your code so that actions don't get lost in the constant delaying. This kind of logic is essential to any real-time control.

Good luck!

Edit: Pat, you beat me by seconds.

Hello everyone,

A huge thanks to everyone!
I corrected the == to =, works wonders! Thanks ChrisTenone and patduino!
When it comes to the timing side of things, its not so bright - I don’t have the time to correct it. The project is due tomorrow! However, I learnt a lot and that’s what counts. Esp as I’m a Vnewbie :wink:

I was also wondering if anyone could help me on this:
I want to read a sensor, and store only the highest value that comes from it. So for an altimeter, it would go from 0 to 40 to 60, and on and on, but it would only store the value when it peaked. How do I do this?
I tried this, but it doesn’t seem to work. I suppose its full of felonious errors, so pls pick it apart.

  if(maxAlt < (bmp.readAltitude(101500))){
    maxAlt = (bmp.readAltitude(101500));
  }

  lcd.print("Max Altitude = ");
  lcd.setCursor(0, 1);
  lcd.print(maxAlt);
  lcd.print(" metres");
  delay(1000);
  lcd.clear();

Thanks!

Warwick

What happens with your code?

LarryD: What happens with your code?

Would you care to elucidate?

Warwick

If you add that code to the sketch, what results do you get form that code?

Edit: What is supposed to be the trigger to store the maximum value? .

Values that go both up and down. I'll run up the stairs, and it will read 251 metres ASL, then I'll run down the stairs and it will go back to 249 metres ASL. I don't want that, I want it to retain the highest value and show only that. Does that make sense?

Warwick

P.S. - "ASL" is Above Sea Level.

May we see the current whole sketch?

I'll run up the stairs,

You must be young ;)

.

:slight_smile: 18 to be precise! (And it is nice to run now and again - I have arthritis, so suchlike activities are rare)
I seem to have figured out my own problem.
But here is the code. If you see any glitches pls let me know!

#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>

int maxAlt = 0;
int rledPin = 3;
int gledPin = 2;
int buttonPin = 4;
int buttonState = 0;
unsigned long previousMillis = 0;
unsigned long previousMillisServo = 6000;
const long interval = 500;
const long intervalServo = 3700;
/*************************************************** 
  This is an example for the BMP085 Barometric Pressure & Temp Sensor

  Designed specifically to work with the Adafruit BMP085 Breakout 
  ----> https://www.adafruit.com/products/391

  These displays use I2C to communicate, 2 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
// Connect GND to Ground
// Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5
// Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4
// EOC is not used, it signifies an end of conversion
// XCLR is a reset pin, also not used here

Adafruit_BMP085 bmp;

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Servo servo;

void setup(){
  Serial.begin(9600);
  bmp.begin();  
  lcd.begin(16, 2);
  pinMode(rledPin, OUTPUT);
  pinMode(gledPin, OUTPUT);
  servo.attach(8);
  servo.write(180);
  for(int n = 0; n < 9; n++){
    digitalWrite(gledPin, HIGH);
    delay(500);
    digitalWrite(gledPin, LOW);
    delay(500);
  }
  digitalWrite(gledPin, HIGH);
  digitalWrite(rledPin, HIGH);
}
  
void loop(){
  servoDo();
  altRead();
}

void servoDo(){
  unsigned long stateTime = millis();
  if (stateTime - previousMillisServo >= intervalServo) {
    // save the last time you blinked the LED
    previousMillisServo = stateTime;
    servo.write(75);
  }
}

void altRead(){
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    
    if(maxAlt < (bmp.readAltitude(101500))){
      maxAlt = (bmp.readAltitude(101500));
    }
    
    lcd.clear();
    lcd.print("Max Altitude = ");
    lcd.setCursor(0, 1);
    lcd.print(maxAlt);
    lcd.print(" metres");
  }
  if(currentMillis == 3000){
    servo.write(75);
  }
  if(currentMillis == 4000){
    servo.write(180);
  }

}

Warwick

  if(currentMillis == 3000){
    servo.write(75);
  }
  if(currentMillis == 4000){
    servo.write(180);
  }

Do you realize these may not evaluate as, millis() therefore currentMillis will only be 3000 and 4000 once every ~49 days. If you aren't checking these lines at those exact times there will be no compare.

.

Yes, I know - I just want it to go back and forth once. It is to release a parachute. BTW, I have a new problem. The LCD which is supposed to display the details works when the Arduino is plugged into the computer, but when it is plugged into a 9V battery, it quits. Also, when I plug it back into the computer, the led connected to pin 13 just flashes constantly and blocks the code. Any suggestions?

Warwick