most functionality to splashdwon, find neutral and start mission. short timeouts still in code for testing, will adjust to go directly to sit_idle after splashdown

Dependencies:   mbed MODSERIAL FATFileSystem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers StateMachine.cpp Source File

StateMachine.cpp

00001 #include "StateMachine.hpp"
00002 #include "StaticDefs.hpp"
00003  
00004 StateMachine::StateMachine() {
00005     _timeout = 20;            // generic timeout for every state, seconds
00006     _yo_time = 40;         // previously= 400 ;  timeout for a dive or rise yo, not set for other ops
00007     _state_transition_time = 20;  // previously =60;   time to allow motors to come to rest in float_broadcast
00008     _pitchTolerance = 5.0;     // pitch angle tolerance for FLOAT_LEVEL state
00009  
00010     _bceFloatPosition = bce().getTravelLimit();      // bce position for "float" states                  (max travel limit for BCE is 320 mm)
00011     _battFloatPosition = batt().getTravelLimit();    // batt position tail high for "broadcast" state    (max travel limit for battery is 75 mm)
00012     
00013     _disconnect_batt_pos_mm = _battFloatPosition;  // all the way forward
00014     _batt_flying_pos_mm  = 22.0;
00015     _timeout_splashdown = 120;  // two minutes??
00016     _motorDisconnect_triggered = 0;
00017     _depth_command = 2.0;                        // user keyboard depth (default)
00018     _pitch_command = -20.0;                      // user keyboard pitch (default)
00019     _heading_command = 0.0;
00020     _start_swim_entry = SIT_IDLE;
00021     _neutral_entry_state = SIT_IDLE;
00022     //new commands
00023     _BCE_dive_offset = 0.0;     //starting at the limits
00024     _BMM_dive_offset = 0.0;
00025     //new commands
00026     
00027     _neutral_timer        = 0;                  //timer used in FIND_NEUTRAL sub-FSM
00028     _neutral_success = 0;    // used if find neutral has not been run and neutral_setval is also not 1 from neutral.txt file
00029 ////////////////////////////// 
00030 
00031     _state = SIT_IDLE;                          // select starting state here
00032     _isTimeoutRunning = false;                  // default timer to not running
00033     _isSubStateTimerRunning = false;            // default timer to not running
00034 /////////////////////////////    
00035     _multi_dive_counter = 0;
00036     _multi_leg_counter = 0;
00037     _depth_KP = depthLoop().getControllerP();  // load current depth value
00038     _depth_KI = depthLoop().getControllerI();  // load current depth value
00039     _depth_KD = depthLoop().getControllerD();  // load current depth value
00040     
00041     _pitch_KP = pitchLoop().getControllerP();  // load current pitch value
00042     _pitch_KI = pitchLoop().getControllerI();  // load current pitch value
00043     _pitch_KD = pitchLoop().getControllerD();  // load current pitch value
00044     
00045     _neutral_bce_pos_mm = depthLoop().getOutputOffset(); //load current neutral buoyancy position offset
00046     _neutral_batt_pos_mm = pitchLoop().getOutputOffset(); //load current neutral buoyancy position offset
00047     
00048     _state_array_counter = 1;                   //used to iterate through and record states
00049     _substate_array_counter = 0;                //used to iterate through and record substates
00050 
00051     _state_array[0] = SIT_IDLE;  //system starts in the SIT_IDLE state, record this
00052     
00053     _substate = NEUTRAL_SINKING;                //start sub-FSM in NEUTRAL_SINKING
00054     _previous_substate = -1;                    //to start sub-FSM
00055     _previous_state = -1;                       //for tracking FSM states
00056     
00057     _max_recorded_depth_neutral = -99;          //float to record max depth
00058     _max_recorded_depth_dive = -99;             //float to record max depth
00059     
00060     _max_recorded_auto_neutral_depth = -99;
00061     
00062     _debug_menu_on = false;                     //toggle between debug and simple menu screens
00063     
00064     //new file stuff
00065     _pitch_filter_freq = pitchLoop().getFilterFrequency();
00066     _pitch_deadband = pitchLoop().getDeadband();
00067     
00068     _depth_filter_freq = depthLoop().getFilterFrequency();
00069     _depth_deadband = depthLoop().getDeadband();
00070 }
00071  
00072 //Finite State Machine (FSM)
00073 int StateMachine::runStateMachine() {   // ends about line 1022
00074     // finite state machine ... each state has at least one exit criteria
00075     static int lpd_oneshots=0;
00076     static int lpr_oneshots=0;
00077     static int finish_leg=0;  // allow a rise to complete ( if it takes less than a yo_time, then exit to FB)
00078     static float leg_max_depth = 0;
00079     static float leg_min_depth =0;
00080     static float leg_heading = 90;  //go east!
00081     char buf[256];
00082     switch (_state) {
00083     case ENDLEG_WAIT:   
00084        if(!_isTimeoutRunning) {
00085           _yotimer.reset();  _yotimer.start();  _fsm_timer.reset(); _fsm_timer.start();
00086           _isTimeoutRunning = 1;
00087           }
00088           keyboard();  //keyboard function now needs to know about this state and its timeout
00089           break; 
00090         case FLYING_IDLE:   // wait for some signal and the move the battery by a known amount
00091             //  then wait until you drop to START_SWIM on a timeout
00092             if (!_isTimeoutRunning)  {      //     start in the correct state, tell it once where to move
00093                 _fsm_timer.reset();
00094                 _fsm_timer.start();
00095                 _isTimeoutRunning = 1;
00096                 batt().unpause();
00097                 batt().setPosition_mm(_batt_flying_pos_mm); // do nothing - may include not bothering to log data - yes both SIT_IDLE and FLYING_IDLE do not log  27mar2019
00098                 sprintf(buf, "FLYING_IDLE started in statemachine\n\n\r");
00099                 mbedLogger().appendDiagFile(buf,0);
00100             }
00101             if (motorDisconnect().read() || (_fsm_timer >  13))  {     //  for real case, only test is motorDisconnect().read(), timeout check is for testing only
00102                 _motorDisconnect_triggered = 1;  // once hardware has switched once, do not need it again
00103                 // move the battery
00104                 // reset and start the timer for post disconnect wait
00105                 sprintf(buf, "FLYING_IDLE:  motorDisconnect.read() at timeout=13sec, to end\n\r");
00106                 mbedLogger().appendDiagFile(buf,0);
00107                 _fsm_timer.reset();
00108                 _fsm_timer.start();
00109                 _isTimeoutRunning = 1;
00110                 batt().unpause();   //this is now active
00111                 batt().setPosition_mm(_disconnect_batt_pos_mm);
00112 
00113             }
00114             _timeout_splashdown = 6;    // timeout_splashdown reduced to 6 seconds for testing, usually 120 sec
00115             if( _motorDisconnect_triggered && _isTimeoutRunning) {
00116                 // how end  - timeout
00117                 if (_fsm_timer > _timeout_splashdown) {  // timeout_splashdown reduced to 6 seconds for testing, usually 120 sec
00118                     xbee().printf("FLYING_IDLE ended: timed out! Go to START_SWIM \r\n");  // go to start_swim
00119                     //tare the  pressure sensor
00120                     depth().tare(); // tares to ambient (do on surface)
00121                     _state = START_SWIM;  // alternately, go into the legStruct and set start_swim now? rather than leg, or leg_position_dive
00122                     _start_swim_entry = FLYING_IDLE;
00123                     sprintf(buf, "FLYING_IDLE ended on splashdown timeout  go to Start_swim\n\n\r");
00124                     mbedLogger().appendDiagFile(buf,3);
00125 
00126                     //sprintf(buf, "FLYING_IDLE ended on splashdown timeout.  FOR testing go to ENDLEG_WAIT instead of   go to Start_swim\n\n\r");
00127                     //mbedLogger().appendDiagFile(buf,0);
00128                     //_state = ENDLEG_WAIT;
00129                     _fsm_timer.reset();
00130                     _isTimeoutRunning = false;
00131                 }
00132             }
00133             break; 
00134     case SIT_IDLE:   // sit_idle and fb_exit fall through to keyboard actions, since they do not have break statements
00135     case FB_EXIT:               
00136     case KEYBOARD :
00137         // there actually is no timeout test for SIT_IDLE, but this enables some one-shot actions
00138         if (!_isTimeoutRunning) {   // presumably the first time back in this block, whatever ended stopped the timeout_running.
00139             //tare pressure sensor
00140             depth().tare(); // tares to ambient (do on surface)
00141             
00142             if (_debug_menu_on)
00143                 printDebugMenu();
00144             else
00145                 printSimpleMenu();
00146             xbee().printf("\r\n\nstate: SIT_IDLE\r\n");
00147             _isTimeoutRunning = true; 
00148  
00149             // what is active?
00150             bce().pause();
00151             batt().pause();
00152                      
00153             //reset sub FSM
00154             _isSubStateTimerRunning = false;
00155         }
00156         
00157         // how exit?
00158         keyboard(); // keyboard function will change the state if needed
00159         break;
00160         
00161     case CHECK_TUNING :                 // state used to check the tuning of the pressure vessel
00162         // start local state timer and init any other one-shot actions
00163         if (!_isTimeoutRunning) {
00164             xbee().printf("\r\n\nstate: CHECK_TUNING\r\n");
00165             _fsm_timer.reset(); // timer goes back to zero
00166             _fsm_timer.start(); // background timer starts running
00167             _isTimeoutRunning = true; 
00168             
00169             // what needs to be started?
00170             bce().unpause();    //this is now active
00171             batt().unpause();   //this is now active
00172  
00173             // what are the commands? (DRIVE THE MOTORS "DIRECTLY")
00174             bce().setPosition_mm(_neutral_bce_pos_mm);              //this variable is loaded from the file at initialization
00175             batt().setPosition_mm(_neutral_batt_pos_mm);            //this variable is loaded from the file at initialization
00176             
00177             // getSetPosition_mm is the commanded position in the LinearActuator class
00178             
00179             xbee().printf("CHECK_TUNING: BCE cmd: %3.1f (BCE current position: %3.1f)\r\n", bce().getSetPosition_mm(), bce().getPosition_mm());
00180             xbee().printf("CHECK_TUNING: BATT cmd: %3.1f (BATT current position: %3.1f)\r\n", batt().getSetPosition_mm(), bce().getPosition_mm());
00181         }
00182     
00183         // how exit?
00184         if (_fsm_timer > _timeout) {
00185             xbee().printf("CHECK_TUNING: timed out!\r\n");
00186             _state = FLOAT_BROADCAST;
00187             _fsm_timer.reset();
00188             _isTimeoutRunning = false;
00189         }
00190         
00191         //WHAT IS ACTIVE?
00192         // the inner loop position controls are maintaining the positions of the linear actuators
00193         
00194         //print status to screen continuously
00195         xbee().printf("CHECK_TUNING: BCE_position: %0.1f, BATT_position: %0.1f (BCE_cmd: %0.1f, BATT_cmd: %0.1f)(depth: %0.1f m,pitch: %0.1f deg,heading: %0.1f)     [%0.1f sec]\r",
00196         bce().getPosition_mm(),batt().getPosition_mm(),bce().getSetPosition_mm(),batt().getSetPosition_mm(),depthLoop().getPosition(),
00197         pitchLoop().getPosition(),imu().getHeading(),_fsm_timer.read());
00198         
00199         break;
00200  
00201     case EMERGENCY_CLIMB :
00202         // start local state timer and init any other one-shot actions
00203         if (!_isTimeoutRunning) {
00204             xbee().printf("\r\n\nstate: EMERGENCY_CLIMB\r\n");
00205             _fsm_timer.reset(); // timer goes back to zero
00206             _fsm_timer.start(); // background timer starts running
00207             _yotimer.reset();
00208             _yotimer.start();
00209             _isTimeoutRunning = true; 
00210             
00211             // what needs to be started?
00212             bce().unpause();
00213             batt().unpause();
00214  
00215             // what are the commands?
00216             bce().setPosition_mm(bce().getTravelLimit());
00217             batt().setPosition_mm(10.0);    //pull nose up (0.0 was sketchy)    
00218         }
00219         
00220         // how exit?
00221         if ((_fsm_timer > _timeout ) || (_yotimer > _yo_time)) {
00222             xbee().printf("EC: timed out\r\n");
00223             _state = FLOAT_BROADCAST;
00224             _fsm_timer.reset(); _yotimer.reset();
00225             _isTimeoutRunning = false;
00226         }
00227         else if (depthLoop().getPosition() < 2.0) { //if the depth is greater than 0.2 feet, go to float broadcast
00228             _state = FLOAT_BROADCAST;
00229             _fsm_timer.reset(); _yotimer.reset();
00230             _isTimeoutRunning = false;
00231             sprintf(buf, "EMERGENCY_CLIMB - at surface ... now go to  FLOAT_BROADCAST\n\n\r");
00232                    mbedLogger().appendDiagFile(buf,3);
00233         }
00234         
00235         //WHAT IS ACTIVE?
00236         //print status to screen continuously
00237         xbee().printf("EC: depth: %3.1f, pitch: %0.1f deg [BCE:%0.1f (cmd: %0.1f) BMM:%0.1f (cmd: %0.1f)] [%0.1f sec]\r",depthLoop().getPosition(),pitchLoop().getPosition(),bce().getPosition_mm(), bce().getSetPosition_mm(),batt().getPosition_mm(), batt().getSetPosition_mm(),_fsm_timer.read());
00238         
00239         break;
00240  
00241     case FIND_NEUTRAL :
00242         // start local state timer and init any other one-shot actions
00243         if (!_isTimeoutRunning) {
00244             xbee().printf("\r\n\nstate: FIND_NEUTRAL\r\n");
00245             _fsm_timer.reset(); // timer goes back to zero
00246             _fsm_timer.start(); // background timer starts running
00247             _isTimeoutRunning = true;
00248             
00249             // what needs to be started?
00250             bce().unpause();
00251             batt().unpause();
00252             
00253             //start with a small offset from MANUAL neutral positions on the BCE only, BMM was pitching too much
00254             float bce_find_neutral_mm = _neutral_bce_pos_mm + 10.0;
00255             //float batt_find_neutral_mm = _neutral_batt_pos_mm + 10.0;
00256             
00257             bce().setPosition_mm(bce_find_neutral_mm);
00258             batt().setPosition_mm(_neutral_batt_pos_mm);    //set battery to the same neutral position
00259             
00260             //first iteration goes into Neutral Finding Sub-FSM 
00261             //set the first state of the FSM, and start the sub-FSM
00262             _substate = NEUTRAL_SINKING;        //first state in neutral sub-FSM is the pressure vessel sinking
00263             _previous_substate = -1;
00264             
00265             //save this state to the array
00266             _substate_array[_substate_array_counter] = NEUTRAL_SINKING;  //save to state array
00267             _substate_array_counter++;     
00268                    
00269             runNeutralStateMachine(); 
00270         }
00271  
00272         // how exit? (exit with the timer, if timer still running continue processing sub FSM)
00273         if (_fsm_timer > _timeout) {
00274             xbee().printf("FN: timed out [time: %0.1f sec]\r\n", _fsm_timer.read());
00275             sprintf(buf, "FIND_NEUTRAL  - timed out  roll=%f  depth = %f   now exit to EMERG_CLIMB\n\n", imu().getRoll(), depthLoop().getPosition());
00276                    mbedLogger().appendDiagFile(buf,3);
00277             _state = EMERGENCY_CLIMB;         //new behavior (if this times out it emergency surfaces)
00278             _fsm_timer.reset();
00279             sprintf(buf, "FN: timed out [time:%0.1f sec], _neutral_success = -1 for info to float_broadcast\n", _fsm_timer.read());
00280                    mbedLogger().appendDiagFile(buf,3);
00281             _fsm_timer.reset();
00282             _neutral_success = -1;
00283             _isTimeoutRunning = false;
00284             
00285             //record this to the NEUTRAL sub-FSM tracker
00286             _substate_array[_substate_array_counter] = EMERGENCY_CLIMB;  //save to state array
00287             _substate_array_counter++;
00288         }
00289         
00290         
00291         //what is active? (neutral finding sub-function runs until completion)        
00292         //check if substate returned exit state, if so stop running the sub-FSM
00293         
00294         else if (runNeutralStateMachine() == NEUTRAL_EXIT) {   // but this line will repeatedly runneutralstatemachine as long as the overall state is FIND_NEUTRAL
00295             //if successful, FIND_NEUTRAL then goes to RISE
00296             xbee().printf("*************************************** FIND_NEUTRAL sequence complete.  Rising.\r\n\n");
00297              sprintf(buf, "FIND_NEUTRAL - at Neutral EXIT  now go to RISE\n\n");
00298                    mbedLogger().appendDiagFile(buf,3);
00299             if(_neutral_success == 0 ) {   // failed in finding neutral - bad exit states
00300                  configFileIO().report_no_neutral_found( bce().getPosition_mm(), batt().getPosition_mm());   // this is a message "no_float.txt"
00301                                                                                                              //to the raspberry Pi control computer
00302                  }
00303             _state = RISE;  // adjust this to leg_position_dive  with an if statement - if not sent via keyboard
00304                             // also set flags/structures that neutral was found successfully.
00305               if (_neutral_entry_state == START_SWIM ) { 
00306                    _state = EMERGENCY_CLIMB;  finish_leg =1;
00307                    sprintf(buf, "FN  neutral_EXIT: but entry via start_swim, so radio call is next\n\n\r");
00308                    mbedLogger().appendDiagFile(buf,3); 
00309                 }   //exit case when not entered by keyboard
00310             _isTimeoutRunning = false;
00311         }
00312         break;   
00313         
00314     case DIVE :
00315         // start local state timer and init any other one-shot actions
00316                
00317         if (!_isTimeoutRunning) {
00318             xbee().printf("\r\n\nstate: DIVE\r\n");
00319             _fsm_timer.reset(); // timer goes back to zero
00320             _fsm_timer.start(); // background timer starts running
00321             _isTimeoutRunning = true; 
00322             
00323             // what needs to be started?
00324             bce().unpause();
00325             batt().unpause();
00326  
00327             // what are the commands?
00328             depthLoop().setCommand(_depth_command);
00329             pitchLoop().setCommand(_pitch_command);
00330             
00331             headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00332             
00333             xbee().printf("DIVE: depth cmd: %3.1f\r\n",depthLoop().getCommand());
00334             xbee().printf("DIVE: pitch cmd: %3.1f\r\n",pitchLoop().getCommand());
00335             xbee().printf("DIVE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00336             
00337             //reset max dive depth
00338             _max_recorded_depth_dive = -99;            //float to record max depth
00339         }
00340  
00341         // how exit?
00342         if (_fsm_timer.read() > _timeout) {
00343             xbee().printf("DIVE: timed out\r\n\n");
00344             _state = RISE; //new behavior 11/17/2017
00345             _fsm_timer.reset();
00346             _isTimeoutRunning = false;
00347         }
00348         else if (depthLoop().getPosition() > depthLoop().getCommand() - 0.5) { // including offset for low momentum approaches
00349             xbee().printf("DIVE: actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00350             _state = RISE;
00351             _fsm_timer.reset();
00352             _isTimeoutRunning = false;
00353         }
00354  
00355         // WHAT IS ACTIVE?
00356         xbee().printf("DIVE: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg [cmd:%6.1f], heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", 
00357         bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),
00358         depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),pitchLoop().getCommand(),imu().getHeading(),_fsm_timer.read());
00359         bce().setPosition_mm(depthLoop().getOutput());  //constantly checking the Outer Loop output to move the motors
00360         batt().setPosition_mm(pitchLoop().getOutput());
00361         
00362         // ACTIVE RUDDER CONTROL
00363         rudder().setPosition_deg(headingLoop().getOutput());
00364         
00365         if (depthLoop().getPosition() > _max_recorded_depth_dive) {  //debug
00366             _max_recorded_depth_dive = depthLoop().getPosition();    //new max depth recorded
00367         }
00368         
00369         break;
00370     case START_SWIM :
00371         // start local state timer and init any other one-shot actions
00372             if (!_isTimeoutRunning) {
00373                 xbee().printf("\r\n\nstate: START_SWIM\r\n");
00374                 _fsm_timer.reset(); // timer goes back to zero
00375                 _fsm_timer.start(); // background timer starts running
00376                       sprintf(buf, "START_SWIM begun \n\r");
00377                       mbedLogger().appendDiagFile(buf,3);
00378                 _yotimer.reset();
00379                 _yotimer.start();
00380                 _isTimeoutRunning = true;
00381                 //tare the  pressure sensor
00382                     depth().tare(); // tares to ambient (do on surface)     HOW certain am I that this tare only happens at surface?
00383                 if( fabs(imu().getRoll()) > 70  && depthLoop().getPosition() < 9.0) {  //inversion operations
00384                     // what needs to be started?
00385                     bce().unpause();
00386                     batt().unpause();
00387                     rudder().unpause();
00388                     _depth_command = 10;  // this should be meters depth
00389                     _heading_command = 90;
00390                     _timeout = 180;
00391                     sprintf(buf, "START_SWIM found upside down, starting to descend imu().getRoll()= %f \n\r", imu().getRoll());
00392                    mbedLogger().appendDiagFile(buf,3);
00393 
00394                     // what are the commands? (using inner loops except for heading outer loop)
00395                     // These actions happen ONCE in the POSITION_DIVE sequence
00396 
00397                     //DEPTH and HEADING  COMMANDS first
00398                     depthLoop().setCommand(_depth_command);
00399                     headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00400 
00401                      // move BCE and batt to new target positions                     
00402                      bce().setPosition_mm(depthLoop().getOutput());  //constantly checking the Outer Loop output to move the motors
00403                      // depthloop().getOutput()  will tell bce() to basically hold at neutral if you are at the desired depth ( assuming that zeroOffset for depth is correct)
00404                      
00405                      batt().setPosition_mm(pitchLoop().getOutput());  //these together should hold a depth, rather than turn around and rise
00406                                         //batt().setPosition_mm(_neutral_batt_pos_mm + _BMM_dive_offset); // dare not use neutral postions before knowing what neutral is
00407                                         //bce().setPosition_mm(_neutral_bce_pos_mm - _BCE_dive_offset);    // dare not use neutral postions before knowing what neutral is
00408 
00409                     
00410 
00411                     xbee().printf("START_SWIM: inversion  BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //g
00412                     xbee().printf("START_SWIM: inversion  BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());  //g
00413                     xbee().printf("START_SWIM: inversion  starting roll = : %3.1f\r\n",imu().getRoll() );  //g
00414                 }  //end of inversion section
00415                 if( fabs(imu().getRoll()) >70  && depthLoop().getPosition() > 9.0) {  //still inverted
00416                     // what needs to be started?
00417                     bce().unpause();
00418                     batt().unpause();
00419                     rudder().unpause();
00420                     _depth_command = 9;
00421                     _heading_command = 90;
00422                     _timeout = 120;
00423                     _pitch_command = 0;
00424                     
00425                     //DEPTH COMMAND
00426                     depthLoop().setCommand(_depth_command);
00427                     headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00428 
00429                     // what are the commands? (using inner loops except for heading outer loop)
00430                     // These actions happen ONCE in the POSITION_DIVE sequence
00431                                       //batt().setPosition_mm(_neutral_batt_pos_mm - _BMM_dive_offset);  // is this right ??  looks like climb commands
00432                                       //bce().setPosition_mm(_neutral_bce_pos_mm + _BCE_dive_offset); // dare not use neutral postions before knowing what neutral is
00433                      bce().setPosition_mm(depthLoop().getOutput());  //constantly checking the Outer Loop output to move the motors
00434                      batt().setPosition_mm(pitchLoop().getOutput());  //these together should hold a depth, rather than turn around and rise
00435 
00436                     
00437                     xbee().printf("START_SWIM: inversion  BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //g
00438                     xbee().printf("START_SWIM: inversion  BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());  //g
00439                     xbee().printf("START_SWIM: inversion  starting roll = : %3.1f\r\n",imu().getRoll() );  //g
00440                 sprintf(buf, "START_SWIM still upside down but depth>9m, set up to limit descent:  depth = %f   roll=%f\n\n\r", depthLoop().getPosition(), imu().getRoll());
00441                    mbedLogger().appendDiagFile(buf,3);
00442                 }
00443             if( fabs(imu().getRoll()) <70 && _start_swim_entry == FLYING_IDLE ) {  // starts out right side up,  still inside first call to start_swim
00444                 finish_leg = 1;   //this works to get to FB_EXIT, 
00445                 _state = FLOAT_BROADCAST;
00446                 _fsm_timer.reset(); _yotimer.reset();
00447                 _isTimeoutRunning = false;
00448                 sprintf(buf, "START_SWIM now upright, called by flying_idle, so end now.  roll= %f  depth = %f\n\r", imu().getRoll(), depthLoop().getPosition());
00449                    mbedLogger().appendDiagFile(buf,3);
00450              }
00451              if( fabs(imu().getRoll()) <70 && _start_swim_entry != FLYING_IDLE ) {  // starts out right side up,  on second on/off cycle
00452                 _state = FIND_NEUTRAL;
00453                 _neutral_entry_state = START_SWIM;
00454                 _fsm_timer.reset(); _yotimer.reset();
00455                 _isTimeoutRunning = false;
00456                 sprintf(buf, "START_SWIM not called by FLYING_IDLE, so go to find_neutral: depth= %f\n\r", depthLoop().getPosition());
00457                    mbedLogger().appendDiagFile(buf,3);
00458              }
00459         } //end of timeout running ==0
00460         
00461         // how exit?   keep diving and watching depth while also watching imu().getRoll()
00462         if ((_fsm_timer > _timeout ) || (_yotimer > _yo_time)) {  // this is bad, still upside down.
00463             xbee().printf("start_swim: timed out\r\n");
00464             sprintf(buf, "start_swim timed out on yo_time or timeout - still upside down bad - go to FLOAT_BROADCAST  roll=%f \n\n\r", imu().getRoll());
00465                    mbedLogger().appendDiagFile(buf,3);
00466             configFileIO().report_still_inverted( fabs(imu().getRoll()), _yo_time);  // tells how long you waited, puts in file "inverted.txt"
00467             _state = FLOAT_BROADCAST;
00468             _fsm_timer.reset(); _yotimer.reset();
00469             _isTimeoutRunning = false;
00470         }
00471         else if (fabs(imu().getRoll()) <30 ) { // pretty much righted itself  go to FIND_NEUTRAL
00472             _state = FIND_NEUTRAL;
00473             _neutral_entry_state = START_SWIM;
00474             sprintf(buf, "START_SWIM - turned self upright  roll=%f  depth = %f ,    now go toFIND_NEUTRAL\n\n\r", imu().getRoll(), depthLoop().getPosition());
00475                    mbedLogger().appendDiagFile(buf,3);
00476             // print message ?
00477             _fsm_timer.reset(); _yotimer.reset();
00478             _isTimeoutRunning = false;
00479         }
00480         
00481         //WHAT IS ACTIVE?
00482         //print status to screen continuously
00483         xbee().printf("START_SWIM: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg [cmd:%6.1f], heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", 
00484         bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),
00485         depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),pitchLoop().getCommand(),imu().getHeading(),_fsm_timer.read());
00486         
00487         bce().setPosition_mm(depthLoop().getOutput());  //constantly checking the Outer Loop output to move the motors
00488         batt().setPosition_mm(pitchLoop().getOutput());  //these together should hold a depth, rather than turn around and rise
00489         
00490         break;
00491    
00492     case RISE :
00493         // start local state timer and init any other one-shot actions
00494         
00495         if (!_isTimeoutRunning) {
00496             xbee().printf("\r\n\nstate: RISE\r\n");
00497             _fsm_timer.reset(); // timer goes back to zero
00498             _fsm_timer.start(); // background timer starts running
00499             _isTimeoutRunning = true; 
00500             
00501             // what needs to be started?
00502             bce().unpause();
00503             batt().unpause();
00504  
00505             // what are the commands?
00506             depthLoop().setCommand(-1.0);           //make sure to get towards the surface (saw issues at LASR pool)
00507             pitchLoop().setCommand(-_pitch_command);
00508             
00509             headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00510             
00511             xbee().printf("RISE: depth cmd: %3.1f\r\n",depthLoop().getCommand());
00512             xbee().printf("RISE: pitch cmd: %3.1f\r\n",pitchLoop().getCommand());
00513             xbee().printf("RISE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00514         }
00515  
00516         // how exit?
00517         if (_fsm_timer.read() > _timeout) {
00518             xbee().printf("RISE: timed out\r\n");
00519             _state = EMERGENCY_CLIMB;
00520             _fsm_timer.reset();
00521             _isTimeoutRunning = false;
00522         }
00523         
00524         //modified from (depthLoop().getPosition() < depthLoop().getCommand() + 0.5) 
00525         //did not work correctly in bench test (stuck in rise state)
00526         else if (depthLoop().getPosition() < 0.5) {
00527             xbee().printf("RISE: actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00528             sprintf(buf, "in RISE: at surface ...  depth =%g  ... now go to  FLOAT_BROADCAST\n\n\r", depthLoop().getPosition());
00529                    mbedLogger().appendDiagFile(buf,3);
00530             _state = FLOAT_BROADCAST;
00531             _fsm_timer.reset();
00532             _isTimeoutRunning = false;
00533         }
00534  
00535         // WHAT IS ACTIVE?
00536         xbee().printf("RISE: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg [cmd:%6.1f], heading_imu:%6.1f deg>>[%0.2f sec]                                         \r",
00537          bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),
00538          depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),pitchLoop().getCommand(),imu().getHeading(),_fsm_timer.read());
00539         bce().setPosition_mm(depthLoop().getOutput());  //constantly checking the Outer Loop output to move the motors
00540         batt().setPosition_mm(pitchLoop().getOutput());
00541         
00542         // ACTIVE RUDDER CONTROL
00543         rudder().setPosition_deg(headingLoop().getOutput());
00544          
00545         break;
00546         
00547 // NEW DIVE AND RISE SEQUENCES 
00548     case POSITION_DIVE :               
00549         // start local state timer and init any other one-shot actions
00550         if (!_isTimeoutRunning) {
00551             xbee().printf("\r\n\nstate: POSITION DIVE\r\n");
00552             _fsm_timer.reset(); // timer goes back to zero
00553             _fsm_timer.start(); // background timer starts running
00554             _isTimeoutRunning = true; 
00555             
00556             // what needs to be started?
00557             bce().unpause();
00558             batt().unpause();
00559             rudder().unpause();
00560  
00561             // what are the commands? (using inner loops except for heading outer loop)
00562             // These actions happen ONCE in the POSITION_DIVE sequence
00563             batt().setPosition_mm(_neutral_batt_pos_mm + _BMM_dive_offset);
00564             bce().setPosition_mm(_neutral_bce_pos_mm - _BCE_dive_offset);
00565             
00566             //DEPTH COMMAND
00567             depthLoop().setCommand(_depth_command);
00568                         
00569             headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00570             
00571             xbee().printf("POS DIVE: BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //get the actual commanded position
00572             xbee().printf("POS DIVE: BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());    //get the actual commanded position
00573             xbee().printf("POS DIVE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00574             
00575             //reset max dive depth
00576             _max_recorded_depth_dive = -99;            //float to record max depth
00577         }
00578  
00579         // how exit?
00580         // timer runs out goes to POSITION_RISE
00581         if (_fsm_timer.read() > _timeout) {
00582             xbee().printf("POS DIVE timed out\r\n\n");
00583             _state = POSITION_RISE; //new behavior 11/17/2017
00584             _fsm_timer.reset();
00585             _isTimeoutRunning = false;
00586         }
00587         
00588         // when you reach the dive threshold, surface
00589         else if (depthLoop().getPosition() > depthLoop().getCommand() - 0.5) { // including offset for low momentum approaches
00590             xbee().printf("POS DIVE: actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00591             _state = POSITION_RISE;
00592             _fsm_timer.reset();
00593             _isTimeoutRunning = false;
00594         }
00595  
00596         // what is active?
00597         xbee().printf("POS DIVE: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg, heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", 
00598         bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),
00599         depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),imu().getHeading(),_fsm_timer.read());
00600         
00601         if (depthLoop().getPosition() > _max_recorded_depth_dive) {
00602             _max_recorded_depth_dive = depthLoop().getPosition();    //new max depth recorded when it is larger than previous values
00603         }
00604         
00605         // ACTIVE RUDDER CONTROL
00606         rudder().setPosition_deg(headingLoop().getOutput());
00607         
00608         break;
00609  
00610     case LEG_POSITION_DIVE :               
00611         // start local state timer and init any other one-shot actions
00612         if (!_isTimeoutRunning) {
00613             xbee().printf("\r\n\nstate: LEG POSITION DIVE first time - start timer\r\n");
00614             sprintf(buf, "LEG POSITION DIVE start first dive start timer\n\n\r");
00615             mbedLogger().appendDiagFile(buf,0);
00616             _fsm_timer.reset(); // timer goes back to zero  I am not sure about this reset  jcw
00617             _fsm_timer.start(); // background timer starts running
00618             _isTimeoutRunning = true; 
00619             _yotimer.reset();
00620             _yotimer.start();   //sets the yo_timer running on the dive
00621             
00622             // what needs to be started?
00623             bce().unpause();
00624             batt().unpause();
00625             rudder().unpause();
00626  
00627             // what are the commands? (using inner loops except for heading outer loop)
00628             // These actions happen ONCE in the POSITION_DIVE sequence
00629             batt().setPosition_mm(_neutral_batt_pos_mm + _BMM_dive_offset);
00630             bce().setPosition_mm(_neutral_bce_pos_mm - _BCE_dive_offset);
00631             
00632             
00633             //retrieve commands from structs (loaded from legfile.txt file)
00634             stateMachine().getLegParams();
00635             
00636             leg_max_depth = currentLegStateStruct.max_depth;
00637             leg_heading = currentLegStateStruct.heading;
00638     
00639             
00640             //DEPTH COMMAND
00641             //depthLoop().setCommand(_depth_command);  // I want this to be the max_depth in the legStruct
00642             depthLoop().setCommand(leg_max_depth);  // I want this to be the max_depth in the legStruct
00643                         
00644             //headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00645             headingLoop().setCommand(leg_heading);     //ACTIVE HEADING (mimic of dive and rise code)
00646             
00647             xbee().printf("LEG POS DIVE: BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //get the actual commanded position
00648             xbee().printf("LEG POS DIVE: BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());    //get the actual commanded position
00649             xbee().printf("LEG POS DIVE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00650             
00651             //reset max dive depth
00652             _max_recorded_depth_dive = -99;            //float to record max depth
00653             lpd_oneshots = 1;
00654         }
00655   
00656         if (!lpd_oneshots) {
00657                 xbee().printf("\r\n\nstate: LEG POSITION DIVE oneshots\r\n");
00658                 //   _fsm_timer.reset(); // timer goes back to zero  I am not sure about this reset  jcw
00659                 // sm_timer.start(); // background timer starts running
00660                 _yotimer.reset();   //sets the yo_timer running  on the NEW dive
00661                 _yotimer.start();
00662                 //_isTimeoutRunning = true;
00663 
00664                 // what needs to be started?
00665                 bce().unpause();
00666                 batt().unpause();
00667                 rudder().unpause();
00668 
00669                 // what are the commands? (using inner loops except for heading outer loop)
00670                 // These actions happen ONCE in the POSITION_DIVE sequence
00671                 batt().setPosition_mm(_neutral_batt_pos_mm + _BMM_dive_offset);
00672                 bce().setPosition_mm(_neutral_bce_pos_mm - _BCE_dive_offset);
00673                 //retrieve commands from structs (loaded from missionleg.cfg file)
00674                 leg_max_depth = currentLegStateStruct.max_depth;
00675                 leg_heading = currentLegStateStruct.heading;
00676                 sprintf(buf, "LEG POSITION DIVE entered via Leg_pos_rise - lpd_oneshots, only restart _yotimer\n\n\r");
00677                    mbedLogger().appendDiagFile(buf,0);
00678 
00679                 //DEPTH COMMAND
00680                 //depthLoop().setCommand(_depth_command);  // I want this to be the max_depth in the legStruct
00681                 depthLoop().setCommand(leg_max_depth);  // I want this to be the max_depth in the legStruct
00682 
00683                 //headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00684                 headingLoop().setCommand(leg_heading);     //ACTIVE HEADING (mimic of dive and rise code)
00685 
00686                 xbee().printf("LEG POS DIVE: BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //get the actual commanded position
00687                 xbee().printf("LEG POS DIVE: BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());    //get the actual commanded position
00688                 xbee().printf("LEG POS DIVE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00689 
00690                 lpd_oneshots = 1;
00691                 //reset max dive depth
00692                 //_max_recorded_depth_dive = -99;            //float to record max depth
00693           }  // lpd_oneshots  if timer is already running
00694 
00695             // how exit?
00696             // timer runs out goes to LEG_POSITION_RISE but finish_leg flag is turned on.
00697             if (_fsm_timer.read() > _timeout) {
00698                 xbee().printf("LEG POSITION DIVE timed out for overall leg time\r\n\n");
00699                 _state = LEG_POSITION_RISE; //  now start a timer on yo_timer for rise
00700                 finish_leg =1;
00701                 lpr_oneshots=0;
00702                 sprintf(buf, "go to LEG POSITION DIVE on overall leg timeout, set finish_leg=1\n\n\r");
00703             mbedLogger().appendDiagFile(buf,0);
00704                 // _fsm_timer.reset();
00705                 // _isTimeoutRunning = false;
00706             }
00707 
00708             // when you reach the dive threshold, surface
00709             else if (depthLoop().getPosition() > depthLoop().getCommand() - 0.5) { // including offset for low momentum approaches
00710                 xbee().printf("LEG POS DIVE: actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00711                 _state = LEG_POSITION_RISE;
00712                 lpr_oneshots = 0;
00713                 
00714                 // _fsm_timer.reset();  // reset time if still inside legg long timeout?
00715                 // _isTimeoutRunning = false;
00716             } else if(_yotimer.read() > _yo_time ) {
00717             xbee().printf("LEG POS DIVE: yo_time timed out - go to LEG_POSITION_RISE actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00718                 sprintf(buf, "LEG POS DIVE: yo_time timed out - go to LEG_POSITION_RISE\n\n\r");
00719     mbedLogger().appendDiagFile(buf,3);
00720                 _state = LEG_POSITION_RISE;
00721                 finish_leg =1;
00722                 //_yotimer.reset();
00723                 //_yotimer.start();    // restart the yo timer for next yo in rise mode    -- test if depth is small fraction of max_depth and exit to EC if small enough??
00724                 lpr_oneshots=0;
00725                 if (depthLoop().getPosition() < 0.7* depthLoop().getCommand()) {     //too slow - exit
00726                     _state = EMERGENCY_CLIMB;  // overridden here for testing
00727                     finish_leg = 1;
00728                     xbee().printf("LEG POS DIVE:descent too slow (<0.7*maxdepth) - go to EMERGENCY_CLIMB actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00729                     sprintf(buf, "LEG POS DIVE: descent too slow yo_time timed out - go to emergency climb but not really for testing\n\n\r");
00730                     mbedLogger().appendDiagFile(buf,3);
00731                    _state = LEG_POSITION_RISE;
00732               //      _fsm_timer.reset();
00733               //      _isTimeoutRunning = false;
00734                 }
00735             }
00736 
00737             // what is active?
00738             xbee().printf("LEG POS DIVE: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg, heading_imu:%6.1f deg>>[%0.2f sec]                                         \r",
00739                           bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),
00740                           depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),imu().getHeading(),_fsm_timer.read());
00741 
00742             if (depthLoop().getPosition() > _max_recorded_depth_dive) {
00743             _max_recorded_depth_dive = depthLoop().getPosition();    //new max depth recorded when it is larger than previous values
00744             }
00745 
00746             // ACTIVE RUDDER CONTROL
00747             rudder().setPosition_deg(headingLoop().getOutput());
00748 
00749             break;  // end LEG POSITION DIVE
00750     
00751     case POSITION_RISE :
00752         // start local state timer and init any other one-shot actions
00753         
00754         if (!_isTimeoutRunning) {
00755             xbee().printf("\r\n\nstate: POSITION RISE\r\n");
00756             _fsm_timer.reset(); // timer goes back to zero
00757             _fsm_timer.start(); // background timer starts running
00758             _isTimeoutRunning = true; 
00759             
00760             // what needs to be started?
00761             bce().unpause();
00762             batt().unpause();
00763  
00764             // what are the commands? (using inner loops except for heading outer loop)            
00765             batt().setPosition_mm(_neutral_batt_pos_mm - _BMM_dive_offset);          //reversing the BCE and BATT positions
00766             bce().setPosition_mm(_neutral_bce_pos_mm + _BCE_dive_offset);            //reversing the BCE and BATT positions
00767             
00768             headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
00769             
00770             xbee().printf("POS RISE: BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //get the actual commanded position
00771             xbee().printf("POS RISE: BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());    //get the actual commanded position
00772             xbee().printf("POS RISE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00773         }
00774  
00775         // how exit?
00776         if (_fsm_timer.read() > _timeout) {
00777             xbee().printf("POS RISE: timed out\r\n");
00778             _state = EMERGENCY_CLIMB;
00779             _fsm_timer.reset();
00780             _isTimeoutRunning = false;
00781         }
00782         else if (depthLoop().getPosition() < 0.5) {
00783             xbee().printf("POS RISE: actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00784             _state = FLOAT_BROADCAST;
00785             _fsm_timer.reset();
00786             _isTimeoutRunning = false;
00787         }
00788  
00789         // what is active?
00790         xbee().printf("POS RISE: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg, heading_imu:%6.1f deg>>[%0.2f sec]                                         \r",
00791             bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),
00792             rudder().getSetPosition_deg(),depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),imu().getHeading(),_fsm_timer.read());
00793         
00794         // ACTIVE RUDDER CONTROL
00795         rudder().setPosition_deg(headingLoop().getOutput());
00796          
00797         break;   //end of POS RISE
00798         
00799        case LEG_POSITION_RISE :
00800         // start local state timer and init any other one-shot actions
00801            leg_min_depth = currentLegStateStruct.min_depth;
00802            leg_heading = currentLegStateStruct.heading;
00803             
00804         if (!_isTimeoutRunning) {  // this should never occur. the only entry into this case is from LEG_POSITION_DIVE exit
00805             xbee().printf("\r\n\nstate: LEG POSITION RISE\r\n");
00806             sprintf(buf, "state: LEG POSITION RISE  entered  with timeout NOT running should not happen\n\n\r");
00807     mbedLogger().appendDiagFile(buf,3);
00808           // go and read the legparams just in case
00809           
00810           //retrieve commands from structs (loaded from legfile.txt file)
00811             stateMachine().getLegParams();
00812             leg_min_depth = currentLegStateStruct.min_depth;
00813             leg_heading = currentLegStateStruct.heading;
00814             
00815             //_fsm_timer.reset(); // timer goes back to zero  --no
00816             _fsm_timer.start(); // background timer starts running
00817             _isTimeoutRunning = true; 
00818             _yotimer.reset();    //reset yo_timer;
00819             _yotimer.start();    //and start it
00820             
00821             // what needs to be started?
00822             bce().unpause();
00823             batt().unpause();
00824             stateMachine().getLegParams();
00825  
00826             // what are the commands? (using inner loops except for heading outer loop)            
00827             batt().setPosition_mm(_neutral_batt_pos_mm - _BMM_dive_offset);          //reversing the BCE and BATT positions
00828             bce().setPosition_mm(_neutral_bce_pos_mm + _BCE_dive_offset);            //reversing the BCE and BATT positions
00829             //retrieve commands from structs (loaded from missionleg.cfg file)
00830       
00831             headingLoop().setCommand(leg_heading);     //ACTIVE HEADING (mimic of dive and rise code)
00832             
00833             xbee().printf("LEG POS RISE: BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //get the actual commanded position
00834             xbee().printf("LEG POS RISE: BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());    //get the actual commanded position
00835             xbee().printf("LEG POS RISE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00836             lpr_oneshots = 1;
00837         }
00838         if (!lpr_oneshots) {
00839             xbee().printf("\r\n\nstate: LEG POSITION RISE  entered via LEG_POSiTION_DIVE finish\r\n");
00840             sprintf(buf, "state: LEG POSITION RISE  entered via LEG_POSITION_DIVE\n\n\r");
00841             mbedLogger().appendDiagFile(buf,3);
00842             //_fsm_timer.reset(); // timer goes back to zero  --no
00843             _yotimer.reset();    //reset yo_timer;
00844             _yotimer.start();    //and start it
00845             //_fsm_timer.start();  timer is already running // background timer starts running
00846             // _isTimeoutRunning = true; 
00847             
00848             // what needs to be started?
00849             bce().unpause();
00850             batt().unpause();
00851  
00852             // what are the commands? (using inner loops except for heading outer loop)            
00853             batt().setPosition_mm(_neutral_batt_pos_mm - _BMM_dive_offset);          //reversing the BCE and BATT positions
00854             bce().setPosition_mm(_neutral_bce_pos_mm + _BCE_dive_offset);            //reversing the BCE and BATT positions
00855             //retrieve commands from structs (loaded from missionleg.cfg file)
00856       
00857             headingLoop().setCommand(leg_heading);     //ACTIVE HEADING (mimic of dive and rise code)
00858             
00859             xbee().printf("LEG POS RISE: BATT cmd: %3.1f\r\n",batt().getSetPosition_mm());  //get the actual commanded position
00860             xbee().printf("LEG POS RISE: BCE cmd: %3.1f\r\n",bce().getSetPosition_mm());    //get the actual commanded position
00861             xbee().printf("LEG POS RISE: heading cmd: %3.1f\r\n",headingLoop().getCommand());
00862             lpr_oneshots = 1;
00863         }    // end if(!lpr_oneshots)
00864  
00865         // how exit?
00866         if (_fsm_timer.read() > _timeout) {
00867             xbee().printf("LEG POS RISE: timed out on overall timeout\r\n");
00868             //  _state = EMERGENCY_CLIMB;
00869             finish_leg = 1;  // not going immediately to Emergency_climb and not resetting timers means it will take 1 yo-time of rising first
00870             // _fsm_timer.reset();
00871             sprintf(buf, "LEG POSITION DIVE  Ended via overall timeout\n\n\r");
00872             mbedLogger().appendDiagFile(buf,0);
00873             // _isTimeoutRunning = false;
00874         }
00875         else if (depthLoop().getPosition() < leg_min_depth - 0.5  ) {  // add in check for finish_leg. Don't flip flop between states in that case
00876             xbee().printf("LEG POS RISE: actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00877             _state = LEG_POSITION_DIVE;
00878             sprintf(buf, "LEG POSITION RISE  flip-flops to LEG_POSITION_DIVE on near surface pressure \n\n\r");
00879             mbedLogger().appendDiagFile(buf,0);
00880             //_fsm_timer.reset();
00881             //_isTimeoutRunning = false;
00882             lpd_oneshots=0;
00883                if(finish_leg ==1) { 
00884                _state = EMERGENCY_CLIMB;
00885                _fsm_timer.reset(); _yotimer.reset();
00886                _isTimeoutRunning = false;
00887                sprintf(buf, "LEG POSITION RISE ... ENDS,  and since finish_leg=1, go to Emergency climb\n\n\r");
00888             mbedLogger().appendDiagFile(buf,0);
00889                }
00890         }
00891         else if(_yotimer.read() > _yo_time ) {
00892             xbee().printf("LEG POS RISE: yo_time timed out - go to Emergency_CLIMB. Actual depth: %3.1f (cmd: %3.1f)\r\n", depthLoop().getPosition(), depthLoop().getCommand());
00893             _state = EMERGENCY_CLIMB; // add diagnostics message
00894             finish_leg = 1;
00895             _fsm_timer.reset(); _yotimer.reset();
00896             _isTimeoutRunning = false;
00897             sprintf(buf, "LEG POSITION DIVE ... ENDS on yo_time too long, exit to emergnecy climb + finish_leg=1\n\n\r");
00898             mbedLogger().appendDiagFile(buf,0);
00899             }
00900  
00901         // what is active?
00902         xbee().printf("LEG POS RISE: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg, heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", 
00903         bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),
00904         rudder().getSetPosition_deg(),depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),imu().getHeading(),_fsm_timer.read());
00905         
00906         // ACTIVE RUDDER CONTROL
00907         rudder().setPosition_deg(headingLoop().getOutput());
00908          
00909         break;   // end LEG POS RISE
00910 // NEW DIVE AND RISE SEQUENCES 
00911     
00912     case FLOAT_LEVEL :
00913         // start local state timer and init any other one-shot actions
00914         if (!_isTimeoutRunning) {
00915             xbee().printf("\r\n\nstate: FLOAT_LEVEL\r\n");
00916             _fsm_timer.reset(); // timer goes back to zero
00917             _fsm_timer.start(); // background timer starts running
00918             _isTimeoutRunning = true; 
00919             
00920             // what needs to be started?
00921             bce().unpause();
00922             batt().unpause();
00923  
00924             // what are the commands?
00925             bce().setPosition_mm(_bceFloatPosition);
00926             pitchLoop().setCommand(0.0);
00927         }
00928         
00929         // how exit?
00930         if (_fsm_timer > _timeout) {
00931             xbee().printf("FL: timed out\r\n");
00932             _state = FLOAT_BROADCAST;
00933             _fsm_timer.reset();
00934             _isTimeoutRunning = false;
00935         }
00936         else if (fabs(imu().getPitch() - pitchLoop().getCommand()) < fabs(_pitchTolerance)) {         //current tolerance is 5 degrees
00937             xbee().printf("FL: pitch: %3.1f mm, set pos: %3.1f mm, deadband: %3.1f mm\r\n",imu().getPitch(), pitchLoop().getCommand(), _pitchTolerance);
00938             _state = FLOAT_BROADCAST;
00939             _fsm_timer.reset();
00940             _isTimeoutRunning = false;
00941         }
00942         
00943         // what is active?
00944         xbee().printf("FL: pitchLoop output: %3.1f, batt pos: %3.1f, piston pos: %3.1f [%0.1f sec]\r", pitchLoop().getOutput(), batt().getPosition_mm(), bce().getPosition_mm(), _fsm_timer.read());
00945         batt().setPosition_mm(pitchLoop().getOutput());
00946         
00947         break;
00948     
00949     case FLOAT_BROADCAST :
00950         // start local state timer and init any other one-shot actions
00951         if (!_isTimeoutRunning) {
00952             xbee().printf("\r\n\nstate: FLOAT_BROADCAST\r\n");
00953             _fsm_timer.reset(); // timer goes back to zero
00954             _fsm_timer.start(); // background timer starts running
00955             _yotimer.reset();
00956             _yotimer.start();
00957             _isTimeoutRunning = true; 
00958             
00959             // what needs to be started?
00960             bce().unpause();
00961             batt().unpause();
00962  
00963             // what are the commands?
00964             bce().setPosition_mm(_bceFloatPosition);        // 320.0
00965             batt().setPosition_mm(_battFloatPosition);      // 73.0
00966             
00967             //set rudder to center
00968             rudder().setPosition_deg(0.0);  //set rudder to center, zero degrees
00969         }
00970         
00971         // how exit?
00972         
00973         if (_fsm_timer > _timeout || ( _yotimer > _state_transition_time)) {
00974             xbee().printf("FB: timed out\r\n");
00975             sprintf(buf, "in FLOAT_BRADCAST timed out  ...  go to SIT_IDLE\n\n");
00976             mbedLogger().appendDiagFile(buf,3);
00977             _state = SIT_IDLE;
00978             _fsm_timer.reset();
00979             
00980             //stop recording data
00981             //mbedLogger().closeFile();
00982             
00983             _isTimeoutRunning = false;
00984             if(finish_leg == 1) { 
00985                 _state = ENDLEG_WAIT;
00986                 sprintf(buf, "in FLOAT_BROADCAST still timed out .... but also finish_leg==1 so go to ENDLEG_WAIT\n\n");
00987                 mbedLogger().appendDiagFile(buf,3); 
00988             }  // allows wait at surface for xbee messaging to not close program
00989         }
00990         
00991         //fix on float_broadcast to account for BCE stopping early in current hardware
00992         else if ( (fabs(bce().getPosition_mm() - bce().getSetPosition_mm()) < 4.0 ) and
00993                   (fabs(batt().getPosition_mm() - batt().getSetPosition_mm()) < batt().getDeadband()) ) {
00994             xbee().printf("FB: position: %3.1f mm, set pos: %3.1f mm, deadband: %3.1f mm\r\n",bce().getPosition_mm(), bce().getSetPosition_mm(), bce().getDeadband());
00995             _state = SIT_IDLE;
00996             _fsm_timer.reset();
00997             _isTimeoutRunning = false;
00998             
00999             //stop recording data
01000             //mbedLogger().closeFile();
01001             if(finish_leg == 1) { _state = ENDLEG_WAIT; }  // allows exit via wait at surface first
01002           }
01003         
01004         // what is active?
01005         xbee().printf("FB: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg, heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", 
01006         bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),
01007         depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),imu().getHeading(),_fsm_timer.read());
01008         
01009         //   if (finish_leg == 1) { _state = FB_EXIT;}
01010         break;
01011         
01012     case MULTI_DIVE :
01013         // start local state timer and init any other one-shot actions        
01014         if (!_isTimeoutRunning) {
01015             xbee().printf("\r\n\nstate: MULTI-DIVE\r\n");
01016             _fsm_timer.reset(); // timer goes back to zero
01017             _fsm_timer.start(); // background timer starts running
01018             _isTimeoutRunning = true; 
01019                 
01020             // what needs to be started?
01021             bce().unpause();
01022             batt().unpause();
01023             
01024             //retrieve commands from structs (loaded from sequence.cfg file)
01025             float sequence_depth_command = currentStateStruct.depth;
01026             float sequence_pitch_command = currentStateStruct.pitch;
01027     
01028             // what are the commands?            
01029             depthLoop().setCommand(sequence_depth_command);
01030             pitchLoop().setCommand(sequence_pitch_command);
01031             
01032             
01033             headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
01034             xbee().printf("MULTI-DIVE: depth cmd: %3.1f m, pitch cmd: %3.1f deg\r\n",depthLoop().getCommand(), pitchLoop().getCommand());
01035             
01036             //no max depth recording right now
01037         }
01038         
01039         // how exit?
01040         if (_fsm_timer > _timeout) {
01041             xbee().printf("\r\n\nMULTI-DIVE: timed out [time: %0.1f]\r\n\n", _fsm_timer.read());
01042             _state = MULTI_RISE; //new behavior 11/17/2017
01043             _fsm_timer.reset();
01044             _isTimeoutRunning = false;
01045         }
01046         else if (depthLoop().getPosition() > depthLoop().getCommand()) {
01047             xbee().printf("MULTI-DIVE: depth: %3.1f, cmd: %3.1f\r\n", depthLoop().getPosition(), depthLoop().getCommand());
01048             _state = MULTI_RISE;
01049             _fsm_timer.reset();
01050             _isTimeoutRunning = false;
01051         }
01052         
01053         // WHAT IS ACTIVE?
01054         xbee().printf("MD: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg [cmd:%6.1f], heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),pitchLoop().getCommand(),imu().getHeading(),_fsm_timer.read());
01055         bce().setPosition_mm(depthLoop().getOutput());
01056         batt().setPosition_mm(pitchLoop().getOutput());
01057         
01058         // ACTIVE RUDDER CONTROL
01059         rudder().setPosition_deg(headingLoop().getOutput());
01060         
01061         break;
01062     
01063     case MULTI_RISE :
01064         // start local state timer and init any other one-shot actions
01065         if (!_isTimeoutRunning) {
01066             xbee().printf("\r\n\nstate: MULTI-RISE\r\n");
01067             _fsm_timer.reset(); // timer goes back to zero
01068             _fsm_timer.start(); // background timer starts running
01069             _isTimeoutRunning = true; 
01070             
01071             // what needs to be started?
01072             bce().unpause();
01073             batt().unpause();
01074  
01075             //NEW: retrieve depth and pitch commands from config file struct
01076             // concept is to load this each time the multi-dive restarts
01077             stateMachine().getDiveSequence();
01078             
01079             //retrieve just pitch command from struct
01080             float sequence_pitch_command = currentStateStruct.pitch;
01081  
01082             // what are the commands? (send back to 0.5 feet, not surface) // 11/21/2017
01083             depthLoop().setCommand(0.5);
01084             pitchLoop().setCommand(-sequence_pitch_command);            
01085             
01086             headingLoop().setCommand(_heading_command);     //ACTIVE HEADING (mimic of dive and rise code)
01087             xbee().printf("MULTI-RISE: depth cmd: 0.0 m, pitch cmd: %3.1f deg\r\n",depthLoop().getCommand(), pitchLoop().getCommand());
01088         }
01089         
01090         // how exit?
01091         if (_fsm_timer > _timeout) {
01092             xbee().printf("MULTI-RISE: timed out [time: %0.1f]\r\n\n", _fsm_timer.read());
01093             _state = EMERGENCY_CLIMB;
01094             _fsm_timer.reset();
01095             _isTimeoutRunning = false;
01096             
01097             //reset multi-dive sequence to start
01098             _multi_dive_counter = 0;
01099             
01100 //            //Reload the dive sequence on exit
01101 //            sequenceController().loadSequence();
01102         }
01103         else if (depthLoop().getPosition() < 0.5) { // depth is less than 0.5 (zero is surface level)
01104             xbee().printf("MULTI-RISE: depth: %3.1f, cmd: %3.1f\r\n", depthLoop().getPosition(), depthLoop().getCommand());
01105             
01106             //going to next state            
01107             _isTimeoutRunning = false;
01108             
01109             //successful dive-rise sequence CONTINUES the multi-dive sequence
01110             _multi_dive_counter++;
01111             
01112             //UPDATE THE SEQUENCE DATA HERE
01113             stateMachine().getDiveSequence();
01114             
01115             //check if this is the end of the dive sequence
01116             //CHECK BEFORE ANYTHING ELSE that you have reached the "exit" state (FLOAT_BROADCAST)
01117             if (currentStateStruct.state == FLOAT_BROADCAST) {
01118 //                //Reload the dive sequence on exit
01119 //                sequenceController().loadSequence();
01120             
01121                 _state = FLOAT_BROADCAST;
01122             }
01123             
01124             else 
01125                 _state = MULTI_DIVE;    //Note: need to test if this else statement is necessary
01126             
01127             //have to stop this with the _multi_dive_counter variable!
01128         }
01129         
01130         // WHAT IS ACTIVE?
01131         xbee().printf("MR: BcePos (cmd):%6.1f mm(%0.1f), BattPos:%6.1f mm(%0.1f), RUD_deg_cmd: %5.1f <<current depth:%6.1f m [cmd:%6.1f]), pitch:%6.1f deg [cmd:%6.1f], heading_imu:%6.1f deg>>[%0.2f sec]                                         \r", bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),depthLoop().getCommand(),pitchLoop().getPosition(),pitchLoop().getCommand(),imu().getHeading(),_fsm_timer.read());
01132         bce().setPosition_mm(depthLoop().getOutput());  //constantly checking the Outer Loop output to move the motors
01133         batt().setPosition_mm(pitchLoop().getOutput()); 
01134         
01135         // ACTIVE RUDDER CONTROL
01136         rudder().setPosition_deg(headingLoop().getOutput());
01137         
01138         break; 
01139         
01140     case TX_MBED_LOG:        
01141         if (!_isTimeoutRunning) {            
01142             xbee().printf("\r\n\nstate: TX_MBED_LOG\r\n");
01143             _fsm_timer.reset(); // timer goes back to zero
01144             _fsm_timer.start(); // background timer starts running
01145             _isTimeoutRunning = true; 
01146             
01147             //mbedLogger().openFileForTransmit();     //starts _fp file pointer at the beginning of the file
01148             
01149             xbee().printf("TX_MBED_LOG set to zero\n\r");
01150             
01151             //function to read the file and get number of lines (packets to transmit)
01152             _timeout = mbedLogger().getNumberOfPacketsInCurrentLog();
01153             
01154             mbedLogger().setTransmitPacketNumber(0); //reset to zero
01155         }
01156         
01157     //TIMED OUT
01158         if (_fsm_timer.read() > _timeout) {
01159             xbee().printf("\r\nTX_MBED_LOG: timed out!\r\n");
01160             
01161             //STATE
01162             _state = SIT_IDLE;
01163             
01164             _fsm_timer.reset();
01165             _isTimeoutRunning = false;
01166             
01167             //mbedLogger().closeLogFile();
01168             xbee().printf("\r\n\nstate: TX_MBED_LOG (log filed closed)\r\n");
01169         }
01170         
01171     //received end transmission packet (if this is true)
01172         if (mbedLogger().endTransmitPacket()) {
01173              //STATE
01174              led3() = !led3();
01175              
01176             _state = SIT_IDLE;
01177             
01178             //reset timer
01179             _fsm_timer.reset();
01180             
01181             //mbedLogger().closeLogFile();
01182             
01183             xbee().printf("\r\n\nTX_MBED_LOG: Received end transmission packet.)\r\n");
01184         }
01185         
01186         //What is active?
01187         //mbedLogger().fsmTransmitData();
01188         mbedLogger().checkForPythonTransmitRequest();
01189         led1() = !led1();
01190         
01191         break; 
01192         
01193     case RX_SEQUENCE :
01194         xbee().printf("state: RX_SEQUENCE\r\n");
01195     
01196         if (!_isTimeoutRunning) {
01197             xbee().printf("RX_SEQUENCE _isTimeoutRunning\r\n");
01198             _fsm_timer.reset(); // timer goes back to zero
01199             _fsm_timer.start(); // background timer starts running
01200             _isTimeoutRunning = true; 
01201         }
01202         
01203         if (_fsm_timer.read() > _timeout) {
01204             xbee().printf("RX_SEQUENCE: timed out!\r\n");
01205             _state = SIT_IDLE;
01206             _fsm_timer.reset();
01207             _isTimeoutRunning = false;
01208         }
01209         
01210         // what is active?
01211         xbee().printf("Receive sequence active?\r\n");
01212         
01213         break;
01214     
01215     default :
01216         xbee().printf("DEBUG: SIT_IDLE\r\n");
01217         _state = SIT_IDLE;
01218     }
01219     
01220     //save the state to print to user
01221     if (_previous_state != _state) {
01222         _state_array[_state_array_counter] = _state;  //save to state array
01223         _state_array_counter++;
01224         
01225         _previous_state = _state;
01226     }
01227     
01228     return _state;
01229 }   /* end of runStateMachine */
01230  
01231 // output the keyboard menu for user's reference
01232 void StateMachine::printSimpleMenu() {   
01233     xbee().printf("\r\r\n\nSIMPLE KEYBOARD MENU (08/13/2018):\r\r\n");        //make sure depth sensor tares itself on startup
01234     xbee().printf(" Neutral Positions BCE: %0.1f BMM: %0.1f (LIMIT: BCE: %0.1f BATT: %0.1f)\r\n\n", _neutral_bce_pos_mm, _neutral_batt_pos_mm, bce().getTravelLimit(),batt().getTravelLimit());
01235     
01236     xbee().printf("  V to POSITION DIVE (initiate motor position-based dive cycle)\r\n");
01237     xbee().printf("  J to float level\r\n");
01238     xbee().printf("  B to float at broadcast pitch\r\n");
01239     xbee().printf("  E to initiate emergency climb\r\n");
01240     xbee().printf("  P to print the current log file.\r\n");
01241     xbee().printf("  G to transmit MBED log file\r\n");
01242     xbee().printf("  I to receive multi-dive sequence file\r\n");
01243     xbee().printf("  ~ to erase mbed log file. (clear before logging more than a few runs)\r\n");
01244     
01245     xbee().printf("Q to TYPE in the BMM offset: %0.1f (BMM Dive POS: %0.1f, Rise POS: %0.1f) (positive input offset = pitch down)\r\n",_BMM_dive_offset, _neutral_batt_pos_mm + _BMM_dive_offset, _neutral_batt_pos_mm - _BMM_dive_offset);  
01246     xbee().printf("A to TYPE in the BCE offset: %0.1f (BCE Dive POS: %0.1f, Rise POS: %0.1f) (positive input offset = dive)\r\n",_BCE_dive_offset, _neutral_bce_pos_mm - _BCE_dive_offset, _neutral_bce_pos_mm + _BCE_dive_offset);
01247     xbee().printf("W to TYPE in the heading command: %0.1f deg (imu heading: %0.1f)\r\n",_heading_command,imu().getHeading());
01248     xbee().printf("S to TYPE in depth setpoint: %0.1f (Current depth: %0.1f m)\r\n",_depth_command, depthLoop().getPosition());
01249     xbee().printf("T to TYPE in the timeout (default is 60 seconds): %d s\r\n",_timeout);    
01250     
01251     xbee().printf("  C See sensor readings (and max recorded depth of dive & neutral sequences)\r\n");
01252     xbee().printf("  8 STREAM SENSOR STATUS (and channel readings)\r\n");    
01253     xbee().printf("  ? to reset mbed\r\n");
01254     xbee().printf("  * (asterisk) to go to DEBUG keyboard menu\r\n");
01255 }
01256 
01257 void StateMachine::printDebugMenu() {
01258     xbee().printf("\r\r\n\nDEBUG KEYBOARD MENU (08/08/2018):\r\r\n");
01259     xbee().printf("  Y to go into CHECK NEUTRAL TUNING (This is on a timer! Uses NEUTRAL positions!)\r\n");
01260     xbee().printf("  N to find neutral\r\n");
01261     xbee().printf("  M to initiate multi-dive cycle\r\n");
01262     xbee().printf("  D to initiate dive cycle\r\n");
01263     xbee().printf("  R to initiate rise\r\n");
01264     xbee().printf("  J to float level\r\n");
01265     xbee().printf("  B to float at broadcast pitch\r\n");
01266     xbee().printf("  E to initiate emergency climb\r\n");
01267     xbee().printf("  '}' to HOME the BCE (5 second delay)\r\n");
01268     xbee().printf("  '|' to HOME the BMM (5 second delay)\r\n");
01269     xbee().printf("  Z to show FSM and sub-FSM states.\r\n");
01270     xbee().printf("  P to print the current log file.\r\n");
01271     xbee().printf("  X to print the list of log files.\r\n");
01272     xbee().printf("  I to receive data.\r\n");
01273     xbee().printf("  G to transmit MBED log file (60 second timeout)\r\n");
01274     xbee().printf("  ~ to erase mbed log file. (clear before logging more than a few runs)\r\n");
01275     xbee().printf("; or : to TYPE in the BCE neutral position: %0.1f\r\n", _neutral_bce_pos_mm);
01276     xbee().printf("[ or { to TYPE in the BMM neutral position: %0.1f\r\n", _neutral_batt_pos_mm);
01277     xbee().printf("Q to TYPE in pitch setpoint: %0.1f (Current IMU pitch: %0.1f deg)\r\n",_pitch_command,imu().getPitch());
01278     xbee().printf("A to TYPE in depth setpoint: %0.1f (Current depth: %0.1f m)\r\n",_depth_command, depthLoop().getPosition());
01279     xbee().printf("W to TYPE in the heading command: %0.1f deg (imu heading: %0.1f)\r\n",_heading_command,imu().getHeading());
01280     xbee().printf("T to enter in the timeout (default is 60 seconds): %d s\r\n",_timeout);
01281 
01282     xbee().printf("  1 BCE PID sub-menu (type in inputs)\r\n");
01283     xbee().printf("  2 BATT PID sub-menu (type in inputs)\r\n");
01284     xbee().printf("  3 Depth PID sub-menu (type in inputs)\r\n");
01285     xbee().printf("  4 Pitch PID sub-menu (type in inputs)\r\n");
01286     xbee().printf("  5 Rudder (servo) sub-menu\r\n");
01287     xbee().printf("  6 HEADING PID sub-menu (type in inputs)\r\n");
01288     xbee().printf("  7 MANUAL_TUNING sub-menu (does not have a timer!)  *** MOTORS ARE ACTIVE *** (bce 200, bmm 40, rudder 1640)\r\n");
01289     xbee().printf("  8 STREAM SENSOR STATUS (and channel readings)\r\n");
01290     
01291     xbee().printf(" C See sensor readings (and max recorded depth of dive & neutral sequences)\r\n");
01292     xbee().printf(" ? to reset mbed\r\n");
01293     xbee().printf(" * (asterisk) to go to SIMPLE keyboard menu\r\n");
01294 }
01295  
01296 //FIND_NEUTRAL sub-Finite State Machine (sub-FSM)
01297 // Note: the sub-FSM only moves the pistons once at the start of each timer loop
01298 //  (timer completes, moves piston, timer completes, moves piston, etc)
01299 int StateMachine::runNeutralStateMachine() {  
01300        char buf[256];              
01301     switch (_substate) {
01302         case NEUTRAL_SINKING :
01303             //start the 10 second timer
01304             if (!_isSubStateTimerRunning) {                
01305                 _neutral_timer = _fsm_timer.read() + 5; //record the time when this block is first entered and add 5 seconds
01306                 
01307                 xbee().printf("\r\n\nNEUTRAL_SINKING: Next retraction at %0.1f sec [current time: %0.1f] (pitch: %0.1f) (BCE getSetPosition: %0.1f)\r\n", _neutral_timer, _fsm_timer.read(), pitchLoop().getPosition(), bce().getSetPosition_mm());
01308                 
01309                 // what are the commands? (BCE linear actuator active, no BMM or pitch movement)
01310                 bce().setPosition_mm(bce().getSetPosition_mm() - 2.5);
01311                 
01312                 xbee().printf("NEUTRAL_SINKING: Retracting piston 2.5 mm [BCE CMD : %0.1f] (pitch: %0.1f)\r\n", bce().getSetPosition_mm(), pitchLoop().getPosition());
01313                 
01314                 _isSubStateTimerRunning = true;    //disable this block after one iteration
01315             }
01316  
01317             // how exit?
01318             //once reached the travel limit, no need to keep trying, so exit
01319             if (bce().getPosition_mm() <= 0) {
01320                 xbee().printf("\r\nDEBUG: BCE current position is %0.1f mm (NEXT SUBSTATE NEUTRAL EXIT)\r\n", bce().getPosition_mm());
01321                 sprintf(buf, "in RUNneutral: state failed at bce.getPosition()\n\n");
01322                 mbedLogger().appendDiagFile(buf,3);
01323                 _substate = NEUTRAL_EXIT;
01324                  _neutral_success = 0;
01325                 _isSubStateTimerRunning = false; // reset the sub state timer
01326             }
01327             
01328             //Troy: Pressure vessel went beyond set depth limit, goes to next state
01329             //once deeper than the commanded setpoint...
01330             else if (depthLoop().getPosition() > _depth_command) {
01331                 _substate = NEUTRAL_SLOWLY_RISE; // next state
01332                 _isSubStateTimerRunning = false; //reset the sub state timer
01333             }
01334             else if ( (depthLoop().getVelocity()  > 0.05) && (depthLoop().getPosition() >  0.6 * _depth_command) )  {  // need to code in FILTERED vertical velocity
01335                 _substate = NEUTRAL_SLOWLY_RISE; // next state
01336                 _isSubStateTimerRunning = false; //reset the sub state timer
01337             }
01338             // what is active?
01339             //once the 10 second timer is complete, reset the timeout so the state one-shot entry will move the setpoint
01340             if (_fsm_timer.read() >= _neutral_timer) {
01341                 xbee().printf("\r\n\n NEUTRAL_SINKING TIMER COMPLETE! [current time: %0.1f]\r\n", _fsm_timer.read());
01342                 
01343                 _isSubStateTimerRunning = false; // reset the sub state timer to do one-shot actions again
01344             }
01345             
01346             // what is active? (only the buoyancy engine moved every 5 seconds at start)
01347             xbee().printf("BCE current pos: %0.1f mm (BCE setpoint: %0.1f mm) (current depth: %0.1f m)\r", bce().getPosition_mm(),bce().getSetPosition_mm(),depthLoop().getPosition()); //debug
01348             
01349             //the BCE moves every 5 seconds. No BMM or rudder movement.
01350             
01351             break;
01352             
01353         case NEUTRAL_SLOWLY_RISE:
01354             if (!_isSubStateTimerRunning) {                                
01355                 _neutral_timer = _fsm_timer.read()+ 5; //record the time when this block is first entered and add 5 seconds
01356                 
01357                 xbee().printf("\r\n\nNEUTRAL_SLOWLY_RISE: Next extension at %0.1f sec) [current time: %0.1f]\r\n",_neutral_timer,_fsm_timer.read());
01358                 
01359                 // what are the commands?
01360                 //move piston at start of sequence (default: extend 2.0 mm)
01361                 //Pressure vessel should slowly rise
01362                 bce().setPosition_mm(bce().getSetPosition_mm() + 2.0);  //no depth command, only motor position
01363                 
01364                 //Troy: I commented out this command, we're finding pitch in the next state.
01365                 // it's okay to run the pitch outer loop now since we've already found pitch level in the previous state
01366                 //pitchLoop().setCommand(0.0);
01367                 
01368                 xbee().printf("NEUTRAL_SLOWLY_RISE: Extending BCE piston 2.0 mm [BCE CMD : %0.1f] (pitch: %0.1f)\r\n", bce().getSetPosition_mm(), pitchLoop().getPosition());
01369 
01370                 _isSubStateTimerRunning = true;    //disable this block after one iteration
01371             }
01372             
01373             // how exit?
01374             //once at full travel limit (setPosition) and haven't yet risen, time to give up and exit
01375             if (bce().getSetPosition_mm() >= bce().getTravelLimit()) {
01376                 _substate = NEUTRAL_EXIT;  
01377                 sprintf(buf, "in RUNneutral: SLOWLY RISE state failed at bce.getsetPosition()\n\n");
01378                 mbedLogger().appendDiagFile(buf,3);
01379                 _neutral_success =0;  //another failed state   
01380                 _isSubStateTimerRunning = false; // reset the sub state timer
01381             }
01382             //Troy: Depth rate will go negative as the pressure vessel starts rising
01383             //depth rate or sink rate < 0 ft/s, go to the next substate the next iteration
01384             else if (depthLoop().getVelocity() < 0) { //less than zero ft/s  should now be m/s
01385                 xbee().printf("\r\n\nNEUTRAL_SLOWLY_RISE: Sink Rate < 0 m/s [time: %0.1f]\r\n", _fsm_timer.read());
01386                 _substate = NEUTRAL_CHECK_PITCH;
01387                 _isSubStateTimerRunning = false; // reset the sub state timer
01388             }        
01389             // what is active?
01390             //once 5 second timer complete, reset the timeout so the state one-shot entry will move the setpoint
01391             if (_fsm_timer.read() >= _neutral_timer) {
01392                 xbee().printf("\r\n\n NEUTRAL_SLOWLY_RISE TIMER COMPLETE! [timer: %0.1f]\r\n", _fsm_timer.read());
01393    
01394                 _isSubStateTimerRunning = false; // reset the sub state timer to do one-shot actions again
01395             }
01396                         
01397             // what is active? (only the buoyancy engine moved every 5 seconds)
01398             xbee().printf("depthLoop getOutput: %0.1f\r", depthLoop().getOutput()); //debug
01399             
01400             break;   
01401                 
01402         case NEUTRAL_CHECK_PITCH : // fall thru to next state is desired
01403             // start local state timer and init any other one-shot actions
01404             
01405             if (!_isSubStateTimerRunning) {                    
01406                 _neutral_timer = _fsm_timer.read() + 10; // record time when this block is entered and add several seconds
01407                 xbee().printf("\r\nNEUTRAL_CHECK_PITCH: Next move in %0.1f sec \r\n",_neutral_timer - _fsm_timer.read());
01408                 
01409                 // what are the commands? (default: retract or extend 0.5 mm)
01410                 if (pitchLoop().getPosition() > 2) { // nose is high (extend batteries)
01411                     batt().setPosition_mm(batt().getSetPosition_mm() + 0.5); // move battery forward (using setpoint from linear actuator)
01412                     xbee().printf("\r\nNeutral Check Pitch: moving battery FWD in 0.5 mm increments\r\n\n");
01413                 }
01414                 else if (pitchLoop().getPosition() < -2) { // nose is low (retract batteries)
01415                     batt().setPosition_mm(batt().getSetPosition_mm() - 0.5); // move battery aft (using setpoint from linear actuator)
01416                     xbee().printf("\r\nNeutral Check Pitch: moving battery AFT in 0.5 mm increments\r\n\n");
01417                 }
01418 
01419                 _isSubStateTimerRunning = true;    //disable this block after one iteration
01420             }
01421  
01422             // how exit?            
01423             //pitch angle and pitch rate within small tolerance
01424             //benchtop tests confirm angle needs to be around 2 degrees
01425             if ((fabs(pitchLoop().getPosition()) < 2.0) and (fabs(pitchLoop().getVelocity()) < 5.0)) { 
01426                 xbee().printf("Debug: Found Level (NEUTRAL_CHECK_PITCH or NEUTRAL_FIRST_PITCH)\r\n");    //debug
01427                 // found level, but don't need to save anything this time
01428                 
01429                 if (depthLoop().getPosition() > _max_recorded_depth_neutral) {  //debug
01430                     _max_recorded_depth_neutral = depthLoop().getPosition();    //new max depth recorded
01431                 }
01432                 
01433                 // found level and at depth too, so save it all now               
01434                 if (_substate == NEUTRAL_CHECK_PITCH) {
01435                     //save positions locally
01436                     _neutral_batt_pos_mm = batt().getPosition_mm();
01437                     _neutral_bce_pos_mm = bce().getPosition_mm();
01438                     
01439                     //set the neutral positions in each outer loop
01440                     depthLoop().setOutputOffset(_neutral_bce_pos_mm);
01441                     pitchLoop().setOutputOffset(_neutral_batt_pos_mm);
01442                     
01443                     // save into the depth.txt and pitch.txt files
01444        
01445                     configFileIO().savePitchData(_pitch_KP, _pitch_KI, _pitch_KD, _neutral_batt_pos_mm, _pitch_filter_freq, _pitch_deadband); //P,I,D,batt zeroOffset
01446                     configFileIO().saveDepthData(_depth_KP, _depth_KI, _depth_KD, _neutral_bce_pos_mm, _depth_filter_freq, _depth_deadband); //P,I,D, bce zeroOffset
01447 
01448                     xbee().printf("\r\n\n>>> Saving Positions: BCE: %0.1f mm, BATT: %0.1f <<<\r\n\n",_neutral_bce_pos_mm,_neutral_batt_pos_mm);
01449                     
01450                     _isSubStateTimerRunning = false; // reset the sub state timer to do one-shot actions again  
01451                     _substate = NEUTRAL_EXIT;
01452                     sprintf(buf, "in RUNneutral: state succeeded! at NEUTRAL_CHECK PITCH line 1452\n\n");
01453                 mbedLogger().appendDiagFile(buf,3);
01454                     _neutral_success = 1;
01455                     configFileIO().saveNeutralStatus(_neutral_success, _neutral_bce_pos_mm, _neutral_batt_pos_mm);  // saves to tell re-started program neutral has been found
01456                     
01457                 }
01458                 
01459                 else {
01460                     xbee().printf("\r\nDid not find NEUTRAL_CHECK_PITCH or NEUTRAL_FIRST_PITCH, how did I get here?!\r\n");
01461                     _substate = NEUTRAL_EXIT;
01462                     sprintf(buf, "in RUNneutral: state failed at final fallthrough point line 1462\n\n");
01463                     mbedLogger().appendDiagFile(buf,3);
01464                 }
01465             }
01466             
01467             // what is active?
01468             //once timer complete, reset the timeout so the state one-shot entry will move the setpoint
01469             if (_fsm_timer.read() >= _neutral_timer) {
01470                 xbee().printf("\r\n\nlevel timer COMPLETE!");
01471                 xbee().printf("\r\n\n (BATT POS: %0.1f) moving 1 mm [timer: %0.1f]\r\n", batt().getPosition_mm(), _fsm_timer.read());
01472                 _isSubStateTimerRunning = false; // reset the sub state timer to do one-shot actions again
01473             }
01474 
01475             break;
01476              
01477         //this state could be removed, it is only used as a transition but is needed to stop entering this function
01478         case NEUTRAL_EXIT :
01479             xbee().printf("substate: NEUTRAL_EXIT\r\n");            
01480             break;
01481             
01482         default :
01483             xbee().printf("how did we get to substate: default?\r\n"); //debug
01484             //a default within the sub-state machine
01485             _substate = NEUTRAL_EXIT;            
01486             break;
01487     }
01488     
01489     // reset the sub-FSM if needed (useful if you need to redo the neutral-finding sequence)
01490     if (_substate == NEUTRAL_EXIT) {
01491         xbee().printf("********************************  EXITING sub-FSM! *******************************\r\n\n");
01492 
01493         //reset internal sub-state back to first entry conditions (first state is immediately sinking)
01494         _substate = NEUTRAL_SINKING;
01495         _isSubStateTimerRunning = false; // reset the sub state timer
01496         
01497         //record sub-states to view after sequence
01498         _substate_array[_substate_array_counter] = NEUTRAL_EXIT;  //save exit to state array
01499         _substate_array_counter++;
01500         
01501         //reset _previous_substate on exit (has to be done in FIND_NEUTRAL if emergency exit)
01502         _previous_substate = -1;
01503 
01504         //NEUTRAL_EXIT state is used to tell the greater FSM that this sub-FSM has completed
01505         return NEUTRAL_EXIT; // message to calling function we just exited
01506     }
01507     else {
01508         //record sub-states to view after sequence (when changed)
01509         if (_previous_substate != _substate) {
01510             _substate_array[_substate_array_counter] = _substate;  //save current state to state array
01511             _substate_array_counter++;
01512             
01513             //record the current substate for comparison 
01514             _previous_substate = _substate;
01515         }       
01516         
01517         return _substate; // message to calling function of what sub-state it's in
01518     }
01519 }
01520  
01521 /*  keyboard runs independently of the state machine, handling one key at a time
01522     keyboard updates the desired _keyboard_state that is used in the state machine
01523     and only allows input when the state is "idle" */
01524     
01525 void StateMachine::keyboard() {
01526     char user_input;
01527     char buf[256];
01528  
01529     // check keyboard and make settings changes as requested
01530     // states can be changed only at the start of a sequence (when the system is in SIT_IDLE)
01531     
01532     //TEST
01533     int _keyboard_state = 0;   //made this a local variable because it was retaining the last keyboard state
01534     static int yocount = -3;
01535     static float htime = 0.0;
01536     if(_state == ENDLEG_WAIT) {
01537       yocount = int(_yotimer.read());
01538       if ( ( (yocount % 5) == 0 ) && ( _yotimer.read() > 2.5+htime) )  {  // send out a heartbeat message, need to cast as an int from float
01539         xbee().printf("FSG on surface at end of leg, hit c to wake up\r\n");
01540         sprintf(buf, "ENDLEG WAIT heartbeat message sent yotimer=%f  \n\n\r", _yotimer.read());
01541             mbedLogger().appendDiagFile(buf,0);
01542             htime = _yotimer.read();
01543         }
01544       if( _yotimer > _state_transition_time) {
01545             _keyboard_state = FB_EXIT;
01546             _state = FB_EXIT;
01547             }
01548       }
01549     if (xbee().readable() && (_state == SIT_IDLE || _state == KEYBOARD  || _state == ENDLEG_WAIT)) {  //ends at very end of function  1740     
01550         // then get the key
01551         user_input = xbee().getc();   
01552         // and exit from ENDLEG_WAIT - you got a keyboard input
01553        if(_state == ENDLEG_WAIT) {
01554          _keyboard_state = SIT_IDLE;  // this is installed in _state at end of function
01555          } 
01556         
01557         //record that the keyboard was used
01558         _state_array[_state_array_counter] = KEYBOARD;
01559         _state_array_counter++;
01560         
01561         // keyboard has to reset timer each time it's used
01562         _isTimeoutRunning = false;
01563         
01564         // check command against desired control buttons
01565  
01566     /***************************** COMMON COMMANDS *****************************/ 
01567         if (user_input == 'W') {
01568             xbee().printf(">> Please enter the heading (deg).\r\n");
01569             _heading_command = getFloatUserInput();
01570         }
01571         
01572 //////////////////// TEST                   
01573 //        else if (user_input == 'l') {
01574 //            xbee().printf("CUT OFF RUDDER SERVO????\n\r");
01575 //            rudder().pwm_pulse_off();
01576 //        }
01577 //////////////////// TEST
01578         
01579         else if (user_input == 'K') {
01580             xbee().printf("(K) BLAST DATA AND EXIT! \n\r");
01581             mbedLogger().blastData();
01582         }
01583         
01584         else if (user_input == 'U') {
01585             xbee().printf("(U) TRANSMIT MULTIPLE PACKETS \n\r");
01586                         
01587             mbedLogger().transmitMultiplePackets();
01588         }
01589         
01590         else if (user_input == 'H') {
01591             xbee().printf("(H) BLAST DATA AND MULTIPLE PACKETS! \n\r");
01592             wait(1);
01593             mbedLogger().blastData();
01594             
01595             mbedLogger().transmitMultiplePackets(); 
01596         }
01597         
01598         else if (user_input == 'G') {
01599             xbee().printf("(G) BLAST DATA TEST and use FSM! \n\r");
01600             wait(1);
01601             mbedLogger().blastData();
01602             
01603             _keyboard_state = TX_MBED_LOG;
01604         }
01605         
01606         else if (user_input == 'I') {
01607             xbee().printf("(I) Receive Multi-Dive Sequence! \n\r");
01608             mbedLogger().receiveSequenceFile();    //receive sequence.txt files
01609         }
01610         
01611         else if (user_input == '8') {
01612             keyboard_menu_STREAM_STATUS();
01613         }
01614                     
01615         else if (user_input == '?') {
01616             xbee().printf("\n\n\n>>> Resetting MBED <<<\n\n\n");
01617             wait(0.5);
01618             mbed_reset();
01619         }
01620         
01621         else if (user_input == 'T') {
01622             xbee().printf("Please enter the timeout (timer) value below: \n\r");
01623             _timeout = fabs(getFloatUserInput());
01624         }
01625         
01626         else if (user_input == '~') {
01627             xbee().printf("MBED LOG FILE MENU!\r\n");
01628             stateMachine().logFileMenu();
01629                 
01630             //xbee().printf("ERASING MBED LOG FILE\r\n");   //legacy method
01631             //mbedLogger().eraseFile();
01632         }
01633         
01634         else if (user_input == 'C' or user_input == 'c') {
01635                 
01636             xbee().printf("\r\n\nCURRENT STATUS AND PARAMETERS:\r\n");
01637             
01638             xbee().printf("raw BCE pos: %d \r\n",adc().readCh0());
01639             xbee().printf("raw BMM pos: %d \r\n",adc().readCh1());
01640             xbee().printf("raw BCE current sense: %d \r\n",adc().readCh2());
01641             xbee().printf("raw BMM current sense: %d \r\n",adc().readCh3());
01642             xbee().printf("raw depth pressure: %d \r\n",adc().readCh4());
01643             xbee().printf("raw vessel pressure %d (internal psi: %0.1f)\r\n", adc().readCh5(),sensors().getInternalPressurePSI());
01644             //xbee().printf("raw vessel pressure: %d \r\n",adc().readCh5());
01645             xbee().printf("raw board voltage: %d (%0.1f volts)\r\n",adc().readCh6(),sensors().getVoltageInput());
01646             xbee().printf("raw board current: %d (%0.3f amps)\r\n",adc().readCh7(), sensors().getCurrentInput());
01647             xbee().printf("raw BCE limit switch: %d \r\n",bce().getSwitch());
01648             xbee().printf("raw BMM limit switch: %d \r\n",batt().getSwitch());
01649             xbee().printf("calc vessel pressure: %f (counts: %d) \r\n",sensors().getInternalPressurePSI(),adc().readCh5());
01650             // End of ADC Test
01651             
01652             xbee().printf("depth: %3.1f m\r\n",depthLoop().getPosition());
01653             xbee().printf("pitch: %3.1f deg\r\n",imu().getPitch());
01654             xbee().printf("bce().getPosition_mm(): %3.1f\r\n",bce().getPosition_mm());
01655             xbee().printf("bce().getSetPosition_mm(): %3.1f\r\n",bce().getSetPosition_mm());
01656             xbee().printf("batt().getPosition_mm(): %3.1f\r\n",batt().getPosition_mm());
01657             xbee().printf("batt().getSetPosition_mm(): %3.1f\r\n",batt().getSetPosition_mm());
01658             xbee().printf("depthLoop().getCommand(): %3.1f\r\n",depthLoop().getCommand());
01659             xbee().printf("pitchLoop().getCommand(): %3.1f\r\n",pitchLoop().getCommand());
01660             
01661             xbee().printf("\r\nNeutral Buoyancy Positions: bce: %0.1f, batt: %0.1f\r\n",_neutral_bce_pos_mm,_neutral_batt_pos_mm);
01662             xbee().printf("depthLoop().getOutputOffset(): %0.1f\r\n",depthLoop().getOutputOffset());
01663             xbee().printf("pitchLoop().getOutputOffset(): %0.1f\r\n",pitchLoop().getOutputOffset());
01664             xbee().printf("Max recorded depth: neutral: %0.1f, dive: %0.1f, auto_neutral_depth: %0.1f\r\n\n",_max_recorded_depth_neutral, _max_recorded_depth_dive, _max_recorded_auto_neutral_depth);
01665             
01666             xbee().printf("\r\n");
01667             xbee().printf("bce      P:%6.2f, I:%6.2f, D:%6.2f,   zero offset: %3i, limit %6.1f mm, slope %0.5f, filter_freq: %0.1f, deadband: %0.1f\r\n", bce().getControllerP(), bce().getControllerI(), bce().getControllerD(), bce().getZeroCounts(), bce().getTravelLimit(), bce().getPotSlope(), bce().getFilterFrequency(), bce().getDeadband());
01668             xbee().printf("batt     P:%6.2f, I:%6.2f, D:%6.2f,   zero offset: %3i, limit %6.1f mm, slope %0.5f, filter_freq: %0.1f, deadband: %0.1f\r\n", batt().getControllerP(), batt().getControllerI(), batt().getControllerD(), batt().getZeroCounts(), batt().getTravelLimit(), batt().getPotSlope(), batt().getFilterFrequency(), batt().getDeadband());
01669             xbee().printf("rudder   min_pwm:%6.1f, center_pwm:%6.1f, max_pwm:%6.1f (min_deg:%6.1f max_deg:%6.1f)\r\n",rudder().getMinPWM(),rudder().getCenterPWM(),rudder().getMaxPWM(),rudder().getMinDeg(),rudder().getMaxDeg());
01670             xbee().printf("depth    P:%6.2f, I:%6.2f, D:%6.2f, output offset: %6.1f mm, filter_freq: %0.1f, deadband: %0.1f \r\n", depthLoop().getControllerP(), depthLoop().getControllerI(), depthLoop().getControllerD(), depthLoop().getOutputOffset(),depthLoop().getFilterFrequency(),depthLoop().getDeadband());
01671             xbee().printf("pitch    P:%6.2f, I:%6.2f, D:%6.2f, output offset: %6.1f mm, filter_freq: %0.1f, deadband: %0.1f \r\n", pitchLoop().getControllerP(), pitchLoop().getControllerI(), pitchLoop().getControllerD(), pitchLoop().getOutputOffset(),pitchLoop().getFilterFrequency(),pitchLoop().getDeadband());
01672             xbee().printf("heading  P:%6.2f, I:%6.2f, D:%6.2f, output offset: %6.1f mm, filter_freq: %0.1f, deadband: %0.1f \r\n", headingLoop().getControllerP(), headingLoop().getControllerI(), headingLoop().getControllerD(), headingLoop().getOutputOffset(),headingLoop().getFilterFrequency(),headingLoop().getDeadband());
01673         }
01674         
01675     /***************************** COMMON COMMANDS *****************************/
01676         
01677 /***************************** DEBUG MENU *****************************/             
01678         if (_debug_menu_on) {  // ends around +175 lines          
01679             if (user_input == 'D') {
01680                 _keyboard_state = DIVE;
01681             }
01682             
01683             else if (user_input == '}') {
01684                 xbee().printf("HOMING the BCE (5 second delay)\r\n");
01685                 wait(5);
01686                 bce().homePiston();
01687             }
01688             
01689             else if (user_input == '|') {
01690                 xbee().printf("HOMING the BMM (5 second delay)\r\n");
01691                 wait(5);
01692                 batt().homePiston();
01693             }
01694             
01695             else if (user_input == 'N') {
01696                 _keyboard_state = FIND_NEUTRAL;
01697             }
01698             else if (user_input == 'M') {
01699                 //currently does not run if there is no file.
01700                 
01701                 //need to add method to Sequence Controller that returns -1 
01702                 //   or some check that insures you cannot run the dive sequence without a file
01703                 
01704                 //load sequence from file
01705                 _multi_dive_counter = 0;
01706                 sequenceController().loadSequence();
01707                 wait(1);    //test if this resets the sequence
01708                 
01709                 stateMachine().getDiveSequence();               //get first sequence on keyboard press
01710                 _keyboard_state = currentStateStruct.state;
01711                 
01712                 xbee().printf("Starting Dive Sequence Controller! (state: %d)\r\n", _keyboard_state);  //neutral sequence and dive cycles
01713             }
01714             else if (user_input == 'R') {
01715                 _keyboard_state = RISE;
01716             }
01717             else if (user_input == 'J') {
01718                 _keyboard_state = FLOAT_LEVEL;
01719             }
01720             else if (user_input == 'B') {
01721                 _keyboard_state = FLOAT_BROADCAST;
01722             }
01723             else if (user_input == 'E') {
01724                 _keyboard_state = EMERGENCY_CLIMB;
01725             }
01726             
01727             else if (user_input == 'Y') {
01728                 _keyboard_state = CHECK_TUNING;
01729             }
01730             
01731             // some debug tools below
01732             else if (user_input == 'P') {
01733                 //Print current SD card log file
01734                 //printCurrentSdLog();
01735                 mbedLogger().printCurrentLogFile();        //print the current log file to the screen
01736             }
01737             else if (user_input == 'X') {
01738                 mbedLogger().printMbedDirectory();        //print all log files to the screen
01739             }
01740             else if (user_input == 'Z') {
01741                 xbee().printf("FSG FSM States: \r\n");
01742                 string string_state;
01743                 
01744                 for (int i = 0; i < _state_array_counter; i++) {
01745                     if (_state_array[i] == SIT_IDLE)
01746                         string_state = "SIT_IDLE              <END>";
01747                     else if (_state_array[i] == FIND_NEUTRAL)
01748                         string_state = "FIND_NEUTRAL";
01749                     else if (_state_array[i] == DIVE)
01750                         string_state = "DIVE";
01751                     else if (_state_array[i] == RISE)
01752                         string_state = "RISE";
01753                     else if (_state_array[i] == FLOAT_LEVEL)
01754                         string_state = "FLOAT_LEVEL";
01755                     else if (_state_array[i] == FLOAT_BROADCAST)
01756                         string_state = "FLOAT_BROADCAST";          
01757                     else if (_state_array[i] == EMERGENCY_CLIMB)
01758                         string_state = "EMERGENCY_CLIMB";
01759                     else if (_state_array[i] == MULTI_DIVE)
01760                         string_state = "MULTI_DIVE";
01761                     else if (_state_array[i] == MULTI_RISE)
01762                         string_state = "MULTI_RISE";
01763                     else if (_state_array[i] == KEYBOARD)
01764                         string_state = "KEYBOARD";
01765                     else if (_state_array[i] == LEG_POSITION_DIVE)
01766                         string_state = "LEG_POS_DIVE";
01767                     else if (_state_array[i] == LEG_POSITION_RISE)
01768                         string_state = "LEG_POS_RISE";
01769                     else if (_state_array[i] == FB_EXIT)
01770                         string_state = "FB_EXIT"; 
01771                     else if (_state_array[i] == ENDLEG_WAIT)
01772                         string_state = "ENDLEG_WAIT";                    
01773                     xbee().printf("State #%d: %d (%s)\r\n", i, _state_array[i], string_state.c_str());
01774                 }
01775                 
01776                 xbee().printf("\r\nNeutral sub-FSM States: \r\n");
01777                 string string_substate;
01778                 
01779                 for (int i = 0; i < _substate_array_counter; i++) {
01780                     if (_substate_array[i] == NEUTRAL_SINKING)
01781                         string_substate = "NEUTRAL_SINKING";
01782                     else if (_substate_array[i] == NEUTRAL_SLOWLY_RISE)
01783                         string_substate = "NEUTRAL_SLOWLY_RISE";
01784                     else if (_substate_array[i] == NEUTRAL_CHECK_PITCH)
01785                         string_substate = "NEUTRAL_CHECK_PITCH";
01786                     else if (_substate_array[i] == NEUTRAL_EXIT)
01787                         string_substate = "NEUTRAL_EXIT                  <--   ";
01788                     else if (_substate_array[i] == EMERGENCY_CLIMB)
01789                         string_substate = " -- > EMERGENCY_CLIMB  <-- ";                
01790                     xbee().printf("Neutral Substate #%d: %d (%s)\r\n", i, _state_array[i], string_substate.c_str());
01791                 }
01792                 xbee().printf("\r\n");  //make space between printouts
01793             }    
01794             //BATTERY/PITCH
01795             else if (user_input == '[' or user_input == '{') {
01796                 xbee().printf("Please TYPE in the new BATT neutral position.\n\r");
01797                 _neutral_batt_pos_mm = getFloatUserInput();
01798                 pitchLoop().setOutputOffset(_neutral_batt_pos_mm); // decrease the batt neutral setpoint
01799                 xbee().printf("Adjusting batt neutral position. new offset: %0.1f\r\n",pitchLoop().getOutputOffset());
01800                 // save neutral pitch value to config file
01801                 configFileIO().savePitchData(_pitch_KP, _pitch_KI, _pitch_KD, _neutral_batt_pos_mm, _pitch_filter_freq, _pitch_deadband); //P,I,D,batt zeroOffset
01802             }
01803             
01804             //BCE/DEPTH
01805             else if (user_input == ';' or user_input == ':') {
01806                 xbee().printf("Please TYPE in the new BCE neutral position.\n\r");
01807                 _neutral_bce_pos_mm = getFloatUserInput();
01808                 depthLoop().setOutputOffset(_neutral_bce_pos_mm); // decrease the bce neutral setpoint
01809                 xbee().printf("Adjusting bce neutral position. new offset: %0.1f\r\n",depthLoop().getOutputOffset());
01810                 // save neutral depth value to config file
01811                 configFileIO().saveDepthData(_depth_KP, _depth_KI, _depth_KD, _neutral_bce_pos_mm, _depth_filter_freq, _depth_deadband);
01812             }
01813      
01814     // change settings
01815             //heading is in the common controls        
01816             else if (user_input == 'Q') {
01817                 xbee().printf(">> Please enter the desired PITCH (deg).\r\n");
01818                 _pitch_command = getFloatUserInput();
01819             }
01820             else if (user_input == 'A') {
01821                 xbee().printf(">> Please enter the desired DEPTH (m).\r\n");
01822                 _depth_command = getFloatUserInput();
01823             }
01824             
01825             else if (user_input == '5') {
01826                 keyboard_menu_RUDDER_SERVO_settings();
01827             }
01828             
01829             else if (user_input == '6') {
01830                 keyboard_menu_HEADING_PID_settings();
01831             }  
01832             
01833             // go to tuning sub-menu
01834             else if (user_input == '7') {
01835                 keyboard_menu_MANUAL_TUNING();
01836             }
01837             
01838 //            else if (user_input == 'U') {
01839 //                keyboard_menu_POSITION_READINGS();
01840 //            }
01841             
01842             // go to sub-menus for the PID gains (this is blocking)
01843             else if (user_input == '1') {
01844                 keyboard_menu_BCE_PID_settings();
01845             }
01846             else if (user_input == '2') {
01847                 keyboard_menu_BATT_PID_settings();
01848             }
01849             else if (user_input == '3') {
01850                 keyboard_menu_DEPTH_PID_settings();
01851             }
01852             else if (user_input == '4') {
01853                 keyboard_menu_PITCH_PID_settings();
01854             }
01855                      
01856             else if (user_input == '*') {
01857                 xbee().printf("SWITCHING TO SIMPLE MENU!\r\n"); 
01858                 wait(1);
01859                 _debug_menu_on = false;
01860             }
01861         }   //end of debug menu   matches line 1445   approx -180
01862 /***************************** DEBUG MENU *****************************/
01863             
01864 /***************************** SIMPLE MENU *****************************/
01865         else {     
01866             if (user_input == 'V') {
01867                 _keyboard_state = POSITION_DIVE;
01868             }
01869             else if (user_input == 'N') {
01870                 _keyboard_state = FIND_NEUTRAL;
01871             }
01872             else if (user_input == 'J') {
01873                 _keyboard_state = FLOAT_LEVEL;
01874             }
01875             else if (user_input == 'B') {
01876                 _keyboard_state = FLOAT_BROADCAST;
01877             }
01878             else if (user_input == 'E') {
01879                 _keyboard_state = EMERGENCY_CLIMB;
01880             }
01881             
01882             // some debug tools below
01883             else if (user_input == 'P') {
01884                 //Print current SD card log file
01885                 //printCurrentSdLog();
01886                 mbedLogger().printCurrentLogFile();        //print the current log file to the screen
01887             }
01888             
01889 //POSITION DIVE COMMANDS
01890             else if (user_input == 'Q') {
01891                 xbee().printf(">> Please enter the desired BMM offset (mm).\r\n");
01892                 _BMM_dive_offset = getFloatUserInput();
01893             }
01894             else if (user_input == 'A') {
01895                 xbee().printf(">> Please enter the desired BCE offset (mm).\r\n");
01896                 _BCE_dive_offset = getFloatUserInput();
01897             }
01898             
01899             else if (user_input == 'S') {
01900                 xbee().printf(">> Please enter the desired DEPTH (m).\r\n");
01901                 _depth_command = getFloatUserInput();
01902             }
01903 //POSITION DIVE COMMANDS
01904             
01905             else if (user_input == '*') {
01906                 xbee().printf("SWITCHING TO DEBUG MENU!\r\n"); 
01907                 _debug_menu_on = true;
01908                 wait(1);
01909             }
01910         }
01911 /***************************** END  SIMPLE MENU *****************************/
01912         
01913         //when you read the keyboard successfully, change the state
01914         _state = _keyboard_state;   //set state at the end of this function
01915         //xbee().printf("\r\n\n ********* KEYBOARD STATE: %d *********\r\n\n", _state);
01916     }  //matches very top of function - first if()
01917 }
01918 
01919 void StateMachine::keyboard_menu_STREAM_STATUS() {
01920     char STATUS_key;
01921         
01922     // show the menu
01923     xbee().printf("\r\n8: STATUS DEBUG MENU (EXIT WITH 'X' !)\r\n");
01924     
01925     while (1) {
01926         if (xbee().readable()) {
01927             STATUS_key = xbee().getc();   //get each keystroke
01928         }
01929         
01930         else {
01931             
01932             wait(1);         
01933             
01934             
01935 //            xbee().printf("BCE POS (CMD): %0.1f (%0.1f) BATT POS: %0.1f (%0.1f) PRESS_psi: %0.2f [depth_m: %0.2f], PITCH: %0.2f, HEADING: %0.2f, rudder_servo_pwm: %0.1f \n[FILT/RAW 0(%d,%d),1(%d),2(%d),6(%d),4(%d),5(%d),6(%d),7(%d)] Switch: BCE(%d) BMM(%d)\r",bce().getPosition_mm(), bce().getSetPosition_mm(),batt().getPosition_mm(), batt().getSetPosition_mm(),depth().getPsi(),depthLoop().getPosition(),imu().getPitch(),imu().getHeading(),rudder().getSetPosition_pwm(),adc().readCh0(),adc().readCh1(),adc().readCh2(),adc().readCh3(),adc().readCh4(),adc().readCh5(),adc().readCh6(),adc().readCh7(), bce().getHardwareSwitchStatus(),batt().getHardwareSwitchStatus()); 
01936             xbee().printf("BCE POS: %0.1f (cmd %0.1f) BATT POS: %0.1f (cmd %0.1f) PRESS_psi: %0.2f [depth_m: %0.2f], PITCH: %0.2f, HEADING: %0.2f, rdr_pwm: %0.1f [FILT/RAW 0(%d,%d),1(%d,%d),2(%d,%d),3(%d,%d),4(%d,%d),5(%d,%d),6(%d,%d),7(%d,%d)] Switch: BCE(%d) BMM(%d)\r",
01937             bce().getPosition_mm(), bce().getSetPosition_mm(),batt().getPosition_mm(), batt().getSetPosition_mm(),depth().getPsi(),
01938             depthLoop().getPosition(),imu().getPitch(),imu().getHeading(),rudder().getSetPosition_pwm(),adc().readCh0(),adc().readRawCh0(),
01939             adc().readCh1(),adc().readRawCh1(),adc().readCh2(),adc().readRawCh2(),adc().readCh3(),adc().readRawCh3(),adc().readCh4(),
01940             adc().readRawCh4(),adc().readCh5(),adc().readRawCh5(),adc().readCh6(),adc().readRawCh6(),adc().readCh7(),adc().readRawCh7(),
01941             bce().getHardwareSwitchStatus(),batt().getHardwareSwitchStatus()); 
01942             
01943             continue; // didn't get a user input, so keep waiting for it
01944         }
01945     
01946         // process the keys            
01947         if (STATUS_key == 'X') {  
01948             xbee().printf("\r\nX: EXITING STATUS DEBUG MENU\r\n");             
01949             break;  //exit the while loop
01950         }
01951         
01952         else {
01953             xbee().printf("\r\nThis key (%c) does nothing here.                                  ", STATUS_key);
01954         }
01955     }
01956 }
01957 
01958 void StateMachine::keyboard_menu_RUDDER_SERVO_settings() {
01959     //load current parameters from the rudder
01960     float rudder_min_pwm = rudder().getMinPWM();
01961     float rudder_max_pwm = rudder().getMaxPWM();
01962     float rudder_ctr_pwm = rudder().getCenterPWM();
01963     float rudder_min_deg = rudder().getMinDeg();
01964     float rudder_max_deg = rudder().getMaxDeg();
01965     
01966     char RUDDER_PID_key;
01967  
01968     // print the menu
01969     xbee().printf("\r\nRUDDER (servo driver) settings (MENU)");
01970     xbee().printf("\r\nAdjust min_pwm/max_pwm/center_pwm/min_deg/max_deg settings with the following keys: N, M, C, K, L");
01971     xbee().printf("\r\nHit shift + X to exit w/o saving.  Hit shift + S to save.\r\n");
01972     xbee().printf("RUDDER min pwm: %f, max pwm: %f, center pwm: %f, min deg: %f, max deg: %f\r\n", rudder().getMinPWM(), rudder().getMaxPWM(), rudder().getCenterPWM(), rudder().getMinDeg(), rudder().getMaxDeg());
01973  
01974     // handle the key presses
01975     while(1) {
01976         // get the user's keystroke from either of the two inputs
01977         if (xbee().readable()) {
01978             RUDDER_PID_key = xbee().getc();
01979         }
01980         else {
01981             continue; // didn't get a user input, so keep waiting for it
01982         }
01983  
01984     // handle the user's key input                
01985         if (RUDDER_PID_key == 'S') { // user wants to save the modified values
01986             // set global values
01987             rudder().setMinPWM(rudder_min_pwm);
01988             rudder().setMaxPWM(rudder_max_pwm);
01989             rudder().setCenterPWM(rudder_ctr_pwm);
01990             rudder().setMinDeg(rudder_min_deg);
01991             rudder().setMaxDeg(rudder_max_deg);
01992             
01993             // save rudder servo driver values for inner loop
01994             configFileIO().saveRudderData(rudder_min_deg, rudder_max_deg, rudder_ctr_pwm, rudder_min_pwm, rudder_max_pwm);
01995             xbee().printf("RUDDER min pwm: %f, max pwm: %f, center pwm: %f, min deg: %f, max deg: %f\r\n", rudder().getMinPWM(), rudder().getMaxPWM(), rudder().getCenterPWM(), rudder().getMinDeg(), rudder().getMaxDeg());
01996             xbee().printf("Adjust min_pwm/max_pwm/center_pwm/min_deg/max_deg settings with the following keys: N, M, C, K, L\r\n");
01997         }
01998         else if (RUDDER_PID_key == 'X') {    
01999             break;  //exit the while loop
02000         }
02001             // MIN PWM
02002         else if (RUDDER_PID_key == 'N') {
02003             xbee().printf(">> Type in rudder_min_pwm with keyboard.\r\n");
02004             rudder_min_pwm = getFloatUserInput();
02005         }
02006     // MAX PWM
02007         else if (RUDDER_PID_key == 'M') {
02008             xbee().printf(">> Type in rudder_max_pwm with keyboard.\r\n");
02009             rudder_max_pwm = getFloatUserInput();
02010         }
02011     // CENTER PWM
02012         else if (RUDDER_PID_key == 'C') {
02013             xbee().printf(">> Type in rudder_ctr_pwm with keyboard.\r\n");
02014             rudder_ctr_pwm = getFloatUserInput();
02015         }
02016     // MIN DEG
02017         else if (RUDDER_PID_key == 'K') {
02018             xbee().printf(">> Type in rudder_min_deg with keyboard.\r\n");
02019             rudder_min_deg = getFloatUserInput();
02020         }
02021     // MAX DEG
02022         else if (RUDDER_PID_key == 'L') {
02023             xbee().printf(">> Type in rudder_max_deg with keyboard.\r\n");
02024             rudder_max_deg = getFloatUserInput();
02025         }       
02026         else {
02027             xbee().printf("RUDDER SETUP: [%c] This key does nothing here.                           \r", RUDDER_PID_key);
02028         }
02029     }
02030 }
02031 
02032 void StateMachine::keyboard_menu_COUNTS_STATUS() {
02033     // DELETE REMOVE  
02034 }
02035 
02036 void StateMachine::keyboard_menu_MANUAL_TUNING() {
02037     char TUNING_key;
02038         
02039     //made these into internal parameters
02040     float _tuning_bce_pos_mm = 200.0;   //safe starting position
02041     float _tuning_batt_pos_mm = 40.0;   //safe starting position
02042     float _tuning_rudder_pos_deg = 0.0; //safe starting position
02043     float _tuning_rudder_pwm = 1640.0;
02044     
02045     //immediately start at those positions
02046     bce().setPosition_mm(_tuning_bce_pos_mm);
02047     batt().setPosition_mm(_tuning_batt_pos_mm);
02048     rudder().setPosition_deg(_tuning_rudder_pos_deg);
02049     
02050     // show the menu
02051     xbee().printf("\r\n7: MANUAL TUNING MENU (EXIT WITH 'X' !) (Pause and Unpause rudder ticker with P and U\n");
02052     xbee().printf("\r\n(Adjust BCE and BATT positions in real-time.  Timeout NOT running! (decrease/increase BCE with A/S, BATT with Q/W, RUDDER with E/R)\r\n");
02053     xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02054         
02055     // what needs to be started?
02056     bce().unpause();    //this is now active
02057     batt().unpause();   //this is now active
02058     rudder().unpause();
02059     
02060     while (1) {
02061         wait(0.1);  
02062                       
02063         if (xbee().readable()) {
02064             TUNING_key = xbee().getc();   //get each keystroke
02065         }
02066         
02067         else {   
02068             //xbee().printf("MT: POS (CMD) BCE %3.1f mm (%3.1f mm), BATT %3.1f mm (%3.1f mm) SERVO: %0.1f deg, (%0.1f pwm) PITCH: %0.1f,HEADING: %0.1f                                  \r", bce().getPosition_mm(), bce().getSetPosition_mm(), batt().getPosition_mm(), batt().getSetPosition_mm(), rudder().getSetPosition_deg(), rudder().getSetPosition_pwm(),imu().getPitch(),imu().getHeading());         
02069             continue; // didn't get a user input, so keep waiting for it
02070         }
02071     
02072         // process the keys            
02073         if (TUNING_key == 'X') {    
02074             // STOP THE MOTORS BEFORE LEAVING! (Just in case.)
02075             bce().pause();
02076             batt().pause();
02077             rudder().pause();
02078             
02079             //right now the rudder is always active................................................hmm
02080             //deactivate the pin? new/delete?
02081             
02082             break;  //exit the while loop
02083         }
02084         
02085         //Buoyancy Engine
02086         else if (TUNING_key == 'A' or TUNING_key == 'a') {
02087             _tuning_bce_pos_mm = _tuning_bce_pos_mm - 1.0;
02088             bce().setPosition_mm(_tuning_bce_pos_mm);              //this variable is loaded from the file at initialization
02089             xbee().printf("\r\nMANUAL_TUNING: (BCE CHANGE: %0.1f)\r\n BCE_position: %0.1f, BATT_position: %0.1f (depth: %0.1f m, pitch: %0.1f deg)\r",bce().getSetPosition_mm(),bce().getPosition_mm(),batt().getPosition_mm(),depthLoop().getPosition(),pitchLoop().getPosition());
02090             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02091         }
02092         
02093         else if (TUNING_key == 'S' or TUNING_key == 's') {
02094             _tuning_bce_pos_mm = _tuning_bce_pos_mm + 1.0;
02095             bce().setPosition_mm(_tuning_bce_pos_mm);              //this variable is loaded from the file at initialization
02096             xbee().printf("\r\nMANUAL_TUNING: (BCE CHANGE: %0.1f)\r\n BCE_position: %0.1f, BATT_position: %0.1f (depth: %0.1f m, pitch: %0.1f deg)\r",bce().getSetPosition_mm(),bce().getPosition_mm(),batt().getPosition_mm(),depthLoop().getPosition(),pitchLoop().getPosition());
02097             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02098         }
02099         
02100         //BATTERY
02101         else if (TUNING_key == 'Q' or TUNING_key == 'q') {
02102             _tuning_batt_pos_mm = _tuning_batt_pos_mm - 1.0;
02103             batt().setPosition_mm(_tuning_batt_pos_mm);              //this variable is loaded from the file at initialization
02104             xbee().printf("\r\nMANUAL_TUNING: (BATT CHANGE: %0.1f)\r\n BCE_position: %0.1f, BATT_position: %0.1f (depth: %0.1f m, pitch: %0.1f deg)\r",batt().getSetPosition_mm(),bce().getPosition_mm(),batt().getPosition_mm(),depthLoop().getPosition(),pitchLoop().getPosition());
02105             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02106         }
02107         
02108         else if (TUNING_key == 'W' or TUNING_key == 'w') {
02109             _tuning_batt_pos_mm = _tuning_batt_pos_mm + 1.0;
02110             batt().setPosition_mm(_tuning_batt_pos_mm);              //this variable is loaded from the file at initialization
02111             xbee().printf("\r\nMANUAL_TUNING: (BATT CHANGE: %0.1f)\r\n BCE_position: %0.1f, BATT_position: %0.1f (depth: %0.1f m, pitch: %0.1f deg)\r",batt().getSetPosition_mm(),bce().getPosition_mm(),batt().getPosition_mm(),depthLoop().getPosition(),pitchLoop().getPosition());
02112             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02113         }
02114         
02115         else if (TUNING_key == 'c' or TUNING_key == 'C') {
02116             xbee().printf("\r\nMT: (CURRENT POSITIONS) BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02117         }
02118         
02119         //RUDER
02120         else if (TUNING_key == 'R' or TUNING_key == 'r') {
02121             _tuning_rudder_pos_deg = _tuning_rudder_pos_deg - 0.5;
02122             rudder().setPosition_deg(_tuning_rudder_pos_deg);
02123             xbee().printf("MT: RUDDER CHANGE %0.1f deg [servo pwm: %f, %0.1f deg] (headingLoop heading: % 0.1f deg, IMU heading: %0.1f deg)\r\n", _tuning_rudder_pos_deg, rudder().getSetPosition_pwm(), rudder().getSetPosition_deg(), headingLoop().getPosition(), imu().getHeading());
02124             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02125         }
02126         
02127         else if (TUNING_key == 'E' or TUNING_key == 'e') {
02128             _tuning_rudder_pos_deg = _tuning_rudder_pos_deg + 0.5;
02129             rudder().setPosition_deg(_tuning_rudder_pos_deg);
02130             xbee().printf("MT: RUDDER CHANGE %0.1f deg [servo pwm: %f, %0.1f deg] (headingLoop heading: % 0.1f deg, IMU heading: %0.1f deg)\r\n", _tuning_rudder_pos_deg, rudder().getSetPosition_pwm(), rudder().getSetPosition_deg(), headingLoop().getPosition(), imu().getHeading());
02131             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02132         }
02133         
02134         else if (TUNING_key == '-' or TUNING_key == '_') {
02135             _tuning_rudder_pwm -= 10.0;
02136             rudder().setPWM(_tuning_rudder_pwm);
02137             xbee().printf("MT: (-) RUDDER CHANGE %0.1f pwm\n\r", rudder().getSetPosition_pwm());
02138             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02139         }
02140             
02141         else if (TUNING_key == '=' or TUNING_key == '+') {
02142             _tuning_rudder_pwm += 10.0;
02143             rudder().setPWM(_tuning_rudder_pwm);
02144             xbee().printf("MT: (+) RUDDER CHANGE %0.1f pwm\n\r", rudder().getSetPosition_pwm());
02145             xbee().printf("\r\nMT: BCE pos:%5.1f (cmd:%5.1f), BMM:%5.1f (cmd:%5.1f), RUDDER:%6.1f (%6.1f deg) (depth: %0.1f m, pitch: %0.1f deg, headingLoop heading: %0.1f deg, IMU heading: %0.1f deg)                                                  \n\n\r",bce().getPosition_mm(),bce().getSetPosition_mm(),batt().getPosition_mm(),batt().getSetPosition_mm(),rudder().getSetPosition_pwm(),rudder().getSetPosition_deg(),depthLoop().getPosition(),pitchLoop().getPosition(), headingLoop().getPosition(),imu().getHeading());
02146         }
02147         
02148         else {
02149             xbee().printf("\r\nMANUAL_TUNING: [%c] This key does nothing here.                                  \r", TUNING_key);
02150         }            
02151     }
02152 }
02153 
02154 void StateMachine::keyboard_menu_CHANNEL_READINGS() {
02155     char TUNING_key;
02156         
02157     // show the menu
02158     xbee().printf("\r\n8: CHANNEL READINGS (EXIT WITH 'X' !)");
02159     
02160     while (1) {
02161         if (xbee().readable()) {
02162             TUNING_key = xbee().getc();   //get each keystroke
02163         }
02164         
02165                 // process the keys            
02166         if (TUNING_key == 'X') {    
02167             // STOP THE MOTORS BEFORE LEAVING! (Just in case.)
02168             bce().pause();
02169             batt().pause();
02170             
02171             break;  //exit the while loop
02172         }
02173         
02174         else {
02175             wait(0.5);                    
02176             xbee().printf("0(%d),1(%d),2(%d),6(%d),4(%d),5(%d),6(%d),7(%d)\r\n",adc().readCh0(),adc().readCh1(),adc().readCh2(),adc().readCh3(),adc().readCh4(),adc().readCh5(),adc().readCh6(),adc().readCh7()); 
02177             continue; // didn't get a user input, so keep waiting for it
02178         }            
02179     }
02180 }
02181  
02182 void StateMachine::keyboard_menu_BCE_PID_settings() {    
02183     char BCE_PID_key;
02184     
02185     // load current values from files
02186     float bce_KP = bce().getControllerP();
02187     float bce_KI = bce().getControllerI();
02188     float bce_KD = bce().getControllerD();
02189     
02190     float bce_deadband = bce().getDeadband();
02191     float bce_frequency = bce().getFilterFrequency();
02192     int bce_zero_offset = bce().getZeroCounts(); 
02193     //BCE frequency and deadband are hardcoded!
02194  
02195     // show the menu
02196     xbee().printf("\n\rBuoyancy Engine PID gain settings (MENU). ADJUST WITH CARE!");
02197     xbee().printf("\n\rAdjust PID settings with the following keys: P  I  D. Filter = F, deadband = B, zero offset = Z\n\r");
02198     xbee().printf("\n\r(Hit shift + X to exit w/o saving.  Hit shift + S to save.)\n\n\n\r");
02199     xbee().printf("bce      P:%6.2f, I:%6.2f, D:%6.2f,   zero offset: %3i, limit %6.1f mm, slope %0.5f, filter_freq: %0.1f, deadband: %0.1f\r\n", bce().getControllerP(), bce().getControllerI(), bce().getControllerD(), bce().getZeroCounts(), bce().getTravelLimit(), bce().getPotSlope(), bce().getFilterFrequency(), bce().getDeadband());    
02200     
02201     // handle the key presses
02202     while(1) {
02203         // get the user's keystroke from either of the two inputs
02204         if (xbee().readable()) {
02205             BCE_PID_key = xbee().getc();
02206         }
02207         else {
02208             continue; // didn't get a user input, so keep waiting for it
02209         }
02210     
02211         // handle the user's key input
02212         if (BCE_PID_key == 'S') { // user wants to save these modified values
02213             // set values
02214             bce().setControllerP(bce_KP);
02215             bce().setControllerI(bce_KI);
02216             bce().setControllerD(bce_KD); 
02217             
02218             bce().setDeadband(bce_deadband);
02219             bce().setFilterFrequency(bce_frequency);
02220             bce().setZeroCounts(bce_zero_offset); //integer value
02221  
02222             // save to "BCE.TXT" file
02223             //saveBattData(float batt_p_gain, float batt_i_gain, float batt_d_gain, int batt_zeroOffset, float batt_filter_freq, float batt_deadband)
02224             configFileIO().saveBCEData(bce_KP, bce_KI, bce_KD, bce_zero_offset, bce_frequency, bce_deadband);
02225             xbee().printf("bce      P:%6.2f, I:%6.2f, D:%6.2f,   zero offset: %3i, limit %6.1f mm, slope %0.5f, filter_freq: %0.1f, deadband: %0.1f\r\n", bce().getControllerP(), bce().getControllerI(), bce().getControllerD(), bce().getZeroCounts(), bce().getTravelLimit(), bce().getPotSlope(), bce().getFilterFrequency(), bce().getDeadband());
02226         }
02227         else if (BCE_PID_key == 'X') {    
02228             break;  //exit the while loop
02229         }
02230         else if (BCE_PID_key == 'P') {
02231             xbee().printf(">> Type in proportional gain with keyboard.\n\r");
02232             bce_KP = getFloatUserInput();
02233         }
02234         else if (BCE_PID_key == 'I') {
02235             xbee().printf(">> Type in integral gain with keyboard.\n\r");
02236             bce_KI = getFloatUserInput();
02237         }
02238         else if (BCE_PID_key == 'D') {
02239             xbee().printf(">> Type in derivative gain with keyboard.\n\r");
02240             bce_KD = getFloatUserInput();
02241         }
02242         else if (BCE_PID_key == 'F') {
02243             xbee().printf(">> Type in FILTER FREQUENCY with keyboard.\n\r");
02244             bce_frequency = getFloatUserInput();
02245         }
02246         else if (BCE_PID_key == 'B') {
02247             xbee().printf(">> Type in DEADBAND with keyboard.\n\r");
02248             bce_deadband = getFloatUserInput();
02249         }
02250         else if (BCE_PID_key == 'Z') {
02251             xbee().printf(">> Type in zero count offset with keyboard.\n\r");
02252             bce_zero_offset = (int)getFloatUserInput();
02253         }
02254         else {
02255             xbee().printf("\n\rBCE: [%c] This key does nothing here.                                  \r", BCE_PID_key);
02256         }
02257     }
02258 }
02259 
02260 void StateMachine::keyboard_menu_BATT_PID_settings() {    
02261     char BMM_PID_key;
02262 
02263     // load current values from files
02264     float batt_KP = batt().getControllerP();
02265     float batt_KI = batt().getControllerI();
02266     float batt_KD = batt().getControllerD();
02267     
02268     float batt_deadband = batt().getDeadband();
02269     float batt_frequency = batt().getFilterFrequency();
02270     int batt_zero_offset = batt().getZeroCounts(); 
02271     //BATT frequency and deadband are hardcoded!
02272  
02273     // print the menu
02274     xbee().printf("\n\rBattery Motor PID gain settings (MENU)");
02275     xbee().printf("\n\rAdjust PID settings with the following keys: P I D. Filter = F, deadband = B.\n\r");
02276     xbee().printf("\n\r(Hit shift + X to exit w/o saving.  Hit shift + S to save.)\n\n\n\r");
02277     xbee().printf("batt     P:%6.2f, I:%6.2f, D:%6.2f,   zero offset: %3i, limit %6.1f mm, slope %0.5f, filter_freq: %0.1f, deadband: %0.1f\r\n", batt().getControllerP(), batt().getControllerI(), batt().getControllerD(), batt().getZeroCounts(), batt().getTravelLimit(), batt().getPotSlope(), batt().getFilterFrequency(), batt().getDeadband());
02278 
02279     // handle the key presses
02280     while(1) {
02281         // get the user's keystroke from either of the two inputs
02282         if (xbee().readable()) {
02283             BMM_PID_key = xbee().getc();
02284         }
02285         else {
02286             continue; // didn't get a user input, so keep waiting for it
02287         }
02288     
02289         // handle the user's key input
02290         if (BMM_PID_key == 'S') { // user wants to save these modified values
02291             // set values
02292             batt().setControllerP(batt_KP);
02293             batt().setControllerI(batt_KI);
02294             batt().setControllerD(batt_KD);
02295             
02296             batt().setDeadband(batt_deadband);
02297             batt().setFilterFrequency(batt_frequency);
02298             batt().setZeroCounts(batt_zero_offset); //integer value
02299  
02300             // save to "BATT.TXT" file
02301             //saveBCEData(float bce_p_gain, float bce_i_gain, float bce_d_gain, int bce_zeroOffset, float bce_filter_freq, float bce_deadband)
02302             configFileIO().saveBattData(batt_KP, batt_KI, batt_KD, batt_zero_offset, batt_frequency, batt_deadband);
02303             xbee().printf("batt     P:%6.2f, I:%6.2f, D:%6.2f,   zero offset: %3i, limit %6.1f mm, slope %0.5f, filter_freq: %0.1f, deadband: %0.1f\r\n", batt().getControllerP(), batt().getControllerI(), batt().getControllerD(), batt().getZeroCounts(), batt().getTravelLimit(), batt().getPotSlope(), batt().getFilterFrequency(), batt().getDeadband());
02304         }
02305         else if (BMM_PID_key == 'X') {    
02306             break;  //exit the while loop
02307         }
02308         else if (BMM_PID_key == 'P') {
02309             xbee().printf(">> Type in proportional gain with keyboard.\n\r");
02310             batt_KP = getFloatUserInput();
02311         }
02312         else if (BMM_PID_key == 'I') {
02313             xbee().printf(">> Type in integral gain with keyboard.\n\r");
02314             batt_KI = getFloatUserInput();
02315         }
02316         else if (BMM_PID_key == 'D') {
02317             xbee().printf(">> Type in derivative gain with keyboard.\n\r");
02318             batt_KD = getFloatUserInput();
02319         }
02320         else if (BMM_PID_key == 'F') {
02321             xbee().printf(">> Type in FILTER FREQUENCY with keyboard.\n\r");
02322             batt_frequency = getFloatUserInput();
02323         }
02324         else if (BMM_PID_key == 'B') {
02325             xbee().printf(">> Type in DEADBAND with keyboard.\n\r");
02326             batt_deadband = getFloatUserInput();
02327         }
02328         else if (BMM_PID_key == 'Z') {
02329             xbee().printf(">> Type in zero count offset with keyboard.\n\r");
02330             batt_zero_offset = (int)getFloatUserInput();
02331         }
02332         else {
02333             xbee().printf("\n\rBATT: [%c] This key does nothing here.                                  \r", BMM_PID_key);
02334         }
02335     }
02336 }
02337  
02338 void StateMachine::keyboard_menu_DEPTH_PID_settings() {    
02339     char DEPTH_PID_key;
02340     
02341     float depth_KP = depthLoop().getControllerP();       // load current depth value
02342     float depth_KI = depthLoop().getControllerI();       // load current depth value
02343     float depth_KD = depthLoop().getControllerD();       // load current depth value
02344     
02345     float depth_freq = depthLoop().getFilterFrequency();
02346     float depth_deadband = depthLoop().getDeadband();
02347  
02348     // print the menu
02349     xbee().printf("\n\rDEPTH (Buoyancy Engine O.L.) PID gain settings (MENU)");
02350     xbee().printf("\n\rAdjust PID settings with the following keys: P I D. Filter = F, deadband = B.\n\r");
02351     xbee().printf("\n\r(Hit shift + X to exit w/o saving.  Hit shift + S to save.)\n\n\n\r");
02352     xbee().printf("DEPTH P: %3.3f, I: %3.3f, D %3.3f, offset: %3.1f mm (filter: %0.2f, deadband: %0.2f)\r\n", depthLoop().getControllerP(), depthLoop().getControllerI(), depthLoop().getControllerD(),depthLoop().getOutputOffset(),depthLoop().getFilterFrequency(),depthLoop().getDeadband());
02353     
02354     // handle the key presses
02355     while(1) {
02356         // get the user's keystroke from either of the two inputs
02357         if (xbee().readable()) {
02358             DEPTH_PID_key = xbee().getc();
02359         }
02360         else {
02361             continue; // didn't get a user input, so keep waiting for it
02362         }
02363     
02364         // handle the user's key input
02365         if (DEPTH_PID_key == 'S') { // user wants to save these modified values
02366             // set values
02367             depthLoop().setControllerP(depth_KP);
02368             depthLoop().setControllerI(depth_KI);
02369             depthLoop().setControllerD(depth_KD);
02370             
02371             depthLoop().setFilterFrequency(depth_freq);
02372             depthLoop().setDeadband(depth_deadband);
02373  
02374             // save to "DEPTH.TXT" file
02375             configFileIO().saveDepthData(depth_KP, depth_KI, depth_KD, _neutral_bce_pos_mm, depth_freq, depth_deadband); //P,I,D, bce zeroOffset
02376             
02377             xbee().printf("DEPTH P: %3.3f, I: %3.3f, D %3.3f, offset: %3.1f mm (filter: %0.2f, deadband: %0.2f)\r\n", depthLoop().getControllerP(), depthLoop().getControllerI(), depthLoop().getControllerD(),depthLoop().getOutputOffset(),depthLoop().getFilterFrequency(),depthLoop().getDeadband());
02378             
02379             //set class variables that will be used in find neutral sequence
02380             _depth_KP = depthLoop().getControllerP();       // load current depth value
02381             _depth_KI = depthLoop().getControllerI();       // load current depth value
02382             _depth_KD = depthLoop().getControllerD();       // load current depth value
02383         }
02384         else if (DEPTH_PID_key == 'X') {    
02385             break;  //exit the while loop
02386         }
02387         else if (DEPTH_PID_key == 'P') {
02388             xbee().printf(">> Type in proportional gain with keyboard.\n\r");
02389             depth_KP = getFloatUserInput();
02390         }
02391         else if (DEPTH_PID_key == 'I') {
02392             xbee().printf(">> Type in integral gain with keyboard.\n\r");
02393             depth_KI = getFloatUserInput();
02394         }
02395         else if (DEPTH_PID_key == 'D') {
02396             xbee().printf(">> Type in derivative gain with keyboard.\n\r");
02397             depth_KD = getFloatUserInput();
02398         }
02399         else if (DEPTH_PID_key == 'F') {
02400             xbee().printf(">> Type in FILTER FREQUENCY with keyboard.\n\r");
02401             depth_freq = getFloatUserInput();
02402         }
02403         else if (DEPTH_PID_key == 'B') {
02404             xbee().printf(">> Type in DEADBAND with keyboard.\n\r");
02405             depth_deadband = getFloatUserInput();
02406         }
02407         else {
02408             xbee().printf("\n\rDEPTH: [%c] This key does nothing here.                                  \r", DEPTH_PID_key);
02409         }
02410     }
02411 }
02412  
02413 void StateMachine::keyboard_menu_PITCH_PID_settings() {    
02414     char PITCH_PID_key;
02415     
02416     float pitch_KP = pitchLoop().getControllerP();       // load current pitch value
02417     float pitch_KI = pitchLoop().getControllerI();       // load current pitch value
02418     float pitch_KD = pitchLoop().getControllerD();       // load current pitch value
02419 
02420     float pitch_freq = pitchLoop().getFilterFrequency();
02421     float pitch_deadband = pitchLoop().getDeadband();
02422  
02423     // print the menu
02424     xbee().printf("\n\rPITCH (Battery Motor O.L.) PID gain settings (MENU)");
02425     xbee().printf("\n\rAdjust PID settings with the following keys: P I D. Filter = F, deadband = B.\n\r");
02426     xbee().printf("\n\r(Hit shift + X to exit w/o saving.  Hit shift + S to save.)\n\n\n\r");
02427     xbee().printf("PITCH P: %3.3f, I: %3.3f, D %3.3f, offset: %3.1f mm (filter: %0.2f, deadband: %0.2f)\r\n", pitchLoop().getControllerP(), pitchLoop().getControllerI(), pitchLoop().getControllerD(), pitchLoop().getOutputOffset(),pitchLoop().getFilterFrequency(),pitchLoop().getDeadband());
02428     
02429     // handle the key presses
02430     while(1) {
02431         // get the user's keystroke from either of the two inputs
02432         if (xbee().readable()) {
02433             PITCH_PID_key = xbee().getc();
02434         }
02435         else {
02436             continue; // didn't get a user input, so keep waiting for it
02437         }
02438     
02439         // handle the user's key input
02440         if (PITCH_PID_key == 'S') { // user wants to save these modified values
02441             // set values
02442             pitchLoop().setControllerP(pitch_KP);
02443             pitchLoop().setControllerI(pitch_KI);
02444             pitchLoop().setControllerD(pitch_KD);
02445             
02446             pitchLoop().setFilterFrequency(pitch_freq);
02447             pitchLoop().setDeadband(pitch_deadband);
02448  
02449             // save to "PITCH.TXT" file (doesn't modify neutral position)
02450             configFileIO().savePitchData(pitch_KP, pitch_KI, pitch_KD, _neutral_batt_pos_mm, pitch_freq, pitch_deadband);
02451             
02452             xbee().printf("PITCH P: %3.3f, I: %3.3f, D %3.3f, zeroOffset: %3.1f mm (filter: %0.2f, deadband: %0.2f)\r\n", pitchLoop().getControllerP(), pitchLoop().getControllerI(), pitchLoop().getControllerD(), pitchLoop().getOutputOffset(),pitchLoop().getFilterFrequency(),pitchLoop().getDeadband());
02453 
02454             _pitch_KP = pitchLoop().getControllerP();       // load current pitch value
02455             _pitch_KI = pitchLoop().getControllerI();       // load current pitch value
02456             _pitch_KD = pitchLoop().getControllerD();       // load current pitch value
02457         }
02458         else if (PITCH_PID_key == 'X') {    
02459             break;  //exit the while loop
02460         }
02461         else if (PITCH_PID_key == 'P') {
02462             xbee().printf(">> Type in proportional gain with keyboard.\n\r");
02463             pitch_KP = getFloatUserInput();
02464         }
02465         else if (PITCH_PID_key == 'I') {
02466             xbee().printf(">> Type in integral gain with keyboard.\n\r");
02467             pitch_KI = getFloatUserInput();
02468         }
02469         else if (PITCH_PID_key == 'D') {
02470             xbee().printf(">> Type in derivative gain with keyboard.\n\r");
02471             pitch_KD = getFloatUserInput();
02472         }
02473         else if (PITCH_PID_key == 'F') {
02474             xbee().printf(">> Type in FILTER FREQUENCY with keyboard.\n\r");
02475             pitch_freq = getFloatUserInput();
02476         }
02477         else if (PITCH_PID_key == 'B') {
02478             xbee().printf(">> Type in DEADBAND with keyboard.\n\r");
02479             pitch_deadband = getFloatUserInput();
02480         }
02481         else {
02482             xbee().printf("\n\rPITCH: [%c] This key does nothing here.                                  \r", PITCH_PID_key);
02483         }
02484     }
02485 }
02486 
02487 void StateMachine::keyboard_menu_HEADING_PID_settings() {    
02488     char HEADING_PID_key;
02489     
02490     float heading_KP = headingLoop().getControllerP();
02491     float heading_KI = headingLoop().getControllerI();
02492     float heading_KD = headingLoop().getControllerD(); 
02493        
02494     float heading_offset_deg = headingLoop().getOutputOffset();
02495     float heading_freq = headingLoop().getFilterFrequency();
02496     float heading_deadband = headingLoop().getDeadband();
02497  
02498     // print the menu
02499     xbee().printf("\n\rHEADING (rudder outer loop) PID gain settings (MENU)");
02500     xbee().printf("\n\rAdjust PID settings with the following keys: P I D. Filter = F, deadband = B.\n\r");
02501     xbee().printf("\n\r   Adjust zero offset with O (oh).");
02502     xbee().printf("\n\r(Hit shift + X to exit w/o saving.  Hit shift + S to save.\n\r");
02503     xbee().printf("HEADING P: %3.3f, I: %3.3f, D %3.3f, zeroOffset: %3.1f mm (filter: %0.2f, deadband: %0.2f)\r\n\r\n", headingLoop().getControllerP(),headingLoop().getControllerI(),headingLoop().getControllerD(),headingLoop().getOutputOffset(),headingLoop().getFilterFrequency(),headingLoop().getDeadband());
02504  
02505     // handle the key presses
02506     while(1) {
02507         // get the user's keystroke from either of the two inputs
02508         if (xbee().readable()) {
02509             HEADING_PID_key = xbee().getc();
02510         }
02511         else {
02512             continue; // didn't get a user input, so keep waiting for it
02513         }
02514  
02515         // handle the user's key input     
02516         if (HEADING_PID_key == 'S') { // user wants to save the modified values
02517             // set global values
02518             headingLoop().setControllerP(heading_KP);
02519             headingLoop().setControllerI(heading_KI);
02520             headingLoop().setControllerD(heading_KD);
02521             headingLoop().setOutputOffset(heading_offset_deg);
02522             headingLoop().setFilterFrequency(heading_freq);
02523             headingLoop().setDeadband(heading_deadband);
02524  
02525             // save pitch PID values for outer loop (must save neutral position also)
02526             configFileIO().saveHeadingData(heading_KP, heading_KI, heading_KD, heading_offset_deg, heading_freq, heading_deadband);    //_neutral_heading_pos_deg);
02527             xbee().printf("HEADING P: %3.3f, I: %3.3f, D %3.3f, zeroOffset: %3.1f mm (filter: %0.2f, deadband: %0.2f)\r\n\r\n", headingLoop().getControllerP(),headingLoop().getControllerI(),headingLoop().getControllerD(),headingLoop().getOutputOffset(),headingLoop().getFilterFrequency(),headingLoop().getDeadband());
02528         }
02529         else if (HEADING_PID_key == 'X') {    
02530             break;  //exit the while loop
02531         }
02532         
02533         else if (HEADING_PID_key == 'P') {
02534             heading_KP = getFloatUserInput();;
02535         }
02536         else if (HEADING_PID_key == 'I') {
02537             heading_KI = getFloatUserInput();
02538         }
02539         else if (HEADING_PID_key == 'D') {
02540             heading_KD = getFloatUserInput();
02541         }
02542         else if (HEADING_PID_key == 'F') {
02543             xbee().printf(">> Type in FILTER FREQUENCY with keyboard.\n\r");
02544             heading_freq = getFloatUserInput();
02545         }
02546         else if (HEADING_PID_key == 'B') {
02547             xbee().printf(">> Type in DEADBAND with keyboard.\n\r");
02548             heading_deadband = getFloatUserInput();
02549         }
02550         else if (HEADING_PID_key == 'O') {
02551             heading_offset_deg = getFloatUserInput();
02552         }
02553         else {
02554             xbee().printf("HEADING SETUP: [%c] This key does nothing here.                           \r", HEADING_PID_key);
02555         }
02556     }
02557 }
02558  
02559 float StateMachine::getDepthCommand() {
02560     return _depth_command;
02561 }
02562  
02563 float StateMachine::getPitchCommand() {
02564     return _pitch_command;
02565 }
02566 
02567 float StateMachine::getDepthReading() {
02568     return _depth_reading;
02569 }
02570  
02571 float StateMachine::getPitchReading() {
02572     return _pitch_reading;
02573 }
02574 
02575 float StateMachine::getTimerReading() {
02576     return _timer_reading;
02577 }
02578 
02579 void StateMachine::setState(int input_state) {
02580     _state = input_state;
02581     
02582     _isTimeoutRunning = false;  //to start each state you have to reset this
02583 }
02584  
02585 int StateMachine::getState() {
02586     return _state;  //return the current state of the system
02587 }
02588  
02589 void StateMachine::setTimeout(float input_timeout) {
02590     _timeout = input_timeout;
02591 }
02592  
02593 void StateMachine::setDepthCommand(float input_depth_command) {
02594     _depth_command = input_depth_command;
02595 }
02596  
02597 void StateMachine::setPitchCommand(float input_pitch_command) {
02598     _pitch_command = input_pitch_command;
02599 }
02600  
02601 void StateMachine::setNeutralPositions(float batt_pos_mm, float bce_pos_mm) {
02602     _neutral_batt_pos_mm = batt_pos_mm;
02603     _neutral_bce_pos_mm = bce_pos_mm;
02604     
02605     xbee().printf("Neutral Buoyancy Positions: batt: %0.1f, bce: %0.1f\r\n",_neutral_batt_pos_mm,_neutral_bce_pos_mm);
02606 }
02607  
02608 //process one state at a time
02609 void StateMachine::getDiveSequence() {
02610     //iterate through this sequence using the FSM
02611     currentStateStruct.state = sequenceController().sequenceStructLoaded[_multi_dive_counter].state;
02612     currentStateStruct.timeout = sequenceController().sequenceStructLoaded[_multi_dive_counter].timeout;
02613     currentStateStruct.depth = sequenceController().sequenceStructLoaded[_multi_dive_counter].depth;
02614     currentStateStruct.pitch = sequenceController().sequenceStructLoaded[_multi_dive_counter].pitch;
02615     
02616     _timeout = currentStateStruct.timeout;  //set timeout before exiting this function
02617 }
02618 //process one state at a time
02619 void StateMachine::getLegParams() {
02620     //iterate through this sequence using the FSM
02621     currentLegStateStruct.state = legController().legStructLoaded[_multi_leg_counter].state;
02622     currentLegStateStruct.timeout = legController().legStructLoaded[_multi_leg_counter].timeout;
02623     currentLegStateStruct.yo_time = legController().legStructLoaded[_multi_leg_counter].yo_time;  //timer for each up/down segment
02624     currentLegStateStruct.min_depth = legController().legStructLoaded[_multi_leg_counter].min_depth;
02625     currentLegStateStruct.max_depth = legController().legStructLoaded[_multi_leg_counter].max_depth;
02626     currentLegStateStruct.heading = legController().legStructLoaded[_multi_leg_counter].heading;
02627     
02628     _timeout = currentLegStateStruct.timeout;  //set timeout before exiting this function
02629     _yo_time = currentLegStateStruct.yo_time;
02630     _state   = currentLegStateStruct.state;
02631     // _multi_leg_counter += 1;  // this is wrong, because this subroutine is called multiple times on the same leg, I need indicator of 'next_leg', first.
02632 }
02633 void StateMachine::setstate_frommain(int set_state_val, int new_timeout) {  // used for setting state from main, when find_neutral has not been run
02634     _state = set_state_val;
02635     _timeout = new_timeout;
02636     }
02637 
02638 
02639 void StateMachine::printCurrentSdLog() {
02640     xbee().printf("SD card log work in progress\r\n");
02641     //might be worth saving the last few logs to the MBED...
02642 }
02643 
02644 // 06/06/2018
02645 float StateMachine::getFloatUserInput() {
02646     float float_conversion = 0.0;
02647     
02648     while(1) {
02649         bool valid_input = false;                   //flag for valid or invalid input
02650         
02651         xbee().printf("\n\rPlease enter your number below and press ENTER:\r\n");
02652         char user_string [80];                      //variable to store input as a character array
02653     
02654         xbee().scanf("%s", user_string);              //read formatted data from stdin
02655         xbee().printf("\n\n\ruser_string was <%s>\r\n", user_string);
02656         
02657         //check through the string for invalid characters (decimal values 43 through 57)
02658         for (int c = 0; c < strlen(user_string); c++) {
02659             //xbee().printf("character is [%c]\r\n", user_string[c]);   //debug
02660             if (user_string[c] >= 43 and user_string[c] <= 57) {
02661                 //xbee().printf("VALID CHARACTER!\r\n"); //debug
02662                 ;
02663             }
02664             else {
02665                 xbee().printf("INVALID INPUT!\r\n");
02666                 break;
02667             }
02668             
02669             if (c == (strlen(user_string) - 1)) {
02670                 valid_input = true;
02671             }
02672         }
02673         
02674         if (valid_input) {
02675             float_conversion = atof(user_string);
02676             xbee().printf("VALID INPUT!  Your input was: %3.3f (PRESS \"S\" (shift + S) to save!)\r\n", float_conversion);
02677             break;
02678         }
02679     }
02680     
02681     return float_conversion;
02682 }
02683 
02684 float StateMachine::getTimerValue() {
02685     return _fsm_timer;    
02686 }
02687 
02688 void StateMachine::logFileMenu() {    
02689     char FILE_MENU_key;
02690     
02691     // print the menu
02692     xbee().printf("\n\r>>> LOG FILE MENU. Y = Yes, erase file (and exit).  N = No, keep file (and exit).  P = Print file size.<<<\n\r");
02693     
02694     // handle the key presses
02695     while(1) {
02696         // get the user's keystroke from either of the two inputs
02697         if (xbee().readable()) {
02698             xbee().printf("\n\r>>> LOG FILE MENU. Y = Yes, erase file (and exit).  N = No, keep file (and exit).  P = Print file size.<<<\n\r");
02699             FILE_MENU_key = xbee().getc();
02700         }
02701         else {
02702             continue; // didn't get a user input, so keep waiting for it
02703         }
02704     
02705         // handle the user's key input
02706         if (FILE_MENU_key == 'P') { // user wants to save these modified values
02707             xbee().printf("\n\r>> Printing log file size!\n\r");
02708             wait(2);
02709             mbedLogger().getFileSize("/local/LOG000.csv");
02710         }
02711         else if (FILE_MENU_key == 'Y') {
02712             xbee().printf("\n\r>> Erasing MBED LOG FILE!\n\r");
02713             wait(2);
02714             mbedLogger().eraseFile();
02715             break;
02716         }
02717         else if (FILE_MENU_key == 'N') {
02718             xbee().printf("\n\r>> EXITING MENU. Log file intact.\n\r");
02719             wait(2);
02720             break;
02721         }
02722         else {
02723             xbee().printf("\n\r[%c] This key does nothing here.                                  \r", FILE_MENU_key);
02724         }
02725     }
02726 }