diff --git a/static_test_driver/autosequence.ino b/static_test_driver/autosequence.ino index 0534922..feb888c 100644 --- a/static_test_driver/autosequence.ino +++ b/static_test_driver/autosequence.ino @@ -40,7 +40,8 @@ typedef enum { MAINSTAGE, OXYGEN_SHUTDOWN, SHUTDOWN, - COOL_DOWN + COOL_DOWN, + STATIC_TEST_COMPLETE } state_t; // Convenience @@ -48,7 +49,7 @@ typedef enum { state = STATE; \ write_state(#STATE); \ } - + long start_time = 0; long shutdown_time = 0; @@ -82,7 +83,7 @@ void start_countdown() { if (valve_status[FUEL_PRE] || valve_status[FUEL_MAIN] || valve_status[OX_PRE] || - valve_status[OX_MAIN]) { + valve_status[OX_MAIN] ||) { Serial.println(F("Countdown aborted due to unexpected initial state")); SET_STATE(STAND_BY) // Set state to signal countdown was aborted } @@ -105,18 +106,21 @@ void abort_autosequence() { case PRESTAGE_READY: set_valve(FUEL_PRE, 0); set_valve(OX_PRE, 0); + set_valve(N2_CHOKE. 0); SET_STATE(STAND_BY) break; case PRESTAGE: + set_valve(N2_CHOKE, 0); set_valve(OX_PRE, 0); set_valve(FUEL_PRE, 0); reset_igniter(); SET_STATE(COOL_DOWN) shutdown_time = millis(); break; - + case MAINSTAGE: + set_valve(N2_CHOKE, 0); set_valve(OX_PRE, 0); set_valve(FUEL_PRE, 0); SET_STATE(SHUTDOWN) @@ -156,6 +160,7 @@ void run_control() { #endif if (run_time >= PRESTAGE_PREP_TIME) { SET_STATE(PRESTAGE_READY) + set_valve(N2_CHOKE, 1); set_valve(FUEL_PRE, 1); set_valve(OX_PRE, 1); } @@ -214,6 +219,7 @@ void run_control() { case SHUTDOWN: // Both prestage valves are closed, others may still be open if (millis() >= shutdown_time + PRE_LEADTIME) { + set_valve(N2_CHOKE, 0); set_valve(OX_MAIN, 0); set_valve(FUEL_MAIN, 0); SET_STATE(COOL_DOWN) @@ -228,5 +234,37 @@ void run_control() { start_time = 0; } break; + + case STATIC_TEST_COMPLETE: + // State that requires manual input to open Kero valve once static test is completed for the day + char state; + for (int i=1; i<10; i++){ + cout << "Are you done test firing for the day? [Y/N]"; + cin >> state; + if (state=='Y'){ + cout << "Are you sure you're done? [Y/N]"; + cin >> state; + if (state=='Y'){ + cout << "Draining Kerosene valve...vwooosh"; + set_valve(KERO_DRAIN, 1); + return; + } + else if (state=='N'){ + cout << "Let the firing resume!"; + return; + } + else{ + break; + } + } + else if (state=='N'){ + cout << "Let the firing resume!"; + return; + } + else{ + break; + } + } + break; } } diff --git a/static_test_driver/sensors.ino b/static_test_driver/sensors.ino index dbd2e84..e6e4eeb 100644 --- a/static_test_driver/sensors.ino +++ b/static_test_driver/sensors.ino @@ -1,147 +1,238 @@ - -#define SENSOR_ERROR_LIMIT 5 // Max number of errors in a row before deciding a sensor is faulty - -#define PRESSURE_CALIBRATION_FACTOR 246.58 -#define PRESSURE_OFFSET 118.33 -#define PRESSURE_MIN_VALID -100 -#define PRESSURE_MAX_VALID 1000 - -#define TEMP_MIN_VALID -10 -#define TEMP_MAX_VALID 120 - -#define FORCE_MIN_VALID -50 -#define FORCE_MAX_VALID 500 - -#if CONFIGURATION == MK_2 -#define LOAD_CELL_CALIBRATION_FACTOR 20400.0 //This value is obtained using the SparkFun_HX711_Calibration sketch -#else -#define LOAD_CELL_CALIBRATION_FACTOR 20400 -#endif - -#define LOAD_CELL_RETRY_INTERVAL 10 -#define LOAD_CELL_MAX_RETRIES 20 - -String sensor_errors = ""; - -float mean(const float *data, unsigned int size) { - float result = 0; - for (int i = 0; i < size; i++) - result += data[i]; - return result / size; -} - -void update_sensor_errors() { - set_lcd_errors(sensor_errors); - sensor_errors = ""; -} - -void error_check(int &error, bool working, const String &sensor_type, const String &sensor_name="", const String &sensor_short_name="") { - if (working) { - error = 0; - } else { - if (sensor_errors.length()) { - sensor_errors += ','; - } - sensor_errors += sensor_type.substring(0, min(sensor_type.length(), 2)) + sensor_short_name; - if (!error) { - Serial.print(sensor_name); - if (sensor_name.length()) { - Serial.print(' '); - } - Serial.print(sensor_type); - Serial.println(F(" sensor error")); - } - error++; - if (error > SENSOR_ERROR_LIMIT) { - sensor_status = false; - } - } -} - -float read_temp(int sensor, int &error, const String &sensor_name, const String &sensor_short_name) { - float result = analogRead(sensor) * 5.0 * 100 / 1024; - error_check(error, result > TEMP_MIN_VALID && result < TEMP_MAX_VALID, "temp", sensor_name, sensor_short_name); - return result; -} - -float read_pressure(int sensor, int &error, const String &sensor_name, const String &sensor_short_name) { - float result = (analogRead(sensor) * 5 / 1024.0) * PRESSURE_CALIBRATION_FACTOR - PRESSURE_OFFSET; - error_check(error, result > PRESSURE_MIN_VALID && result < PRESSURE_MAX_VALID, sensor_name, "pressure"); - return result; -} - -void init_accelerometer(Adafruit_MMA8451 &mma) { - bool working = false; - if (mma.begin()) { - mma.setRange(MMA8451_RANGE_2_G); // set acc range (2 4 8) - Serial.print(F("Accelerometer range ")); - Serial.print(2 << mma.getRange()); - Serial.println("G"); - working = true; - } - int error = 0; - error_check(error, working, "accelerometer"); - delay(100); -} - -sensors_vec_t read_accelerometer(Adafruit_MMA8451 &mma, int &error) { - sensors_event_t event; - mma.getEvent(&event); - sensors_vec_t accel = event.acceleration; - error_check(error, !(mma.x == -1 && mma.y == -1 && mma.z == -1), "accelerometer"); - return accel; -} - -void init_force(HX711 &scale) { - scale.begin(LOAD_CELL_DOUT, LOAD_CELL_CLK); - - // Calibrate load cell - scale.set_scale(LOAD_CELL_CALIBRATION_FACTOR); // This value is obtained by using the SparkFun_HX711_Calibration sketch - scale.tare(); // Load Cell, Assuming there is no weight on the scale, reset to 0 - - // Try reading a value from the load cell - int error = 0; - read_force(scale, error); - - if (!error) { - Serial.println(F("Load cell amp connected")); - } - delay(100); -} - -float read_force(HX711 &scale, int &error) { - // Wait for load cell data to become ready - bool is_ready = false; - for (unsigned i = 0; i < LOAD_CELL_MAX_RETRIES; i++) { - if (scale.is_ready()) { - is_ready = true; - break; - } - delay(LOAD_CELL_RETRY_INTERVAL); - } - - // Read a value from the load cell - float result = 0; - if (is_ready) { - result = scale.get_units(); - } - error_check(error, is_ready && !isnan(result) && result > FORCE_MIN_VALID && result < FORCE_MAX_VALID, "Force"); - return result; -} - -void init_thermocouple(Adafruit_MAX31855 &thermocouple, const String &sensor_name, const String &sensor_short_name) { - int error = 0; - thermocouple.begin(); - read_thermocouple(thermocouple, error, sensor_name, sensor_short_name); - if (!error) { - Serial.print(sensor_name); - Serial.println(F(" theromocouple connected")); - } - delay(100); -} - -float read_thermocouple(Adafruit_MAX31855 &thermocouple, int &error, const String &sensor_name, const String &sensor_short_name) { - float result = thermocouple.readCelsius(); - error_check(error, !isnan(result) && result > 0, "thermocouple", sensor_name, sensor_short_name); - return result; -} + +#define SENSOR_ERROR_LIMIT 5 // Max number of errors in a row before deciding a sensor is faulty + +#define PRESSURE_CALIBRATION_FACTOR 246.58 +#define PRESSURE_OFFSET 118.33 +#define PRESSURE_MIN_VALID -100 +#define PRESSURE_MAX_VALID 1000 + +#define TEMP_MIN_VALID -10 +#define TEMP_MAX_VALID 120 + +#define FORCE_MIN_VALID -50 +#define FORCE_MAX_VALID 500 + +#if CONFIGURATION == MK_2 +#define LOAD_CELL_CALIBRATION_FACTOR 20400.0 //This value is obtained using the SparkFun_HX711_Calibration sketch +#else +#define LOAD_CELL_CALIBRATION_FACTOR 20400 +#endif + +#define LOAD_CELL_RETRY_INTERVAL 10 +#define LOAD_CELL_MAX_RETRIES 20 + + + +String sensor_errors = ""; + +//Number of Sensors +//Load Cells - 4 +//Pressure Transducers - 4 +//Thermocouples - n/a (not a priority) +//Accelerometer - probably 1 so no need to work on that too much. + +//------------------------------------------------------------------------------------------- +//Utility Functions +//------------------------------------------------------------------------------------------- + +float mean(const float *data, unsigned int size) { + float result = 0; + for (int i = 0; i < size; i++) + result += data[i]; + return result / size; +} + +void update_sensor_errors() { + set_lcd_errors(sensor_errors); + sensor_errors = ""; +} + +void error_check(int &error, bool working, const String &sensor_type, const String &sensor_name="", const String &sensor_short_name="") { + if (working) { + error = 0; + } else { + if (sensor_errors.length()) { + sensor_errors += ','; + } + sensor_errors += sensor_type.substring(0, min(sensor_type.length(), 2)) + sensor_short_name; + if (!error) { + Serial.print(sensor_name); + if (sensor_name.length()) { + Serial.print(' '); + } + Serial.print(sensor_type); + Serial.println(F(" sensor error")); + } + error++; + if (error > SENSOR_ERROR_LIMIT) { + sensor_status = false; //static_test_driver + } + + + } +} + + +//------------------------------------------------------------------------------------------- +//LoadCell +//------------------------------------------------------------------------------------------- + +//SENSOR DEVICE 1 + +class LoadCell +{ + private: + HX711 m_scale; + + public: + uint8_t m_dout; //Digital out pin + uint8_t m_clk; //Clock pin + double m_calibrationFactor; + + int m_error; + + LoadCell(){} + LoadCell(uint8_t dout, uint8_t clk) : m_calibrationFactor{LOAD_CELL_CALIBRATION_FACTOR} , m_dout {dout} , m_clk {clk}, m_error{0} {} + + float read_force(); + void init_force(); +}; + +void LoadCell::init_force() { + m_scale.begin(m_dout, m_clk); + + // Calibrate load cell + m_scale.set_scale(m_calibrationFactor); // This value is obtained by using the SparkFun_HX711_Calibration sketch + //Calibration is just the slope of the data function we get from the cell, we use it to find force at the values we get. + m_scale.tare(); // Load Cell, Assuming there is no weight on the scale, reset to 0 mark intial valeue of cell as 0 + + // Try reading a value from the load cell + read_force(); + + if (!m_error) { + Serial.println(F("Load cell amp connected")); + } + delay(100); +} + +float LoadCell::read_force() { + // Wait for load cell data to become ready + bool is_ready = false; + for (unsigned int i = 0; i < LOAD_CELL_MAX_RETRIES; i++) { + if (m_scale.is_ready()) { + is_ready = true; + break; + } + delay(LOAD_CELL_RETRY_INTERVAL); + } + + // Read a value from the load cell + float result = 0; + if (is_ready) { + result = m_scale.get_units(); + } + error_check(m_error, is_ready && !isnan(result) && result > FORCE_MIN_VALID && result < FORCE_MAX_VALID, "Force"); + return result; +} + + +//------------------------------------------------------------------------------------------- +//Thermocouple +//------------------------------------------------------------------------------------------- + +//SENSOR DEVICE 2 + + +class Thermocouple +{ + private: + Adafruit_MAX31855 m_thermocouple; + public: + int m_thermocouplepin; + int m_error; + const String m_sensor_name; + const String m_sensor_short_name; + + Thermocouple(int8_t pin, const String& name, const String& shortname) : m_thermocouplepin {pin}, m_sensor_name { name } , m_sensor_short_name { shortname }, m_error{0} , m_thermocouple{pin} {} + + void init_thermocouple(); + float read_thermocouple(); + float read_temp(); + +}; + +float Thermocouple::read_temp() { + float result = analogRead(m_thermocouplepin) * 5.0 * 100 / 1024; + error_check(m_error, result > TEMP_MIN_VALID && result < TEMP_MAX_VALID, "temp", m_sensor_name, m_sensor_short_name); + return result; +} + +void Thermocouple::init_thermocouple() { + int error = 0; + m_thermocouple.begin(); + read_thermocouple(); + if (!m_error) { + Serial.print(m_sensor_name); + Serial.println(F(" theromocouple connected")); + } + delay(100); +} + +float Thermocouple::read_thermocouple() { + float result = m_thermocouple.readCelsius(); + error_check(m_error, !isnan(result) && result > 0, "thermocouple", m_sensor_name, m_sensor_short_name); + return result; +} + + + +//------------------------------------------------------------------------------------------- +//Pressure Transducers +//------------------------------------------------------------------------------------------- + +//Sensor Device 3 + +class PressureTransducer +{ + public: + int m_pressurepin; + int m_error; + const String m_sensor_name; + const String m_sensor_short_name; + PressureTransducer(int pin, const String& name, const String& shortname) : m_pressurepin{pin}, m_sensor_name{name}, m_sensor_short_name{shortname} , m_error{0} {} + + float read_pressure(int sensor); + +}; + +float PressureTransducer::read_pressure(int sensor) { + float result = (analogRead(sensor) * 5 / 1024.0) * PRESSURE_CALIBRATION_FACTOR - PRESSURE_OFFSET; + error_check(m_error, result > PRESSURE_MIN_VALID && result < PRESSURE_MAX_VALID, m_sensor_name, "pressure"); + return result; +}; + +//------------------------------------------------------------------------------------------- +//Accelerometer +//------------------------------------------------------------------------------------------- + +void init_accelerometer(Adafruit_MMA8451 &mma) { + bool working = false; + if (mma.begin()) { + mma.setRange(MMA8451_RANGE_2_G); // set acc range (2 4 8) + Serial.print(F("Accelerometer range ")); + Serial.print(2 << mma.getRange()); + Serial.println("G"); + working = true; + } + int error = 0; + error_check(error, working, "accelerometer"); + delay(100); +} + +sensors_vec_t read_accelerometer(Adafruit_MMA8451 &mma, int &error) { + sensors_event_t event; + mma.getEvent(&event); + sensors_vec_t accel = event.acceleration; + error_check(error, !(mma.x == -1 && mma.y == -1 && mma.z == -1), "accelerometer"); + return accel; +} diff --git a/static_test_driver/static_test_driver.ino b/static_test_driver/static_test_driver.ino index 5708b8e..705745a 100644 --- a/static_test_driver/static_test_driver.ino +++ b/static_test_driver/static_test_driver.ino @@ -28,6 +28,17 @@ int accel_error = 0; #define NUMBER_OF_TEMP_SENSORS 4 int temp_error[NUMBER_OF_TEMP_SENSORS] = {0,0}; +// Igniter pin assignment +uint8_t IGNITER_PIN = 15; + +// Valve pin assignment +uint8_t FUEL_PRE_PIN = 34; +uint8_t FUEL_MAIN_PIN = 33; +uint8_t OX_PRE_PIN = 32; +uint8_t OX_MAIN_PIN = 31; +uint8_t N2_CHOKE_PIN = 30; +uint8_t N2_DRAIN_PIN = 29; + // Pressure Setup #define PRESSURE_FUEL A0 #define PRESSURE_OX A1 @@ -76,10 +87,12 @@ typedef enum { FUEL_PRE, FUEL_MAIN, OX_PRE, - OX_MAIN + OX_MAIN, + N2_CHOKE, + N2_DRAIN } valve_t; -bool valve_status[] = {false, false, false, false}; +bool valve_status[] = {false, false, false, false, false, false}; unsigned long last_heartbeat = 0; @@ -104,27 +117,27 @@ void setup() { Serial.println(F("Mk 2 static test driver")); #endif Serial.println(F("Initializing...")); - + // wait for chips to stabilize delay(500); - + // Initialize Pressure Sensors pinMode(PRESSURE_FUEL, INPUT); pinMode(PRESSURE_OX, INPUT); pinMode(PRESSURE_FUEL_INJECTOR, INPUT); pinMode(PRESSURE_OX_INJECTOR, INPUT); - + // Initialize Analog Temp Sensors pinMode(INLET_TEMP, INPUT); pinMode(OUTLET_TEMP, INPUT); - + // Initialize load cell init_force(scale); - + // Initialize accelerometer Wire.begin(); init_accelerometer(mma); - + // Initialize thermocouples for Mk.2 #if CONFIGURATION == MK_2 char thermo_name[] = "chamber n"; @@ -135,51 +148,59 @@ void setup() { } #endif - // Initialize engine controls - init_engine(); + // Initialize valves + init_valve(FUEL_PRE_PIN); + init_valve(FUEL_MAIN_PIN); + init_valve(OX_PRE_PIN); + init_valve(OX_MAIN_PIN); + init_valve(N2_CHOKE_PIN); + init_valve(N2_DRAIN_PIN); + + // Initialize igniter + init_igniter(IGNITER_PIN); // Set initial state init_autosequence(); - + Serial.println("Setup Complete"); } void loop() { // Grab force data force = read_force(scale, force_error); // Force is measured in lbs - + // Grab pressure data pressure_fuel = read_pressure(PRESSURE_FUEL, pressure_error[0], "fuel", "Fl"); pressure_ox = read_pressure(PRESSURE_OX, pressure_error[1], "oxygen", "Ox"); pressure_fuel_injector = read_pressure(PRESSURE_FUEL_INJECTOR, pressure_error[2], "injector fuel", "FlE"); pressure_ox_injector = read_pressure(PRESSURE_OX_INJECTOR, pressure_error[3], "injector oxygen", "OxE"); - + // Update pressure tare data pressure_hist_vals[0][pressure_val_num] = pressure_fuel; pressure_hist_vals[1][pressure_val_num] = pressure_ox; pressure_hist_vals[2][pressure_val_num] = pressure_fuel_injector; pressure_hist_vals[3][pressure_val_num] = pressure_ox_injector; - + // Tare pressures pressure_fuel -= pressure_zero_val[0]; pressure_ox -= pressure_zero_val[1]; pressure_fuel_injector -= pressure_zero_val[2]; pressure_ox_injector -= pressure_zero_val[3]; - + pressure_val_num++; if (pressure_val_num >= PRESSURE_NUM_HIST_VALS) { pressure_val_num = 0; pressure_zero_ready = true; } - + // Grab analog temperature data inlet_temp = read_temp(INLET_TEMP, temp_error[0], "inlet", "In"); outlet_temp = read_temp(OUTLET_TEMP, temp_error[1], "outlet", "Out"); - + // Grab accelerometer data (acceleration is measured in m/s^2) sensors_vec_t accel = read_accelerometer(mma, accel_error); x=accel.x; y=accel.y; z=accel.z; - + // Grab thermocouple data for Mk.2 #if CONFIGURATION == MK_2 char thermo_name[] = "chamber n"; @@ -192,7 +213,7 @@ void loop() { // Update sensor diagnostic message on LCD update_sensor_errors(); - + // Run autonomous control run_control(); @@ -220,13 +241,13 @@ void loop() { // Read a command bool valve_command; - + BEGIN_READ READ_FLAG(zero_force) { Serial.println(F("Zeroing load cell")); scale.tare(); // Load Cell, Assuming there is no weight on the scale, reset to 0 } - + READ_FLAG(zero_pressure) { if (pressure_zero_ready) { Serial.println(F("Zeroing fuel pressure")); @@ -240,7 +261,7 @@ void loop() { Serial.println(F("Pressure zero values not ready")); } } - + READ_FLAG(heartbeat) { heartbeat(); } @@ -270,6 +291,12 @@ void loop() { READ_FIELD(ox_main_command, "%d", valve_command) { set_valve(OX_MAIN, valve_command); } + READ_FIELD(n2_choke_command, "%d", valve_command) { + set_valve(N2_CHOKE, valve_command); + } + READ_FIELD(n2_drain_command, "%d", valve_command) { + set_valve(N2_DRAIN, valve_command); + } READ_DEFAULT(data_name, data) { Serial.print(F("Invalid data field recieved: ")); Serial.print(data_name); @@ -278,3 +305,4 @@ void loop() { } END_READ } +