Using debounce button as on/off button to trigger BMP280 to read altitude

I'd simplify the code like this:

case ARMED:
      buttonState = digitalRead(buttonPin);
      if (buttonState == 0) break; //nothing to do - assuming pulldown resistor!
      bmp280.getAltitude(launchSiteAltitude);  //until launched
      //delay(100); //debounce only required if bmp280 reading too fast
      if (!digitalRead(buttonPin)) break; //short form of above, still nothing to do

    //else launch
        Serial.println(F("Launching"));
        Serial.print(launchSiteAltitude);
        Serial.println("m");
        stateMachine = LAUNCH;
        ledState = 1;
        digitalWrite(ledPin, ledState); //does this really launch the rocket?
      break;


    case LAUNCH:
      altitude = bmp280.getAltitude(currentAltitude) - launchSiteAltitude;
      if (altitude > threshold)
      {
        Serial.println("LAUNCHED");
        stateMachine = DEPLOY;
      }
      break;

Thanks DrDiettrich! I will definitely try out these codes and hopefully they would resolve the issue that I have.
Thanks again! :smiley: :raised_hands:

I have switched to use the simplified code that you suggested, it's good, but I still have the same problem with the codes not being able to move on to the next phrase after the ARMED phrase :disappointed_relieved:
In the serial monitor, when I pressed the button, it successfully printed "Launching" and "0.00m", but the next phrases didn't happened even when the altitude changed 2m (i moved the sensor from the floor and lift it up to above my head on a chair; i set the threshold to 1m). If it worked as planned, the flaps should be deployed when the the altitude is one meter over the threshold.
May I ask if you can help me check these functions bmp280.getAltitude(launchSiteAltitude);
and

altitude = bmp280.getAltitude(currentAltitude) - launchSiteAltitude;
      if (altitude > threshold)
      {
        Serial.println("LAUNCHED");
        stateMachine = DEPLOY;
      }

to see if they are written correctly? Because I don't seem to be able to get and store a launchSiteAltitude and get the calculation to function as it should.
I intend for the BMP280 to sample and store a starting altitude, and then once the rocket is launched, as it climbs vertically, new altitude readings will be sampled. Once the rocket reach 800 feet in the air, the servos will be activated and the airbrakes deployed.
I'm using this library #include <BMP280_DEV.h> for the BMP280.
If you can help me figure this will be great. Thanks again!

Debug print both the launchSiteAltitude as well as the currentAltitude. The code relies on

returning the absolute altitude. I don't know what your library (which one?) does.

Hi @mikami2020

If you post your latest current code in full, I'll set it up on my Mega and have a look.

Did you monitor the values coming from the altimeter while you performed the chair experiment? Or just run the program, which doesn't show you those?

Hello MartinL,

This is the latest current code. Thanks for your help!

#include <Servo.h>                                // Include the Servo.h library
#include <BMP280_DEV.h>                           // Include the BMP280_DEV.h library

int ledState = 0;             //starting state of LED
int ledPin = 13;              //the number of the LED pin
int buttonPin = 2;            //the number of the button pin
//int buttonNew;                //new button state
//int buttonOld = 1;            //old button state
//int dt = 100;                 //delay time
int buttonState;
int servoPin1 = 9;            // the number of servo pin 1
int servoPin2 = 10;           // the number of servo pin 2
int servoPin3 = 11;           // the number of servo pin 3
int servoPos = 0;             //the starting servo position
Servo Myservo1;               //define servo 1
Servo Myservo2;               //define servo 2
Servo Myservo3;               //define servo 3

float temperature, pressure, altitude;            // Create the temperature, pressure and altitude variables
BMP280_DEV bmp280;

enum stateMachine { DISARMED,
                    ARMED,
                    LAUNCH,
                    DEPLOY,
                    ABORT
                  } stateMachine = DISARMED;

bool armedInput = false, launchInput = false, abortInput = false;
bool servosActivated = false;
float currentAltitude;
float launchSiteAltitude;
float threshold = 1.0f;   // Altitude above launch site in meters

void initializeBarometer()
{
  bmp280.begin();                                 // Default initialisation, place the BMP280 into SLEEP_MODE
  //bmp280.setPresOversampling(OVERSAMPLING_X4);    // Set the pressure oversampling to X4
  //bmp280.setTempOversampling(OVERSAMPLING_X1);    // Set the temperature oversampling to X1
  //bmp280.setIIRFilter(IIR_FILTER_4);              // Set the IIR filter to setting 4
  bmp280.setTimeStandby(TIME_STANDBY_62MS);     // Set the standby time to 0.062 seconds
  bmp280.startNormalConversion();   // Start BMP280 continuous conversion in NORMAL_MODE

}

