24 Commits

Author SHA1 Message Date
jonny_ji7
ef0ac39c9b Update diagram pdf files, cad files (guides)
- update / export pdf version from current drawio connection-plan and
  function-diagram
- update cad files
2022-10-13 14:01:19 +02:00
jonny_l480
ad2ce8c33b Adjust speed thresholds, increase custom length range
Update speed thresholds to slow down earlier
Increase custom length range from 30 to 50m
2022-10-11 11:48:54 +02:00
jonny_ji7
8f5b33c554 Add LENGTH_OFFSET and REACHED_TOLERANCE options
Add feature and config option #define TARGET_LENGTH_OFFSET
that makes it possible to set a distance that gets added to the target
length, thus preventing falling short on the actual length when spools
rotates back slightly after stop.

Also move reached tolerance to config.
2022-09-30 13:14:48 +02:00
jonny_ji7
592351c265 Add CAD-files, wire-labels, docs/datasheets
Add add cad files of all designed and 3d-printed parts.
Mostly Freecad and a few older SolidEdge files (_SE)

Add wire-labels.fods containing the printed labels for wires in
control-box and switching cabinet

Add docs folder with relevant images and datasheets of the used components
2022-09-29 19:39:56 +02:00
jonny_ji7
d473bf6b8c Add autoCut-cancel with any button; Fix display init
- Pending auto cut (countdown) can be canceled using any button on the
    panel
- Reset button does not reset the length when countdown cancledo

- Fix bug where display did not initialize correctly after start some
  times
  -> simply init again after welcome msg

- reduce countdown time by 500ms
2022-09-29 13:57:26 +02:00
jonny_ji7
4cb6b41a6b Add blinking at RESET; Adjust preset values
Blink 'IST' value on top display when reset (as with presets)
Adjust preset values to current labeling
2022-09-23 10:33:42 +02:00
jonny_ji7
bf87be2590 Merge branch 'cutter'
New cutter feature is tested and works reliably in automatic mode with
delay or manual mode via button
2022-09-23 10:29:47 +02:00
jonny_ji7
63706e4aa7 Update connection-plan, Add wiring-plan
Update connection plan to match the actual current wiring
Add page to connection plan which describes which cables are connected
between what components
2022-09-23 10:09:55 +02:00
jonny_ji7
5b49406cb8 Add basic LAMP functionality; Fix comments
- Basic lamp functionality: simply turn on when not in COUNTING or TARGET_REACHED
    state

- Remove unnecessary comments, fix code formatting in several files
2022-09-22 11:23:48 +02:00
jonny_ji7
2cf1762569 Optimize auto-cut delay
Optimize delay to auto cut by adding a new state AUTO_CUT_WAITING
this removes some confusing / unnecessary complex code
2022-09-20 09:52:02 +02:00
jonny_l480
826dd983c4 Add cutter stop via btn; Prevent cut while winding
Add conditions to CUT button pressed case
- when cutter already on -> stop
- when in state where motor is active -> dont start
- else: error
2022-09-19 19:10:28 +02:00
jonny_l480
bb7cdddc6c Fix display priority, Add stop countdown
Fix bug where display is stuck when countdown stopped via reset button
Add functionality to stop countdown via turning auto-cut switch off

Fix display priority issues with using 2 boolean variables and a delay
before counting
2022-09-19 19:00:09 +02:00
jonny_ji7
8a265c2bae Add display-messages: cutting, countdown to cut 2022-09-19 17:38:26 +02:00
jonny_l480
6dfa47e3e8 Adjust parameters
While testing the machine with current firmware, a few parameters got
slightly adjusted:
- dynamic spped lvl later slow
- longer slow speed at start
- less threshold for stying in target reached
- decreased countdown beep interval at auto cut
- adjusted display interval in manual mode (faster)
2022-09-19 14:57:26 +02:00
jonny_ji7
2f86fbeb80 Add delay to auto-cut, beep countdown
Add 3s delay between target reached and automatic cut
During that delay the buzzer keeps beeping faster until the cut starts.
2022-09-19 14:35:44 +02:00
jonny_ji7
9b386c3d73 Add beep at AUTO_CUT toggle and CUT trigger
cutter.hpp:
  change from enum to enum class
control.cpp:
   add beeping to cut buttons
2022-09-19 13:55:29 +02:00
jonny_ji7
992d852189 Add auto-cut functionality: diagram, switches, new state
control.cpp:
    - Add new systemState CUTTING
    - change systemState_t from enum to enum class (conflicting with
      cutter enum)

    - Add CUTTING functionality to CUT switch and auto cut after target
      reached if enabled

cutter.cpp:
    - Add function cutter_isRunning()

config:
    - Add GPIO_LAMP macro to config
2022-09-17 11:42:38 +02:00
jonny_ji7
824bad930e Add switches for cutter to con-plan and config 2022-09-17 10:37:39 +02:00
jonny_ji7
ced7cda002 Update connection plan: New Control-panel layout
Replace previous control panel with to scale svg exported from cad with
button descriptions
2022-09-15 22:20:37 +02:00
jonny_l480
6242d6a5fc Merge branch 'main' into cutter 2022-09-12 13:48:58 +02:00
jonny_l480
59df1a9aa2 Merge branch '4swToAdc' 2022-09-12 13:26:15 +02:00
jonny_l480
fab75661c2 Fix random cutter stops (evaluateSwitch)
- use evaluatedSwitch class for position switch instead of reading gpio
directly because it triggered incorrectly too often

