Atsushi Hattori
/
20210627_Logger
hattori&ide
Embed:
(wiki syntax)
Show/hide line numbers
Loggermain.cpp
00001 /*更新情報 00002 * 2016/01/20 00003 * LCD表示 現在時刻から経過時間へ変更 00004 * LCD表示 単位記号の位置変更 00005 * 00006 * 2016/01/29 00007 * postアドレス変更 TEST→myLogger 00008 * 00009 * 2016/01/30 00010 * サーバー送信データ変更,末尾にデータ取得時間追加 00011 * 00012 * 2016/02/08 00013 * 配列の要素数をconst定数化 00014 * LapUSBSaveDataのcsvデータがおかしかったので修正 00015 * ラップをラップタイムが3分30秒以内の場合は加算しないように修正 00016 * CalculateSet関数を分割 00017 * 00018 * 2016/02/22 00019 * 初期化ルーチンを関数に分割 00020 * GPS対応 00021 * データバックアップ,引き継ぎ機能追加,ファイル名を日付に変更 00022 * 00023 * 2016/02/24 00024 * エラー処理追加, メンテナンス 00025 * 00026 * 2016/04~ 00027 * タイマー処理測定→http送信による遅延を無害化 00028 * 加速度センサデータ保存、モーター回転数から速度算出 00029 * 00030 * 2016/04/24 00031 * ラップスイッチ ピン変化割り込み化 00032 * 配列過剰書き込み 対策済み 00033 00034 * 2016/05/11 00035 * ファイル名変更 日付/各データ(ファイル構造化) 00036 * GPSセンテンス保存 走行ラインGoogle Earth等で閲覧可 00037 * 00038 * 2016/06/01 00039 * スタート前時,積算しないように設定(関数の引数で変更可) 00040 * 00041 * 2016/06/10 00042 * INA226設定レジスタ変更 00043 * wait変更 00044 * 00045 * 2016/06/15 00046 * MITSUBA CANデータ対応 回転数データ取得 00047 * 00048 * 2016/07/03 00049 * INA226 異常データ対策 00050 * 絶縁監視(漏れ電流)エラー出力機能追加 00051 * 00052 * 2016/07/11 00053 * DriverEmergency機能追加 00054 * 00055 * 2016/07/17 00056 * Web送信データ変更 平均→積算 00057 * LAP送信データ追加 コントロールライン通過時刻 00058 * 00059 * 2016/07/25 00060 * Webデータ送信 桁数一部変更 00061 * CalculateSet関数修正 00062 * 00063 * 2016/08/02 00064 * ReadyStartLCD()にGPSがfixしたらGPS OKと表示するようにした 00065 * 00066 * 2017/08/02 00067 * INA226 測定平均回数 16 → 128 00068 * 2017/08/05 12:00:00自動スタート 00069 * 00070 * 2021/07/10 00071 * バッテリー容量を3.6 * 3.35 * 30 * 14から3.6 * 3.45 * 26 * 16 に変更 00072 * 00073 */ 00074 00075 #include "mbed.h" 00076 #include "INA226.hpp" 00077 #include "TextOLED.h" 00078 #include "MSCFileSystem.h" 00079 #include "EthernetNetIf.h" 00080 #include "TCPSocket.h" 00081 #include "TinyHTTP.h" 00082 #include "NTPClient.h" 00083 #include "RTC.h" 00084 #include "MBed_Adafruit_GPS.h" 00085 #include "MITSUBA_CAN.h" 00086 //#include "MMA8652.h" 00087 00088 // INA226用I2Cアドレス I2Cアドレスはmbedの場合1ビット左シフトしたアドレスになる 00089 const int batteryMonitorAddress = 0x80; // 0b10000000 (GG) 00090 const int panelMonitorAddress = 0x82; // 0b10000010 (G1) 00091 const int motorMonitorAddress = 0x9E; // 0b10011110 (CC) 00092 const unsigned short configuration = 0x4897; // 平均化処理やタイミング 00093 00094 /*------------------------------設定変更厳禁------------------------------*/ 00095 const double voltageCalibration = 10 / 1.1; // 分圧比(10倍に補正) 00096 const unsigned short calibration = 0x1400; // シャント電圧補正係数 00097 const unsigned short calibrationPanel = 0x2800; // シャント電圧補正係数(パネル) 00098 const double currentCalibration[] = {1.5, 0.5, 1.5}; 00099 // [0]: バッテリ [1]: パネル [2]: モータ 00100 /*------------------------------設定変更厳禁------------------------------*/ 00101 00102 const double batteryCapacity = 3.6 * 3.45 * 26 * 16; // 公称電圧*電流容量*直列数*並列数←2021鈴鹿仕様に変更 00103 00104 const int offsetTime = 60 * 60 * 9; // 9時間(標準時との時差) = 日本時間 00105 const int storageTime = 8; // 8秒ごとにサーバーへ送信 10秒はサイズ的に厳しい 00106 const int storageOffset = 5; // 5秒間分余分に配列を用意しておく 00107 const int lapTime_limit = 60 * 4; // LAPタイム 4分00秒以内はキャンセル 00108 const double kmph = 1.852; // 1ノット = 1.852 km/h 00109 const double pulseConvert = 0.1303; // 車速パルス -> 速度変換係数 00110 const double rpmConvert = 0.104399; // rpm -> km/h 変換係数 00111 00112 /*各配列要素数*/ 00113 const int RealtimeData_i = 3; 00114 const int RealtimeData_j = 5; 00115 const int LapoutData_i = 3; 00116 const int LapoutData_j = 3; 00117 const int timeStr_i = 6; 00118 const int preLapdata_i = 3; 00119 const int preLapdata_j = 2; 00120 00121 // バッファーサイズ 00122 const int RequestStr_maxsize = 1210; // 1600とかでは送信できない メモリ破壊? 00123 const int LapRequestStr_maxsize = 110; 00124 const int SerialSendStr_maxsize = 200; 00125 const int timeStr_maxsize = 32; 00126 const int fileName_maxsize = 32; 00127 00128 Serial debug(USBTX, USBRX); 00129 Serial Xbee(p13, p14); 00130 Serial gpsSerial(p28, p27); 00131 Adafruit_GPS myGPS(&gpsSerial); 00132 00133 CAN mitsuba_can(p30, p29); 00134 MITSUBA canlog(mitsuba_can, 250000); 00135 //MMA8652 acc(p9, p10); // sda, scl 00136 00137 DigitalOut sublogger_sec(p24); 00138 DigitalOut sublogger_min(p25); 00139 // 引数は(rs,e,d4,d5,d6,d7) 接続しないピンはGNDに落としておくと安定する 00140 TextOLED lcd(p15, p16, p17, p18, p19, p20, TextOLED::LCD20x4); 00141 00142 I2C i2c(p9, p10); // sda, scl 00143 INA226 BatteryMonitor(i2c, batteryMonitorAddress, 10000); 00144 INA226 PanelMonitor(i2c, panelMonitorAddress, 10000); 00145 INA226 MotorMonitor(i2c, motorMonitorAddress, 10000); 00146 00147 MSCFileSystem msc("usb"); // USBメモリには/usb/...でアクセス 00148 00149 EthernetNetIf eth; 00150 NTPClient ntp; 00151 00152 DigitalOut isoError(p6); // 絶縁監視エラー出力 00153 00154 InterruptIn lapSw(p7); // lapスイッチ ON: 0, OFF:1 00155 InterruptIn motorPulse(p12); // モーターパルス 00156 00157 struct LogData { 00158 char timeStr[timeStr_i][timeStr_maxsize]; 00159 /* [0]:タイムスタンプ 20160801121356 00160 [1]:現在時刻 12:13:56 00161 [2]:経過時間 00:13:56 00162 [3]:カウント用 00:01:30 00163 [4]:LCD用ラップタイム 05:15 00164 [5]:通過時刻 12:05:00*/ 00165 unsigned int lap; // ラップ数 00166 unsigned int lapTime; // ラップタイム 00167 int totalTime; // 経過時間 00168 double RealtimeData[RealtimeData_i][RealtimeData_j]; // 1秒毎の測定データ 00169 double LapoutData[LapoutData_i][LapoutData_j]; // ラップ平均等 00170 double batteryVoltage; // バッテリー電圧 00171 double remainBatteryParcent; // バッテリー残量[%] 00172 double remainBatteryWh; // バッテリー残量[Wh] 00173 double motorSpeed; // モーター速度[km/h] CAN 00174 double motorSpeed_pulse; // モーター速度[km/h] パルス 00175 double motorAngle; 00176 double gpsSpeed; // GPS速度[km/h] 00177 // float accData[3]; // 3軸加速度 0:x, 1:y, 2:z[何Gか] 00178 double latitude; // 緯度 00179 double longitude; // 経度 00180 }; 00181 00182 // グローバル変数 00183 bool secTimer = false; 00184 bool lapSave = false; 00185 bool lapSave_forsub=false; 00186 bool emergency = false; 00187 time_t startUnixTime = 0; 00188 struct LogData logdata = {0}; 00189 struct LogData Postdata[storageTime + storageOffset] = {0}; // storageTimeかつかつはまずい? 00190 unsigned int postcount = 0; // logdataを貯める時間をカウント 00191 unsigned int lapTimeValue = 0; // スイッチ判定用のラップタイム 00192 unsigned int pulseCount = 0; // 車速パルスカウント 00193 time_t prelapUnixTime = 0; // 前のラップタイムのUNIXタイム 00194 double preLapdata[preLapdata_i][preLapdata_j] = {0}; // 前のラップデータ 00195 00196 // プロトタイプ宣言 00197 void SetTimer(void); 00198 void MainFuncTimer(void); 00199 void SwFuncInterrupt(void); 00200 void MotorPulseCount(void); 00201 void print(const char *str, int row, int col); 00202 int SetupINA226(void); 00203 int SetupEthernet(void); 00204 int SetupUSB(struct LogData *data, char name[][fileName_maxsize]); 00205 int ReadBackup(struct LogData *data, double predata[][preLapdata_j], time_t *preTime); 00206 int FetchGPSdata(const char name[][fileName_maxsize]); 00207 void CalculateSet(struct LogData *data, bool run); 00208 unsigned int CalculateTimeSet(struct LogData *data, time_t preTime); 00209 void LapCalculateSet(struct LogData *data, double predata[][preLapdata_j], time_t *preTime); 00210 int httpPost(const struct LogData postdata[], int *httpRes); 00211 void LaphttpPost(const struct LogData *data, int *httpRes); 00212 void EmergencyhttpPost(const struct LogData *data); 00213 void LCD(const struct LogData *data); 00214 void ReadyStartLCD(const struct LogData *data); 00215 int USBSaveData(const struct LogData postdata[], const char name[][fileName_maxsize]); 00216 int LapUSBSaveData(const struct LogData *data, const char name[][fileName_maxsize]); 00217 int SaveBackup(const struct LogData *data, const double predata[][preLapdata_j], time_t preTime); 00218 void XbeeSerial(const struct LogData *data); 00219 void InsulateMonitor(const struct LogData *data); 00220 00221 int main(){ 00222 int httpResponce = 0; // httpリクエスト送信時のレスポンス 00223 int LaphttpResponce = 0; 00224 char fileName[3][fileName_maxsize] = {0}; // USBファイル名 [0]:LOG, [1]:LAP, [2]:GPS 00225 00226 debug.baud(9600); 00227 Xbee.baud(57600); // 安心と信頼()の57600bps 00228 myGPS.begin(9600); 00229 myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); 00230 myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); 00231 myGPS.sendCommand(PGCMD_ANTENNA); 00232 00233 lcd.cls(); 00234 00235 sublogger_sec=0; 00236 sublogger_min=0; 00237 00238 // エラー時は自動的にリセット 00239 00240 if(SetupINA226()) { 00241 NVIC_SystemReset(); 00242 return -1; 00243 } 00244 00245 if(SetupEthernet()) { 00246 NVIC_SystemReset(); 00247 return -1; 00248 } 00249 00250 // Host server(IpAddr(), 123, "ntp.jst.mfeed.ad.jp"); // NTP時刻取得 調子悪い? 00251 Host server(IpAddr(), 123, "ntp.nict.jp"); 00252 ntp.setTime(server); // RTCにセット 00253 00254 if(SetupUSB(&logdata, fileName)) { 00255 NVIC_SystemReset(); 00256 return -1; 00257 } 00258 00259 wait(1.0); 00260 lcd.cls(); 00261 00262 RTC::attach(&SetTimer, RTC::Second); // SetTimer()を1秒毎に実行する 00263 00264 // スタート前ループ 00265 // 初回起動時 backup.csvが存在していないときのみ実行 00266 if(ReadBackup(&logdata, preLapdata, &prelapUnixTime)) { 00267 while(1) { 00268 if(!lapSw || time(NULL) == 1564801200) { // 2019/8/3/12:00:00 自動スタート←2年前になってたかも 00269 startUnixTime = time(NULL) + offsetTime+600; // スタート時刻取得 00270 break; 00271 } 00272 if(secTimer) { 00273 CalculateTimeSet(&logdata, prelapUnixTime); 00274 CalculateSet(&logdata, false); 00275 ReadyStartLCD(&logdata); 00276 InsulateMonitor(&logdata); 00277 secTimer = false; 00278 } 00279 } 00280 } 00281 /* 00282 else { 00283 // NTP時刻が異常な時(スタートから5時間以上) 自動的にリセット 00284 if(labs(startUnixTime - (time(NULL) + offsetTime)) > 5 * 3600) { 00285 print("NTP Time isoError\n", 0, 0); 00286 RTC::detach(RTC::Second); 00287 NVIC_SystemReset(); 00288 return -1; 00289 } 00290 } 00291 */ 00292 lapSw.fall(&SwFuncInterrupt); // ピン立ち下がり割り込みに設定 00293 motorPulse.fall(&MotorPulseCount); 00294 00295 RTC::detach(RTC::Second); 00296 lcd.cls(); 00297 wait(0.5); // lapSwが0になるのを待つ 00298 00299 RTC::attach(&MainFuncTimer, RTC::Second); // MainFuncTimerを1秒ごとに実行 00300 00301 // メインループ 00302 while(1) { 00303 FetchGPSdata(fileName); // GPSセンテンス取得・解析 00304 if(emergency) { 00305 EmergencyhttpPost(&logdata); 00306 emergency = false; 00307 } 00308 if(lapSave) { 00309 LaphttpPost(&logdata, &LaphttpResponce); // LAPデータ送信 00310 LapUSBSaveData(&logdata, fileName); 00311 lapSave = false; 00312 } 00313 if(secTimer) { // fopen関連は割り込みで実行できない 00314 SaveBackup(&logdata, preLapdata, prelapUnixTime); // バックアップ 00315 secTimer = false; 00316 } 00317 if(postcount >= storageTime) { // storageTime個のデータが集まったら 00318 postcount = 0; 00319 USBSaveData(Postdata, fileName); // USBにデータ保存 00320 httpPost(Postdata, &httpResponce); 00321 // debug.printf("\n%d\n", httpResponce); 00322 } 00323 } 00324 } 00325 00326 /*--------------------------割り込み実行の関数 ここから-------------------------------*/ 00327 // RTCタイマーで1秒ごとに実行(スタート前) 00328 void SetTimer(){ 00329 secTimer = true; 00330 } 00331 00332 // RTCタイマーで1秒ごとに実行(走行時) 00333 void MainFuncTimer(){ 00334 secTimer = true; 00335 canlog.GetCanData(FRAME0); // FRAME0のデータを取得 00336 lapTimeValue = CalculateTimeSet(&logdata, prelapUnixTime); // 時間に関するデータを計算 00337 CalculateSet(&logdata, true); // データ取得・計算し,格納 00338 LCD(&logdata); // LCDにデータ表示 00339 Postdata[postcount++] = logdata; // 蓄積 00340 if(postcount >= storageTime + storageOffset) { // 配列上限超えると強制リセット 00341 postcount = 0; 00342 } 00343 InsulateMonitor(&logdata); 00344 } 00345 00346 // スイッチ割り込み 00347 // lapTime_limit未満は緊急スイッチとして動作→非表示に(2019.8.1) 00348 void SwFuncInterrupt(){ 00349 if(lapTimeValue >= lapTime_limit) { 00350 LapCalculateSet(&logdata, preLapdata, &prelapUnixTime); // LAPデータ計算 00351 XbeeSerial(&logdata); // LAPデータをxbeeで送信 00352 lapSave = true; // Web 送信,USB保存のフラグ 00353 lapSave_forsub=true; 00354 } 00355 else{ 00356 //lcd.cls(); 00357 //print("Driver Emergency", 2, 1); 00358 wait(1.0); 00359 lcd.cls(); 00360 emergency = true; // 緊急スイッチ,web送信フラグ 00361 } 00362 } 00363 00364 void MotorPulseCount(){ 00365 pulseCount++; // ストリーム等でデバックすると遅延で正確にパルス数を測定できない 00366 } 00367 00368 /*--------------------------割り込み実行の関数 ここまで-------------------------------*/ 00369 00370 /*-------------------------------ユーザー定義関数-------------------------------------*/ 00371 00372 /** 全てのストリーム系に文字列を出力 00373 * @param const char *str 送信文字列 00374 * @param int row 列 00375 * @param int col 行 00376 */ 00377 void print(const char *str, int row, int col){ 00378 debug.printf("%s", str); 00379 Xbee.printf("%s", str); 00380 lcd.locate(row, col); 00381 lcd.printf("%s", str); 00382 } 00383 00384 /** INA226 レジスタ書き込み等 00385 * @return 0:成功 -1:失敗 00386 */ 00387 int SetupINA226(){ 00388 unsigned short val_1 = 0; 00389 unsigned short val_2 = 0; 00390 unsigned short val_3 = 0; 00391 00392 // INA226の存在を確認 00393 if(!BatteryMonitor.isExist()) { 00394 print("INA226B not found!\n", 0, 0); 00395 } 00396 if(!PanelMonitor.isExist()) { 00397 print("INA226P not found!\n", 0, 1); 00398 } 00399 if(!MotorMonitor.isExist()) { 00400 print("INA226M not found!\n", 0, 2); 00401 return -1; 00402 } 00403 00404 // INA226のレジスタの値を正しく読めるか確認 00405 if(BatteryMonitor.rawRead(0x00, &val_1) != 0) { 00406 print("INA226B read Error!\n", 0, 0); 00407 return -1; 00408 } 00409 if(PanelMonitor.rawRead(0x00, &val_2) != 0) { 00410 print("INA226P read Error!\n", 0, 1); 00411 return -1; 00412 } 00413 if(MotorMonitor.rawRead(0x00, &val_3) != 0) { 00414 print("INA226M read Error!\n", 0, 2); 00415 return -1; 00416 } 00417 00418 // 各INA226にレジスタ値を書き込む 00419 BatteryMonitor.setConfiguration(configuration); 00420 PanelMonitor.setConfiguration(configuration); 00421 MotorMonitor.setConfiguration(configuration); 00422 BatteryMonitor.setCurrentCalibration(calibration); 00423 PanelMonitor.setCurrentCalibration(calibrationPanel); 00424 MotorMonitor.setCurrentCalibration(calibration); 00425 00426 print("INA226 OK!\n", 0, 0); 00427 return 0; 00428 } 00429 00430 /** ネット関連 初期化 00431 * @return 0: 成功 -1: 失敗 00432 */ 00433 int SetupEthernet(){ 00434 EthernetErr ethErr = eth.setup(); 00435 if(ethErr) { 00436 debug.printf("Error %d in setup.\n", ethErr); 00437 Xbee.printf("Error %d in setup.\n", ethErr); 00438 lcd.locate(0, 1); 00439 lcd.printf("Setup Error %d", ethErr); 00440 return -1; 00441 } 00442 00443 print("Ethernet OK!\n", 0, 1); 00444 return 0; 00445 } 00446 00447 /** USBメモリ書き込み初期化 ファイル名設定 00448 * @param struct LogData LogData 構造体 00449 * @param char name ファイル名が書き込まれる配列 00450 * 00451 * @return 0: 成功 -1: 失敗 00452 */ 00453 int SetupUSB(struct LogData *data, char name[][fileName_maxsize]){ 00454 time_t createdTime = time(NULL) + offsetTime; 00455 // 日付がファイル名 00456 strftime(name[0], fileName_maxsize, "/usb/%y%m%d_log.csv", localtime(&createdTime)); 00457 strftime(name[1], fileName_maxsize, "/usb/%y%m%d_LAPdata.csv", localtime(&createdTime)); 00458 strftime(name[2], fileName_maxsize, "/usb/%y%m%d_GPSNMEA.log", localtime(&createdTime)); 00459 00460 FILE *fp = fopen(name[0], "a"); 00461 if(fp == NULL) { 00462 print("USB can\'t be opened!\n", 0, 2); 00463 return -1; 00464 } 00465 else{ 00466 strftime(data->timeStr[0], timeStr_maxsize, "%Y%m%d%H%M%S", localtime(&createdTime)); 00467 fprintf(fp, "%s\n", data->timeStr[0]); // 試しに現在時刻を書き込み 00468 } 00469 fclose(fp); 00470 00471 print("USB OK!\n", 0, 2); 00472 return 0; 00473 } 00474 00475 /** バックアップデータを読み込み,LogData構造体に格納 00476 * @param struct LogData バックアップからLogData 構造体に書き込む 00477 * @param double predata バックアップから前のラップタイムデータを書き込む 00478 * @param time_t *preTime バックアップから前のラップタイムを書き込む 00479 * 00480 * @return 0:成功 1:バックアップデータが存在していない 00481 */ 00482 int ReadBackup(struct LogData *data, double predata[][preLapdata_j], time_t *preTime){ 00483 int i; 00484 FILE *fp_back = fopen("/usb/backup.csv", "r"); 00485 if(fp_back == NULL) { 00486 debug.printf("Backup File No Exist\n"); 00487 return 1; // 初回起動時 backup.csvはSaveBackup関数が実行された時に作成される 00488 } 00489 else{ 00490 fscanf(fp_back, "%d,%d,%d,%d", &(data->lap), &(data->lapTime), &startUnixTime, preTime); 00491 for(i = 0; i < RealtimeData_i; i++) { 00492 fscanf(fp_back, "%lf,%lf,", &(data->RealtimeData[i][2]), &(data->RealtimeData[i][3])); // 電流和,電力和 00493 } 00494 for(i = 0; i < preLapdata_i; i++) { 00495 fscanf(fp_back, "%lf,%lf,", &predata[i][0], &predata[i][1]); 00496 } 00497 } 00498 fclose(fp_back); 00499 return 0; 00500 } 00501 00502 /** シリアルGPSデータを解析,保存 00503 * @param const char name ファイル名が保存されている配列 00504 * 00505 * @return 0:成功 -1:失敗 00506 */ 00507 int FetchGPSdata(const char name[][fileName_maxsize]){ 00508 // char c; 00509 while(1) { 00510 myGPS.read(); // ただ読むだけでなくて,GPSセンテンスを文字列化している 00511 // if (c) debug.printf("%c", c); 00512 if (myGPS.newNMEAreceived()) { // センテンスが一文取得できたかどうか 00513 if (!myGPS.parse(myGPS.lastNMEA())) { // 解析が完了したかどうか していない場合はもう一度ループ(breakスキップ) 00514 continue; 00515 } 00516 break; // 解析終了した場合はループを抜ける 00517 } 00518 } 00519 // 直前のGPSセンテンスをUSBに保存 00520 FILE *fp = fopen(name[2], "a"); 00521 if(fp == NULL) { 00522 debug.printf("USB Error\n"); 00523 return -1; 00524 } 00525 else{ 00526 fprintf(fp, "%s", myGPS.lastNMEA()); 00527 } 00528 fclose(fp); 00529 return 0; 00530 } 00531 00532 /** 1秒毎に電圧・電流測定,計算後のデータを構造体に格納 00533 * @param struct LogData 00534 * @param bool run : true 積算する false 積算しない 00535 */ 00536 void CalculateSet(struct LogData *data, bool run){ 00537 int i; 00538 bool retry = false; 00539 int count = 0; 00540 00541 double voltage_tmp = 0; // 仮に電圧,電流データを保存しておく 00542 double current_tmp[RealtimeData_i] = {0}; 00543 00544 // 異常な値の場合は,再度データを取り直す 00545 do { 00546 retry = false; 00547 BatteryMonitor.getVoltage(&voltage_tmp); // 電圧 00548 BatteryMonitor.getCurrent(¤t_tmp[0]); // バッテリー電流 00549 PanelMonitor.getCurrent(¤t_tmp[1]); // パネル電流 00550 MotorMonitor.getCurrent(¤t_tmp[2]); // モーター電流 00551 00552 if(voltage_tmp > 200) retry = true; // 電圧が200V以上は異常 00553 for(i = 0; i < RealtimeData_i; i++) { 00554 if(current_tmp[i] > 200) retry = true; // 電流が200A以上は異常 00555 } 00556 count++; 00557 } while(retry && count < 5); // 5回とっても異常な場合はさすがにループを抜ける 00558 00559 // 0割の有無を確認した後,配列に格納する 00560 if(data->totalTime != 0) { 00561 data->batteryVoltage = voltage_tmp * voltageCalibration; // 分圧電圧を補正 00562 for(i = 0; i < RealtimeData_i; i++) { 00563 data->RealtimeData[i][0] = current_tmp[i] * currentCalibration[i]; // 電流補正 00564 data->RealtimeData[i][1] = data->batteryVoltage * data->RealtimeData[i][0]; // 電力 00565 if(run) data->RealtimeData[i][2] += data->RealtimeData[i][0]; // 電流の和 00566 if(run) data->RealtimeData[i][3] += data->RealtimeData[i][1]; // 電力の和 00567 data->RealtimeData[i][4] = data->RealtimeData[i][3] / 3600; // 積算電力 00568 } 00569 data->remainBatteryWh = batteryCapacity - data->RealtimeData[0][4]; // バッテリー残量[Wh] 00570 data->remainBatteryParcent = (data->remainBatteryWh / batteryCapacity) * 100; // バッテリー残量[%] 00571 data->motorSpeed = canlog.rpmMotor * rpmConvert; // CAN通信で回転数取得 km/h変換 00572 data->motorAngle = canlog.angle; // 進角 00573 debug.printf("angle:%.2f\n", canlog.angle); 00574 data->motorSpeed_pulse = pulseCount * pulseConvert; // 1秒間でカウントしたパルスを速度に変換 00575 pulseCount = 0; 00576 data->gpsSpeed = myGPS.speed * kmph; // GPS速度 00577 data->latitude = myGPS.latitude; // GPS緯度 00578 data->longitude = myGPS.longitude; // GPS経度 00579 //acc.ReadXYZ(data->accData); // 3軸加速度 00580 } 00581 } 00582 00583 /** 時刻関連のデータを計算,格納 00584 * @param struct LogData 00585 * @param time_t preTime 前のラップタイム 00586 * 00587 * @return unsigned int ラップタイム 00588 */ 00589 unsigned int CalculateTimeSet(struct LogData *data, time_t preTime){ 00590 time_t nowTime; // 現在時刻 00591 time_t laptime_temp; // ラップタイム算出用 00592 time_t totalTime_temp; // 経過時間用 00593 00594 nowTime = time(NULL) + offsetTime; // RTCからUNIXタイムを取得し,日本時間に修正 現在時刻 00595 totalTime_temp = nowTime - startUnixTime; // 経過時間 (現在時刻とスタート時刻の差) 00596 data->totalTime = (int) totalTime_temp; // 経過時間(秒) 00597 if(!data->lap) { 00598 if(nowTime < startUnixTime){ 00599 laptime_temp = 0; 00600 } 00601 else{ 00602 laptime_temp = nowTime - startUnixTime; 00603 } // 現在時刻とスタート時刻の差 = 初回のラップタイム 00604 } 00605 else{ 00606 laptime_temp = nowTime - preTime; // 現在時刻と前のラップタイムの時刻の差 = ラップタイム 00607 } 00608 if(laptime_temp<0){ 00609 laptime_temp = 0; 00610 } 00611 // strftimeでUNIXタイムを適切にフォーマット 00612 strftime(data->timeStr[0], timeStr_maxsize, "%Y%m%d%H%M%S", localtime(&nowTime)); // PHP,USB用 00613 strftime(data->timeStr[1], timeStr_maxsize, "%T", localtime(&nowTime)); // LCDの現在時刻用 00614 strftime(data->timeStr[2], timeStr_maxsize, "%T", localtime(&totalTime_temp)); // LCDの経過時間用 00615 strftime(data->timeStr[3], timeStr_maxsize, "%M\'%S", localtime(&laptime_temp)); // LCDのラップ経過時刻用 00616 00617 00618 if(lapSave_forsub==true){ 00619 sublogger_min=1; 00620 lapSave_forsub=false; 00621 } 00622 else{ sublogger_min=0;} 00623 sublogger_sec=1; 00624 sublogger_sec=0; 00625 00626 00627 00628 return (unsigned int) laptime_temp; 00629 } 00630 00631 /** ラップ平均・積算値を計算し構造体に格納 00632 * @param struct LogData 00633 * @param double predata 前のラップタイムのデータ 00634 * @param time_t *preTime 前のラップタイムを書き込む 00635 */ 00636 void LapCalculateSet(struct LogData *data, double predata[][preLapdata_j], time_t *preTime){ 00637 int i, j; 00638 time_t laptime_temp; 00639 00640 // 0周目から1周目になるときの動作 00641 if(!data->lap) { 00642 data->lapTime = (int)(time(NULL) + offsetTime - startUnixTime); 00643 if(time(NULL) + offsetTime - startUnixTime<0){ 00644 laptime_temp = 0; 00645 } 00646 else{ 00647 laptime_temp = time(NULL) + offsetTime - startUnixTime; 00648 } // 現在時刻とスタート時刻の差 = 初回のラップタイム 00649 strftime(data->timeStr[4], timeStr_maxsize, "%M\'%S", localtime(&laptime_temp)); // LCD用にフォーマット 00650 } 00651 // それ以外の動作 00652 else{ 00653 data->lapTime = (unsigned int)(time(NULL) + offsetTime - *preTime); 00654 laptime_temp = time(NULL) + offsetTime - *preTime; 00655 strftime(data->timeStr[4], timeStr_maxsize, "%M\'%S", localtime(&laptime_temp)); 00656 } 00657 data->lap = data->lap + 1; // ラップ加算 00658 *preTime = time(NULL) + offsetTime; // 現在時刻を前のラップタイムのUNIXタイムとする 00659 strftime(data->timeStr[5], timeStr_maxsize, "%T", localtime(preTime)); // コントロールライン通過時刻 00660 00661 // 0割の有無を確認した後,配列に格納 前のデータとの差で一周分を算出 00662 if(data->lapTime) { 00663 for(i = 0; i < LapoutData_i; i++) { 00664 data->LapoutData[i][0] = (data->RealtimeData[i][2] - predata[i][0]) / data->lapTime; // ラップ平均電流 00665 data->LapoutData[i][1] = (data->RealtimeData[i][3] - predata[i][1]) / data->lapTime; // ラップ平均電力 00666 data->LapoutData[i][2] = (data->RealtimeData[i][3] - predata[i][1]) / 3600; // ラップ電力量 00667 } 00668 for(i = 0; i < preLapdata_i; i++) { 00669 for(j = 0; j < preLapdata_j; j++) { 00670 predata[i][j] = data->RealtimeData[i][j + 2]; // 前のデータを記憶しておく 00671 } 00672 } 00673 } 00674 } 00675 00676 /*この関数では構造体を引数に,httpリクエスト文を作成しサーバーにポストします 00677 * リクエスト文(POSTデータ) key[]=value1&key[]=value2&... 00678 * keyがp[]でvalueがカンマで結合した1秒間データ(8秒分なので8個作ることになる) 00679 * keyをkey[]形式にするとphp側で添字配列として受け取ることができる 00680 ---骨格--- 00681 構造体のデータをchar型に変換してsnprintfでフォーマットしていく(追記方式) 00682 そうして,httpRequest関数に渡す 00683 */ 00684 /** データをネット送信 00685 * @param const struct LogData 00686 * @param *httpRes HTTPレスポンスコード 00687 */ 00688 int httpPost(const struct LogData postdata[], int *httpRes){ 00689 IpAddr ip(133, 68, 205, 140); 00690 Host host; 00691 host.setName("solar-car.club.nitech.ac.jp"); 00692 host.setIp(ip); 00693 00694 int i, j, k; 00695 char RequestStr[RequestStr_maxsize] = {0}; 00696 00697 // リクエスト文を作成していく 00698 for(k = 0; k < storageTime; k++) { 00699 snprintf(RequestStr, RequestStr_maxsize, "%sp[]=%s,%d,%d,%d,%.2f", // pがkey 00700 RequestStr, 00701 postdata[k].timeStr[1], 00702 postdata[k].lap, 00703 postdata[k].lapTime, 00704 postdata[k].totalTime, 00705 postdata[k].batteryVoltage); 00706 for(j = 0; j < 2; j++) { 00707 for(i = 0; i < RealtimeData_i; i++) { 00708 snprintf(RequestStr, RequestStr_maxsize, "%s,%.1f", RequestStr, postdata[k].RealtimeData[i][j]); // 電流,電力 00709 } 00710 } 00711 for(i = 0; i < RealtimeData_i; i++) { 00712 snprintf(RequestStr, RequestStr_maxsize, "%s,%.1f", RequestStr, postdata[k].RealtimeData[i][4]); // 積算電力 00713 } 00714 snprintf(RequestStr, RequestStr_maxsize, "%s,%.2f,%.2f,%.1f,%.4f,%.4f,%s", 00715 RequestStr, 00716 postdata[k].remainBatteryParcent, 00717 postdata[k].remainBatteryWh, 00718 postdata[k].motorSpeed, 00719 postdata[k].latitude, 00720 postdata[k].longitude, 00721 postdata[k].timeStr[0]); 00722 if(k < (storageTime - 1)) { 00723 snprintf(RequestStr, RequestStr_maxsize, "%s&", RequestStr); // 最後のデータの末尾には&は不要 00724 } 00725 } 00726 *httpRes = httpRequest(METHOD_POST, 8000, &host,"/myLogger/Get/GetRealtimeData.php", "Content-Type: application/x-www-form-urlencoded\r\n", RequestStr); 00727 // debug.printf("%s", RequestStr); 00728 00729 return 0; 00730 } 00731 00732 void LaphttpPost(const struct LogData *data, int *httpRes){ 00733 IpAddr ip(133, 68, 205, 140); 00734 Host host; 00735 host.setName("solar-car.club.nitech.ac.jp"); 00736 host.setIp(ip); 00737 00738 char LapRequestStr[LapRequestStr_maxsize] = {0}; 00739 int i, j; 00740 00741 snprintf(LapRequestStr, LapRequestStr_maxsize, "q=%s,%d,%d", data->timeStr[5], data->lap, data->lapTime); 00742 for(j = 0; j < LapoutData_j; j++) { 00743 for(i = 0; i < LapoutData_i; i++) { 00744 snprintf(LapRequestStr, LapRequestStr_maxsize, "%s,%.2f", LapRequestStr, data->LapoutData[i][j]); // 列に関して出力 00745 } 00746 } 00747 snprintf(LapRequestStr, LapRequestStr_maxsize, "%s,%s", LapRequestStr, data->timeStr[0]); 00748 *httpRes = httpRequest(METHOD_POST, HTTP_TIMEOUT, &host, "/myLogger/Get/GetLapoutData.php", "Content-Type: application/x-www-form-urlencoded\r\n", LapRequestStr); 00749 // debug.printf("%s", LapRequestStr); 00750 } 00751 00752 void EmergencyhttpPost(const struct LogData *data){ 00753 IpAddr ip(133, 68, 205, 140); 00754 Host host; 00755 host.setName("solar-car.club.nitech.ac.jp"); 00756 host.setIp(ip); 00757 00758 char sendStr[32] = {0}; 00759 00760 snprintf(sendStr, 32, "p=%s,%s", data->timeStr[1], data->timeStr[0]); 00761 httpRequest(METHOD_POST, HTTP_TIMEOUT, &host, "/myLogger/Get/GetEmergency.php", "Content-Type: application/x-www-form-urlencoded\r\n", sendStr); 00762 } 00763 00764 /*LCDへのデータ表示を行う locate関数は0行0列からはじまり,引数は(列,行)*/ 00765 void LCD(const struct LogData *data){ 00766 lcd.locate(0, 0); 00767 lcd.printf("SP"); 00768 lcd.locate(3, 0); 00769 lcd.printf("%3.0f", data->motorSpeed); 00770 lcd.locate(7, 0); 00771 lcd.printf("km/h"); 00772 lcd.locate(12, 0); 00773 lcd.printf("%s", data->timeStr[1]); 00774 00775 lcd.locate(0, 1); 00776 lcd.printf("B"); 00777 lcd.locate(3, 1); 00778 lcd.printf("%5.1f", data->remainBatteryParcent); 00779 lcd.locate(9, 1); 00780 lcd.printf("%%"); 00781 lcd.locate(15, 1); 00782 lcd.printf("%s", data->timeStr[3]); 00783 00784 lcd.locate(0, 2); 00785 lcd.printf("V"); 00786 lcd.locate(3, 2); 00787 lcd.printf("%5.1f", data->batteryVoltage); 00788 lcd.locate(9, 2); 00789 lcd.printf("V"); 00790 lcd.locate(12, 2); 00791 lcd.printf("LAP"); 00792 lcd.locate(15, 2); 00793 lcd.printf("%s", data->timeStr[4]); 00794 00795 lcd.locate(0, 3); 00796 lcd.printf("M"); 00797 lcd.locate(1, 3); 00798 lcd.printf("%7.1f", data->RealtimeData[2][1]); 00799 lcd.locate(9, 3); 00800 lcd.printf("W"); 00801 lcd.locate(12, 3); 00802 lcd.printf("%3.0f", data->LapoutData[2][2]); 00803 lcd.locate(15, 3); 00804 lcd.printf("Wh"); 00805 lcd.locate(18, 3); 00806 lcd.printf("%d", data->lap); 00807 } 00808 00809 void ReadyStartLCD(const struct LogData *data){ 00810 lcd.locate(2, 0); 00811 lcd.printf(">>Push to Start<<"); 00812 00813 lcd.locate(0, 1); 00814 lcd.printf("B"); 00815 lcd.locate(2, 1); 00816 lcd.printf("%5.1f", data->remainBatteryParcent); 00817 lcd.locate(8, 1); 00818 lcd.printf("%%"); 00819 lcd.locate(11, 1); 00820 lcd.printf("Now Time"); 00821 00822 lcd.locate(0, 2); 00823 lcd.printf("V"); 00824 lcd.locate(2, 2); 00825 lcd.printf("%5.1f", data->batteryVoltage); 00826 lcd.locate(8, 2); 00827 lcd.printf("V"); 00828 lcd.locate(11, 2); 00829 lcd.printf("%s", data->timeStr[1]); 00830 00831 lcd.locate(0, 3); 00832 lcd.printf("P"); 00833 lcd.locate(1, 3); 00834 lcd.printf("%6.1f", data->RealtimeData[0][1]); 00835 lcd.locate(8, 3); 00836 lcd.printf("W"); 00837 if(myGPS.fix) { 00838 lcd.locate(11, 3); 00839 lcd.printf("GPS OK"); 00840 } 00841 } 00842 00843 /*構造体のデータをUSBメモリへデータを保存(csvファイル)*/ 00844 int USBSaveData(const struct LogData postdata[], const char name[][fileName_maxsize]){ 00845 int i, j, k; 00846 FILE *fp = fopen(name[0], "a"); 00847 00848 if(fp == NULL) { 00849 debug.printf("USB can\'t open\n"); 00850 return -1; 00851 } 00852 else{ 00853 for(k = 0; k < storageTime; k++) { 00854 fprintf(fp, "%s,%d,%d,%d,%.2f,", postdata[k].timeStr[1], postdata[k].lap, postdata[k].lapTime, postdata[k].totalTime, postdata[k].batteryVoltage); 00855 for(j = 0; j < RealtimeData_j; j++) { 00856 for(i = 0; i < RealtimeData_i; i++) { 00857 fprintf(fp, "%.3f,", postdata[k].RealtimeData[i][j]); // 列に関して出力(全データ) 00858 } 00859 } 00860 fprintf(fp, "%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n", postdata[k].remainBatteryParcent, postdata[k].remainBatteryWh, postdata[k].motorSpeed, postdata[k].motorSpeed_pulse, postdata[k].gpsSpeed, postdata[k].motorAngle); 00861 /* 00862 for(i = 0; i < 3; i++) { 00863 if(i == 2) { 00864 fprintf(fp, "%.5f\n", postdata[k].accData[i]); 00865 } 00866 else{ 00867 fprintf(fp, "%.5f,", postdata[k].accData[i]); 00868 } 00869 } 00870 */ 00871 } 00872 } 00873 fclose(fp); 00874 return 0; 00875 } 00876 00877 int LapUSBSaveData(const struct LogData *data, const char name[][fileName_maxsize]){ 00878 int i, j; 00879 00880 FILE *fp = fopen(name[1], "a"); 00881 if(fp == NULL) { 00882 debug.printf("USB can\'t open\n"); 00883 return -1; 00884 } 00885 else{ 00886 fprintf(fp, "\n%s,%d,%d,%d", data->timeStr[5], data->lap, data->lapTime, data->totalTime); 00887 for(j = 0; j < LapoutData_j; j++) { 00888 for(i = 0; i < LapoutData_i; i++) { 00889 fprintf(fp, ",%7.2f", data->LapoutData[i][j]); // 列に関して(ラップ平均等の全データ) 00890 } 00891 } 00892 } 00893 fclose(fp); 00894 00895 return 0; 00896 } 00897 00898 /** 蓄積されているデータをcsvファイルにバックアップ 00899 * @param const strct LogData 00900 * @param const double predata 00901 * @param time_t preTime 00902 */ 00903 int SaveBackup(const struct LogData *data, const double predata[][preLapdata_j], time_t preTime){ 00904 int i, j; 00905 00906 FILE *fp_back = fopen("/usb/backup.csv", "w"); 00907 if(fp_back == NULL) { 00908 debug.printf("USB can\'t open!\n"); 00909 return -1; 00910 } 00911 else{ 00912 fprintf(fp_back, "%d,%d,%d,%d\r\n", data->lap, data->totalTime, (unsigned int)startUnixTime, (unsigned int)preTime); 00913 for(i = 0; i < RealtimeData_i; i++) { 00914 for(j = 0; j < 2; j++) { 00915 fprintf(fp_back, "%f,", data->RealtimeData[i][j+2]); // 電流和,電力和 00916 } 00917 fprintf(fp_back, "\r\n"); 00918 } 00919 for(i = 0; i < preLapdata_i; i++) { 00920 for(j = 0; j < preLapdata_j; j++) { 00921 fprintf(fp_back, "%f,", predata[i][j]); 00922 } 00923 fprintf(fp_back, "\r\n"); 00924 } 00925 } 00926 fclose(fp_back); 00927 00928 return 0; 00929 } 00930 00931 /*基本はhttp通信を使いますが,何かあったときにシリアル通信できるようにしておきます 00932 *送信データは基本的にラップ数,ラップタイム,LapoutData 00933 */ 00934 void XbeeSerial(const struct LogData *data){ 00935 int i, j; 00936 char SerialSendStr[SerialSendStr_maxsize] = {0}; 00937 00938 snprintf(SerialSendStr, SerialSendStr_maxsize, "\nLAP: %d, %s, BV:%6.2f[V],%6.2f[%%],%7.2f[Wh],\n", 00939 data->lap, 00940 data->timeStr[4], 00941 data->batteryVoltage, 00942 data->remainBatteryParcent, 00943 data->remainBatteryWh); 00944 snprintf(SerialSendStr, SerialSendStr_maxsize, "%s Battery, Panel, Motor\nAllAve[W]: ", SerialSendStr); 00945 for(i = 0; i < RealtimeData_i; i++) { 00946 snprintf(SerialSendStr, SerialSendStr_maxsize, "%s%7.2f,", SerialSendStr, data->RealtimeData[i][4]); // 平均電力 00947 } 00948 snprintf(SerialSendStr, SerialSendStr_maxsize, "%s\nlapAve[W]: ", SerialSendStr); // 改行 00949 for(j = 1; j < LapoutData_j; j++) { 00950 for(i = 0; i < LapoutData_i; i++) { 00951 snprintf(SerialSendStr, SerialSendStr_maxsize, "%s%7.2f,", SerialSendStr, data->LapoutData[i][j]); // ラップ平均,積算 00952 } 00953 if(j == 1) snprintf(SerialSendStr, SerialSendStr_maxsize, "%s\nlapWh[Wh]: ", SerialSendStr); // 改行 00954 } 00955 Xbee.printf("%s\n", SerialSendStr); // Xbeeでシリアル送信 00956 } 00957 00958 // 絶縁監視機能(漏れ電流測定) 00959 // 電流の値が0.5A以下の場合は例外 00960 // バッテリ+パネル電流ーモータ電流が1A以上になった場合、エラー出力 00961 void InsulateMonitor(const struct LogData *data){ 00962 bool stopDecison = false; 00963 00964 for(int i = 0; i < RealtimeData_i; i++) { 00965 if(data->RealtimeData[i][0] < 0.5) { 00966 stopDecison = true; 00967 break; 00968 } 00969 } 00970 if(!stopDecison) { 00971 if((data->RealtimeData[0][0] + data->RealtimeData[1][0] - data->RealtimeData[2][0]) < 1) { 00972 isoError = 0; // 正常 00973 } 00974 else{ 00975 // isoError = 1; // エラー 00976 } 00977 } 00978 } 00979
Generated on Sun Dec 18 2022 08:16:46 by 1.7.2