void initializeServos()
{
  Myservo1.attach(servoPin1);
  Myservo2.attach(servoPin2);
  Myservo3.attach(servoPin3);

}

void initializeButton()
{
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

}



void activateServos ()
{
  Myservo1.write(90);
  Myservo2.write(90);
  Myservo3.write(90);

}

void deactivateServos ()
{
  Myservo1.write(0);
  Myservo2.write(0);
  Myservo3.write(0);
}

void setup()
{
  initializeBarometer();      //done
  initializeServos();         //done
  Myservo1.write(0);
  Myservo2.write(0);
  Myservo3.write(0);
  initializeButton(); //done

  Serial.begin(115200);       // Initialise the serial port
}

void loop()
{


 if (bmp280.getMeasurements(temperature, pressure, altitude))    // Check if the measurement is complete
  {
    Serial.print(temperature);                    // Display the results
    Serial.print(F("*C   "));
    Serial.print(pressure);
    Serial.print(F("hPa   "));
    Serial.print(altitude);
    Serial.println(F("m"));
  }



  switch (stateMachine)
  {
    case DISARMED:

      stateMachine = ARMED;
      break;

    case ARMED:
      buttonState = digitalRead(buttonPin);
      if (buttonState == 0) break; //nothing to do - assuming pulldown resistor!
      bmp280.getAltitude(launchSiteAltitude);  //until launched
      //delay(100); //debounce only required if bmp280 reading too fast
      if (!digitalRead(buttonPin)) break; //short form of above, still nothing to do

    //else launch
        Serial.println(F("Launching"));
        Serial.print(launchSiteAltitude);
        Serial.println("m");
        stateMachine = LAUNCH;
        ledState = 1;
        digitalWrite(ledPin, ledState); 
      break;


    case LAUNCH:

      altitude = bmp280.getAltitude(currentAltitude) - launchSiteAltitude;
      if (altitude > threshold)
      {
        Serial.println("LAUNCHED");
        stateMachine = DEPLOY;
      }
      break;


    case DEPLOY:
      if (servosActivated == false)
      {
        activateServos();
        delay (3000);
        deactivateServos();
        servosActivated = true;
      }
      break;

    case ABORT:
      // add abort code
      break;
    default:
      break;
  }
}

I was monitoring the change in altitude in the Serial Monitor while performing the chair experiment. The altitude reading was shown changing when I move the sensor to 2m above

If the altitude is given in meters then a >= comparison may be better.

I'd add a check that the button is not active here. You don't want to risk a launch just after power on!

Also the LED should get the inactive state. I wonder how you really launch the rocket and how you prevent ignition on power on.

Thanks for the input! I will use the a>= comparison to my code.
My rocket is probably not as advance as you think haha :sweat_smile:
The airbrake system is separate from the actual launching system, so powering on this device will not set off the rocket. We'll turn on the airbrake device prior loading the rocket on the launch tower, and then the rocket will be launched by an Estes Pro Series II controller like the more traditional model rockets.

I forgot that the Arduino sits inside the rocket, don't it? But how then does it connect to the button?

Yes, I plan to put an Arduino Nano, the sensor, the button and the LED on a perfboard and then put the perfboard and the battery in an electronic bay made from a coupler.
The electronic bay coupler will be inside the upper section airframe; the airframe is 2.6 inches in diameter. The upper section will also have a payload area closer to the nosecone that carries two eggs and the padding for the eggs.
So I will have to take out the electronic bay to turn on the Arduino and press the button to initiate the sensor, and then put the thing back into the airframe before we can launch it.

Hi @mikami2020

I setup your system using an Arduino Uno, that's functionally closest to the Nano that you intend to use, seeing as I don't have a Nano to hand. I also implmented the active high button with a 10k pull-down resistor together with a BMP280 breakout board.

I modified your code to also incorporate @DrDiettrich 's suggestion, to test the button before launch. If the button test passes, the state machine moves on to the ARMED phase.

Pressing the button activates LAUNCH. In the LAUNCH phase the altitude is monitored and moves to the DEPOLY phase the moment the altitude threshold is exceeded.

DEPLOY simply activates the servos and then immediately moves on to RETRACT phase. RETRACT waits for 3 seconds before retracting the servos and finally reaching STOP.

Here's your modified code:

#include <Servo.h>                                // Include the Servo.h library
#include <BMP280_DEV.h>                           // Include the BMP280_DEV.h library

#define BUTTON_PIN 2

#define SERVO_PIN1 9
#define SERVO_PIN2 10
#define SERVO_PIN3 11

