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
Diff: StateMachine/StateMachine.cpp
- Revision:
- 17:7c16b5671d0e
- Parent:
- 16:3363b9f14913
- Child:
- 18:85a7535af8fd
--- a/StateMachine/StateMachine.cpp Mon Nov 06 22:57:56 2017 +0000 +++ b/StateMachine/StateMachine.cpp Tue Nov 21 22:03:26 2017 +0000 @@ -2,7 +2,7 @@ #include "StaticDefs.hpp" StateMachine::StateMachine() { - timeout = 60; // generic timeout for every state, seconds + _timeout = 20; // generic timeout for every state, seconds depthTolerance = 0.25; // depth tolerance for neutral finding exit critera pitchTolerance = 1.0; // pitch angle tolerance for neutral finding exit criteria bceFloatPosition = 300; // bce position for "float" states @@ -10,41 +10,52 @@ depthCommand = 3.5; // user keyboard depth pitchCommand = -20.0; // user keyboard depth + + _neutral_sink_timer = 10; + _neutral_rise_timer = 5; + + previousPosition_mm = 220; //centered, overwritten by the state machine (LOAD THIS FROM CONFIG?) + _state = SIT_IDLE; // select starting state here + + isTimeoutRunning = false; // default timer to not running + isSubStateTimeoutRunning = false; + + _neutral_buoyancy_bce_pos_mm = 0; + _neutral_buoyancy_batt_pos_mm = 0; + + //new + _next_state = -1; //next state is used to prevent states from changing as the FSM executes + _state_counter = 0; } -void StateMachine::runStateMachine() { - static int state = SIT_IDLE; // select starting state here - static bool isTimeoutRunning = false; // default timer to not running - +//Finite State Machine (FSM) +void StateMachine::runStateMachine() { + //use the _next_state when the state machine is run again (so that it cannot change states while the FSM executes) + + static bool runFirstNeutral = false; + + //use the _next_state when the state machine is run again (so that it cannot change states while the FSM executes) + if (_next_state > -1) + _state = _next_state; //current state comes from the state at the completion of the FSM + // finite state machine ... each state has at least one exit criteria - switch (state) { + switch (_state) { case SIT_IDLE : // there actually is no timeout for SIT_IDLE, but this enables some one-shot actions if (!isTimeoutRunning) { showMenu(); pc().printf("\r\n\nstate: SIT_IDLE\r\n"); - isTimeoutRunning = true; + isTimeoutRunning = true; // what is active? bce().pause(); batt().pause(); + + //reset sub FSM + isSubStateTimeoutRunning = false; } // how exit? - if (pc().readable()) { - state = KEYBOARD; - isTimeoutRunning = false; - } - break; - - case KEYBOARD : - pc().printf("\r\n\nstate: KEYBOARD\r\n"); - if (pc().readable()) { - state = keyboard(); // get new state command - if (state == -1) { // error, that wasn't a new state command - state = SIT_IDLE; - } - //pc().printf("new state is: %d \r\n",state); - } + // separate keyboard function will change the states break; case EMERGENCY_CLIMB : @@ -53,7 +64,7 @@ pc().printf("\r\n\nstate: EMERGENCY_CLIMB\r\n"); timer.reset(); // timer goes back to zero timer.start(); // background timer starts running - isTimeoutRunning = true; + isTimeoutRunning = true; // what needs to be started? bce().unpause(); @@ -64,64 +75,72 @@ batt().setPosition_mm(0.0); } // how exit? - if (timer > timeout) { + if (timer > _timeout) { pc().printf("EC: timed out\r\n"); - state = FLOAT_LEVEL; + _next_state = FLOAT_BROADCAST; timer.reset(); isTimeoutRunning = false; } - else if (depthLoop().getPosition() < 0.2) { + else if (depthLoop().getPosition() < 0.2) { //if the depth is greater than 0.2 feet, go to float broadcast pc().printf("EC: depth: %3.1f, cmd: 0.5 [%0.1f sec]\r",depthLoop().getPosition(), timer.read()); - state = FLOAT_LEVEL; + _next_state = FLOAT_BROADCAST; timer.reset(); isTimeoutRunning = false; } break; case FIND_NEUTRAL : - // start local state timer and init any other one-shot actions + /* start local state timer and init any other one-shot actions */ if (!isTimeoutRunning) { pc().printf("\r\n\nstate: FIND_NEUTRAL\r\n"); timer.reset(); // timer goes back to zero timer.start(); // background timer starts running - isTimeoutRunning = true; + isTimeoutRunning = true; // what needs to be started? bce().unpause(); batt().unpause(); - - // what is active? - depthLoop().setCommand(depthCommand); - pitchLoop().setCommand(0.0); + + //first iteration sends SINKING sub-state + runFirstNeutral = true; } - // how exit? - if (timer > timeout) { - pc().printf("FN: timed out\r\n"); - state = FLOAT_LEVEL; + + /* how exit? (exit with the timer, if timer still running continue processing sub FSM) */ + if (timer > _timeout) { + pc().printf("FN: timed out [time: %0.1f sec]\r\n", timer.read()); + _next_state = EMERGENCY_CLIMB; //new behavior (if this times out it emergency surfaces) timer.reset(); isTimeoutRunning = false; } - //depth tolerance of 0.25 feet, pitch tolerance of 1.0 degree - else if ((abs(depthLoop().getPosition() - depthLoop().getCommand()) < depthTolerance) and - (abs(imu().getPitch() - pitchLoop().getCommand()) < pitchTolerance)) { - state = RISE; - timer.reset(); - isTimeoutRunning = false; + // what is active? (call neutral finding sub-function every iteration) + if (runFirstNeutral) { + //pc().printf("First iteration of find neutral\n\r"); // debug (confirmed working) + _sub_state = findNeutralSubState(NEUTRAL_SINKING); + _previous_sub_state = _sub_state; //save previous sub-state + runFirstNeutral = false; } - // what is active? - pc().printf("FN: bce pos: %3.1f mm, batt pos: %3.1f mm (pitchLoop: 0.0 deg)(depthLoop POS: %3.1f ft) [%0.1f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); - bce().setPosition_mm(depthLoop().getOutput()); - batt().setPosition_mm(pitchLoop().getOutput()); - break; - + + //second and further iterations this is running + else { + _sub_state = findNeutralSubState(_previous_sub_state); + _previous_sub_state = _sub_state; //save previous sub-state + + //if sub-FSM has completed its state machine + if (_sub_state == NEUTRAL_EXIT) { + pc().printf("DEBUG: FIND_NEUTRAL sub FSM completed!\n\r"); + _next_state = RISE; //your next state will be RISE in the FSM + } + } + break; + case DIVE : // start local state timer and init any other one-shot actions if (!isTimeoutRunning) { pc().printf("\r\n\nstate: DIVE\r\n"); timer.reset(); // timer goes back to zero timer.start(); // background timer starts running - isTimeoutRunning = true; + isTimeoutRunning = true; // what needs to be started? bce().unpause(); @@ -134,20 +153,20 @@ pc().printf("DIVE: pitch cmd: %3.1f\r\n",pitchLoop().getCommand()); } // how exit? - if (timer > timeout) { - pc().printf("DIVE: timed out\r\n"); - state = EMERGENCY_CLIMB; + if (timer > _timeout) { + pc().printf("DIVE: timed out\n\n\r"); + _next_state = RISE; //new behavior 11/17/2017 timer.reset(); isTimeoutRunning = false; } else if (depthLoop().getPosition() > depthLoop().getCommand()) { pc().printf("DIVE: depth: %3.1f, cmd: %3.1f\r\n", depthLoop().getPosition(), depthLoop().getCommand()); - state = RISE; + _next_state = RISE; timer.reset(); isTimeoutRunning = false; } // what is active? - pc().printf("DIVE: bce pos: %3.1f mm, batt pos: %3.1f mm (depthLoop POS: %3.1f ft) [%0.1f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); + pc().printf("DIVE: bce pos: %3.1f mm, batt pos: %3.1f mm (depthLoop POS: %3.1f ft) [%0.2f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); bce().setPosition_mm(depthLoop().getOutput()); batt().setPosition_mm(pitchLoop().getOutput()); break; @@ -158,7 +177,7 @@ pc().printf("\r\n\nstate: RISE\r\n"); timer.reset(); // timer goes back to zero timer.start(); // background timer starts running - isTimeoutRunning = true; + isTimeoutRunning = true; // what needs to be started? bce().unpause(); @@ -171,22 +190,22 @@ pc().printf("RISE: pitch cmd: %3.1f\r\n",pitchLoop().getCommand()); } // how exit? - if (timer > timeout) { + if (timer > _timeout) { pc().printf("RISE: timed out\r\n"); - state = FLOAT_LEVEL; + _next_state = EMERGENCY_CLIMB; timer.reset(); isTimeoutRunning = false; } else if (depthLoop().getPosition() < depthLoop().getCommand()) { pc().printf("RISE: depth: %3.1f, cmd: %3.1f\r\n", depthLoop().getPosition(), depthLoop().getCommand()); - state = FLOAT_LEVEL; + _next_state = FLOAT_LEVEL; timer.reset(); isTimeoutRunning = false; } pc().printf("RISE: bce pos: %3.1f mm, batt pos: %3.1f mm (depthLoop POS: %3.1f ft) [%0.1f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); // what is active? - bce().setPosition_mm(depthLoop().getOutput()); - batt().setPosition_mm(pitchLoop().getOutput()); + bce().setPosition_mm(depthLoop().getOutput()); //constantly checking the Outer Loop output to move the motors + batt().setPosition_mm(pitchLoop().getOutput()); break; case FLOAT_LEVEL : @@ -195,7 +214,7 @@ pc().printf("\r\n\nstate: FLOAT_LEVEL\r\n"); timer.reset(); // timer goes back to zero timer.start(); // background timer starts running - isTimeoutRunning = true; + isTimeoutRunning = true; // what needs to be started? bce().unpause(); @@ -206,15 +225,15 @@ pitchLoop().setCommand(0.0); } // how exit? - if (timer > timeout) { + if (timer > _timeout) { pc().printf("FL: timed out\r\n"); - state = FLOAT_BROADCAST; + _next_state = FLOAT_BROADCAST; timer.reset(); isTimeoutRunning = false; } - else if (abs(imu().getPitch() - pitchLoop().getCommand()) < abs(pitchTolerance)) { + else if (fabs(imu().getPitch() - pitchLoop().getCommand()) < fabs(pitchTolerance)) { pc().printf("FL: pitch: %3.1f mm, set pos: %3.1f mm, deadband: %3.1f mm\r\n",imu().getPitch(), pitchLoop().getCommand(), pitchTolerance); - state = FLOAT_BROADCAST; + _next_state = FLOAT_BROADCAST; timer.reset(); isTimeoutRunning = false; } @@ -229,7 +248,7 @@ pc().printf("\r\n\nstate: FLOAT_BROADCAST\r\n"); timer.reset(); // timer goes back to zero timer.start(); // background timer starts running - isTimeoutRunning = true; + isTimeoutRunning = true; // what needs to be started? bce().unpause(); @@ -240,31 +259,147 @@ batt().setPosition_mm(battFloatPosition); } // how exit? - if (timer > timeout) { + if (timer > _timeout) { pc().printf("FB: timed out\r\n"); - state = SIT_IDLE; + _next_state = SIT_IDLE; timer.reset(); isTimeoutRunning = false; } - if ( (abs(bce().getPosition_mm() - bce().getSetPosition_mm()) < bce().getDeadband()) and - (abs(batt().getPosition_mm() - batt().getSetPosition_mm()) < batt().getDeadband()) ) { + if ( (fabs(bce().getPosition_mm() - bce().getSetPosition_mm()) < bce().getDeadband()) and + (fabs(batt().getPosition_mm() - batt().getSetPosition_mm()) < batt().getDeadband()) ) { pc().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()); - state = SIT_IDLE; + _next_state = SIT_IDLE; timer.reset(); isTimeoutRunning = false; } pc().printf("FB: bce pos: %3.1f mm, batt pos: %3.1f mm (depthLoop POS: %3.1f ft) [%0.1f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); break; + + case MULTI_DIVE : + // start local state timer and init any other one-shot actions + if (!isTimeoutRunning) { + pc().printf("\r\n\nstate: MULTI-DIVE\r\n"); + timer.reset(); // timer goes back to zero + timer.start(); // background timer starts running + isTimeoutRunning = true; + + // what needs to be started? + bce().unpause(); + batt().unpause(); + + //NEW: retrieve depth and pitch commands from config file struct + // concept is to load this each time the multi-dive restarts + + //keyboard starts sequence at 0 from keyboard function + //stateMachine().getDiveSequence(); + + //retrieve commands from structs + float sequenceDepthCommand = currentStateStruct.depth; + float sequencePitchCommand = currentStateStruct.pitch; + + // what are the commands? + depthLoop().setCommand(sequenceDepthCommand); + pitchLoop().setCommand(sequencePitchCommand); + pc().printf("MULTI-DIVE: depth cmd: %3.1f\r\n",depthLoop().getCommand()); + pc().printf("MULTI-DIVE: pitch cmd: %3.1f\r\n",pitchLoop().getCommand()); + } + // how exit? + if (timer > _timeout) { + pc().printf("MULTI-DIVE: timed out\n\n\r"); + _next_state = MULTI_RISE; //new behavior 11/17/2017 + timer.reset(); + isTimeoutRunning = false; + } + else if (depthLoop().getPosition() > depthLoop().getCommand()) { + pc().printf("MULTI-DIVE: depth: %3.1f, cmd: %3.1f\r\n", depthLoop().getPosition(), depthLoop().getCommand()); + _next_state = MULTI_RISE; + timer.reset(); + isTimeoutRunning = false; + } + // what is active? + pc().printf("MULTI-DIVE: bce pos: %3.1f mm, batt pos: %3.1f mm (depthLoop POS: %3.1f ft) [%0.1f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); + bce().setPosition_mm(depthLoop().getOutput()); + batt().setPosition_mm(pitchLoop().getOutput()); + break; + + case MULTI_RISE : + // start local state timer and init any other one-shot actions + if (!isTimeoutRunning) { + pc().printf("\r\n\nstate: MULTI-RISE\r\n"); + timer.reset(); // timer goes back to zero + timer.start(); // background timer starts running + isTimeoutRunning = true; + + // what needs to be started? + bce().unpause(); + batt().unpause(); + + //NEW: retrieve depth and pitch commands from config file struct + // concept is to load this each time the multi-dive restarts + stateMachine().getDiveSequence(); + + //retrieve just pitch command from struct + float sequencePitchCommand = currentStateStruct.pitch; + + // what are the commands? (send back to 0.5 feet, not surface) // 11/21/2017 + depthLoop().setCommand(0.5); + pitchLoop().setCommand(-sequencePitchCommand); + pc().printf("MULTI-RISE: depth cmd: 0.0\r\n"); + pc().printf("MULTI-RISE: pitch cmd: %3.1f\r\n",pitchLoop().getCommand()); + } + // how exit? + if (timer > _timeout) { + pc().printf("MULTI-RISE: timed out\r\n"); + _next_state = EMERGENCY_CLIMB; + timer.reset(); + isTimeoutRunning = false; + + //reset multi-dive sequence to start + _state_counter = 0; + } + + //depth is less than 0.5 (zero is surface level) + else if (depthLoop().getPosition() < 0.5) { + pc().printf("MULTI-RISE: depth: %3.1f, cmd: %3.1f\r\n", depthLoop().getPosition(), depthLoop().getCommand()); + + //going to next state + isTimeoutRunning = false; + + //successful dive-rise sequence CONTINUES the multi-dive sequence + _state_counter++; + + //UPDATE THE SEQUENCE DATA HERE + stateMachine().getDiveSequence(); + + //check if this is the end of the dive sequence + //CHECK BEFORE ANYTHING ELSE that you have reached the "exit" state (Float_Level) + if (currentStateStruct.state == FLOAT_LEVEL) { + _next_state = FLOAT_LEVEL; + return; + } + + else + _next_state = MULTI_DIVE; + + //have to stop this with the _state_counter variable! + } + pc().printf("MULTI-RISE: bce pos: %3.1f mm, batt pos: %3.1f mm (depthLoop POS: %3.1f ft) [%0.1f sec]\r", bce().getPosition_mm(), batt().getPosition_mm(), depthLoop().getPosition(), timer.read()); + // what is active? + bce().setPosition_mm(depthLoop().getOutput()); //constantly checking the Outer Loop output to move the motors + batt().setPosition_mm(pitchLoop().getOutput()); + break; default : - state = SIT_IDLE; - } + pc().printf("DEBUG: SIT_IDLE\n\r"); + _next_state = SIT_IDLE; + } } // output the keyboard menu for user's reference void StateMachine::showMenu() { pc().printf("\r\r\n\nKEYBOARD MENU:\r\r\n"); pc().printf(" N to find neutral\r\n"); + pc().printf(" M to initiate multi-dive cycle\r\n"); pc().printf(" D to initiate dive cycle\r\n"); pc().printf(" R to initiate rise\r\n"); pc().printf(" L to float level\r\n"); @@ -276,9 +411,7 @@ pc().printf("</> to change batt neutral position\r\n"); pc().printf("Q/W to decrease/increase pitch setpoint: %3.1f\r\n",pitchCommand); pc().printf("A/S to decrease/increase depth setpoint: %3.1f\r\n",depthCommand); - //pc().printf("Q/W to decrease/increase pitch setpoint: %3.1f\r\n",pitchLoop().getCommand()); - //pc().printf("A/S to decrease/increase depth setpoint: %3.1f\r\n",depthLoop().getCommand()); - pc().printf("+/- to decrease/increase timeout: %d s\r\n",timeout); + pc().printf("+/- to decrease/increase timeout: %d s\r\n",_timeout); pc().printf(" 1 BCE PID sub-menu\r\n"); pc().printf(" 2 BATT PID sub-menu\r\n"); pc().printf(" 3 Depth PID sub-menu\r\n"); @@ -287,42 +420,195 @@ pc().printf(" ? to reset mbed\r\n"); } +//Find Neutral sub finite state machine +// Note: the sub-fsm only moves the pistons once at the start of each timer loop +// (timer completes, move piston, timer completes, move piston, etc) +int StateMachine::findNeutralSubState(int input_substate) { + float pitch_angle = pitchLoop().getPosition(); + float pitch_rate = pitchLoop().getVelocity(); + + float abs_pitch_angle = fabs(pitch_angle); + float abs_pitch_rate = fabs(pitch_rate); + + //output substate is the input substate unless it is changed in the sub FSM + static int output_substate = NEUTRAL_SINKING; //to start + //int output_substate = input_substate; + + switch (input_substate) { + case NEUTRAL_SINKING: + //start the 10 second timer + if (!isSubStateTimeoutRunning) { + pc().printf(" input_substate: %d\n\r", input_substate); //debug + _neutral_sink_timer = timer.read()+ 10; //record the time when this block is first entered and add 10 seconds + pc().printf("\r\n\n(8) START NEUTRAL_SINKING (_neutral_sink_timer will go off at %0.1f sec) %3.1f\r\n", _neutral_sink_timer,timer.read()); + + // what is active? + //move piston at start of sequence (retract 10 mm) + pc().printf("Neutral Sinking: Retracting piston 10 mm\n\r"); + previousPosition_mm -= 10; + bce().setPosition_mm(previousPosition_mm); //no depth command + + isSubStateTimeoutRunning = true; //disable this block after one iteration + } + + //once the 10 second timer is complete move the piston with code above + if (timer.read() >= _neutral_sink_timer) { + pc().printf("\r\n\n(8) NEUTRAL_SINKING TIMER COMPLETE! %3.1f\r\n", timer.read()); + pc().printf("\r\n\n(8) (BATT POS: %0.1f) retract 10 mm (time: %3.1f)\r\n", previousPosition_mm, timer.read()); + + //when you finish executing the motor controls, reset the neutral sinking timer in the next state + isSubStateTimeoutRunning = false; + } + + + + //depth >= depth command, go to the next substate the next iteration + if (depthLoop().getPosition() > depthCommand) { + pc().printf("Next substate: NEUTRAL_SLOWLY_RISE\n\r"); + output_substate = NEUTRAL_SLOWLY_RISE; + + //when you finish executing the motor controls, reset the neutral sinking timer in the next state + isSubStateTimeoutRunning = false; + } + + //before the sub-fsm runs again, make sure the piston is in a safe position + //NEW: need to double-check this behavior + //need to set a max travel position ? or just hardcode? or use bceFloatPosition? + if (bce().getPosition_mm() >= 320) { + output_substate = NEUTRAL_EXIT; + //the "case" NEUTRAL_EXIT is used to tell the greater FSM that this sub-FSM has completed + } + break; + + case NEUTRAL_SLOWLY_RISE: + if (!isSubStateTimeoutRunning) { + pc().printf("\r\n\n(9) START NEUTRAL_SLOWLY_RISE (will go off at %0.1f sec)\r\n", timer.read()); + _neutral_sink_timer = timer.read()+ 5; //record the time when this block is first entered and add 10 seconds + + isSubStateTimeoutRunning = true; //disable this block after one iteration + + // what is active? + //move piston at start of sequence (retract 10 mm) + pc().printf("Neutral Slowly Rise: Extending piston 1 mm\n\r"); + previousPosition_mm += 1; + bce().setPosition_mm(previousPosition_mm); //no depth command + } + + //once 5 second timer complete move the piston with code above + if (timer.read() >= _neutral_sink_timer) { + pc().printf("\r\n\n(9)NEUTRAL_SLOWLY_RISE TIMER COMPLETE! (time: %3.1f)\r\n", timer.read()); + pc().printf("\r\n\n(9) (BATT POS: %0.1f) extend 1 mm %3.1f\r\n", previousPosition_mm, timer.read()); + + //when you finish executing the motor controls, reset the neutral sinking timer in the next state + isSubStateTimeoutRunning = false; + } + + //depth rate or sink rate < 0 ft/s, go to the next substate the next iteration + if (depthLoop().getVelocity() < 0) { //less than zero ft/s + pc().printf("\r\n\n(9) NEUTRAL_SLOWLY_RISE: Sink Rate below 0 ft/s [time: %0.1f]\r\n", timer.read()); + + pc().printf("Next substate: NEUTRAL_CHECK_PITCH\n\r"); + output_substate = NEUTRAL_CHECK_PITCH; + } + + //before the sub-fsm runs again, make sure the piston is in a safe position + //NEW: need to double-check this behavior + //need to set a max travel position ? or just hardcode? or use bceFloatPosition? + if (bce().getPosition_mm() >= 320) { + output_substate = NEUTRAL_EXIT; + //the "case" NEUTRAL_EXIT is used to tell the greater FSM that this sub-FSM has completed + } + break; + + case NEUTRAL_CHECK_PITCH: + //no timeout in this sub FSM state (find_neutral timer still running) + + //what is active? + //the BCE piston is maintaining its position + //the battery is maintaining the pitch at zero degrees + + //check sink rate < 0.5 ft/s, go to the next substate the next iteration (pitch velocity) + //check pitch angle is less than 1.0 degree + + pc().printf("(10) NEUTRAL_CHECK_PITCH (time: %3.1f) [%0.1f deg, %0.1f deg/s] \r", timer.read(), pitch_angle, pitch_rate); //debug + output_substate = NEUTRAL_CHECK_PITCH; + + //benchtop tests confirm it needs to be around 2 degrees + if ((abs_pitch_rate < 0.5) && (abs_pitch_angle < 2.0)) { //less than zero ft/s and 1 degree + //SAVE POSITIONS + _neutral_buoyancy_bce_pos_mm = bce().getPosition_mm(); + _neutral_buoyancy_batt_pos_mm = batt().getPosition_mm(); + + //save to neutral.cfg + ConfigFileIO().saveNeutralPositions(_neutral_buoyancy_bce_pos_mm,_neutral_buoyancy_batt_pos_mm); //BCE, BATT + + pc().printf("Saving Positions: BCE: %0.1f mm, BATT: %0.1f\n\r",_neutral_buoyancy_bce_pos_mm,_neutral_buoyancy_batt_pos_mm); + pc().printf("Next substate: NEUTRAL_EXIT\n\r"); + output_substate = NEUTRAL_EXIT; //the "case" NEUTRAL_EXIT is used to tell the greater FSM that this sub-FSM has completed + } + break; + + default: + pc().printf("DEFAULT: check_pitch (state 10)\n\r"); //debug + output_substate = NEUTRAL_CHECK_PITCH; //a default within the sub-state machine + break; + } + return output_substate; +} + // keyboard currently handles a key at a time // returns -1 if not a state command // returns a positive number to command a new state -int StateMachine::keyboard() { +void StateMachine::keyboard() { char userInput; // check keyboard and make settings changes as requested - if (pc().readable()) { + // states can be changed only at the start of a sequence (when the system is in SIT_IDLE) + if (pc().readable() && (_state == SIT_IDLE)) { // get the key - userInput = pc().getc(); + userInput = pc().getc(); + + isTimeoutRunning = false; //keyboard resets timer each time it's used + + pc().printf("KEYBOARD isTimeoutRunning: %d\n\r", isTimeoutRunning); + + //_keyboard_state = SIT_IDLE; //new // check command against desired control buttons // change state if (userInput == 'D' or userInput == 'd') { - return DIVE; + _keyboard_state = DIVE; } else if (userInput == 'N' or userInput == 'n') { - return FIND_NEUTRAL; + _keyboard_state = FIND_NEUTRAL; + } + else if (userInput == 'M' or userInput == 'm') { + //currently does not run if there is no file. + + //need to add method to Sequence Controller that returns -1 + // or some check that insures you cannot run the dive sequence without a file + + stateMachine().getDiveSequence(); //get first sequence on keyboard press + _keyboard_state = currentStateStruct.state; + + pc().printf("Starting Dive Sequence Controller! (state: %d)\n\r", _keyboard_state); //neutral sequence and dive cycles } else if (userInput == 'R' or userInput == 'r') { - return RISE; + _keyboard_state = RISE; } else if (userInput == 'L' or userInput == 'l') { - return FLOAT_LEVEL; + _keyboard_state = FLOAT_LEVEL; } else if (userInput == 'B' or userInput == 'b') { - return FLOAT_BROADCAST; + _keyboard_state = FLOAT_BROADCAST; } else if (userInput == 'E' or userInput == 'e') { - return EMERGENCY_CLIMB; + _keyboard_state = EMERGENCY_CLIMB; } else if (userInput == 'H' or userInput == 'h') { pc().printf("running homing procedure\r\n"); bce().unpause(); bce().homePiston(); bce().pause(); batt().unpause(); batt().homePiston(); batt().pause(); - return SIT_IDLE; } else if (userInput == 'T' or userInput == 't') { pc().printf("taring depth sensor\r\n"); @@ -377,12 +663,12 @@ pc().printf(">>> new depth setpoint: %0.3f ft (rise)\r\n", depthLoop().getCommand()); } else if (userInput == '-') { - timeout -= 10.0; //decrement the timeout - pc().printf(">>> timeout decreased: %d\r\n", timeout); + _timeout -= 10.0; //decrement the timeout + pc().printf(">>> timeout decreased: %d\r\n", _timeout); } else if (userInput == '=' or userInput == '+') { - timeout += 10.0; //increment the timeout - pc().printf(">>> timeout increased: %d\r\n", timeout); + _timeout += 10.0; //increment the timeout + pc().printf(">>> timeout increased: %d\r\n", _timeout); } // add keyboard commands to move the neutral zero offsets, both bce and batt @@ -412,12 +698,26 @@ pc().printf("pitchLoop().getCommand(): %3.1f\r\n",pitchLoop().getCommand()); } else { - return (-1); + _keyboard_state = -1; } + + //when you read the keyboard successfully, change the state + _next_state = _keyboard_state; //set state at the end of this function } - return (-1); } +//11/19/2017 +//you want to modify the keyboard to return the values that will be used in the state machine +//BUT the state machine does not call they keyboard +//the keyboard runs independently and only allows input when the state is "idle" +//therefore keyboard should run maybe 1/10th of a second when pc readable +//and it will change a class variable that says what the current state is + +//make it void + + + + void StateMachine::keyboard_menu_BCE_PID_settings() { char PID_key; float gain_step_size = 0.01; // modify this to change gain step size @@ -691,4 +991,48 @@ float StateMachine::getPitchCommand() { return pitchCommand; +} + +void StateMachine::setState(int input_state) { + //pc().printf("input_state: %d\n\r", input_state); //debug + //_state = input_state; //changing wrong variable + _next_state = input_state; +} + +int StateMachine::getState() { + return _state; //return the current state of the system +} + +void StateMachine::setTimeout(float input_timeout) { + _timeout = input_timeout; +} + +void StateMachine::setDepthCommand(float input_depth_command) { + depthCommand = input_depth_command; +} + +void StateMachine::setPitchCommand(float input_pitch_command) { + pitchCommand = input_pitch_command; +} + +void StateMachine::setNeutralPositions(float batt_pos_mm, float bce_pos_mm) { + _neutral_buoyancy_batt_pos_mm = batt_pos_mm; + _neutral_buoyancy_bce_pos_mm = bce_pos_mm; + + pc().printf("Neutral Buoyancy Positions: batt: %0.1f, bce: %0.1f\n\r",_neutral_buoyancy_batt_pos_mm,_neutral_buoyancy_bce_pos_mm); +} + +int StateMachine::timeoutRunning() { + return isTimeoutRunning; +} + +//process one state at a time +void StateMachine::getDiveSequence() { + //iterate through this sequence using the FSM + currentStateStruct.state = sequenceController().sequenceStructLoaded[_state_counter].state; + currentStateStruct.timeout = sequenceController().sequenceStructLoaded[_state_counter].timeout; + currentStateStruct.depth = sequenceController().sequenceStructLoaded[_state_counter].depth; + currentStateStruct.pitch = sequenceController().sequenceStructLoaded[_state_counter].pitch; + + _timeout = currentStateStruct.timeout; //set timeout before exiting this function } \ No newline at end of file