diff --git a/function-diagram.drawio b/function-diagram.drawio index 79c9291..496684e 100644 --- a/function-diagram.drawio +++ b/function-diagram.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/main/control.cpp b/main/control.cpp index 34012df..6a9ec92 100644 --- a/main/control.cpp +++ b/main/control.cpp @@ -24,7 +24,6 @@ QueueHandle_t init_encoder(rotary_encoder_info_t * info){ - //==================== //==== variables ===== //==================== @@ -63,7 +62,7 @@ bool autoCutEnabled = false; //store state of toggle switch (no hotswitch) //function for changing the controlState with log output void changeState (systemState_t stateNew) { //only proceed when state actually changed - if (controlState == stateNew){ + if (controlState == stateNew) { return; //already at target state -> nothing to do } //log change @@ -73,7 +72,8 @@ void changeState (systemState_t stateNew) { //update timestamp timestamp_changedState = esp_log_timestamp(); } - + + //===== handle Stop Condition ===== //function that checks whether start button is released or target is reached (used in multiple states) @@ -120,7 +120,7 @@ void setDynSpeedLvl(uint8_t lvlMax = 3){ lvl = 3; } //limit to max lvl - if (lvl > lvlMax){ + if (lvl > lvlMax) { lvl = lvlMax; } //update vfd speed level @@ -182,15 +182,12 @@ void task_control(void *pvParameter) // Poll current position and direction rotary_encoder_get_state(&encoder, &encoderState); //--- calculate distance --- - //lengthNow = (float)encoderState.position * (MEASURING_ROLL_DIAMETER * PI) / 600; //TODO dont calculate constant factor every time FIXME: ROUNDING ISSUE float-int? lengthNow = (float)encoderState.position * 1000 / STEPS_PER_METER; - //--------------------------- //--------- buttons --------- //--------------------------- - //TODO: ADD PRESET SWITCHES HERE //--- RESET switch --- if (SW_RESET.risingEdge) { rotary_encoder_reset(&encoder); @@ -200,7 +197,6 @@ void task_control(void *pvParameter) //cutter_stop(); } - //--- CUT switch --- //start cut cycle immediately if (SW_CUT.risingEdge) { @@ -217,14 +213,13 @@ void task_control(void *pvParameter) } //error cant cut while motor is on else { - buzzer.beep(6, 70, 50); + buzzer.beep(6, 100, 50); } } - //--- AUTO_CUT toggle sw --- //beep at change - if (SW_AUTO_CUT.risingEdge){ + if (SW_AUTO_CUT.risingEdge) { buzzer.beep(2, 100, 50); } else if (SW_AUTO_CUT.fallingEdge) { buzzer.beep(1, 400, 50); @@ -233,7 +228,7 @@ void task_control(void *pvParameter) if (SW_AUTO_CUT.state) { //enable autocut when not in target_reached state //(prevent immediate/unexpected cut) - if (controlState != systemState_t::TARGET_REACHED){ + if (controlState != systemState_t::TARGET_REACHED) { autoCutEnabled = true; } } else { @@ -241,7 +236,6 @@ void task_control(void *pvParameter) autoCutEnabled = false; } - //--- manual mode --- //switch to manual motor control (2 buttons + poti) if ( SW_PRESET2.state && (SW_PRESET1.state || SW_PRESET3.state) && controlState != systemState_t::MANUAL ) { @@ -250,7 +244,6 @@ void task_control(void *pvParameter) buzzer.beep(3, 100, 60); } - //--- set custom target length --- //set target length to poti position when SET switch is pressed if (SW_SET.state == true) { @@ -289,7 +282,7 @@ void task_control(void *pvParameter) //--- target length presets --- if (controlState != systemState_t::MANUAL) { //dont apply preset length while controlling motor with preset buttons - if (SW_PRESET1.risingEdge){ + if (SW_PRESET1.risingEdge) { lengthTarget = 1000; buzzer.beep(lengthTarget/1000, 25, 30); displayBot.blink(3, 100, 100, "S0LL "); @@ -318,11 +311,10 @@ void task_control(void *pvParameter) switch (controlState) { case systemState_t::COUNTING: //no motor action vfd_setState(false); - //TODO check stop condition before starting - prevents motor from starting 2 cycles when + //TODO check stop condition before starting - prevents motor from starting 2 cycles when already at target //--- start winding to length --- if (SW_START.risingEdge) { changeState(systemState_t::WINDING_START); - //TODO apply dynamic speed here too (if started when already very close) vfd_setSpeedLevel(1); //start at low speed vfd_setState(true); //start motor timestamp_motorStarted = esp_log_timestamp(); //save time started @@ -341,10 +333,10 @@ void task_control(void *pvParameter) break; case systemState_t::WINDING: //wind fast, slow down when close - //set vfd speed depending on remaining distance + //set vfd speed depending on remaining distance setDynSpeedLvl(); //slow down when close to target handleStopCondition(&displayTop, &displayBot); //stops if button released or target reached - //TODO: cancel when there is no cable movement anymore e.g. empty / timeout? + //TODO: cancel when there is no cable movement anymore e.g. empty / timeout? break; case systemState_t::TARGET_REACHED: @@ -355,14 +347,14 @@ void task_control(void *pvParameter) } //switch initiate countdown to auto-cut else if ( (autoCutEnabled) - && (esp_log_timestamp() - timestamp_changedState > 300) ){ //wait for dislay msg "reached" to finish + && (esp_log_timestamp() - timestamp_changedState > 300) ) { //wait for dislay msg "reached" to finish changeState(systemState_t::AUTO_CUT_WAITING); } //show msg when trying to start, but target is reached - if (SW_START.risingEdge){ - buzzer.beep(3, 40, 30); - displayTop.blink(2, 600, 800, " S0LL "); - displayBot.blink(2, 600, 800, "ERREICHT"); + if (SW_START.risingEdge) { + buzzer.beep(2, 50, 30); + displayTop.blink(2, 600, 500, " S0LL "); + displayBot.blink(2, 600, 500, "ERREICHT"); } break; @@ -370,18 +362,18 @@ void task_control(void *pvParameter) //handle delayed start of cut cut_msRemaining = autoCut_delayMs - (esp_log_timestamp() - timestamp_changedState); //- countdown stop conditions - - if (!autoCutEnabled || !SW_AUTO_CUT.state || SW_RESET.state || SW_CUT.state){ //TODO: also stop when target not reached anymore? + if (!autoCutEnabled || !SW_AUTO_CUT.state || SW_RESET.state || SW_CUT.state) { //TODO: also stop when target not reached anymore? changeState(systemState_t::COUNTING); } //- trigger cut if delay passed - - else if (cut_msRemaining <= 0){ + else if (cut_msRemaining <= 0) { cutter_start(); changeState(systemState_t::CUTTING); } //- beep countdown - //time passed since last beep > time remaining / 6 else if ( (esp_log_timestamp() - timestamp_cut_lastBeep) > (cut_msRemaining / 6) - && (esp_log_timestamp() - timestamp_cut_lastBeep) > 50 ){ //dont trigger beeps faster than beep time + && (esp_log_timestamp() - timestamp_cut_lastBeep) > 50 ) { //dont trigger beeps faster than beep time buzzer.beep(1, 50, 0); timestamp_cut_lastBeep = esp_log_timestamp(); } @@ -389,7 +381,7 @@ void task_control(void *pvParameter) case systemState_t::CUTTING: //exit when finished cutting - if (cutter_isRunning() == false){ + if (cutter_isRunning() == false) { //TODO stop if start buttons released? changeState(systemState_t::COUNTING); //TODO reset automatically or wait for manual reset? @@ -411,14 +403,14 @@ void task_control(void *pvParameter) } //P2 + P1 -> turn left else if ( SW_PRESET1.state && !SW_PRESET3.state ) { - vfd_setSpeedLevel(level); //TODO: use poti input for level + vfd_setSpeedLevel(level); vfd_setState(true, REV); sprintf(buf_disp2, "[--%02i ", level); // 123 45 678 } //P2 + P3 -> turn right else if ( SW_PRESET3.state && !SW_PRESET1.state ) { - vfd_setSpeedLevel(level); //TODO: use poti input for level + vfd_setSpeedLevel(level); vfd_setState(true, FWD); sprintf(buf_disp2, " %02i--]", level); } @@ -461,7 +453,7 @@ void task_control(void *pvParameter) //run handle function displayTop.handle(); //indicate upcoming cut when pending - if (controlState == systemState_t::AUTO_CUT_WAITING){ + if (controlState == systemState_t::AUTO_CUT_WAITING) { displayTop.blinkStrings(" CUT 1N ", " ", 70, 30); } //otherwise show current position @@ -493,7 +485,7 @@ void task_control(void *pvParameter) displayBot.blinkStrings("CUTTING]", "CUTTING[", 100, 100); } //show ms countdown to cut when pending - else if (controlState == systemState_t::AUTO_CUT_WAITING){ + else if (controlState == systemState_t::AUTO_CUT_WAITING) { sprintf(buf_disp2, " %04d ", cut_msRemaining); //displayBot.showString(buf_disp2); //TODO:blink "erreicht" overrides this. for now using blink as workaround displayBot.blinkStrings(buf_disp2, buf_disp2, 100, 100); @@ -507,13 +499,25 @@ void task_control(void *pvParameter) } + //---------------------------- + //------- control lamp ------- + //---------------------------- + //basic functionality of lamp: + //turn on when not idling + //TODO: add switch-case for different sates + //e.g. blink with different frequencies in different states + if (controlState != systemState_t::COUNTING + && controlState != systemState_t::TARGET_REACHED) { + gpio_set_level(GPIO_LAMP, 1); + } + else { + gpio_set_level(GPIO_LAMP, 0); + } + + + #endif - //TODO: blink disp2 when set button pressed - //TODO: blink disp2 when preset button pressed (exept manual mode) - //TODO: write "MAN CTL" to disp2 when in manual mode - //TODO: display or blink "REACHED" when reached state and start pressed - } } diff --git a/main/control.hpp b/main/control.hpp index e70c6ef..0ab7dcb 100644 --- a/main/control.hpp +++ b/main/control.hpp @@ -26,8 +26,10 @@ extern "C" +//enum describing the state of the system enum class systemState_t {COUNTING, WINDING_START, WINDING, TARGET_REACHED, AUTO_CUT_WAITING, CUTTING, MANUAL}; +//array with enum as strings for logging states extern const char* systemStateStr[7]; - +//task that controls the entire machine (has to be created as task in main function) void task_control(void *pvParameter); diff --git a/main/cutter.cpp b/main/cutter.cpp index e658103..117a4f3 100644 --- a/main/cutter.cpp +++ b/main/cutter.cpp @@ -22,8 +22,6 @@ static const char *TAG = "cutter"; //tag for logging - - //========================= //========= start ========= //========================= diff --git a/main/main.cpp b/main/main.cpp index a60baa3..bbf1992 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -13,19 +13,21 @@ extern "C" #include "config.hpp" #include "control.hpp" #include "buzzer.hpp" - #include "switchesAnalog.hpp" //================================= //=========== functions =========== //================================= +//--- configure output --- //function to configure gpio pin as output void gpio_configure_output(gpio_num_t gpio_pin){ gpio_pad_select_gpio(gpio_pin); gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT); } + +//--- init gpios --- void init_gpios(){ //--- outputs --- //4x stepper mosfets @@ -36,7 +38,7 @@ void init_gpios(){ //gpio_configure_output(GPIO_VFD_D2); only used with 7.5kw vfd //2x power mosfets gpio_configure_output(GPIO_MOS1); //mos1 - gpio_configure_output(GPIO_LAMP); //lamp + gpio_configure_output(GPIO_LAMP); //llamp (mos2) //onboard relay and buzzer gpio_configure_output(GPIO_RELAY); gpio_configure_output(GPIO_BUZZER); @@ -47,12 +49,6 @@ void init_gpios(){ //initialize and configure ADC adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096 adc1_config_channel_atten(ADC_CHANNEL_POTI, ADC_ATTEN_DB_11); //max voltage - ////initialize input for cutter position switch with pullup (now done via evaluatedSwitch construcor) - //gpio_pad_select_gpio(GPIO_CUTTER_POS_SW); - //gpio_set_direction(GPIO_CUTTER_POS_SW, GPIO_MODE_INPUT); - //gpio_pad_select_gpio(GPIO_CUTTER_POS_SW); - //gpio_set_pull_mode(GPIO_CUTTER_POS_SW, GPIO_PULLUP_ONLY); - } @@ -60,8 +56,6 @@ void init_gpios(){ //====================================== //============ buzzer task ============= //====================================== -//TODO: move the task creation to buzzer class (buzzer.cpp) -//e.g. only have function buzzer.createTask() in app_main void task_buzzer( void * pvParameters ){ ESP_LOGI("task_buzzer", "Start of buzzer task..."); //run function that waits for a beep events to arrive in the queue @@ -71,8 +65,6 @@ void task_buzzer( void * pvParameters ){ - - //====================================== //=========== main function ============ //====================================== @@ -97,5 +89,4 @@ extern "C" void app_main() //beep at startup buzzer.beep(3, 70, 50); - }