Servo Myservo1;               //define servo 1
Servo Myservo2;               //define servo 2
Servo Myservo3;               //define servo 3

BMP280_DEV bmp280;

enum stateMachine { DISARMED,
                    ARMED,
                    LAUNCH,
                    DEPLOY,
                    RETRACT,
                    STOP,
                    ABORT
                  } stateMachine = DISARMED;

unsigned long currentTime, previousTime;
float launchSiteAltitude, currentAltitude, relativeAltitude;
float threshold = 1.0f;   // Altitude above launch site in meters

void initializeBarometer()
{
  bmp280.begin();                                 // Default initialisation, place the BMP280 into SLEEP_MODE
  bmp280.setPresOversampling(OVERSAMPLING_X4);    // Set the pressure oversampling to X4
  bmp280.setTempOversampling(OVERSAMPLING_X1);    // Set the temperature oversampling to X1
  bmp280.setIIRFilter(IIR_FILTER_4);              // Set the IIR filter to setting 4
  bmp280.setTimeStandby(TIME_STANDBY_62MS);     // Set the standby time to 0.062 seconds
  bmp280.startNormalConversion();   // Start BMP280 continuous conversion in NORMAL_MODE
}

void initializeServos()
{
  Myservo1.attach(SERVO_PIN1);
  Myservo2.attach(SERVO_PIN2);
  Myservo3.attach(SERVO_PIN3);
}

void initializeButton()
{
  pinMode(BUTTON_PIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
}

void activateServos ()
{
  Myservo1.write(90);
  Myservo2.write(90);
  Myservo3.write(90);
}

void deactivateServos ()
{
  Myservo1.write(0);
  Myservo2.write(0);
  Myservo3.write(0);
}

void setup()
{
  initializeBarometer();      //done
  initializeServos();         //done
  deactivateServos();
  initializeButton(); //done

  Serial.begin(115200);       // Initialise the serial port
  Serial.println(F("DISARMED"));
}

void loop()
{
  switch (stateMachine)
  {
    case DISARMED:
      if (!digitalRead(BUTTON_PIN))
      {
        stateMachine = ARMED;
        Serial.println(F("ARMED"));
      }
      break;
    case ARMED:
      if (bmp280.getAltitude(launchSiteAltitude))  //until launched
      {
        Serial.print(launchSiteAltitude);
        Serial.println(F("m"));
      }
      if (digitalRead(BUTTON_PIN))
      {
        Serial.println(F("LAUNCH!"));
        digitalWrite(LED_BUILTIN, HIGH);
        stateMachine = LAUNCH;
      }
      break;
    case LAUNCH:
      if (bmp280.getAltitude(currentAltitude))
      {
        relativeAltitude = currentAltitude - launchSiteAltitude;
        Serial.print(relativeAltitude);
        Serial.println(F("m"));
      }
      if (relativeAltitude > threshold)
      {
        Serial.println(F("DEPLOY PARACHUTE!"));
        stateMachine = DEPLOY;  
      }
      break;
    case DEPLOY: 
      activateServos();
      Serial.println(F("SERVOS ACTIVATED"));
      stateMachine = RETRACT;  
      previousTime = millis(); 
      break;
    case RETRACT:
      currentTime = millis();
      if (currentTime - previousTime >= 3000)     // Non-blocking 3 second delay
      {
        deactivateServos();
        Serial.println(F("SERVOS RETRACTED"));
        stateMachine = STOP;
        Serial.println(F("STOP"));
      }
      break;
    case STOP:
      // Do nothing...
      break;
    case ABORT:
      // add abort code
      break;
    default:
      break;
  }
}
1 Like

I was thinking more about what altitude values you were receiving when you did that...

@mikami2020 Just thinking, once a given altitude has been exceeded after launch, it should be possible to use the barometer to measure the rocket's vertical velocity.

This would allow the Nano to detect the rocket's point of apogee and automatically deploy the parachute as it starts to descend, rather than deploying at a predefined altitude. It also means that the parachute will deploy if the rocket fails to reach the desired alititude due to a malfunction.

OMG it worked!!!!!!!
Thank you so much MartinL! This is exactly how I would imagine that the system works. Now I can move to soldering the component on the perfboard and also begin the construction of the rocket.
Thanks again for all your help! :smiley:

That will definitely be something I want to try in my future rocket projects :sunglasses:
For this rocket, the goal is only to reach a specific altitude and return the rocket to the ground within a specific time frame. The parachute will be ejected by the rocket motor's ejection charge after a six second delay after the propellent burnout :sweat_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.