2021年3月伊豆大島共同打上実験の電装メインプログラム
Dependencies: PQ_ES920 mbed PQ_LPS22HB SDFileSystem PQ_EEPROM PQ_ADXL375 PQ_MPU9250 PQ_INA226 PQ_GPS
main.cpp
- Committer:
- tanahashi
- Date:
- 2021-03-13
- Revision:
- 6:d951f75ce5e8
- Parent:
- 5:dc80ccf0904e
File content as of revision 6:d951f75ce5e8:
/* * ハイブリッドロケット(2021年3月伊豆大島共同打上実験)アビオニクスメインモジュール */ #include "mbed.h" #include "SDFileSystem.h" #include "PQ_ADXL375.h" #include "PQ_GPS.h" #include "PQ_EEPROM.h" #include "PQ_ES920.h" #include "PQ_INA226.h" #include "PQ_LPS22HB.h" #include "PQ_MPU9250.h" const float BURN_TIME = 3.27f; // エンジン燃焼時間[s] const float T_APOGEE = 13.44f; // 離床検知から弾道頂点までの時間[s] const float T_SEP = 12.0f; // 分離にかける時間[s] const float SAMPLING_FREQUENCY = 10.0f; // データのサンプリングレート[Hz] const float DOWNLINK_RATE = 2.0f; // ダウンリンクのレート[Hz] Serial pc(USBTX, USBRX, 115200); Serial gps_serial(p9, p10, 115200); Serial es_serial(p13, p14, 115200); I2C i2c(p28, p27); ES920 es(es_serial); GPS gps(gps_serial); ADXL375 adxl(i2c, ADXL375::ALT_ADDRESS_HIGH); // 3軸高加速度 INA226 ina_in(i2c, INA226::A0_VS, INA226::A1_VS); // 電圧,電流(バッテリー) INA226 ina_ex(i2c, INA226::A0_GND, INA226::A1_GND); // 電圧,電流(外部電源) //消す!! LPS22HB lps(i2c, LPS22HB::SA0_LOW); // 気圧,温度 //LPS22HB lps(i2c, LPS22HB::SA0_HIGH); // 気圧,温度 MPU9250 mpu(i2c, MPU9250::AD0_HIGH); // 3軸加速度,3軸角速度,3軸地磁気 SDFileSystem sd(p5, p6, p7, p8, "sd"); EEPROM eeprom(i2c); // 24FC1025*4(0x000000~0x07FFFF) Timer mission_timer; // 電源投入からの時間 Timer flight_timer; // 離床検知からの時間 Timer sd_timer; // SD用(fcloseのため) Timer sep_timer; // 分離時間 Ticker downlink_ticker; // ダウンリンク Ticker record_ticker; // データ保存 DigitalIn flight(p20); // 離床検知用フライトピン(外部プルアップ) DigitalIn signal(p24); // ミッション基板の生存信号 DigitalOut mission(p18); // ミッション基板の動作制御 DigitalOut relay(p19); // ミッション基板のリレースイッチング DigitalOut sep(p21); // 分離機構のニクロム線制御 DigitalOut buzzer(p23); // 捜索用ブザー void init(); // 初期化処理 void read(); // タイマー,GPS,センサの読み取り void command_handler(char *command); // アップリンクコマンドの処理 void downlink(); // データのダウンリンク void record(); // EEPROM,SDへの記録 char file_name[64]; FILE *fp; bool launched = false; // 打ちあがっているか:true=離床済み bool burning = false; // エンジンが燃焼中か:true=燃焼中 bool use_apogee = true; // 頂点検知を行うか:true=行う bool apogee = false; // 頂点検知したか:true=頂点検知済み bool separated = false; // 分離したか:true=分離済み bool landed = false; // 着水したか:true=着水済み float t = 0; // 頂点検知用 int addr; // EEPROMの書き込みアドレス int mission_timer_reset; // mission_timerをリセットした回数 float mission_time; // ミッション開始からの時間 float flight_time; // 離床検知からの時間 // 運用フェーズ enum { SAFETY, // 動作無し(READYへコマンドで移行) READY, // 離床検知待機(SAFETY,FLIGHTへコマンドで移行) FLIGHT, // 離床検知(フライトピン)から分離まで(コマンドでSEP,EMERGENCYへ移行) SEP, // パラシュート分離 EMERGENCY, // 離床失敗した場合の緊急停止(パラシュート分離の禁止,コマンドによる) RECOVERY // 分離終了から回収まで } phase; // 動作フラグ:1=有効,0=無効 char f_sd; // SDカード char f_gps; // GPS char f_adxl; // ADXL375 char f_ina_in; // INA226(バッテリー) char f_ina_ex; // INA226(外部電源) char f_lps; // LPS22HB char f_mpu; // MPU9250 float lat; // 緯度[deg] float lon; // 経度[deg] int sat; // 衛星数 int fix; // 位置特定品質 float hdop; // 水平精度低下率 float alt; // 海抜高度[m] float geoid; // ジオイド[m] float high_accel[3]; // 高加速度[G} float voltage_in; // バッテリー電圧[mV] float current_in; // バッテリー電流[mA] float voltage_ex; // 外部電源電圧[mV] float current_ex; // 外部電源電流[mA] float press; // 気圧[hPa] float temp; // 温度[C] float accel[3]; // 加速度[G] float gyro[3]; // 角速度[rad/s] char sound = 1; // 移動中央値 float press_buf[10]; int press_count; float press_median; // ローパスフィルタ float coef = 0.01; float press_prev_LPF; float press_LPF; float press_LPF_prev; float press_LPF_diff; float press_LPF_ground; int main() { wait(2); // ES920LRのブートローダー起動待ち init(); while(1) { read(); switch(phase) { case SAFETY: mission = 0; relay = 1; sep = 0; buzzer = 0; break; case READY: mission = 0; relay = 1; sep = 0; buzzer = 0; press_LPF_ground = press_LPF; if(flight.read() == 1) phase = FLIGHT; break; case FLIGHT: mission = 1; relay = 1; sep = 0; buzzer = 0; if(!launched) { flight_timer.start(); launched = true; burning = true; } if(flight_timer.read() > BURN_TIME) { if(burning) { burning = false; press_LPF_prev = press_LPF; } if(flight_timer.read() - t > 0.25) { if(press_LPF - press_LPF_prev > 0.0f) { if(use_apogee){ apogee = true; } } press_LPF_prev = press_LPF; t = flight_timer.read(); } if(!burning && (apogee || flight_timer.read() > T_APOGEE)) { phase = SEP; } } break; case SEP: mission = 0; relay = 1; sep = 1; buzzer = 1; if(!separated) { sep_timer.start(); separated = true; } if(sep_timer.read() > T_SEP) { phase = RECOVERY; } break; case EMERGENCY: mission = 1; relay = 1; sep = 0; buzzer = 0; break; case RECOVERY: mission = 0; if(!landed && press_LPF > press_LPF_ground) { relay = 0; landed = true; } sep = 0; buzzer = sound; break; } } } void init() { // 連番のファイルを作成 char file_name_format[] = "/sd/IZU2021_AVIONICS_%d.dat"; int file_number = 1; while(1) { sprintf(file_name, file_name_format, file_number); fp = fopen(file_name, "r"); if(fp != NULL) { fclose(fp); file_number++; } else { sprintf(file_name, file_name_format, file_number); break; } } fp = fopen(file_name, "w"); sd_timer.start(); if(fp) { fprintf(fp, "mission_time,flight_time,phase,"); fprintf(fp, "use_apogee,apogee,landed,signal,mission,relay,sep,buzzer,"); fprintf(fp, "flight,f_sd,f_gps,f_adxl,f_ina_in,f_ina_ex,f_lps,f_mpu,"); fprintf(fp, "lat,lon,sat,fix,hdop,alt,geoid,"); fprintf(fp, "high_accel_x,high_accel_y,high_accel_z,"); fprintf(fp, "voltage_in,current_in,"); fprintf(fp, "voltage_ex,current_ex,"); fprintf(fp, "press,temp,"); fprintf(fp, "accel_x,accel_y,accel_z,"); fprintf(fp, "gyro_x,gyro_y,gyro_z,"); fprintf(fp, "mag_x,mag_y,mag_z"); fprintf(fp, "\r\n"); } record_ticker.attach(record, 1.0f / SAMPLING_FREQUENCY); downlink_ticker.attach(downlink, 1.0f / DOWNLINK_RATE); // ミッション基板のリセット mission = 1; relay = 0; sep = 0; buzzer = 0; es.attach(command_handler); adxl.begin(); ina_in.begin(); ina_ex.begin(); lps.begin(); mpu.begin(); mission_timer.start(); } void read() { if(mission_timer.read() >= 30*60) { mission_timer.reset(); mission_timer_reset++; } mission_time = mission_timer.read() + mission_timer_reset*30*60; flight_time = flight_timer.read(); lat = gps.get_lat(); lon = gps.get_lon(); sat = gps.get_sat(); fix = gps.get_fix(); hdop = gps.get_hdop(); alt = gps.get_alt(); geoid = gps.get_geoid(); f_sd = (bool)fp; f_gps = (bool)fix; f_adxl = adxl.test(); if(f_adxl) { adxl.read(high_accel); } f_ina_in = ina_in.test(); if(f_ina_in) { ina_in.read_voltage(&voltage_in); ina_in.read_current(¤t_in); } f_ina_ex = ina_ex.test(); if(f_ina_ex) { ina_ex.read_voltage(&voltage_ex); ina_ex.read_current(¤t_ex); } f_lps = lps.test(); if(f_lps) { lps.read_press(&press); lps.read_temp(&temp); // 移動中央値を求める press_buf[press_count] = press; press_count++; if(press_count > 10) { press_count = 0; } // 配列のコピー float buf[10]; for(int i = 0; i < 10; i++) { buf[i] = press_buf[i]; } // バブルソート for(int i = 0; i < 9; i++) { for(int j = 9; j > i; j--) { if(buf[j] < buf[j - 1]) { float temp = buf[j]; buf[j] = buf[j - 1]; buf[j - 1] = temp; } } } // 中央値 press_median = (buf[4] + buf[5]) / 2; // ローパスフィルタ press_LPF = press_median * coef + press_prev_LPF * (1 - coef); press_prev_LPF = press_LPF; } f_mpu = mpu.test(); if(f_mpu) { mpu.read_accel(accel); mpu.read_gyro(gyro); } } void command_handler(char *command) { switch(command[0]) { case 0xB0: // '0' if(phase == READY) phase = SAFETY; break; case 0xB1: // '1' if(phase == SAFETY) phase = READY; break; case 0xB2: // '2' if(phase == READY) phase = FLIGHT; break; case 0xB3: // '3' if(!burning && phase == FLIGHT) phase = SEP; break; case 0xB4: // '4' if(phase == FLIGHT) phase = EMERGENCY; break; case 0xB5: // '5' if(phase == SEP) phase = RECOVERY; break; case 0xE1: // 'a' use_apogee = !use_apogee; break; case 0xE2: // 'b' sound = !sound; break; case 0xFF: // 'DEL' NVIC_SystemReset(); break; } } void downlink() { short mission_time_bits = (short)mission_time;; short flight_time_bits = (short)(flight_time * 10); char flags1 = 0; flags1 |= (char)use_apogee << 7; flags1 |= (char)apogee << 6; flags1 |= (char)landed << 5; flags1 |= signal.read() << 4; flags1 |= mission.read() << 3; flags1 |= relay.read() << 2; flags1 |= sep.read() << 1; flags1 |= buzzer.read() << 0; char flags2 = 0; flags2 |= flight.read() << 7; flags2 |= f_sd << 6; flags2 |= f_gps << 5; flags2 |= f_adxl << 4; flags2 |= f_ina_in << 3; flags2 |= f_ina_ex << 2; flags2 |= f_lps << 1; flags2 |= f_mpu << 0; int lat_bits = *((int*)&lat); int lon_bits = *((int*)&lon); int alt_bits = *((int*)&alt); short high_accel_bits[3]; for(int i = 0; i < 3; i++) { high_accel_bits[i] = (short)(high_accel[i] / ADXL375_LSB); } short voltage_in_bits = (short)(voltage_in / INA226_VOLTAGE_LSB); short current_in_bits = (short)(current_in / INA226_CURRENT_LSB); short voltage_ex_bits = (short)(voltage_ex / INA226_VOLTAGE_LSB); short current_ex_bits = (short)(current_ex / INA226_CURRENT_LSB); int press_bits = (int)(press * LPS22HB_PRESS_LSB); short temp_bits = (short)(temp / LPS22HB_TEMP_LSB); short accel_bits[3]; for(int i = 0; i < 3; i++) { accel_bits[i] = (short)(accel[i] / (MPU9250_ACCEL_LSB * 8)); } short gyro_bits[3]; for(int i = 0; i < 3; i++) { gyro_bits[i] = (short)(gyro[i] / (MPU9250_GYRO_LSB * 8)); } char data[50]; data[0] = ((char*)&mission_time_bits)[0]; data[1] = ((char*)&mission_time_bits)[1]; data[2] = ((char*)&flight_time_bits)[0]; data[3] = ((char*)&flight_time_bits)[1]; data[4] = phase; data[5] = flags1; data[6] = flags2; data[7] = ((char*)&lat_bits)[0]; data[8] = ((char*)&lat_bits)[1]; data[9] = ((char*)&lat_bits)[2]; data[10] = ((char*)&lat_bits)[3]; data[11] = ((char*)&lon_bits)[0]; data[12] = ((char*)&lon_bits)[1]; data[13] = ((char*)&lon_bits)[2]; data[14] = ((char*)&lon_bits)[3]; data[15] = ((char*)&alt_bits)[0]; data[16] = ((char*)&alt_bits)[1]; data[17] = ((char*)&alt_bits)[2]; data[18] = ((char*)&alt_bits)[3]; data[19] = ((char*)&high_accel_bits[0])[0]; data[20] = ((char*)&high_accel_bits[0])[1]; data[21] = ((char*)&high_accel_bits[1])[0]; data[22] = ((char*)&high_accel_bits[1])[1]; data[23] = ((char*)&high_accel_bits[2])[0]; data[24] = ((char*)&high_accel_bits[2])[1]; data[25] = ((char*)&voltage_in_bits)[0]; data[26] = ((char*)&voltage_in_bits)[1]; data[27] = ((char*)¤t_in_bits)[0]; data[28] = ((char*)¤t_in_bits)[1]; data[29] = ((char*)&voltage_ex_bits)[0]; data[30] = ((char*)&voltage_ex_bits)[1]; data[31] = ((char*)¤t_ex_bits)[0]; data[32] = ((char*)¤t_ex_bits)[1]; data[33] = ((char*)&press_bits)[0]; data[34] = ((char*)&press_bits)[1]; data[35] = ((char*)&press_bits)[2]; data[36] = ((char*)&temp_bits)[0]; data[37] = ((char*)&temp_bits)[1]; data[38] = ((char*)&accel_bits[0])[0]; data[39] = ((char*)&accel_bits[0])[1]; data[40] = ((char*)&accel_bits[1])[0]; data[41] = ((char*)&accel_bits[1])[1]; data[42] = ((char*)&accel_bits[2])[0]; data[43] = ((char*)&accel_bits[2])[1]; data[44] = ((char*)&gyro_bits[0])[0]; data[45] = ((char*)&gyro_bits[0])[1]; data[46] = ((char*)&gyro_bits[1])[0]; data[47] = ((char*)&gyro_bits[1])[1]; data[48] = ((char*)&gyro_bits[2])[0]; data[49] = ((char*)&gyro_bits[2])[1]; es.send(data, 50); } void record() { if(phase >= FLIGHT && !landed) { char data[128]; data[0] = ((char*)&mission_time)[0]; data[1] = ((char*)&mission_time)[1]; data[2] = ((char*)&mission_time)[2]; data[3] = ((char*)&mission_time)[3]; data[4] = ((char*)&flight_time)[0]; data[5] = ((char*)&flight_time)[1]; data[6] = ((char*)&flight_time)[2]; data[7] = ((char*)&flight_time)[3]; data[8] = phase; data[9] = use_apogee; data[10] = apogee; data[11] = landed; data[12] = signal.read(); data[13] = mission.read(); data[14] = relay.read(); data[15] = sep.read(); data[16] = buzzer.read(); data[17] = flight.read(); data[18] = f_sd; data[19] = f_gps; data[20] = f_adxl; data[21] = f_ina_in; data[22] = f_ina_ex; data[23] = f_lps; data[24] = f_mpu; data[25] = ((char*)&lat)[0]; data[26] = ((char*)&lat)[1]; data[27] = ((char*)&lat)[2]; data[28] = ((char*)&lat)[3]; data[29] = ((char*)&lon)[0]; data[30] = ((char*)&lon)[1]; data[31] = ((char*)&lon)[2]; data[32] = ((char*)&lon)[3]; data[33] = ((char*)&sat)[0]; data[34] = ((char*)&sat)[1]; data[35] = ((char*)&sat)[2]; data[36] = ((char*)&sat)[3]; data[37] = ((char*)&fix)[0]; data[38] = ((char*)&fix)[1]; data[39] = ((char*)&fix)[2]; data[40] = ((char*)&fix)[3]; data[41] = ((char*)&hdop)[0]; data[42] = ((char*)&hdop)[1]; data[43] = ((char*)&hdop)[2]; data[44] = ((char*)&hdop)[3]; data[45] = ((char*)&alt)[0]; data[46] = ((char*)&alt)[1]; data[47] = ((char*)&alt)[2]; data[48] = ((char*)&alt)[3]; data[49] = ((char*)&geoid)[0]; data[50] = ((char*)&geoid)[1]; data[51] = ((char*)&geoid)[2]; data[52] = ((char*)&geoid)[3]; data[53] = ((char*)&high_accel[0])[0]; data[54] = ((char*)&high_accel[0])[1]; data[55] = ((char*)&high_accel[0])[2]; data[56] = ((char*)&high_accel[0])[3]; data[57] = ((char*)&high_accel[1])[0]; data[58] = ((char*)&high_accel[1])[1]; data[59] = ((char*)&high_accel[1])[2]; data[60] = ((char*)&high_accel[1])[3]; data[61] = ((char*)&high_accel[2])[0]; data[62] = ((char*)&high_accel[2])[1]; data[63] = ((char*)&high_accel[2])[2]; data[64] = ((char*)&high_accel[2])[3]; data[65] = ((char*)&voltage_in)[0]; data[66] = ((char*)&voltage_in)[1]; data[67] = ((char*)&voltage_in)[2]; data[68] = ((char*)&voltage_in)[3]; data[69] = ((char*)¤t_in)[0]; data[70] = ((char*)¤t_in)[1]; data[71] = ((char*)¤t_in)[2]; data[72] = ((char*)¤t_in)[3]; data[73] = ((char*)&voltage_ex)[0]; data[74] = ((char*)&voltage_ex)[1]; data[75] = ((char*)&voltage_ex)[2]; data[76] = ((char*)&voltage_ex)[3]; data[77] = ((char*)¤t_ex)[0]; data[78] = ((char*)¤t_ex)[1]; data[79] = ((char*)¤t_ex)[2]; data[80] = ((char*)¤t_ex)[3]; data[81] = ((char*)&press)[0]; data[82] = ((char*)&press)[1]; data[83] = ((char*)&press)[2]; data[84] = ((char*)&press)[3]; data[85] = ((char*)&temp)[0]; data[86] = ((char*)&temp)[1]; data[87] = ((char*)&temp)[2]; data[88] = ((char*)&temp)[3]; data[89] = ((char*)&accel[0])[0]; data[90] = ((char*)&accel[0])[1]; data[91] = ((char*)&accel[0])[2]; data[92] = ((char*)&accel[0])[3]; data[93] = ((char*)&accel[1])[0]; data[94] = ((char*)&accel[1])[1]; data[95] = ((char*)&accel[1])[2]; data[96] = ((char*)&accel[1])[3]; data[97] = ((char*)&accel[2])[0]; data[98] = ((char*)&accel[2])[1]; data[99] = ((char*)&accel[2])[2]; data[100] = ((char*)&accel[2])[3]; data[101] = ((char*)&gyro[0])[0]; data[102] = ((char*)&gyro[0])[1]; data[103] = ((char*)&gyro[0])[2]; data[104] = ((char*)&gyro[0])[3]; data[105] = ((char*)&gyro[1])[0]; data[106] = ((char*)&gyro[1])[1]; data[107] = ((char*)&gyro[1])[2]; data[108] = ((char*)&gyro[1])[3]; data[109] = ((char*)&gyro[2])[0]; data[110] = ((char*)&gyro[2])[1]; data[111] = ((char*)&gyro[2])[2]; data[112] = ((char*)&gyro[2])[3]; data[113] = 0; data[114] = 0; data[115] = 0; data[116] = 0; data[117] = 0; data[118] = 0; data[119] = 0; data[120] = 0; data[121] = 0; data[122] = 0; data[123] = 0; data[124] = 0; data[125] = 0; data[126] = 0; data[127] = 0; eeprom.write(addr, data, 128); addr += 0x80; } if(fp) { char *phase_names[] = {"SAFETY", "READY", "FLIGHT", "SEP", "EMERGENCY", "RECOVERY"}; fprintf(fp, "%.3f,%.3f,%s,", mission_time, flight_time, phase_names[phase]); fprintf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,", use_apogee, apogee, landed, signal.read(), mission.read(), relay.read(), sep.read(), buzzer.read()); fprintf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,", flight.read(), f_sd, f_gps, f_adxl, f_ina_in, f_ina_ex, f_lps, f_mpu); fprintf(fp, "%.6f,%.6f,%d,%d,%f,%f,%f,", lat, lon, sat, fix, hdop, alt, geoid); fprintf(fp, "%f,%f,%f,", high_accel[0], high_accel[1], high_accel[2]); fprintf(fp, "%f,%f,", voltage_in, current_in); fprintf(fp, "%f,%f,", voltage_ex, current_ex); fprintf(fp, "%f,%f,", press, temp); fprintf(fp, "%f,%f,%f,", accel[0], accel[1], accel[2]); fprintf(fp, "%f,%f,%f", gyro[0], gyro[1], gyro[2]); fprintf(fp, "\r\n"); } if(sd_timer.read() >= 20) { sd_timer.reset(); if(fp) { fclose(fp); fp = fopen(file_name, "a"); } } }