- cutter_stop()  only switch to CANCELED when not in IDLE already
2022-09-06 14:26:29 +02:00
jonny_ji7
9600932ae8 Add cutter to control, test via preset buttons 2022-09-06 12:18:27 +02:00
jonny_ji7
bb22fb340d Add cutter code (cutter.cpp, cutter.hpp)
Add logic for cutter according to function diagram
Remove use of relay from vfd.cpp
Add pin for cutter switch to config
2022-09-06 12:00:23 +02:00
61 changed files with 4005 additions and 95 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.fcstd text

3
.gitignore vendored
View File

@@ -7,3 +7,6 @@ build
# drawio files # drawio files
*.bkp *.bkp
# freecad backup files
*.FCStd1

Binary file not shown.

BIN
cad/box/box_v1.0.FCStd Normal file

Binary file not shown.

2356
cad/box/panel.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

4
cad/export/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

BIN
docs/3SK1111-1AB30_con1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
docs/3SK1111-1AB30_con2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/LPD3806-dimensions.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -0,0 +1,2 @@
currently the vfd 'T13-750W-12-h' is actually used.
Included documentation about T13-400W here too, modbus specification might be the same.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -6,6 +6,7 @@ idf_component_register(
"buzzer.cpp" "buzzer.cpp"
"vfd.cpp" "vfd.cpp"
"display.cpp" "display.cpp"
"cutter.cpp"
"switchesAnalog.cpp" "switchesAnalog.cpp"
INCLUDE_DIRS INCLUDE_DIRS
"." "."

View File

@@ -9,6 +9,7 @@ gpio_evaluatedSwitch sw_gpio_32(GPIO_NUM_32, true, false); //pullup true, not in
gpio_evaluatedSwitch sw_gpio_33(GPIO_NUM_33, true, false); //pullup true, not inverted (switch to GND, internal pullup used) gpio_evaluatedSwitch sw_gpio_33(GPIO_NUM_33, true, false); //pullup true, not inverted (switch to GND, internal pullup used)
gpio_evaluatedSwitch sw_gpio_25(GPIO_NUM_25, true, false); //pullup true, not inverted (switch to GND, internal pullup used) gpio_evaluatedSwitch sw_gpio_25(GPIO_NUM_25, true, false); //pullup true, not inverted (switch to GND, internal pullup used)
gpio_evaluatedSwitch sw_gpio_26(GPIO_NUM_26, true, false); //pullup true, not inverted (switch to GND, internal pullup used) gpio_evaluatedSwitch sw_gpio_26(GPIO_NUM_26, true, false); //pullup true, not inverted (switch to GND, internal pullup used)
gpio_evaluatedSwitch sw_gpio_14(GPIO_NUM_14, true, false); //pullup true, not inverted (switch to GND, internal pullup used)
//--- switches connected to 4 sw to analog stripboard --- //--- switches connected to 4 sw to analog stripboard ---
//evaluated switches with function to obtain the current input state instead of gpio //evaluated switches with function to obtain the current input state instead of gpio

View File

@@ -17,7 +17,8 @@ extern "C" {
#define GPIO_VFD_D1 GPIO_NUM_15 //ST1 #define GPIO_VFD_D1 GPIO_NUM_15 //ST1
//#define GPIO_VFD_D2 GPIO_NUM_15 //ST1 (D2 only used with 7.5kw vfd) //#define GPIO_VFD_D2 GPIO_NUM_15 //ST1 (D2 only used with 7.5kw vfd)
#define GPIO_MOS2 GPIO_NUM_5 //mos2 #define GPIO_MOS1 GPIO_NUM_18 //mos1 (free)
#define GPIO_LAMP GPIO_NUM_5 //mos2
#define GPIO_RELAY GPIO_NUM_13 #define GPIO_RELAY GPIO_NUM_13
#define GPIO_BUZZER GPIO_NUM_12 #define GPIO_BUZZER GPIO_NUM_12
@@ -40,19 +41,23 @@ extern "C" {
//see config.cpp for available evaluated switch objects //see config.cpp for available evaluated switch objects
#define SW_START sw_gpio_26 #define SW_START sw_gpio_26
#define SW_RESET sw_gpio_25 #define SW_RESET sw_gpio_25
#define SW_CUTTER_POS sw_gpio_14
#define SW_SET sw_gpio_analog_0 #define SW_SET sw_gpio_analog_0
#define SW_PRESET1 sw_gpio_analog_1 #define SW_PRESET1 sw_gpio_analog_1
#define SW_PRESET2 sw_gpio_analog_2 #define SW_PRESET2 sw_gpio_analog_2
#define SW_PRESET3 sw_gpio_analog_3 #define SW_PRESET3 sw_gpio_analog_3
#define SW_CUT sw_gpio_33
#define SW_AUTO_CUT sw_gpio_32
//unused but already available evaluated inputs //unused but already available evaluated inputs
//#define ? sw_gpio_33
//#define ? sw_gpio_32
//#define ? sw_gpio_34 //#define ? sw_gpio_34
//=============================
//======= configuration =======
//=============================
//-------------------------- //--------------------------
//----- display config ----- //----- display config -----
//-------------------------- //--------------------------
@@ -77,11 +82,20 @@ extern "C" {
//-------------------------- //--------------------------
//------ calibration ------- //------ calibration -------
//-------------------------- //--------------------------
//use encoder test for calibration and calculate STEPS_PER_METER //enable mode encoder test for calibration
//#define ENCODER_TEST //show encoder count instead of converted meters //if defined, displays always show length and steps instead of the normal messages
//#define ENCODER_TEST
//steps per meter
#define STEPS_PER_METER 2127 //roll-v3-gummi-86.6mm - d=89.8mm #define STEPS_PER_METER 2127 //roll-v3-gummi-86.6mm - d=89.8mm
//#define MEASURING_ROLL_DIAMETER 86.6 //roll v3 large
//#define PI 3.14159265358979323846 //millimetres added to target length
//to ensure that length does not fall short when spool slightly rotates back after stop
#define TARGET_LENGTH_OFFSET 0
//millimetres lengthNow can be below lengthTarget to still stay in target_reached state
#define TARGET_REACHED_TOLERANCE 5
@@ -96,6 +110,7 @@ extern gpio_evaluatedSwitch sw_gpio_32;
extern gpio_evaluatedSwitch sw_gpio_33; extern gpio_evaluatedSwitch sw_gpio_33;
extern gpio_evaluatedSwitch sw_gpio_25; extern gpio_evaluatedSwitch sw_gpio_25;
extern gpio_evaluatedSwitch sw_gpio_26; extern gpio_evaluatedSwitch sw_gpio_26;
extern gpio_evaluatedSwitch sw_gpio_14;
//--- switches connected to 4-sw-to-analog stripboard --- //--- switches connected to 4-sw-to-analog stripboard ---
extern gpio_evaluatedSwitch sw_gpio_analog_0; extern gpio_evaluatedSwitch sw_gpio_analog_0;

View File

@@ -24,14 +24,14 @@ QueueHandle_t init_encoder(rotary_encoder_info_t * info){
//==================== //====================
//==== variables ===== //==== variables =====
//==================== //====================
static const char *TAG = "control"; //tag for logging static const char *TAG = "control"; //tag for logging
const char* systemStateStr[5] = {"COUNTING", "WINDING_START", "WINDING", "TARGET_REACHED", "MANUAL"}; const char* systemStateStr[7] = {"COUNTING", "WINDING_START", "WINDING", "TARGET_REACHED", "AUTO_CUT_WAITING", "CUTTING", "MANUAL"};
systemState_t controlState = COUNTING; systemState_t controlState = systemState_t::COUNTING;
uint32_t timestamp_changedState = 0;
char buf_disp[20]; //both displays char buf_disp[20]; //both displays
char buf_disp1[10];// 8 digits + decimal point + \0 char buf_disp1[10];// 8 digits + decimal point + \0
@@ -42,31 +42,39 @@ rotary_encoder_info_t encoder; //encoder device/info
QueueHandle_t encoder_queue = NULL; //encoder event queue QueueHandle_t encoder_queue = NULL; //encoder event queue
rotary_encoder_state_t encoderState; rotary_encoder_state_t encoderState;
uint32_t timestamp_pageSwitched = 0;
bool page = false; //store page number currently displayed
int lengthNow = 0; //length measured in mm int lengthNow = 0; //length measured in mm
int lengthTarget = 3000; //target length in mm int lengthTarget = 5000; //default target length in mm
int lengthRemaining = 0; //(target - now) length needed for reaching the target int lengthRemaining = 0; //(target - now) length needed for reaching the target
int potiRead = 0; //voltage read from adc int potiRead = 0; //voltage read from adc
uint32_t timestamp_motorStarted = 0; //timestamp winding started uint32_t timestamp_motorStarted = 0; //timestamp winding started
//encoder test / calibration
int lengthBeeped = 0; //only beep once per meter during encoder test int lengthBeeped = 0; //only beep once per meter during encoder test
//automatic cut
int cut_msRemaining = 0;
uint32_t timestamp_cut_lastBeep = 0;
uint32_t autoCut_delayMs = 2500; //TODO add this to config
bool autoCutEnabled = false; //store state of toggle switch (no hotswitch)
//===== change State ===== //===== change State =====
//function for changing the controlState with log output //function for changing the controlState with log output
void changeState (systemState_t stateNew) { void changeState (systemState_t stateNew) {
//only proceed when state actually changed //only proceed when state actually changed
if (controlState == stateNew){ if (controlState == stateNew) {
return; //already at target state -> nothing to do return; //already at target state -> nothing to do
} }
//log change //log change
ESP_LOGW(TAG, "changed state from %s to %s", systemStateStr[(int)controlState], systemStateStr[(int)stateNew]); ESP_LOGW(TAG, "changed state from %s to %s", systemStateStr[(int)controlState], systemStateStr[(int)stateNew]);
//change state //change state
controlState = stateNew; controlState = stateNew;
//update timestamp
timestamp_changedState = esp_log_timestamp();
} }
//===== handle Stop Condition ===== //===== handle Stop Condition =====
//function that checks whether start button is released or target is reached (used in multiple states) //function that checks whether start button is released or target is reached (used in multiple states)
//returns true when stopped, false when no action //returns true when stopped, false when no action
@@ -75,16 +83,16 @@ bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBo
//stop conditions that are checked in any mode //stop conditions that are checked in any mode
//target reached //target reached
if (lengthRemaining <= 0 ) { if (lengthRemaining <= 0 ) {
changeState(TARGET_REACHED); changeState(systemState_t::TARGET_REACHED);
vfd_setState(false); vfd_setState(false);
displayTop->blink(1, 0, 1500, " S0LL "); displayTop->blink(1, 0, 1000, " S0LL ");
displayBot->blink(1, 0, 1500, "ERREICHT"); displayBot->blink(1, 0, 1000, "ERREICHT");
buzzer.beep(2, 100, 100); buzzer.beep(2, 100, 100);
return true; return true;
} }
//start button released //start button released
else if (SW_START.state == false) { else if (SW_START.state == false) {
changeState(COUNTING); changeState(systemState_t::COUNTING);
vfd_setState(false); vfd_setState(false);
displayTop->blink(2, 900, 1000, "- STOP -"); displayTop->blink(2, 900, 1000, "- STOP -");
displayBot->blink(2, 900, 1000, " TASTER "); displayBot->blink(2, 900, 1000, " TASTER ");
@@ -102,17 +110,17 @@ bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBo
void setDynSpeedLvl(uint8_t lvlMax = 3){ void setDynSpeedLvl(uint8_t lvlMax = 3){
uint8_t lvl; uint8_t lvl;
//define speed level according to difference //define speed level according to difference
if (lengthRemaining < 50) { if (lengthRemaining < 40) {
lvl = 0; lvl = 0;
} else if (lengthRemaining < 200) { } else if (lengthRemaining < 300) {
lvl = 1; lvl = 1;
} else if (lengthRemaining < 600) { } else if (lengthRemaining < 700) {
lvl = 2; lvl = 2;
} else { //more than last step remaining } else { //more than last step remaining
lvl = 3; lvl = 3;
} }
//limit to max lvl //limit to max lvl
if (lvl > lvlMax){ if (lvl > lvlMax) {
lvl = lvlMax; lvl = lvlMax;
} }
//update vfd speed level //update vfd speed level
@@ -146,7 +154,7 @@ void task_control(void *pvParameter)
//===== loop ===== //===== loop =====
//================ //================
while(1){ while(1){
vTaskDelay(20 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
//----------------------------- //-----------------------------
//------ handle switches ------ //------ handle switches ------
@@ -158,8 +166,15 @@ void task_control(void *pvParameter)
SW_PRESET1.handle(); SW_PRESET1.handle();
SW_PRESET2.handle(); SW_PRESET2.handle();
SW_PRESET3.handle(); SW_PRESET3.handle();
SW_CUT.handle();
SW_AUTO_CUT.handle();
//---------------------------
//------ handle cutter ------
//---------------------------
cutter_handle();
//---------------------------- //----------------------------
//------ rotary encoder ------ //------ rotary encoder ------
@@ -167,39 +182,82 @@ void task_control(void *pvParameter)
// Poll current position and direction // Poll current position and direction
rotary_encoder_get_state(&encoder, &encoderState); rotary_encoder_get_state(&encoder, &encoderState);
//--- calculate distance --- //--- 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; lengthNow = (float)encoderState.position * 1000 / STEPS_PER_METER;
//--------------------------- //---------------------------
//--------- buttons --------- //--------- buttons ---------
//--------------------------- //---------------------------
//TODO: ADD PRESET SWITCHES HERE
//--- RESET switch --- //--- RESET switch ---
if (SW_RESET.risingEdge) { if (SW_RESET.risingEdge) {
rotary_encoder_reset(&encoder); //dont reset when press used for stopping pending auto-cut
lengthNow = 0; if (controlState != systemState_t::AUTO_CUT_WAITING) {
buzzer.beep(1, 700, 100); rotary_encoder_reset(&encoder);
lengthNow = 0;
buzzer.beep(1, 700, 100);
displayTop.blink(2, 100, 100, "1ST ");
//TODO: stop cutter with reset switch?
//cutter_stop();
}
} }
//--- CUT switch ---
//start cut cycle immediately
if (SW_CUT.risingEdge) {
//stop cutter if already running
if (cutter_isRunning()) {
cutter_stop();
buzzer.beep(1, 600, 0);
}
else if (controlState == systemState_t::AUTO_CUT_WAITING) {
//do nothing when press used for stopping pending auto-cut
}
//start cutter when motor not active
else if (controlState != systemState_t::WINDING_START //TODO use vfd state here?
&& controlState != systemState_t::WINDING) {
cutter_start();
buzzer.beep(1, 70, 50);
}
//error cant cut while motor is on
else {
buzzer.beep(6, 100, 50);
}
}
//--- AUTO_CUT toggle sw ---
//beep at change
if (SW_AUTO_CUT.risingEdge) {
buzzer.beep(2, 100, 50);
} else if (SW_AUTO_CUT.fallingEdge) {
buzzer.beep(1, 400, 50);
}
//update enabled state
if (SW_AUTO_CUT.state) {
//enable autocut when not in target_reached state
//(prevent immediate/unexpected cut)
if (controlState != systemState_t::TARGET_REACHED) {
autoCutEnabled = true;
}
} else {
//disable anytime (also stops countdown to auto cut)
autoCutEnabled = false;
}
//--- manual mode --- //--- manual mode ---
//switch to manual motor control (2 buttons + poti) //switch to manual motor control (2 buttons + poti)
if ( SW_PRESET2.state && (SW_PRESET1.state || SW_PRESET3.state) && controlState != MANUAL ) { if ( SW_PRESET2.state && (SW_PRESET1.state || SW_PRESET3.state) && controlState != systemState_t::MANUAL ) {
//enable manual control //enable manual control
changeState(MANUAL); changeState(systemState_t::MANUAL);
buzzer.beep(3, 100, 60); buzzer.beep(3, 100, 60);
} }
//--- set custom target length --- //--- set custom target length ---
//set target length to poti position when SET switch is pressed //set target length to poti position when SET switch is pressed
if (SW_SET.state == true) { if (SW_SET.state == true) {
//read adc //read adc
potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095 potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095
//scale to target length range //scale to target length range
int lengthTargetNew = (float)potiRead / 4095 * 30000; int lengthTargetNew = (float)potiRead / 4095 * 50000;
//apply hysteresis and round to whole meters //TODO optimize this //apply hysteresis and round to whole meters //TODO optimize this
if (lengthTargetNew % 1000 < 200) { //round down if less than .2 meter if (lengthTargetNew % 1000 < 200) { //round down if less than .2 meter
ESP_LOGD(TAG, "Poti input = %d -> rounding down", lengthTargetNew); ESP_LOGD(TAG, "Poti input = %d -> rounding down", lengthTargetNew);
@@ -230,22 +288,22 @@ void task_control(void *pvParameter)
//--- target length presets --- //--- target length presets ---
if (controlState != MANUAL) { //dont apply preset length while controlling motor with preset buttons 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 ");
}
else if (SW_PRESET2.risingEdge) {
lengthTarget = 5000; lengthTarget = 5000;
buzzer.beep(lengthTarget/1000, 25, 30); buzzer.beep(lengthTarget/1000, 25, 30);
displayBot.blink(2, 100, 100, "S0LL "); displayBot.blink(2, 100, 100, "S0LL ");
} }
else if (SW_PRESET3.risingEdge) { else if (SW_PRESET2.risingEdge) {
lengthTarget = 10000; lengthTarget = 10000;
buzzer.beep(lengthTarget/1000, 25, 30); buzzer.beep(lengthTarget/1000, 25, 30);
displayBot.blink(2, 100, 100, "S0LL "); displayBot.blink(2, 100, 100, "S0LL ");
} }
else if (SW_PRESET3.risingEdge) {
lengthTarget = 15000;
buzzer.beep(lengthTarget/1000, 25, 30);
displayBot.blink(2, 100, 100, "S0LL ");
}
} }
@@ -254,17 +312,16 @@ void task_control(void *pvParameter)
//--------- control --------- //--------- control ---------
//--------------------------- //---------------------------
//calculate length difference //calculate length difference
lengthRemaining = lengthTarget - lengthNow; lengthRemaining = lengthTarget - lengthNow + TARGET_LENGTH_OFFSET;
//--- statemachine --- //--- statemachine ---
switch (controlState) { switch (controlState) {
case COUNTING: //no motor action case systemState_t::COUNTING: //no motor action
vfd_setState(false); 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 --- //--- start winding to length ---
if (SW_START.risingEdge) { if (SW_START.risingEdge) {
changeState(WINDING_START); 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_setSpeedLevel(1); //start at low speed
vfd_setState(true); //start motor vfd_setState(true); //start motor
timestamp_motorStarted = esp_log_timestamp(); //save time started timestamp_motorStarted = esp_log_timestamp(); //save time started
@@ -272,57 +329,100 @@ void task_control(void *pvParameter)
} }
break; break;
case WINDING_START: //wind slow for certain time case systemState_t::WINDING_START: //wind slow for certain time
//set vfd speed depending on remaining distance //set vfd speed depending on remaining distance
setDynSpeedLvl(1); //limit to speed lvl 1 (force slow start) setDynSpeedLvl(1); //limit to speed lvl 1 (force slow start)
if (esp_log_timestamp() - timestamp_motorStarted > 2000) { if (esp_log_timestamp() - timestamp_motorStarted > 3000) {
changeState(WINDING); changeState(systemState_t::WINDING);
} }
handleStopCondition(&displayTop, &displayBot); //stops if button released or target reached handleStopCondition(&displayTop, &displayBot); //stops if button released or target reached
//TODO: cancel when there was no cable movement during start time? //TODO: cancel when there was no cable movement during start time?
break; break;
case WINDING: //wind fast, slow down when close 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 setDynSpeedLvl(); //slow down when close to target
handleStopCondition(&displayTop, &displayBot); //stops if button released or target reached 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; break;
case TARGET_REACHED: case systemState_t::TARGET_REACHED:
vfd_setState(false); vfd_setState(false);
//switch to counting state when no longer at or above target length //switch to counting state when no longer at or above target length
if ( lengthRemaining > 0 ) { if ( lengthNow < lengthTarget - TARGET_REACHED_TOLERANCE ) {
changeState(COUNTING); changeState(systemState_t::COUNTING);
}
//switch initiate countdown to auto-cut
else if ( (autoCutEnabled)
&& (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 //show msg when trying to start, but target is reached
if (SW_START.risingEdge){ if (SW_START.risingEdge) {
buzzer.beep(3, 40, 30); buzzer.beep(2, 50, 30);
displayTop.blink(2, 600, 800, " S0LL "); displayTop.blink(2, 600, 500, " S0LL ");
displayBot.blink(2, 600, 800, "ERREICHT"); displayBot.blink(2, 600, 500, "ERREICHT");
} }
break; break;
case MANUAL: //manually control motor via preset buttons + poti case systemState_t::AUTO_CUT_WAITING:
//handle delayed start of cut
cut_msRemaining = autoCut_delayMs - (esp_log_timestamp() - timestamp_changedState);
//- countdown stop conditions -
//stop with any button
if (!autoCutEnabled
|| SW_RESET.state || SW_CUT.state
|| SW_SET.state || SW_PRESET1.state
|| SW_PRESET2.state || SW_PRESET3.state) {//TODO: also stop when target not reached anymore?
changeState(systemState_t::COUNTING);
buzzer.beep(5, 100, 50);
}
//- trigger cut if delay passed -
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
buzzer.beep(1, 50, 0);
timestamp_cut_lastBeep = esp_log_timestamp();
}
break;
case systemState_t::CUTTING:
//exit when finished cutting
if (cutter_isRunning() == false) {
//TODO stop if start buttons released?
changeState(systemState_t::COUNTING);
//TODO reset automatically or wait for manual reset?
rotary_encoder_reset(&encoder);
lengthNow = 0;
buzzer.beep(1, 700, 100);
}
break;
case systemState_t::MANUAL: //manually control motor via preset buttons + poti
//read poti value //read poti value
potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095 potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095
//scale poti to speed levels 0-3 //scale poti to speed levels 0-3
uint8_t level = round( (float)potiRead / 4095 * 3 ); uint8_t level = round( (float)potiRead / 4095 * 3 );
//exit manual mode if preset2 released //exit manual mode if preset2 released
if ( SW_PRESET2.state == false ) { if ( SW_PRESET2.state == false ) {
changeState(COUNTING); changeState(systemState_t::COUNTING);
buzzer.beep(1, 1000, 100); buzzer.beep(1, 1000, 100);
} }
//P2 + P1 -> turn left //P2 + P1 -> turn left
else if ( SW_PRESET1.state && !SW_PRESET3.state ) { else if ( SW_PRESET1.state && !SW_PRESET3.state ) {
vfd_setSpeedLevel(level); //TODO: use poti input for level vfd_setSpeedLevel(level);
vfd_setState(true, REV); vfd_setState(true, REV);
sprintf(buf_disp2, "[--%02i ", level); sprintf(buf_disp2, "[--%02i ", level);
// 123 45 678 // 123 45 678
} }
//P2 + P3 -> turn right //P2 + P3 -> turn right
else if ( SW_PRESET3.state && !SW_PRESET1.state ) { else if ( SW_PRESET3.state && !SW_PRESET1.state ) {
vfd_setSpeedLevel(level); //TODO: use poti input for level vfd_setSpeedLevel(level);
vfd_setState(true, FWD); vfd_setState(true, FWD);
sprintf(buf_disp2, " %02i--]", level); sprintf(buf_disp2, " %02i--]", level);
} }
@@ -364,12 +464,18 @@ void task_control(void *pvParameter)
//-------------------------- //--------------------------
//run handle function //run handle function
displayTop.handle(); displayTop.handle();
//show current position on display //indicate upcoming cut when pending
sprintf(buf_tmp, "1ST %5.4f", (float)lengthNow/1000); if (controlState == systemState_t::AUTO_CUT_WAITING) {
// 123456789 displayTop.blinkStrings(" CUT 1N ", " ", 70, 30);
//limit length to 8 digits + decimal point (drop decimal places when it does not fit) }
sprintf(buf_disp1, "%.9s", buf_tmp); //otherwise show current position
displayTop.showString(buf_disp1); else {
sprintf(buf_tmp, "1ST %5.4f", (float)lengthNow/1000);
// 123456789
//limit length to 8 digits + decimal point (drop decimal places when it does not fit)
sprintf(buf_disp1, "%.9s", buf_tmp);
displayTop.showString(buf_disp1);
}
//-------------------------- //--------------------------
@@ -378,13 +484,23 @@ void task_control(void *pvParameter)
//run handle function //run handle function
displayBot.handle(); displayBot.handle();
//setting target length: blink target length //setting target length: blink target length
if (SW_SET.state == true){ if (SW_SET.state == true) {
sprintf(buf_tmp, "S0LL%5.3f", (float)lengthTarget/1000); sprintf(buf_tmp, "S0LL%5.3f", (float)lengthTarget/1000);
displayBot.blinkStrings(buf_tmp, "S0LL ", 300, 100); displayBot.blinkStrings(buf_tmp, "S0LL ", 300, 100);
} }
//manual state: blink "manual" //manual state: blink "manual"
else if (controlState == MANUAL) { else if (controlState == systemState_t::MANUAL) {
displayBot.blinkStrings(" MANUAL ", buf_disp2, 1000, 1000); displayBot.blinkStrings(" MANUAL ", buf_disp2, 400, 800);
}
//notify that cutter is active
else if (cutter_isRunning()) {
displayBot.blinkStrings("CUTTING]", "CUTTING[", 100, 100);
}
//show ms countdown to cut when pending
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);
} }
//otherwise show target length //otherwise show target length
else { else {
@@ -395,12 +511,24 @@ void task_control(void *pvParameter)
} }
#endif //----------------------------
//------- 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);
}
//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 #endif
//TODO: display or blink "REACHED" when reached state and start pressed
} }

View File

@@ -22,11 +22,14 @@ extern "C"
#include "buzzer.hpp" #include "buzzer.hpp"
#include "vfd.hpp" #include "vfd.hpp"
#include "display.hpp" #include "display.hpp"
#include "cutter.hpp"
typedef enum systemState_t {COUNTING, WINDING_START, WINDING, TARGET_REACHED, MANUAL} systemState_t; //enum describing the state of the system
extern const char* systemStateStr[5]; 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); void task_control(void *pvParameter);

169
main/cutter.cpp Normal file
View File

@@ -0,0 +1,169 @@
#include "cutter.hpp"
const char* cutter_stateStr[5] = {"IDLE", "START", "CUTTING", "CANCELED", "TIMEOUT"}; //define strings for logging the state
//---------------------------
//----- local functions -----
//---------------------------
//declare local functions
void setState(cutter_state_t stateNew);
bool checkTimeout();
//---------------------------
//----- local variables -----
//---------------------------
cutter_state_t cutter_state = cutter_state_t::IDLE;
uint32_t timestamp_turnedOn;
uint32_t msTimeout = 3000;
static const char *TAG = "cutter"; //tag for logging
//=========================
//========= start =========
//=========================
void cutter_start(){
setState(cutter_state_t::START);
//starts motor on state change
}
//========================
//========= stop =========
//========================
void cutter_stop(){
if(cutter_state != cutter_state_t::IDLE){
setState(cutter_state_t::CANCELED);
}
//starts motor on state change
}
//===========================
//===== cutter_getState =====
//===========================
cutter_state_t cutter_getState(){
return cutter_state;
}
//============================
//===== cutter_isRunning =====
//============================
bool cutter_isRunning(){
if (cutter_state == cutter_state_t::START
|| cutter_state == cutter_state_t::CUTTING) {
return true;
} else {
return false;
}
}
//---------------------------
//-------- setState ---------
//---------------------------
//local function for changing state, taking corresponding actions and sending log output
void setState(cutter_state_t stateNew){
//only proceed and send log output when state or direction actually changed
if ( cutter_state == stateNew) {
//already at target state -> do nothing
return;
}
//log old and new state
ESP_LOGI(TAG, "CHANGING state from: %s",cutter_stateStr[(int)cutter_state]);
ESP_LOGI(TAG, "CHANGING state to: %s",cutter_stateStr[(int)stateNew]);
//update stored state
cutter_state = stateNew;
switch(stateNew){
case cutter_state_t::IDLE:
case cutter_state_t::TIMEOUT:
case cutter_state_t::CANCELED:
//--- turn motor off ---
gpio_set_level(GPIO_RELAY, 0);
break;
case cutter_state_t::START:
case cutter_state_t::CUTTING:
//--- turn motor on ---
gpio_set_level(GPIO_RELAY, 1);
//update state, timestamp
timestamp_turnedOn = esp_log_timestamp();
break;
}
}
//--------------------------
//------ checkTimeout ------
//--------------------------
//local function that checks for timeout
bool checkTimeout(){
if (esp_log_timestamp() - timestamp_turnedOn > msTimeout){
setState(cutter_state_t::TIMEOUT);
return true;
} else {
return false;
}
}
//========================
//======== handle ========
//========================
//function that handles the cutter logic -> has to be run repeatedly
void cutter_handle(){
//handle evaluated switch (position switch)
SW_CUTTER_POS.handle();
//TODO add custom thresholds once at initialization?
//SW_CUTTER_POS.minOnMs = 10;
//SW_CUTTER_POS.minOffMs = 10;
switch(cutter_state){
case cutter_state_t::IDLE:
case cutter_state_t::TIMEOUT:
case cutter_state_t::CANCELED:
//wait for state change via cutter_start();
break;
case cutter_state_t::START:
//--- moved away from idle position ---
//if (gpio_get_level(GPIO_CUTTER_POS_SW) == 0){ //contact closed
if (SW_CUTTER_POS.state == true) { //contact closed -> not at idle pos
setState(cutter_state_t::CUTTING);
}
//--- timeout ---
else {
checkTimeout();
}
break;
case cutter_state_t::CUTTING:
//--- idle position reached ---
//if (gpio_get_level(GPIO_CUTTER_POS_SW) == 1){ //contact not closed
//TODO: add min on duration
if (SW_CUTTER_POS.state == false) { //contact open -> at idle pos
setState(cutter_state_t::IDLE);
}
//--- timeout ---
else {
checkTimeout();
}
break;
}
}

37
main/cutter.hpp Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
extern "C"
{
#include <stdio.h>
#include "esp_log.h"
}
#include "buzzer.hpp"
#include "display.hpp"
#include "gpio_evaluateSwitch.hpp"
//--- variables ---
//enum for state of cutter
enum class cutter_state_t {IDLE, START, CUTTING, CANCELED, TIMEOUT};
//string for logging the state name
extern const char* cutter_stateStr[5];
//--- functions ---
//trigger cut cycle (no effect if already running)
void cutter_start();
//cancel cutting action
void cutter_stop();
//return current state
cutter_state_t cutter_getState();
//TODO: bool cutter_isOn() (simply return boolean instead of enum)
//check if cutter is currently operating
bool cutter_isRunning();
//handle function - has to be run repeatedly
void cutter_handle();

View File

@@ -34,7 +34,7 @@ max7219_t display_init(){
ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, DISPLAY_PIN_NUM_CS)); ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, DISPLAY_PIN_NUM_CS));
ESP_ERROR_CHECK(max7219_init(&dev)); ESP_ERROR_CHECK(max7219_init(&dev));
//0...15 //0...15
ESP_ERROR_CHECK(max7219_set_brightness(&dev, 8)); ESP_ERROR_CHECK(max7219_set_brightness(&dev, 8)); //TODO add this to config
return dev; return dev;
//display = dev; //display = dev;
ESP_LOGI(TAG, "initializing display - done"); ESP_LOGI(TAG, "initializing display - done");
@@ -50,7 +50,7 @@ void display_ShowWelcomeMsg(max7219_t dev){
//show name and date //show name and date
ESP_LOGI(TAG, "showing startup message..."); ESP_LOGI(TAG, "showing startup message...");
max7219_clear(&dev); max7219_clear(&dev);
max7219_draw_text_7seg(&dev, 0, "CUTTER 20.08.2022"); max7219_draw_text_7seg(&dev, 0, "CUTTER 29.09.2022");
// 1234567812 34 5678 // 1234567812 34 5678
vTaskDelay(pdMS_TO_TICKS(700)); vTaskDelay(pdMS_TO_TICKS(700));
//scroll "hello" over 2 displays //scroll "hello" over 2 displays
@@ -60,6 +60,11 @@ void display_ShowWelcomeMsg(max7219_t dev){
max7219_draw_text_7seg(&dev, 0, hello + (22 - offset) ); max7219_draw_text_7seg(&dev, 0, hello + (22 - offset) );
vTaskDelay(pdMS_TO_TICKS(50)); vTaskDelay(pdMS_TO_TICKS(50));
} }
//noticed rare bug that one display does not initialize / is not configured correctly after start
//initialize display again after the welcome message in case it did not work the first time
ESP_ERROR_CHECK(max7219_init(&dev));
ESP_ERROR_CHECK(max7219_set_brightness(&dev, 8)); //TODO add this to config
} }

View File

@@ -13,39 +13,42 @@ extern "C"
#include "config.hpp" #include "config.hpp"
#include "control.hpp" #include "control.hpp"
#include "buzzer.hpp" #include "buzzer.hpp"
#include "switchesAnalog.hpp" #include "switchesAnalog.hpp"
//================================= //=================================
//=========== functions =========== //=========== functions ===========
//================================= //=================================
//--- configure output ---
//function to configure gpio pin as output //function to configure gpio pin as output
void gpio_configure_output(gpio_num_t gpio_pin){ void gpio_configure_output(gpio_num_t gpio_pin){
gpio_pad_select_gpio(gpio_pin); gpio_pad_select_gpio(gpio_pin);
gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT); gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
} }
//--- init gpios ---
void init_gpios(){ void init_gpios(){
//initialize all outputs //--- outputs ---
//4x stepper mosfets //4x stepper mosfets
gpio_configure_output(GPIO_VFD_FWD); gpio_configure_output(GPIO_VFD_FWD);
gpio_configure_output(GPIO_VFD_D0); gpio_configure_output(GPIO_VFD_D0);
gpio_configure_output(GPIO_VFD_D1); gpio_configure_output(GPIO_VFD_D1);
gpio_configure_output(GPIO_VFD_REV);
//gpio_configure_output(GPIO_VFD_D2); only used with 7.5kw vfd //gpio_configure_output(GPIO_VFD_D2); only used with 7.5kw vfd
//2x power mosfets //2x power mosfets
gpio_configure_output(GPIO_VFD_REV); gpio_configure_output(GPIO_MOS1); //mos1
gpio_configure_output(GPIO_MOS2); gpio_configure_output(GPIO_LAMP); //llamp (mos2)
//onboard relay and buzzer //onboard relay and buzzer
gpio_configure_output(GPIO_RELAY); gpio_configure_output(GPIO_RELAY);
gpio_configure_output(GPIO_BUZZER); gpio_configure_output(GPIO_BUZZER);
//5v regulator //5v regulator
gpio_configure_output(GPIO_NUM_17); gpio_configure_output(GPIO_NUM_17);
//--- inputs ---
//initialize and configure ADC //initialize and configure ADC
adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096 adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096
adc1_config_channel_atten(ADC_CHANNEL_POTI, ADC_ATTEN_DB_11); //max voltage adc1_config_channel_atten(ADC_CHANNEL_POTI, ADC_ATTEN_DB_11); //max voltage
} }
@@ -53,8 +56,6 @@ void init_gpios(){
//====================================== //======================================
//============ buzzer task ============= //============ 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 ){ void task_buzzer( void * pvParameters ){
ESP_LOGI("task_buzzer", "Start of buzzer task..."); ESP_LOGI("task_buzzer", "Start of buzzer task...");
//run function that waits for a beep events to arrive in the queue //run function that waits for a beep events to arrive in the queue
@@ -64,8 +65,6 @@ void task_buzzer( void * pvParameters ){
//====================================== //======================================
//=========== main function ============ //=========== main function ============
//====================================== //======================================
@@ -90,5 +89,4 @@ extern "C" void app_main()
//beep at startup //beep at startup
buzzer.beep(3, 70, 50); buzzer.beep(3, 70, 50);
} }

View File

@@ -38,11 +38,9 @@ void vfd_setState(bool stateNew, vfd_direction_t directionNew){
gpio_set_level(GPIO_VFD_REV, 1); gpio_set_level(GPIO_VFD_REV, 1);
break; break;
} }
gpio_set_level(GPIO_RELAY, 1);
} else { } else {
gpio_set_level(GPIO_VFD_FWD, 0); gpio_set_level(GPIO_VFD_FWD, 0);
gpio_set_level(GPIO_VFD_REV, 0); gpio_set_level(GPIO_VFD_REV, 0);
gpio_set_level(GPIO_RELAY, 0);
} }
} }

1189
wire-labels.fods Normal file

File diff suppressed because it is too large Load Diff