57 Commits

Author SHA1 Message Date
jonny_ji7
04d9a4e12d Merge branch 'dev' into stepper 2023-04-25 19:07:39 +02:00
jonny_l480
279ac0e07e Add more debug output ISSUES
- Add debug output in calc
- disable test mode for testing with encoder
- set loglevel to DEBUG

extend feature currently only works well in testing mode with buttons
issues when running with encoder:
 movement gets extended extremely often due to encoder travel
 interval and rarely does reach target - compared to trigger with
 buttons
 -> while debugging noticed that the current speed gets negative
 and the xISR gets stuck so moves infinitely or not at all

 ideas:
 - rounding issue?
 - SPEED increment also has to be adjusted or set to 0 as step
   increment?
2023-03-26 11:41:46 +02:00
jonny_l480
1c59e0097b Fix feature: extend movement works now! (test mode)
while currently in stepper test mode the extend feature works as
intended now.
you can trigger movement using the buttons and repeating
presses while still moving (coast, accel or decel) extends the movement
without stopping or accelerating again.

Note reversing the direction while still moving is not handled and results
in immediate direction change and distance that makes no sense.

also added alot of debug output and switched to debug level
2023-03-24 15:05:36 +01:00
jonny_l480
5d7c67ab9a stepper-test: Control stepper with buttons
now the stepper test task controls the stepper using button input
this makes debugging modifications to stepper library easier
2023-03-24 13:22:22 +01:00
jonny_l480
8d2428d285 Stepper: Add calc debug output ISSUES
- sometimes deadlock at direction change
    waits for idle state in runAbs
    function, but stepper is not really moving anymore  ISR does not change
    to idle or state changed afterwards?
- every EXTEND operation results in a motor stop thus when extending
    alot is stopped only ramping up and down
    when encoder stop after several extend attempts
    the stepper moves all the remaining steps successfully
2023-03-13 20:25:10 +01:00
jonny_ji7
dc6deeb3d0 Stepper: rework resume functionality 2023-03-13 20:02:22 +01:00
jonny_l480
0a05340763 revert mutex, fix state reset, logging, slower
stepsRemaining not necessary in ISR
comment out forced stop at runAbs
statusPrev not needed
TODO: ISR defines state every time, no need to adjust manually while running
adjust calc function to handle remaining steps

Test: broken - slow moves mork but when "extending" movement it just
vibrates
2023-03-13 18:26:50 +01:00
jonny_ji7
45409676a0 Stepper: add mutex, logging, delay, less steps
When testing last commit the stepper task crashed almost instantly and
moved randomly. Trying to fix/debug that with those changes
2023-03-13 11:12:42 +01:00
jonny_ji7
de42b6252e Stepper: Add resume/update functionality (WIP)
add way to extend current move operation without having to wait for IDLE
state (full decel time)
2023-03-12 13:06:30 +01:00
jonny_ji7
a0032ea07f Add C-project for simulating axis in commandline
before adding the travelMm function the algorithm for moving the
axis between left and right was designed and evaluated via commandline
first.

-> Add this test-code in this commit
2023-03-02 23:35:24 +01:00
jonny_ji7
9595940004 Merge branch 'dev' into stepper
Hardware works so far
Firmware needs improvement: stepper moves but too jerky also not linked
to control task yet
2023-03-02 23:32:18 +01:00
jonny_ji7
423348be9f Add filter-pcb for denoising stepper signals
When the VFD was running the stepper driver did not work correctly.
The especially the DIR signal got unusable and triggered randomly.

Add custom stripboard that reduces the noise on DIR and PULSE data
lines.
The circuit simply increases the current in the data lines significantly
and crops the voltage to 0-5V using a zener diode.
While testing with an oscilloscope the circuit seems effective.

- add kicad schematic
- add spreadsheet with stripboard layout
- update connection: plan with stripboard, update changed 5V connection
2023-03-02 23:12:52 +01:00
jonny_l480
6c9b1b6fcf Fix rounding, Rework step-calc, Tested
- decrease home speed
- invert direction in stepper test and home function due to changed
  wiring
- stretch travel steps calculation to multiple steps and variables for
  better overview and debugging
- prevent partial steps from being lost -> fixes rounding issue

TESTED: works in general, but steper movement is too jerky. Also there
is a Hardware issue: When VFD/motor is on the steper does not work
properly -> 50ohm pullup near stepper driver fixed this
2023-03-01 18:55:26 +01:00
jonny_l480
4edd1780ea Change max loglevel to VERBOSE 2023-03-01 18:12:55 +01:00
jonny_l480
28889bd912 Swap VFD and Stepper pin, Swap Encoder connection
- update config and connection plan
- swap B+ and B- of encoder to invert the rotational direction,
  so the direction in code make more sense
- swap VFD and stepper pin. For some reason stepper did not work with
  dir pin on mos2. Maybe pulse affected dir pin, try again with denoise
  pcb
2023-03-01 18:08:14 +01:00
jonny_ji7
226aa4794c Switch to and Add travelSteps beside travelMm (WIP)
- optimize some variable and macro names
- change/add function that travels guide certain steps
- stepper task: - calculate steps depending on encoder steps
                - move steps if at least 1 step possible
- prepare poti modifier

-> untested
2023-03-01 12:56:24 +01:00
jonny_ji7
118e9714b5 Add Stepper to connection-plan, Add datasheets
- Add datasheets of VFD and stepper driver
- Change pins in config for stepper driver
    - DISABLED LAMP (pin now used for stepper)
- update connection plan with stepper section and wiring
2023-03-01 08:35:19 +01:00
jonny_ji7
ac4ca5450a Fix variable scopes (static), Simplify encoder
- add static type to all local variables in every source file
  so the scope of each variable is limited to that file.
  This prevents conflicting variable names with other source file
  (e.g. 'state' variable in vfd.cpp)

- simplify encoder concept
  wrap all used functions from rotary_encoder.h library in
  custom encoder.hpp file
   -> only one file has to be included where encoder is used
   -> global variable 'encoder' is not necessary anymore
   -> reduces duplicate code for length calculation
- update all files where encoder functions where used accordingly
2023-03-01 01:00:16 +01:00
jonny_ji7
5dd392586d Outsource encoder code to encoder.cpp
To be able to use the encoder in future stepper task as well
- make certain variables global
- initialize encoder in main
- outsorce encoder functions in encoder.cpp / h
- adjust config
2023-03-01 00:09:29 +01:00
jonny_ji7
74adcbc78a Adjust test-params, CAD: enforce axis-mount
While testing the setup
Optimizations of problems noticed while testing the setup:
    - mount too weak
    - only very slow speeds relevant
    - less distance required
2023-02-27 11:38:37 +01:00
jonny_ji7
06ebb1fbc6 Fix include order for compatibility
including the files in source file instead of header file fixed
'conflicting type' errors in idf macros when using newer version
ESP-IDF v4.4.4-148-g4c2afac355
2023-02-22 17:23:37 +01:00
jonny_ji7
3d4f327832 Add cad file (axis mounts)
This file currently contains
  - crude model of linear-axis
  - angled bracket for mounting the axis to item
  - 2 versions of interface between rolls and axis
  - rolls
2023-02-21 21:36:59 +01:00
jonny_ji7
58c5a92d1e Add functional STEPPER_TEST feature
- add macro variable STEPPER_TEST (config.hpp)
    if set: only `task_stepper-test` is started (main.cpp)
- add file for stepper/guide related code (guide-stepper.cpp/hpp)
    currently defines a task that simply moves the axis left to right
    repeatedly with a speed defined by a potentiometer connected to ADC
    GPIO34
2023-02-21 21:27:33 +01:00
jonny_ji7
2651a83ce7 Add stepper library for esp-idf 2023-02-21 21:14:16 +01:00
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
3a99b8bc5c Adjust analog-sw thresholds, Disable logging (loglevel)
=> tested system with new stripboard and actual hardware: system
works as expected with new all combinations of the 4 switches
connected to 1 adc

- Adjust lookup voltage for switch combinations, after connecting the
stripboard to actualy used pcb (apparently there was a >100
difference using an other adc channel + pcb)

- define loglevel for analogswitches to WARN
2022-09-12 13:19:54 +02:00
jonny_ji7
451981b165 Rework switch-assignment, Update connection-plan
Rework config.cpp and config.hpp:
 - different naming convention for evaluated switch objects
 - thus updated macros for switches

 - add new evalswitch instances for 4 switches on 1 adc
 - update switch assignment, use the 4 new inputs

Update connection plan with new assignment, add stripboard details
2022-09-12 11:50:45 +02:00
jonny_ji7
1f53fabd19 Create gpio_adc component - outsource readAdc()
remove duplicate code:
function readAdc was used in multiple files, outsourced this to gpio
component
2022-09-12 11:19:47 +02:00
jonny_ji7
d2d85952df Add evalSwitch instance for sw on adc (testing)
Test all new changes in switchesAnalog and evaluatedSwitch
2022-09-12 09:58:08 +02:00
jonny_ji7
38ad266488 Remove public handle func, add getState functions
switchesAnalog:
- Add functions for obtaining states from each switch
- Remove public handle function, (now run locally at each state request of
a pin)

- adjust main.cpp to work with new functions
2022-09-12 09:57:22 +02:00
jonny_ji7
a932460924 EvalSwitch: Add func as source, remove dupl code
evaluatedSwitch component:
- remove duplicate code for inverted and non-inverted mode
- add new constructor for instance with a function to obtain current
  input state instead of gpio pin (e.g. needed for 4switches on analog input)
2022-09-12 09:47:06 +02:00
jonny_ji7
09ee67f583 Add code for demuxing 4 switch signals from adc pin
- create new files with code for demultiplexing the 4 switches from the
  one analog signal
- define lookup table with measurements done with the build pcb, test
  switches and esp32 breakout board
- add note do config that gpio used for digital in is now used for
  this multiplexer
- main.cpp: disable control task, run new handle function in a loop for
  testing
2022-09-11 19:58:13 +02:00
jonny_ji7
f52a58aa1c Add schematic, layout, calculations for 4swToAdc
Add details and calculations for a stripboard with a resistor network that makes it
possible to connect 4 switches (to gnd) to one adc pin of the controller
2022-09-11 19:53:57 +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
jonny_ji7
7eb06fe228 Add wire-cutter to connection-plan and function-diagram 2022-09-04 11:56:32 +02:00
100 changed files with 9153 additions and 309 deletions

1
.gitattributes vendored Normal file
View File

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

6
.gitignore vendored
View File

@@ -7,3 +7,9 @@ build
# drawio files # drawio files
*.bkp *.bkp
# freecad backup files
*.FCStd1
# kicad backup files
pcb/*/*backups/

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.

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.

View File

@@ -0,0 +1 @@
idf_component_register(SRCS DendoStepper.cpp INCLUDE_DIRS include)

View File

@@ -0,0 +1,448 @@
#include "DendoStepper.h"
#include "esp_log.h"
#define STEP_DEBUG
#ifdef STEP_DEBUG
#define STEP_LOGI(...) ESP_LOGI(__VA_ARGS__)
#define STEP_LOGW(...) ESP_LOGW(__VA_ARGS__)
#define STEP_LOGE(...) ESP_LOGE(__VA_ARGS__)
#else
#define STEP_LOGI(...) while (0)
#define STEP_LOGW(...) while (0)
#define STEP_LOGE(...) ESP_LOGE(__VA_ARGS__)
#endif
bool state = 0;
// PUBLIC definitions
DendoStepper::DendoStepper()
{
}
void DendoStepper::config(DendoStepper_config_t *config)
{
memcpy(&conf, config, sizeof(conf));
}
void DendoStepper::disableMotor()
{
setEn(true);
STEP_LOGI("DendoStepper", "Disabled");
ctrl.status = DISABLED;
}
void DendoStepper::enableMotor()
{
setEn(false);
ctrl.status = IDLE;
STEP_LOGI("DendoStepper", "Enabled");
timerStarted = 0;
}
void DendoStepper::init(uint8_t stepP, uint8_t dirP, uint8_t enP, timer_group_t group, timer_idx_t index, microStepping_t microstepping = MICROSTEP_1, uint16_t stepsPerRot = 200)
{
conf.stepPin = stepP;
conf.dirPin = dirP;
conf.enPin = enP;
conf.timer_group = group;
conf.timer_idx = index;
conf.miStep = microstepping;
ctrl.status = 0;
init();
}
void DendoStepper::init()
{
ESP_LOGW("DendoStepper", "semaphore init");
semaphore_isrVariables = xSemaphoreCreateBinary();
xSemaphoreGive(semaphore_isrVariables);
uint64_t mask = (1ULL << conf.stepPin) | (1ULL << conf.dirPin) | (1ULL << conf.enPin); // put output gpio pins in bitmask
gpio_config_t gpio_conf = {
// config gpios
.pin_bit_mask = mask,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
// set the gpios as per gpio_conf
ESP_ERROR_CHECK(gpio_config(&gpio_conf));
timer_config_t timer_conf = {
.alarm_en = TIMER_ALARM_EN, // we need alarm
.counter_en = TIMER_PAUSE, // dont start now lol
.intr_type = TIMER_INTR_LEVEL, // interrupt
.counter_dir = TIMER_COUNT_UP, // count up duh
.auto_reload = TIMER_AUTORELOAD_EN, // reload pls
.divider = 80000000ULL / TIMER_F, // ns resolution
};
// calculate stepsPerRot
ctrl.stepsPerRot = (360.0 / conf.stepAngle) * conf.miStep;
STEP_LOGI("DendoStepper", "Steps per one rotation:%d", ctrl.stepsPerRot);
if (conf.timer_group != TIMER_GROUP_MAX && conf.timer_idx != TIMER_MAX)
{
// timer was configured explixitly in config structure, we dont need to do it here
goto timer_avail;
}
// try to find free timer
timer_config_t temp;
for (int i = 0; i < 1; i++)
{
for (int j = 0; j < 1; j++)
{
timer_get_config((timer_group_t)i, (timer_idx_t)j, &temp);
if (temp.alarm_en == TIMER_ALARM_DIS)
{
// if the alarm is disabled, chances are no other dendostepper instance is using it
conf.timer_group = (timer_group_t)i;
conf.timer_idx = (timer_idx_t)j;
goto timer_avail;
}
}
}
// if we got here it means that there isnt any free timer available
STEP_LOGE("DendoStepper", "No free timer available, this stepper wont work");
return;
timer_avail:
ESP_ERROR_CHECK(timer_init(conf.timer_group, conf.timer_idx, &timer_conf)); // init the timer
ESP_ERROR_CHECK(timer_set_counter_value(conf.timer_group, conf.timer_idx, 0)); // set it to 0
ESP_ERROR_CHECK(timer_isr_callback_add(conf.timer_group, conf.timer_idx, xISRwrap, this, 0)); // add callback fn to run when alarm is triggrd
}
esp_err_t DendoStepper::runPos(int32_t relative)
{
//TODO only enable when actually moving
if (ctrl.status == DISABLED) // if motor is disabled, enable it
enableMotor();
setDir(relative < 0); // set CCW if <0, else set CW
if (!relative) // why would u call it with 0 wtf
return ESP_ERR_NOT_SUPPORTED;
if (ctrl.status > IDLE) { //currently moving
//ctrl.status = ctrl.status==COAST ? COAST : ACC; //stay at coast otherwise switch to ACC
ctrl.stepsRemaining = ctrl.stepsToGo - ctrl.stepCnt;
calc(abs(relative) + ctrl.stepsRemaining); //calculate new velolcity profile for new+remaining steps
ESP_LOGW("DendoStepper", "EXTEND running movement (stepsRemaining: %d + stepsNew: %d - current state: %d)", ctrl.stepsRemaining, abs(relative), (int)ctrl.status);
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
}
else { //current state is IDLE
//ctrl.statusPrev = ctrl.status; //update previous status
calc(abs(relative)); // calculate velocity profile
ctrl.status = ACC;
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
ESP_ERROR_CHECK(timer_start(conf.timer_group, conf.timer_idx)); // start the timer
}
//printf("runpos end -- steps: %d, status: %d, olddir: %d, newdir: %d\n", relative, ctrl.status, ctrl.dir, newDir);
currentPos += relative; //(target position / not actual)
return ESP_OK;
}
esp_err_t DendoStepper::runPosMm(int32_t relative)
{
if (ctrl.stepsPerMm == 0)
{
STEP_LOGE("DendoStepper", "Steps per millimeter not set, cannot move!");
}
return runPos(relative * ctrl.stepsPerMm);
}
//customized: if already running and direction is the same immediately pass to runPos
esp_err_t DendoStepper::runAbs(uint32_t position)
{
//exit if nothing to do
if (position == currentPos) return 0; //already at position
//calculate steps necessary
int32_t relativeSteps = 0;
relativeSteps = (int32_t)position - currentPos;
//wait if direction needs to change
if (getState() > IDLE){//already moving
bool newDir = (relativeSteps < 0); // CCW if <0, else set CW
if (ctrl.dir != newDir){ //direction differs
STEP_LOGE("DendoStepper", "DIRECTION HOT-CHANGE NOT SUPPORTED - Waiting for move to finish...");
while (getState() > IDLE) vTaskDelay(5); //wait for move to finish
}
}
//call runPos with new target position
ESP_LOGI("DendoStepper", "Cur: %llu move %d", currentPos, relativeSteps);
return runPos(relativeSteps); // run to new position
}
esp_err_t DendoStepper::runAbsMm(uint32_t position)
{
if (ctrl.stepsPerMm == 0)
{
STEP_LOGE("DendoStepper", "Steps per millimeter not set, cannot move!");
}
return runAbs(position * ctrl.stepsPerMm);
}
void DendoStepper::setSpeed(uint32_t speed, uint16_t accT, uint16_t decT)
{
ctrl.speed = speed;
ctrl.acc = ctrl.speed / (accT / 4000.0);
ctrl.dec = ctrl.speed / (decT / 4000.0);
STEP_LOGI("DendoStepper", "Speed set: %d steps/s t+=%d s t-=%d s", speed, accT, decT);
}
void DendoStepper::setSpeedMm(uint32_t speed, uint16_t accT, uint16_t decT)
{
if (ctrl.stepsPerMm == 0)
{
STEP_LOGE("DendoStepper", "Steps per millimeter not set, cannot set the speed!");
}
ctrl.speed = speed * ctrl.stepsPerMm;
ctrl.acc = ctrl.speed / (accT / 4000.0);
ctrl.dec = ctrl.speed / (decT / 4000.0);
STEP_LOGI("DendoStepper", "Speed set: v=%d mm/s t+=%d s t-=%d s", speed, accT, decT);
}
//CUSTOM - change speed while running
//FIXME: this approach does not work, since calc function would have to be run after change, this will mess up target steps...
//void DendoStepper::changeSpeed(uint32_t speed)
//{
// //TODO reduce duplicate code (e.g. call setSpeed function)
// //change speed
// ctrl.speed = speed;
// //change status to ACC/DEC
// STEP_LOGI("DendoStepper", "Speed changed: from v=%.2f rad/s to v=%.2f rad/s", ctrl.speed, speed);
// if (speed > ctrl.speed) ctrl.status = ACC;
// if (speed < ctrl.speed) ctrl.status = DEC;
//}
//
//void DendoStepper::changeSpeedMm(uint32_t speed)
//{
// //TODO reduce duplicate code (e.g. call setSpeedMm function)
// if (ctrl.stepsPerMm == 0)
// {
// STEP_LOGE("DendoStepper", "Steps per millimeter not set, cannot set the speed!");
// }
// //calc new speed
// float speedNew = speed * ctrl.stepsPerMm;
// //change status to ACC/DEC
// if (speedNew > ctl.speed) ctrl.status = ACC;
// if (speedNew < ctl.speed) ctrl.status = DEC;
// //update speed, log output
// ctrl.speed = speedNew;
// STEP_LOGI("DendoStepper", "Speed changed: from v=%.2f rad/s to v=%.2f rad/s", ctrl.speed, speedNew);
//}
void DendoStepper::setStepsPerMm(uint16_t steps)
{
ctrl.stepsPerMm = steps;
}
uint16_t DendoStepper::getStepsPerMm()
{
return ctrl.stepsPerMm;
}
uint8_t DendoStepper::getState()
{
return ctrl.status;
}
uint64_t DendoStepper::getPosition()
{
return currentPos;
}
uint64_t DendoStepper::getPositionMm()
{
return getPosition() / ctrl.stepsPerMm;
}
void DendoStepper::resetAbsolute()
{
currentPos = 0;
}
void DendoStepper::runInf(bool direction)
{
if (ctrl.status > IDLE)
{
STEP_LOGE("DendoStepper", "Motor is moving, this command will be ignored");
return;
}
if (ctrl.status == DISABLED)
{
enableMotor();
}
ctrl.runInfinite = true;
setDir(direction);
calc(UINT32_MAX);
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
ESP_ERROR_CHECK(timer_start(conf.timer_group, conf.timer_idx)); // start the timer
}
uint16_t DendoStepper::getSpeed()
{
return ctrl.speed;
}
float DendoStepper::getAcc()
{
return ctrl.acc;
}
void DendoStepper::stop()
{
if (ctrl.status <= IDLE)
{
return;
}
ctrl.runInfinite = false;
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = IDLE;
ctrl.stepCnt = 0;
gpio_set_level((gpio_num_t)conf.stepPin, 0);
}
// PRIVATE definitions
void DendoStepper::setEn(bool state)
{
ESP_ERROR_CHECK(gpio_set_level((gpio_num_t)conf.enPin, state));
}
void DendoStepper::setDir(bool state)
{
ctrl.dir = state;
ESP_ERROR_CHECK(gpio_set_level((gpio_num_t)conf.dirPin, state));
}
/* Timer callback, used for generating pulses and calculating speed profile in real time */
bool DendoStepper::xISR()
{
GPIO.out_w1ts = (1ULL << conf.stepPin);
// add and substract one step
ctrl.stepCnt++;
////CUSTOM: track actual precice current position
//if (ctrl.dir) {
// ctrl.posActual ++;
//} else {
// ctrl.posActual --;
//}
//CUSTOM: track remaining steps for eventually resuming
//xSemaphoreTake(semaphore_isrVariables, portMAX_DELAY);
//ctrl.stepsRemaining = ctrl.stepCnt - ctrl.stepCnt;
//xSemaphoreGive(semaphore_isrVariables);
// we are done
if (ctrl.stepsToGo == ctrl.stepCnt && !ctrl.runInfinite)
{
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = IDLE;
ctrl.stepCnt = 0;
return 0;
}
if (ctrl.stepCnt > 0 && ctrl.stepCnt < ctrl.accEnd)
{ // we are accelerating
ctrl.currentSpeed += ctrl.accInc;
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = ACC; // we are accelerating, note that*/
}
else if (ctrl.stepCnt > ctrl.coastEnd && !ctrl.runInfinite)
{ // we must be deccelerating then
ctrl.currentSpeed -= ctrl.decInc;
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = DEC; // we are deccelerating
}
else
{
ctrl.currentSpeed = ctrl.targetSpeed;
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = COAST; // we are coasting
}
ctrl.stepInterval = TIMER_F / ctrl.currentSpeed;
// set alarm to calculated interval and disable pin
GPIO.out_w1tc = (1ULL << conf.stepPin);
timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval);
return 1;
}
void DendoStepper::calc(uint32_t targetSteps)
{
//only set initial speed if IDLE
if(ctrl.status == 1){
ctrl.currentSpeed = 0;
ESP_LOGD("DendoStepper", "calc-start: reset speed to 0 (start from idle) %lf\n", ctrl.currentSpeed);
}
else{
ESP_LOGD("DendoStepper", "calc start: NOT resetting speed (extend from ACC/DEC/COAST): %lf\n", ctrl.currentSpeed);
}
//CUSTOM reset counter if already moving
ctrl.stepCnt = 0; //FIXME bugs when set 0 while ISR reads/runs? mutex
//steps from ctrl.speed -> 0:
ctrl.decSteps = 0.5 * ctrl.dec * (ctrl.speed / ctrl.dec) * (ctrl.speed / ctrl.dec);
ESP_LOGD("DendoStepper", "decSteps: %d currspeed: %lf, ctrlSpeed: %lf\n", ctrl.decSteps, ctrl.currentSpeed, ctrl.speed);
//steps from 0 -> ctrl.speed:
//ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc);
//steps from ctrl.currentSpeed -> ctrl.speed:
ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc) * (ctrl.speed - ctrl.currentSpeed) / ctrl.speed;
ESP_LOGD("DendoStepper", "accSteps: %d currspeed: %lf, ctrlSpeed: %lf\n", ctrl.accSteps, ctrl.currentSpeed, ctrl.speed);
if (targetSteps < (ctrl.decSteps + ctrl.accSteps))
{
ESP_LOGI("Dendostepper", "Computing new speed");
ctrl.speed = sqrt(2 * targetSteps * ((ctrl.dec * ctrl.acc) / (ctrl.dec + ctrl.acc)));
//ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc);
ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc) * (ctrl.speed - ctrl.currentSpeed) / ctrl.speed;
ctrl.decSteps = 0.5 * ctrl.dec * (ctrl.speed / ctrl.dec) * (ctrl.speed / ctrl.dec);
}
ctrl.accEnd = ctrl.accSteps;
ctrl.coastEnd = targetSteps - ctrl.decSteps;
ctrl.targetSpeed = ctrl.speed;
ctrl.accInc = (ctrl.targetSpeed - ctrl.currentSpeed) / (double)ctrl.accSteps;
ctrl.decInc = ctrl.targetSpeed / (double)ctrl.decSteps;
//only set initial speed if IDLE
if(ctrl.status == 1){
ctrl.currentSpeed = ctrl.accInc;
ESP_LOGD("DendoStepper", "`reset curr speeed to accinc: %lf\n", ctrl.currentSpeed);
ESP_LOGD("DendoStepper", "status=%d setting speed to initial value: %lf\n",ctrl.status, ctrl.currentSpeed);
}
else{
ESP_LOGD("DendoStepper", "status=%d NOT resetting speed to initial value %lf\n",ctrl.status, ctrl.currentSpeed);
}
ctrl.stepInterval = TIMER_F / ctrl.currentSpeed;
ctrl.stepsToGo = targetSteps;
//debug log output
ESP_LOGD("DendoStepper", "accSteps: %d, accInc: %lf, decSteps: %d, decInc: %lf",
ctrl.accSteps, ctrl.accInc, ctrl.decSteps, ctrl.decInc);
ESP_LOGD("DendoStepper", "speedNow=%.1f, speedTarget=%.1f, accEnd=%d, coastEnd=%d, accSteps=%d, accInc=%.3f\n",
ctrl.currentSpeed, ctrl.targetSpeed, ctrl.accEnd, ctrl.coastEnd, ctrl.accSteps, ctrl.accInc);
ESP_LOGD("DendoStepper", "acc end:%u coastend:%u stepstogo:%u speed:%f acc:%f int: %u",
ctrl.accEnd, ctrl.coastEnd, ctrl.stepsToGo, ctrl.speed, ctrl.acc, ctrl.stepInterval);
}

View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@@ -0,0 +1,139 @@
# DendoStepper
Work in progress, maybe unstable. Opening issues is more than welcome.
This library takes care of pulse generating for stepper motor drivers with STEP/DIR interface. Pulse generating utilizes general purpose timers to achieve some usable accuracy and smoothness.
Currently supports only linear acceleration and deceleration.
### Known limitations
- maximum number of controlled stepper motors is 4, this is limited by number of general purpose timers
- If the motor is moving, it is not possible to move it to another direction.
## Usage
```c++
typedef struct
{
uint8_t stepPin; /** step signal pin */
uint8_t dirPin; /** dir signal pin */
uint8_t enPin; /** enable signal pin */
timer_group_t timer_group; /** timer group, useful if we are controlling more than 2 steppers */
timer_idx_t timer_idx; /** timer index, useful if we are controlling 2steppers */
microStepping_t miStep; /** microstepping configured on driver - used in distance calculation */
float stepAngle; /** one step angle in degrees (usually 1.8deg), used in steps per rotation calculation */
} DendoStepper_config_t;
enum microStepping_t
{
MICROSTEP_1 = 0x1,
MICROSTEP_2,
MICROSTEP_4 = 0x4,
MICROSTEP_8 = 0x8,
MICROSTEP_16 = 0x10,
MICROSTEP_32 = 0x20,
MICROSTEP_64 = 0x40,
MICROSTEP_128 = 0x80,
MICROSTEP_256 = 0x100,
};
```
Configuration struct, can be allocated on stack or heap.
```c++
void init();
```
Initializes GPIO and Timer peripherals, registers ISR. Expects populated config struct is alreay passed to the class using config()
```c++
void config(DendoStepper_config_t* config);
```
Configures the class as per passed config struct pointer.
```c++
void setStepsPerMm(uint16_t steps);
uint16_t getStepsPerMm();
```
Sets or gets steps needed to move one millimiter, useful if stepper is moving along linear axis.
```c++
void setSpeed(uint16_t speed,uint16_t accT, uint16_t decT);
uint16_t getSpeed();
float getAcc();
```
Sets maximum speed in steps per second, acceleration and deceleration time in milliseconds.
Gets speed in steps per second
Gets acceleration in steps per second per second
```c++
void setSpeedMm(uint16_t speed,uint16_t accT, uint16_t decT);
```
Sets maximum speed in mm/s, acceleration and deceleration time in milliseconds. Expects already defined steps per millimeter with setStepsPerMm()
```c++
void runPos(int32_t relative);
```
Runs motor to position relative from current position in steps, respecting constraints set with setSpeed()
```c++
void runPosMm(int32_t relative);
```
Runs motor to position relative from current position in millimeters, respecting constraints set with setSpeed()
Expects already defined steps per millimeter with setStepsPerMm()
```c++
bool runAbsolute(uint32_t position);
```
Runs motor in absolute coordinate plane. Unit: steps (should be constrained with home switch)
```c++
bool runAbsoluteMm(uint32_t position);
```
Runs motor in absolute coordinate plane. Unit: millimeters (should be constrained with home switch)
Expects already defined steps per millimeter with setStepsPerMm()
```c++
bool runInf(bool direction);
```
Runs motor infintely in desired direction with constrains set using setSpeed().
```c++
void disableMotor();
void enableMotor();
```
Disables and enables motor via EN pin
```c++
uint8_t getState();
enum motor_status{
DISABLED,
IDLE,
ACC,
COAST,
DEC,
};
```
Returns current state of motor, return type is enum motor_status
```c++
void resetAbsolute();
```
Resets absolute position to 0. Called for ex. when endswitch is hit.
```c++
void getPosition();
```
Gets current position in absolute coordinate plane in steps.
```c++
void getPositionMm();
```
Gets current position in absolute coordinate plane in millimeters.
Expects already defined steps per millimeter with setStepsPerMm()
```c++
void stop();
```
Stops the motor dead on the spot. No deceleration is performed this way. Eg. e-stop.

View File

View File

@@ -0,0 +1,3 @@
build/
sdkconfig
sdkconfig.old

View File

@@ -0,0 +1,9 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "../")
project(example)

View File

@@ -0,0 +1,32 @@
# _Sample project_
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This is the simplest buildable example. The example is used by command `idf.py create-project`
that copies the project to user specified path and set it's name. For more information follow the [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)
## How to use example
We encourage the users to use the example as a template for the new projects.
A recommended way is to follow the instructions on a [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project).
## Example folder contents
The project **sample_project** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt`
files that provide set of directives and instructions describing the project's source files and targets
(executable, library, or both).
Below is short explanation of remaining files in the project folder.
```
├── CMakeLists.txt
├── main
│   ├── CMakeLists.txt
│   └── main.c
└── README.md This is the file you are currently reading
```
Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system.
They are not used or needed when building with CMake and idf.py.

View File

@@ -0,0 +1,3 @@
idf_component_register(SRCS "main.cpp"
INCLUDE_DIRS "."
REQUIRES DendoStepper freertos)

View File

@@ -0,0 +1,49 @@
#include <stdio.h>
#include "DendoStepper.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
DendoStepper step;
DendoStepper step1;
extern "C" void app_main(void)
{
DendoStepper_config_t step_cfg = {
.stepPin = 16,
.dirPin = 17,
.enPin = 15,
.timer_group = TIMER_GROUP_0,
.timer_idx = TIMER_0,
.miStep = MICROSTEP_32,
.stepAngle = 1.8};
DendoStepper_config_t step1_cfg = {
.stepPin = 18,
.dirPin = 19,
.enPin = 20,
.timer_group = TIMER_GROUP_0,
.timer_idx = TIMER_1,
.miStep = MICROSTEP_32,
.stepAngle = 1.8};
step.config(&step_cfg);
step1.config(&step1_cfg);
step.init();
step1.init();
step.setSpeed(10000, 1000, 1000);
step1.setSpeed(20000, 1000, 1000);
// step.runInf(true);
step.setStepsPerMm(10);
while (1)
{
step.runPosMm(500);
step1.runPos(10000);
vTaskDelay(1000);
// step.runAbs(5000);
}
}

View File

@@ -0,0 +1,283 @@
#pragma once
/* ESP-IDF library for bipolar stepper motor drivers with STEP/DIR interface
Copyright (C) 2022 Denis Voltmann
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef DENDOSTEPPER_H
#define DENDOSTEPPER_H
#include "stdint.h"
#include "stdio.h"
#include <cstring>
#include "driver/timer.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "math.h"
#include "freertos/semphr.h"
//#define STEP_DEBUG
#define NS_TO_T_TICKS(x) (x)
#define TIMER_F 1000000ULL
#define TICK_PER_S TIMER_F
enum motor_status
{
DISABLED,
IDLE,
ACC,
COAST,
DEC
};
enum dir
{
CW,
CCW
};
enum microStepping_t
{
MICROSTEP_1 = 0x1,
MICROSTEP_2,
MICROSTEP_4 = 0x4,
MICROSTEP_8 = 0x8,
MICROSTEP_16 = 0x10,
MICROSTEP_32 = 0x20,
MICROSTEP_64 = 0x40,
MICROSTEP_128 = 0x80,
MICROSTEP_256 = 0x100,
};
/**
* @brief Configuration structure
*/
typedef struct
{
uint8_t stepPin; /** step signal pin */
uint8_t dirPin; /** dir signal pin */
uint8_t enPin; /** enable signal pin */
timer_group_t timer_group; /** timer group, useful if we are controlling more than 2 steppers */
timer_idx_t timer_idx; /** timer index, useful if we are controlling 2steppers */
microStepping_t miStep; /** microstepping configured on driver - used in distance calculation */
float stepAngle; /** one step angle in degrees (usually 1.8deg), used in steps per rotation calculation */
} DendoStepper_config_t;
typedef struct
{
uint32_t stepInterval = 40000; // step interval in ns/25
double targetSpeed = 0; // target speed in steps/s
double currentSpeed = 0;
double accInc = 0;
double decInc = 0;
uint32_t stepCnt = 0; // step counter
uint32_t accEnd; // when to end acc and start coast
uint32_t coastEnd; // when to end coast and start decel
uint32_t stepsToGo = 0; // steps we need to take
float speed = 100; // speed in rad/s
float acc = 100; // acceleration in rad*second^-2
float dec = 100; // decceleration in rad*second^-2
uint32_t accSteps = 0;
uint32_t decSteps = 0;
int32_t stepsRemaining = 0;
//uint64_t posActual = 0; //actual current pos incremented at every step
uint8_t statusPrev = DISABLED; //FIXME currently unused
uint8_t status = DISABLED;
bool dir = CW;
bool runInfinite = false;
uint16_t stepsPerRot; // steps per one revolution, 360/stepAngle * microstep
uint16_t stepsPerMm = 0; /** Steps per one milimiter, if the motor is performing linear movement */
} ctrl_var_t;
class DendoStepper
{
private:
DendoStepper_config_t conf;
ctrl_var_t ctrl;
esp_timer_handle_t dyingTimer;
TaskHandle_t enTask;
SemaphoreHandle_t semaphore_isrVariables = NULL;
uint64_t currentPos = 0; // absolute position
bool timerStarted = 0;
/** @brief PRIVATE: Step interval calculation
* @param speed maximum movement speed
* @param accTimeMs acceleration time in ms
* @param target target position
*/
void calc(uint32_t);
/** @brief sets En GPIO
* @param state 0-LOW,1-HIGH
* @return void
*/
void setEn(bool);
/** @brief sets Dir GPIO
* @param state 0-CW 1-CCW
*/
void setDir(bool);
/** @brief static wrapper for ISR function
* @param _this DendoStepper* this pointer
* @return bool
*/
static bool xISRwrap(void *_this)
{
return static_cast<DendoStepper *>(_this)->xISR();
}
/** @brief enableMotor wrapper
*/
static void _disableMotor(void *_this)
{
static_cast<DendoStepper *>(_this)->disableMotor();
}
bool xISR();
public:
/** @brief Costructor - conf variables to be passed later
*/
DendoStepper();
/** @brief Configuration of library, used with constructor w/o params
* @param config DendoStepper_config_t structure pointer - can be freed after this call
*/
void config(DendoStepper_config_t *config);
/** @brief initialize GPIO and Timer peripherals
* @param stepP step pulse pin
* @param dirP direction signal pin
* @param enP enable signal Pin
* @param group timer group to use (0 or 1)
* @param index which timer to use (0 or 1)
* @param microstepping microstepping performed by the driver, used for more accuracy
* @param stepsPerRot how many steps it takes for the motor to move 2Pi rads. this can be also used instead of microstepping parameter
*/
void init(uint8_t, uint8_t, uint8_t, timer_group_t, timer_idx_t, microStepping_t microstep, uint16_t stepsPerRot);
/** @brief initialize GPIO and Timer peripherals, class must be configured beforehand with @attention config()
*/
void init();
/** @brief runs motor to relative position in steps
* @param relative number of steps to run, negative is reverse
*/
esp_err_t runPos(int32_t relative);
/** @brief runs motor to relative position in mm
* @param relative number of mm to run, negative is reverse
*/
esp_err_t runPosMm(int32_t relative);
/** @brief run motor to position in absolute coordinates (steps)
* @param postition absolute position in steps from home position (must be positive);
* @return ESP_OK if motor can run immediately, ESP_ERR if it is currently moving
*/
esp_err_t runAbs(uint32_t position);
/** @brief run motor to position in absolute coordinates (millimiters)
* @param postition absolute position in mm from home position (must be positive);
* @return ESP_OK if motor can run immediately, ESP_ERR if it is currently moving
*/
esp_err_t runAbsMm(uint32_t position);
/** @brief sets motor speed
* @param speed speed in steps per second
* @param accT acceleration time in ms
* @param decT deceleration time in ms
*/
void setSpeed(uint32_t speed, uint16_t accT, uint16_t decT);
/** @brief sets motor speed and accel in millimeters/second
* @param speed speed mm*s^-1
* @param accT acceleration time in ms
* @param accT deceleration time in ms
*/
void setSpeedMm(uint32_t speed, uint16_t accT, uint16_t decT);
//CUSTOM: change speed while running
void changeSpeedMm(uint32_t speed);
/**
* @brief Set steps per 1 mm of linear movement
*
* @param steps steps needed to move one millimiter
*/
void setStepsPerMm(uint16_t steps);
/**
* @brief get steps per 1mm settings
*
*/
uint16_t getStepsPerMm();
/** @brief set EN pin 1, stops movement
*/
void disableMotor();
/** @brief set EN pin to 0, enables movement
*/
void enableMotor();
/** @brief returns current state
* @return motor_status enum
*/
uint8_t getState();
/** @brief run motor to position in absolute coordinates (millimiters)
* @param postition absolute position in steps from home position (must be positive);
* @return ESP_OK if motor can run immediately, ESP_ERR if it is currently moving
*/
esp_err_t runAbsoluteMm(uint32_t position);
/** @brief returns current absolute position
* @return current absolute postion in steps
*/
uint64_t getPosition();
/** @brief returns current absolute position
* @return current absolute postion in steps
*/
uint64_t getPositionMm();
/** @brief resets absolute pos to 0
*/
void resetAbsolute();
/** @brief
*
*/
void runInf(bool direction);
/** @brief returns current speed in steps per second
*/
uint16_t getSpeed();
/** @brief returns current acceleration time in ms
*/
float getAcc();
/** @brief stops the motor dead, but stays enabled
*/
void stop();
};
#endif

View File

@@ -1,4 +1,6 @@
idf_component_register( idf_component_register(
SRCS "gpio_evaluateSwitch.cpp" SRCS
"gpio_evaluateSwitch.cpp"
"gpio_adc.cpp"
INCLUDE_DIRS "." INCLUDE_DIRS "."
) )

View File

@@ -0,0 +1,21 @@
#include "gpio_adc.hpp"
//=============================
//========= readAdc ===========
//=============================
//function for multisampling an anlog input
int gpio_readAdc(adc1_channel_t adc_channel, bool inverted) {
//make multiple measurements
int adc_reading = 0;
for (int i = 0; i < 32; i++) {
adc_reading += adc1_get_raw(adc_channel);
}
adc_reading = adc_reading / 32;
//return original or inverted result
if (inverted) {
return 4095 - adc_reading;
} else {
return adc_reading;
}
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include <stdio.h>
#include "driver/adc.h"
//function for multisampling an anlog input
//measures 30 times and returns average
//if invertion is used currently 11bit resolution is assumed (subtracts from 4095)
//TODO: rework this function to be more universal
int gpio_readAdc(adc1_channel_t adc_channel, bool inverted = false);

View File

@@ -9,12 +9,12 @@ gpio_evaluatedSwitch::gpio_evaluatedSwitch( //minimal (use default values)
gpio_num = gpio_num_declare; gpio_num = gpio_num_declare;
pullup = true; pullup = true;
inverted = false; inverted = false;
inputSource = inputSource_t::GPIO;
init(); initGpio();
}; };
gpio_evaluatedSwitch::gpio_evaluatedSwitch( //optional parameters given gpio_evaluatedSwitch::gpio_evaluatedSwitch( //optional parameters given
gpio_num_t gpio_num_declare, gpio_num_t gpio_num_declare,
bool pullup_declare, bool pullup_declare,
@@ -23,13 +23,25 @@ gpio_evaluatedSwitch::gpio_evaluatedSwitch( //optional parameters given
gpio_num = gpio_num_declare; gpio_num = gpio_num_declare;
pullup = pullup_declare; pullup = pullup_declare;
inverted = inverted_declare; inverted = inverted_declare;
inputSource = inputSource_t::GPIO;
init(); initGpio();
};
gpio_evaluatedSwitch::gpio_evaluatedSwitch( //with function as input source
bool (*getInputStatePtr_f)(void),
bool inverted_f){
//gpio_num = NULL;
//pullup = NULL;
inverted = inverted_f;
getInputStatePtr = getInputStatePtr_f;
inputSource = inputSource_t::FUNCTION;
}; };
void gpio_evaluatedSwitch::init(){ void gpio_evaluatedSwitch::initGpio(){
ESP_LOGI(TAG, "initializing gpio pin %d", (int)gpio_num); ESP_LOGI(TAG, "initializing gpio pin %d", (int)gpio_num);
//define gpio pin as input //define gpio pin as input
@@ -48,11 +60,33 @@ void gpio_evaluatedSwitch::init(){
}; };
void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge detection void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge detection
//--- get pin state with required method ---
switch (inputSource){
case inputSource_t::GPIO: //from gpio pin
if (gpio_get_level(gpio_num) == 0){ //pin low
inputState = true;
} else { //pin high
inputState = false;
}
break;
case inputSource_t::FUNCTION: //from funtion
inputState = (*getInputStatePtr)();
break;
}
//--- invert state ---
//not inverted: switch switches to GND when active
//inverted: switch switched to VCC when active
if (inverted == true){ if (inverted == true){
inputState = !inputState;
}
//========================================================= //=========================================================
//=========== Statemachine for inverted switch ============ //========= Statemachine for evaluateing switch ===========
//=================== (switch to VCC) =====================
//========================================================= //=========================================================
switch (p_state){ switch (p_state){
default: default:
@@ -61,7 +95,7 @@ void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge det
case switchState::FALSE: //input confirmed high (released) case switchState::FALSE: //input confirmed high (released)
fallingEdge = false; //reset edge event fallingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 1){ //pin high (on) if (inputState == true){ //pin high (on)
p_state = switchState::HIGH; p_state = switchState::HIGH;
timestampHigh = esp_log_timestamp(); //save timestamp switched from low to high timestampHigh = esp_log_timestamp(); //save timestamp switched from low to high
} else { } else {
@@ -70,7 +104,7 @@ void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge det
break; break;
case switchState::HIGH: //input recently switched to high (pressed) case switchState::HIGH: //input recently switched to high (pressed)
if (gpio_get_level(gpio_num) == 1){ //pin still high (on) if (inputState == true){ //pin still high (on)
if (esp_log_timestamp() - timestampHigh > minOnMs){ //pin in same state long enough if (esp_log_timestamp() - timestampHigh > minOnMs){ //pin in same state long enough
p_state = switchState::TRUE; p_state = switchState::TRUE;
state = true; state = true;
@@ -84,7 +118,7 @@ void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge det
case switchState::TRUE: //input confirmed high (pressed) case switchState::TRUE: //input confirmed high (pressed)
risingEdge = false; //reset edge event risingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 0){ //pin low (off) if (inputState == false){ //pin low (off)
timestampLow = esp_log_timestamp(); timestampLow = esp_log_timestamp();
p_state = switchState::LOW; p_state = switchState::LOW;
} else { } else {
@@ -94,7 +128,7 @@ void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge det
break; break;
case switchState::LOW: //input recently switched to low (released) case switchState::LOW: //input recently switched to low (released)
if (gpio_get_level(gpio_num) == 0){ //pin still low (off) if (inputState == false){ //pin still low (off)
if (esp_log_timestamp() - timestampLow > minOffMs){ //pin in same state long enough if (esp_log_timestamp() - timestampLow > minOffMs){ //pin in same state long enough
p_state = switchState::FALSE; p_state = switchState::FALSE;
msPressed = timestampLow - timestampHigh; //calculate duration the button was pressed msPressed = timestampLow - timestampHigh; //calculate duration the button was pressed
@@ -107,65 +141,6 @@ void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge det
break; break;
} }
}else{
//=========================================================
//========= Statemachine for not inverted switch ==========
//=================== (switch to GND) =====================
//=========================================================
switch (p_state){
default:
p_state = switchState::FALSE;
break;
case switchState::FALSE: //input confirmed high (released)
fallingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 0){ //pin low (on)
p_state = switchState::LOW;
timestampLow = esp_log_timestamp(); //save timestamp switched from high to low
} else {
msReleased = esp_log_timestamp() - timestampHigh; //update duration released
}
break;
case switchState::LOW: //input recently switched to low (pressed)
if (gpio_get_level(gpio_num) == 0){ //pin still low (on)
if (esp_log_timestamp() - timestampLow > minOnMs){ //pin in same state long enough
p_state = switchState::TRUE;
state = true;
risingEdge = true;
msReleased = timestampLow - timestampHigh; //calculate duration the button was released
}
}else{
p_state = switchState::FALSE;
}
break;
case switchState::TRUE: //input confirmed low (pressed)
risingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 1){ //pin high (off)
timestampHigh = esp_log_timestamp();
p_state = switchState::HIGH;
} else {
msPressed = esp_log_timestamp() - timestampLow; //update duration pressed
}
break;
case switchState::HIGH: //input recently switched to high (released)
if (gpio_get_level(gpio_num) == 1){ //pin still high (off)
if (esp_log_timestamp() - timestampHigh > minOffMs){ //pin in same state long enough
p_state = switchState::FALSE;
msPressed = timestampHigh - timestampLow; //calculate duration the button was pressed
state=false;
fallingEdge=true;
}
}else{
p_state = switchState::TRUE;
}
break;
}
}
} }

View File

@@ -18,21 +18,30 @@ extern "C"
//switch to VCC (inverted) and dont use internal pullup: //switch to VCC (inverted) and dont use internal pullup:
//gpio_evaluatedSwitch s3(GPIO_NUM_14 false, true); //gpio_evaluatedSwitch s3(GPIO_NUM_14 false, true);
enum class inputSource_t {GPIO, FUNCTION};
class gpio_evaluatedSwitch { class gpio_evaluatedSwitch {
public: public:
//--- input --- //--- input ---
uint32_t minOnMs = 30; uint32_t minOnMs = 30;
uint32_t minOffMs = 30; uint32_t minOffMs = 30;
gpio_evaluatedSwitch( //constructor minimal (default parameters pullup=true, inverted=false)
//constructor minimal (default parameters pullup=true, inverted=false)
gpio_evaluatedSwitch(
gpio_num_t gpio_num_declare gpio_num_t gpio_num_declare
); );
gpio_evaluatedSwitch( //constructor with optional parameters
//constructor with optional parameters
gpio_evaluatedSwitch(
gpio_num_t gpio_num_declare, gpio_num_t gpio_num_declare,
bool pullup_declare, bool pullup_declare,
bool inverted_declare=false bool inverted_declare=false
); );
//constructor with a function as source for input state instead of a gpio pin
gpio_evaluatedSwitch(bool (*getInputStatePtr_f)(void), bool inverted_f=false);
//--- output --- TODO make readonly? (e.g. public section: const int& x = m_x;) //--- output --- TODO make readonly? (e.g. public section: const int& x = m_x;)
bool state = false; bool state = false;
bool risingEdge = false; bool risingEdge = false;
@@ -47,12 +56,15 @@ class gpio_evaluatedSwitch {
gpio_num_t gpio_num; gpio_num_t gpio_num;
bool pullup; bool pullup;
bool inverted; bool inverted;
bool (*getInputStatePtr)(void); //pointer to function for getting current input state
inputSource_t inputSource = inputSource_t::GPIO;
enum class switchState {TRUE, FALSE, LOW, HIGH}; enum class switchState {TRUE, FALSE, LOW, HIGH};
switchState p_state = switchState::FALSE; switchState p_state = switchState::FALSE;
bool inputState = false;
uint32_t timestampLow = 0; uint32_t timestampLow = 0;
uint32_t timestampHigh = 0; uint32_t timestampHigh = 0;
void init(); void initGpio();
}; };

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

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: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Binary file not shown.

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.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -6,6 +6,10 @@ idf_component_register(
"buzzer.cpp" "buzzer.cpp"
"vfd.cpp" "vfd.cpp"
"display.cpp" "display.cpp"
"cutter.cpp"
"switchesAnalog.cpp"
"guide-stepper.cpp"
"encoder.cpp"
INCLUDE_DIRS INCLUDE_DIRS
"." "."
) )

View File

@@ -3,13 +3,20 @@
//--- inputs --- //--- inputs ---
//create and configure objects for evaluated switches //create and configure objects for evaluated switches
gpio_evaluatedSwitch SW_START(GPIO_SW_START, true, false); //pullup true, not inverted (switch to GND, internal pullup used) //gpio_evaluatedSwitch sw_gpio_39(GPIO_NUM_39, false, true); //pullup false, INVERTED (switch to 3V3, pulldown on pcb soldered)
gpio_evaluatedSwitch SW_RESET(GPIO_SW_RESET, true, false); //pullup true, not inverted (switch to GND, internal pullup used) gpio_evaluatedSwitch sw_gpio_34(GPIO_NUM_34, false, true); //pullup false, INVERTED (switch to 3V3, pulldown on pcb soldered)
gpio_evaluatedSwitch SW_SET(GPIO_SW_SET, true, false); //pullup true, not inverted (switch to GND, internal pullup used) gpio_evaluatedSwitch sw_gpio_32(GPIO_NUM_32, true, false); //pullup true, not inverted (switch to GND, internal pullup used)
gpio_evaluatedSwitch SW_PRESET1(GPIO_SW_PRESET1, 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_PRESET2(GPIO_SW_PRESET2, false, true); //pullup false, INVERTED (switch to 3V3, pulldown on pcb soldered) gpio_evaluatedSwitch sw_gpio_25(GPIO_NUM_25, true, false); //pullup true, not inverted (switch to GND, internal pullup used)
gpio_evaluatedSwitch SW_PRESET3(GPIO_SW_PRESET3, false, true); //pullup false, INVERTED (switch to 3V3, pulldown on pcb soldered) 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 ---
//evaluated switches with function to obtain the current input state instead of gpio
gpio_evaluatedSwitch sw_gpio_analog_0(&switchesAnalog_getState_sw0);
gpio_evaluatedSwitch sw_gpio_analog_1(&switchesAnalog_getState_sw1);
gpio_evaluatedSwitch sw_gpio_analog_2(&switchesAnalog_getState_sw2);
gpio_evaluatedSwitch sw_gpio_analog_3(&switchesAnalog_getState_sw3);
//create buzzer object with no gap between beep events //create buzzer object with no gap between beep events
buzzer_t buzzer(GPIO_BUZZER, 0); buzzer_t buzzer(GPIO_BUZZER, 0);

View File

@@ -4,6 +4,7 @@ extern "C" {
} }
#include "gpio_evaluateSwitch.hpp" #include "gpio_evaluateSwitch.hpp"
#include "buzzer.hpp" #include "buzzer.hpp"
#include "switchesAnalog.hpp"
//=================================== //===================================
@@ -11,30 +12,52 @@ extern "C" {
//=================================== //===================================
//4x stepper mosfet outputs for VFD //4x stepper mosfet outputs for VFD
#define GPIO_VFD_FWD GPIO_NUM_4 //ST4 #define GPIO_VFD_FWD GPIO_NUM_4 //ST4
#define GPIO_VFD_REV GPIO_NUM_16 //ST3 #define GPIO_VFD_REV GPIO_NUM_5 //mos2
#define GPIO_VFD_D0 GPIO_NUM_2 //ST2 #define GPIO_VFD_D0 GPIO_NUM_2 //ST2
#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) 2022.02.28: pin used for stepper
#define GPIO_LAMP GPIO_NUM_0 //mos2 (5) 2022.02.28: lamp disabled, pin used for stepper
#define GPIO_RELAY GPIO_NUM_13 #define GPIO_RELAY GPIO_NUM_13
#define GPIO_BUZZER GPIO_NUM_12 #define GPIO_BUZZER GPIO_NUM_12
//================================== //==================================
//===== define input gpio pins ===== //==== define analog input pins ====
//================================== //==================================
#define GPIO_SW_START GPIO_NUM_26
#define GPIO_SW_RESET GPIO_NUM_25
#define GPIO_SW_SET GPIO_NUM_33
#define GPIO_SW_PRESET1 GPIO_NUM_32
#define GPIO_SW_PRESET2 GPIO_NUM_34
#define GPIO_SW_PRESET3 GPIO_NUM_39
#define GPIO_POTI GPIO_NUM_36 #define GPIO_POTI GPIO_NUM_36
#define ADC_CHANNEL_POTI ADC1_CHANNEL_0 #define ADC_CHANNEL_POTI ADC1_CHANNEL_0
#define GPIO_4SW_TO_ANALOG GPIO_NUM_39
#define ADC_CHANNEL_4SW_TO_ANALOG ADC1_CHANNEL_3 //gpio 39
//ADC1_CHANNEL_0 gpio36
//ADC1_CHANNEL_6 gpio_34
//ADC1_CHANNEL_3 gpio_39
//=====================================
//==== assign switches to objects =====
//=====================================
//see config.cpp for available evaluated switch objects
#define SW_START sw_gpio_26
#define SW_RESET sw_gpio_25
#define SW_CUTTER_POS sw_gpio_14
#define SW_SET sw_gpio_analog_0
#define SW_PRESET1 sw_gpio_analog_1
#define SW_PRESET2 sw_gpio_analog_2
#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
//#define ? sw_gpio_34
//=============================
//======= configuration =======
//=============================
//-------------------------- //--------------------------
//----- display config ----- //----- display config -----
//-------------------------- //--------------------------
@@ -56,14 +79,37 @@ extern "C" {
#define ENABLE_HALF_STEPS false // Set to true to enable tracking of rotary encoder at half step resolution #define ENABLE_HALF_STEPS false // Set to true to enable tracking of rotary encoder at half step resolution
#define FLIP_DIRECTION false // Set to true to reverse the clockwise/counterclockwise sense #define FLIP_DIRECTION false // Set to true to reverse the clockwise/counterclockwise sense
//--------------------------
//----- stepper config -----
//--------------------------
//enable stepper test mode (dont start control and encoder task)
//#define STEPPER_TEST
#define STEPPER_STEP_PIN GPIO_NUM_18 //mos1
#define STEPPER_DIR_PIN GPIO_NUM_16 //ST3
#define STEPPER_EN_PIN GPIO_NUM_0 //not connected (-> stepper always on)
//more detailed options for testing are currently defined in guide-stepper.cpp
//-------------------------- //--------------------------
//------ 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 STEPS_PER_METER 2127 //roll-v3-gummi-86.6mm - d=89.8mm //#define ENCODER_TEST
//#define MEASURING_ROLL_DIAMETER 86.6 //roll v3 large
//#define PI 3.14159265358979323846 //steps per meter
#define ENCODER_STEPS_PER_METER 2127 //roll-v3-gummi-86.6mm - d=89.8mm
//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
@@ -71,14 +117,22 @@ extern "C" {
//===== global variables ===== //===== global variables =====
//============================ //============================
//create global evaluated switch objects //create global evaluated switch objects
//--- inputs --- //--- switches on digital gpio pins ---
//create objects for switches at bottom screw temerinals //extern gpio_evaluatedSwitch sw_gpio_39;
extern gpio_evaluatedSwitch SW_START; extern gpio_evaluatedSwitch sw_gpio_34;
extern gpio_evaluatedSwitch SW_RESET; extern gpio_evaluatedSwitch sw_gpio_32;
extern gpio_evaluatedSwitch SW_SET; extern gpio_evaluatedSwitch sw_gpio_33;
extern gpio_evaluatedSwitch SW_PRESET1; extern gpio_evaluatedSwitch sw_gpio_25;
extern gpio_evaluatedSwitch SW_PRESET2; extern gpio_evaluatedSwitch sw_gpio_26;
extern gpio_evaluatedSwitch SW_PRESET3; extern gpio_evaluatedSwitch sw_gpio_14;
//--- switches connected to 4-sw-to-analog stripboard ---
extern gpio_evaluatedSwitch sw_gpio_analog_0;
extern gpio_evaluatedSwitch sw_gpio_analog_1;
extern gpio_evaluatedSwitch sw_gpio_analog_2;
extern gpio_evaluatedSwitch sw_gpio_analog_3;
//create global buzzer object //create global buzzer object
extern buzzer_t buzzer; extern buzzer_t buzzer;

View File

@@ -1,49 +1,5 @@
#include "control.hpp" #include "control.hpp"
#include "encoder.hpp"
//========================
//===== init encoder =====
//========================
QueueHandle_t init_encoder(rotary_encoder_info_t * info){
// esp32-rotary-encoder requires that the GPIO ISR service is installed before calling rotary_encoder_register()
ESP_ERROR_CHECK(gpio_install_isr_service(0));
// Initialise the rotary encoder device with the GPIOs for A and B signals
ESP_ERROR_CHECK(rotary_encoder_init(info, ROT_ENC_A_GPIO, ROT_ENC_B_GPIO));
ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(info, ENABLE_HALF_STEPS));
#ifdef FLIP_DIRECTION
ESP_ERROR_CHECK(rotary_encoder_flip_direction(info));
#endif
// Create a queue for events from the rotary encoder driver.
// Tasks can read from this queue to receive up to date position information.
QueueHandle_t event_queue = rotary_encoder_create_queue();
ESP_ERROR_CHECK(rotary_encoder_set_queue(info, event_queue));
return event_queue;
}
//=============================
//========= readAdc ===========
//=============================
//function for multisampling an anlog input
int readAdc(adc1_channel_t adc_channel, bool inverted = false) {
//make multiple measurements
int adc_reading = 0;
for (int i = 0; i < 16; i++) {
adc_reading += adc1_get_raw(adc_channel);
}
adc_reading = adc_reading / 16;
//return original or inverted result
if (inverted) {
return 4095 - adc_reading;
} else {
return adc_reading;
}
}
//==================== //====================
@@ -51,27 +7,25 @@ int readAdc(adc1_channel_t adc_channel, bool inverted = false) {
//==================== //====================
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;
static uint32_t timestamp_changedState = 0;
char buf_disp[20]; //both displays static char buf_disp1[10];// 8 digits + decimal point + \0
char buf_disp1[10];// 8 digits + decimal point + \0 static char buf_disp2[10];// 8 digits + decimal point + \0
char buf_disp2[10];// 8 digits + decimal point + \0 static char buf_tmp[15];
char buf_tmp[15];
rotary_encoder_info_t encoder; //encoder device/info static int lengthNow = 0; //length measured in mm
QueueHandle_t encoder_queue = NULL; //encoder event queue static int lengthTarget = 5000; //default target length in mm
rotary_encoder_state_t encoderState; static int lengthRemaining = 0; //(target - now) length needed for reaching the target
static int potiRead = 0; //voltage read from adc
static uint32_t timestamp_motorStarted = 0; //timestamp winding started
uint32_t timestamp_pageSwitched = 0; //automatic cut
bool page = false; //store page number currently displayed static int cut_msRemaining = 0;
int lengthNow = 0; //length measured in mm static uint32_t timestamp_cut_lastBeep = 0;
int lengthTarget = 3000; //target length in mm static uint32_t autoCut_delayMs = 2500; //TODO add this to config
int lengthRemaining = 0; //(target - now) length needed for reaching the target static bool autoCutEnabled = false; //store state of toggle switch (no hotswitch)
int potiRead = 0; //voltage read from adc
uint32_t timestamp_motorStarted = 0; //timestamp winding started
int lengthBeeped = 0; //only beep once per meter during encoder test
//===== change State ===== //===== change State =====
@@ -85,9 +39,12 @@ void changeState (systemState_t stateNew) {
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
@@ -96,16 +53,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 ");
@@ -123,11 +80,11 @@ 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;
@@ -148,8 +105,6 @@ void setDynSpeedLvl(uint8_t lvlMax = 3){
//======================== //========================
void task_control(void *pvParameter) void task_control(void *pvParameter)
{ {
//initialize encoder
encoder_queue = init_encoder(&encoder);
//initialize display //initialize display
max7219_t two7SegDisplays = display_init(); max7219_t two7SegDisplays = display_init();
@@ -167,7 +122,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 ------
@@ -179,48 +134,96 @@ 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 ------
//---------------------------- //----------------------------
// Poll current position and direction //--- get current length since last reset ---
rotary_encoder_get_state(&encoder, &encoderState); lengthNow = encoder_getLenMm();
//--- 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 --------- //--------- 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
if (controlState != systemState_t::AUTO_CUT_WAITING) {
encoder_reset();
lengthNow = 0; lengthNow = 0;
buzzer.beep(1, 700, 100); 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 = 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);
@@ -251,22 +254,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 ");
}
} }
@@ -275,17 +278,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
@@ -293,57 +295,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?
encoder_reset();
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 = 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,7 +409,7 @@ void task_control(void *pvParameter)
displayTop.handle(); displayTop.handle();
displayBot.handle(); displayBot.handle();
//-- show encoder steps on display1 --- //-- show encoder steps on display1 ---
sprintf(buf_disp1, "EN %05d", encoderState.position); //count sprintf(buf_disp1, "EN %05d", encoder_getSteps); //count
displayTop.showString(buf_disp1); displayTop.showString(buf_disp1);
//--- show converted distance on display2 --- //--- show converted distance on display2 ---
sprintf(buf_disp2, "Met %5.3f", (float)lengthNow/1000); //m sprintf(buf_disp2, "Met %5.3f", (float)lengthNow/1000); //m
@@ -385,12 +430,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
if (controlState == systemState_t::AUTO_CUT_WAITING) {
displayTop.blinkStrings(" CUT 1N ", " ", 70, 30);
}
//otherwise show current position
else {
sprintf(buf_tmp, "1ST %5.4f", (float)lengthNow/1000); sprintf(buf_tmp, "1ST %5.4f", (float)lengthNow/1000);
// 123456789 // 123456789
//limit length to 8 digits + decimal point (drop decimal places when it does not fit) //limit length to 8 digits + decimal point (drop decimal places when it does not fit)
sprintf(buf_disp1, "%.9s", buf_tmp); sprintf(buf_disp1, "%.9s", buf_tmp);
displayTop.showString(buf_disp1); displayTop.showString(buf_disp1);
}
//-------------------------- //--------------------------
@@ -404,8 +455,18 @@ void task_control(void *pvParameter)
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 {
@@ -416,13 +477,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 #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
} }
} }

View File

@@ -10,7 +10,6 @@ extern "C"
#include "esp_log.h" #include "esp_log.h"
#include "driver/adc.h" #include "driver/adc.h"
#include "rotary_encoder.h"
#include "max7219.h" #include "max7219.h"
} }
@@ -18,14 +17,18 @@ extern "C"
#include "config.hpp" #include "config.hpp"
#include "gpio_evaluateSwitch.hpp" #include "gpio_evaluateSwitch.hpp"
#include "gpio_adc.hpp"
#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 -----
//---------------------------
static cutter_state_t cutter_state = cutter_state_t::IDLE;
static uint32_t timestamp_turnedOn;
static 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
} }

67
main/encoder.cpp Normal file
View File

@@ -0,0 +1,67 @@
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "esp_system.h"
#include "esp_log.h"
#include "rotary_encoder.h"
}
#include "encoder.hpp"
//----------------------------
//----- global variables -----
//----------------------------
static rotary_encoder_info_t encoder; //encoder device/info
QueueHandle_t encoder_queue = NULL; //encoder event queue
//-------------------------
//------- functions -------
//-------------------------
//--- encoder_init ---
//initialize encoder and return event queue
QueueHandle_t encoder_init(){
// esp32-rotary-encoder requires that the GPIO ISR service is installed before calling rotary_encoder_register()
ESP_ERROR_CHECK(gpio_install_isr_service(0));
// Initialise the rotary encoder device with the GPIOs for A and B signals
ESP_ERROR_CHECK(rotary_encoder_init(&encoder, ROT_ENC_A_GPIO, ROT_ENC_B_GPIO));
ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&encoder, ENABLE_HALF_STEPS));
#ifdef FLIP_DIRECTION
ESP_ERROR_CHECK(rotary_encoder_flip_direction(&encoder));
#endif
// Create a queue for events from the rotary encoder driver.
// Tasks can read from this queue to receive up to date position information.
QueueHandle_t event_queue = rotary_encoder_create_queue();
ESP_ERROR_CHECK(rotary_encoder_set_queue(&encoder, event_queue));
return event_queue;
}
//--- encoder_getSteps ---
//get steps counted since last reset
int encoder_getSteps(){
// Poll current position and direction
rotary_encoder_state_t encoderState;
rotary_encoder_get_state(&encoder, &encoderState);
//calculate total distance since last reset
return encoderState.position;
}
//--- encoder_getLenMm ---
//get current length in Mm since last reset
int encoder_getLenMm(){
return (float)encoder_getSteps() * 1000 / ENCODER_STEPS_PER_METER;
}
//--- encoder_reset ---
//reset counted steps / length to 0
void encoder_reset(){
rotary_encoder_reset(&encoder);
return;
}

40
main/encoder.hpp Normal file
View File

@@ -0,0 +1,40 @@
/* in this file all used functions from original rotary_encoder.h library are wrapped with custom functions to reduce global variables and duplicate code
*/
//TODO create a cpp class for an encoder?
#pragma once
extern "C" {
#include <freertos/task.h>
}
#include "config.hpp"
//----------------------------
//----- global variables -----
//----------------------------
//TODO ignore global encoder queue, since it is not used?
extern QueueHandle_t encoder_queue; //encoder event queue
//-------------------------
//------- functions -------
//-------------------------
//--- encoder_init ---
//init encoder
QueueHandle_t encoder_init();
//--- encoder_getSteps ---
//get steps counted since last reset
int encoder_getSteps();
//--- encoder_getLenMm ---
//get current length in Mm since last reset
int encoder_getLenMm();
//--- encoder_reset ---
//reset counted steps / length to 0
void encoder_reset();

307
main/guide-stepper.cpp Normal file
View File

@@ -0,0 +1,307 @@
extern "C"
{
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/adc.h"
}
#include "DendoStepper.h"
#include "config.hpp"
#include "guide-stepper.hpp"
#include "encoder.hpp"
#include "gpio_evaluateSwitch.hpp"
//---------------------
//--- configuration ---
//---------------------
//also see config.hpp
//for pin definition
#define STEPPER_TEST_TRAVEL 65 //mm
//
#define MIN_MM 0
#define MAX_MM 110 //60
#define POS_MAX_STEPS MAX_MM * STEPPER_STEPS_PER_MM
#define POS_MIN_STEPS MIN_MM * STEPPER_STEPS_PER_MM
#define SPEED_MIN 2.0 //mm/s
#define SPEED_MAX 60.0 //mm/s
#define SPEED 10 //35, 100, 50 rev
#define ACCEL_MS 800.0 //ms from 0 to max
#define DECEL_MS 500.0 //ms from max to 0
#define STEPPER_STEPS_PER_ROT 1600
#define STEPPER_STEPS_PER_MM STEPPER_STEPS_PER_ROT/4
#define D_CABLE 6
#define D_REEL 160 //actual 170
#define PI 3.14159
//----------------------
//----- variables ------
//----------------------
static DendoStepper step;
static const char *TAG = "stepper"; //tag for logging
static bool stepp_direction = true;
static bool dir = true, dirPrev; //TODO local variables in travelSteps?
static uint32_t posNow = 0;
//----------------------
//----- functions ------
//----------------------
//move axis certain Steps (relative) between left and right or reverse when negative
void travelSteps(int stepsTarget){
//posNow = step.getPositionMm(); //not otherwise controlled, so no update necessary
int stepsToGo, remaining;
stepsToGo = abs(stepsTarget);
if(stepsTarget < 0) stepp_direction = !stepp_direction; //invert direction in reverse mode
while (stepsToGo != 0){
//--- wait if direction changed ---
//if (dirPrev != dir){
// ESP_LOGW(TAG, " dir-change detected - waiting for move to finish \n ");
// while(step.getState() != 1) vTaskDelay(1); //wait for move to finish
//}
//--- currently moving right ---
if (stepp_direction == true){ //currently moving right
remaining = POS_MAX_STEPS - posNow; //calc remaining distance fom current position to limit
if (stepsToGo > remaining){ //new distance will exceed limit
step.runAbs (POS_MAX_STEPS); //move to limit
dirPrev = dir;
dir = 1;
//while(step.getState() != 1) vTaskDelay(1); //wait for move to finish
posNow = POS_MAX_STEPS;
stepp_direction = false; //change current direction for next iteration
stepsToGo = stepsToGo - remaining; //decrease target length by already traveled distance
ESP_LOGI(TAG, " --- moved to max -> change direction (L) --- \n ");
}
else { //target distance does not reach the limit
step.runAbs (posNow + stepsToGo); //move by (remaining) distance to reach target length
dirPrev = dir;
dir = 1;
//-- dont wait for move to finish since moves in same direction get merged --
//while(step.getState() != 1) vTaskDelay(1); //wait for move to finish
ESP_LOGD(TAG, "moving to %d\n", posNow+stepsToGo);
posNow += stepsToGo;
stepsToGo = 0; //finished, reset target length (could as well exit loop/break)
}
}
//--- currently moving left ---
else {
remaining = posNow - POS_MIN_STEPS;
if (stepsToGo > remaining){
step.runAbs (POS_MIN_STEPS);
dirPrev = dir;
dir = 0;
//while(step.getState() != 1) vTaskDelay(2); //wait for move to finish
posNow = POS_MIN_STEPS;
stepp_direction = true;
stepsToGo = stepsToGo - remaining;
ESP_LOGI(TAG, " --- moved to min -> change direction (R) --- \n ");
}
else {
step.runAbs (posNow - stepsToGo); //when moving left the coordinate has to be decreased
dirPrev = dir;
dir = 0;
//-- dont wait for move to finish since moves in same direction get merged --
//while(step.getState() != 1) vTaskDelay(2); //wait for move to finish
ESP_LOGD(TAG, "moving to %d\n", posNow - stepsToGo);
posNow -= stepsToGo;
stepsToGo = 0;
}
}
}
if(stepsTarget < 0) stepp_direction = !stepp_direction; //undo inversion of stepp_direction after reverse mode is finished
return;
}
//move axis certain Mm (relative) between left and right or reverse when negative
void travelMm(int length){
travelSteps(length * STEPPER_STEPS_PER_MM);
}
//define zero/start position
//currently crashes into hardware limitation for certain time
//TODO: limit switch
void home() {
ESP_LOGW(TAG, "auto-home...");
step.setSpeedMm(100, 500, 10);
step.runInf(1);
vTaskDelay(1500 / portTICK_PERIOD_MS);
step.stop();
step.resetAbsolute();
ESP_LOGW(TAG, "auto-home finished");
}
//initialize/configure stepper instance
void init_stepper() {
ESP_LOGW(TAG, "initializing stepper...");
DendoStepper_config_t step_cfg = {
.stepPin = STEPPER_STEP_PIN,
.dirPin = STEPPER_DIR_PIN,
.enPin = STEPPER_EN_PIN,
.timer_group = TIMER_GROUP_0,
.timer_idx = TIMER_0,
.miStep = MICROSTEP_32,
.stepAngle = 1.8};
step.config(&step_cfg);
step.init();
step.setSpeed(1000, 1000, 1000); //random default speed
step.setStepsPerMm(STEPPER_STEPS_PER_MM); //guide: 4mm/rot
}
//function that updates speed value using ADC input and configured MIN/MAX
void updateSpeedFromAdc() {
int potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095 GPIO34
double poti = potiRead/4095.0;
int speed = poti*(SPEED_MAX-SPEED_MIN) + SPEED_MIN;
step.setSpeedMm(speed, ACCEL_MS, DECEL_MS);
ESP_LOGW(TAG, "poti: %d (%.2lf%%), set speed to: %d", potiRead, poti*100, speed);
}
//----------------------------
//---- TASK stepper-test -----
//----------------------------
void task_stepper_test(void *pvParameter)
{
init_stepper();
home();
step.setSpeedMm(SPEED, ACCEL_MS, DECEL_MS);
//--- move from left to right repeatedly ---
// while (1) {
// updateSpeedFromAdc();
// step.runPosMm(STEPPER_TEST_TRAVEL);
// while(step.getState() != 1) vTaskDelay(2);
// ESP_LOGI(TAG, "finished moving right => moving left");
// 10updateSpeedFromAdc();
// step.runPosMm(-STEPPER_TEST_TRAVEL);
// while(step.getState() != 1) vTaskDelay(2); //1=idle
// ESP_LOGI(TAG, "finished moving left => moving right");
// }
//--- control stepper using preset buttons ---
while(1){
vTaskDelay(20 / portTICK_PERIOD_MS);
//------ handle switches ------
//run handle functions for all switches
SW_START.handle();
SW_RESET.handle();
SW_SET.handle();
SW_PRESET1.handle();
SW_PRESET2.handle();
SW_PRESET3.handle();
SW_CUT.handle();
SW_AUTO_CUT.handle();
if (SW_RESET.risingEdge) {
ESP_LOGI(TAG, "button - stop stepper\n ");
buzzer.beep(1, 1000, 100);
step.stop();
}
if (SW_PRESET1.risingEdge) {
ESP_LOGI(TAG, "button - moving right\n ");
buzzer.beep(2, 300, 100);
step.setSpeedMm(SPEED, ACCEL_MS, DECEL_MS);
step.runPosMm(15);
}
if (SW_PRESET3.risingEdge) {
ESP_LOGI(TAG, "button - moving left\n ");
buzzer.beep(1, 500, 100);
step.setSpeedMm(SPEED, ACCEL_MS, DECEL_MS);
step.runPosMm(-15);
}
if (SW_PRESET2.risingEdge) {
buzzer.beep(1, 100, 100);
ESP_LOGW(TAG, "button - current state: %d\n, pos: %llu", (int)step.getState(), step.getPositionMm());
}
}
}
//----------------------------
//----- TASK stepper-ctl -----
//----------------------------
void task_stepper_ctl(void *pvParameter)
{
//variables
int encStepsNow = 0; //get curret steps of encoder
int encStepsPrev = 0; //steps at last check
int encStepsDelta = 0; //steps changed since last iteration
double cableLen = 0;
double travelStepsExact = 0; //steps axis has to travel
double travelStepsPartial = 0;
int travelStepsFull = 0;
double travelMm = 0;
double turns = 0;
float potiModifier;
init_stepper();
home();
while(1){
//get current length
encStepsNow = encoder_getSteps();
//calculate change
encStepsDelta = encStepsNow - encStepsPrev; //FIXME MAJOR BUG: when resetting encoder/length in control task, diff will be huge!
//read potentiometer and normalize (0-1) to get a variable for testing
potiModifier = (float) gpio_readAdc(ADC_CHANNEL_POTI) / 4095; //0-4095 -> 0-1
//ESP_LOGI(TAG, "current poti-modifier = %f", potiModifier);
ESP_LOGI(TAG, "delaying stepper-ctl task by %.1f ms (poti value)", 2000 * potiModifier);
vTaskDelay(2000 * potiModifier / portTICK_PERIOD_MS);
//calculate steps to move
cableLen = (double)encStepsDelta * 1000 / ENCODER_STEPS_PER_METER;
turns = cableLen / (PI * D_REEL);
travelMm = turns * D_CABLE;
travelStepsExact = travelMm * STEPPER_STEPS_PER_MM + travelStepsPartial; //convert mm to steps and add not moved partial steps
travelStepsPartial = 0;
travelStepsFull = (int)travelStepsExact;
//move axis when ready to move at least 1 step
if (abs(travelStepsFull) > 1){
travelStepsPartial = fmod(travelStepsExact, 1); //save remaining partial steps to be added in the next iteration
ESP_LOGD(TAG, "cablelen=%.2lf, turns=%.2lf, travelMm=%.3lf, travelStepsExact: %.3lf, travelStepsFull=%d, partialStep=%.3lf", cableLen, turns, travelMm, travelStepsExact, travelStepsFull, travelStepsPartial);
ESP_LOGI(TAG, "MOVING %d steps", travelStepsFull);
//TODO: calculate variable speed for smoother movement? for example intentionally lag behind and calculate speed according to buffered data
step.setSpeedMm(SPEED, ACCEL_MS, DECEL_MS);
//testing: get speed from poti
//step.setSpeedMm(35, 1000*potiModifier+1, 1000*potiModifier+1);
travelSteps(travelStepsExact);
encStepsPrev = encStepsNow; //update previous length
}
else {
//TODO use encoder queue to only run this check at encoder event?
vTaskDelay(2);
}
}
}

12
main/guide-stepper.hpp Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
//task that initializes and controls the stepper motor
//current functionality:
// - automatically auto-homes
// - moves left and right repeatedly
// - updates speed from potentiometer each cycle
void task_stepper_test(void *pvParameter);
//task that initializes and controls the stepper motor
// - moves stepper according to encoder movement
void task_stepper_ctl(void *pvParameter);

View File

@@ -13,37 +13,44 @@ extern "C"
#include "config.hpp" #include "config.hpp"
#include "control.hpp" #include "control.hpp"
#include "buzzer.hpp" #include "buzzer.hpp"
#include "switchesAnalog.hpp"
#include "guide-stepper.hpp"
#include "encoder.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
} }
@@ -51,8 +58,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
@@ -62,8 +67,6 @@ void task_buzzer( void * pvParameters ){
//====================================== //======================================
//=========== main function ============ //=========== main function ============
//====================================== //======================================
@@ -75,13 +78,29 @@ extern "C" void app_main()
//enable 5V volate regulator //enable 5V volate regulator
gpio_set_level(GPIO_NUM_17, 1); gpio_set_level(GPIO_NUM_17, 1);
//init encoder (global)
encoder_queue = encoder_init();
//define loglevel //define loglevel
esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("buzzer", ESP_LOG_ERROR); esp_log_level_set("buzzer", ESP_LOG_ERROR);
esp_log_level_set("switches-analog", ESP_LOG_WARN);
esp_log_level_set("control", ESP_LOG_INFO); esp_log_level_set("control", ESP_LOG_INFO);
esp_log_level_set("stepper", ESP_LOG_DEBUG);
esp_log_level_set("DendoStepper", ESP_LOG_DEBUG); //stepper lib
esp_log_level_set("calc", ESP_LOG_WARN); //stepper lib
#ifdef STEPPER_TEST
//create task for stepper testing
xTaskCreate(task_stepper_test, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
#else
//create task for controlling the machine //create task for controlling the machine
xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL); xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
//create task for controlling the machine
xTaskCreate(task_stepper_ctl, "task_stepper_ctl", configMINIMAL_STACK_SIZE * 5, NULL, 5, NULL);
#endif
//create task for handling the buzzer //create task for handling the buzzer
xTaskCreate(&task_buzzer, "task_buzzer", 2048, NULL, 2, NULL); xTaskCreate(&task_buzzer, "task_buzzer", 2048, NULL, 2, NULL);

103
main/switchesAnalog.cpp Normal file
View File

@@ -0,0 +1,103 @@
#include "switchesAnalog.hpp"
#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1) //TODO duplicate code: same macro already used in vfd.cpp
//=====================
//===== Variables =====
//=====================
static const char *TAG = "switches-analog"; //tag for logging
int diffMin = 4095;
int adcValue;
int match_index = 0;
//array that describes voltages for all combinations of the 4 inputs
const int lookup_voltages[] = {
//ADC, S3 S2 S1 S0
4095, //0000
3780, //0001
3390, //0010
3040, //0011
2760, //0100
2542, //0101
2395, //0110
2225, //0111
1964, //1000
1845, //1001
1762, //1010
1664, //1011
1573, //1100
1485, //1101
1432, //1110
1363 //1111
};
//===========================
//===== handle function =====
//===========================
//handle demuxing of 4 switches from 1 adc (has to be run repeatedly)
void handle(){
//read current voltage
adcValue = gpio_readAdc(ADC_CHANNEL_4SW_TO_ANALOG);
ESP_LOGI(TAG, "voltage read: %d", adcValue);
//find closest match in lookup table
diffMin = 4095; //reset diffMin each run
for (int i=0; i<16; i++){
int diff = fabs(adcValue - lookup_voltages[i]);
if (diff < diffMin){
diffMin = diff;
match_index = i;
}
}
//get bool values for each input from matched index
bool s0 = CHECK_BIT(match_index, 0);
bool s1 = CHECK_BIT(match_index, 1);
bool s2 = CHECK_BIT(match_index, 2);
bool s3 = CHECK_BIT(match_index, 3);
//bool s1 = ((match_index & 0b1000) == 0b1000);
//bool s2 = ((match_index & 0b0100) == 0b0100);
//bool s3 = ((match_index & 0b0010) == 0b0010);
//bool s4 = ((match_index & 0b0001) == 0b0001);
//log results
ESP_LOGI(TAG, "adcRead: %d, closest-match: %d, diff: %d, index: %d, switches: %d%d%d%d",
adcValue, lookup_voltages[match_index], diffMin, match_index, (int)s3, (int)s2, (int)s1, (int)s0);
}
//====================
//===== getState =====
//====================
//get state of certain switch (0-3)
bool switchesAnalog_getState(int swNumber){
//run handle function to obtain all current input states
handle();
//get relevant bit
bool state = CHECK_BIT(match_index, swNumber);
ESP_LOGI(TAG, "returned state of switch No. %d = %i", swNumber, (int)state);
return state;
}
bool switchesAnalog_getState_sw0(){
return switchesAnalog_getState(0);
}
bool switchesAnalog_getState_sw1(){
return switchesAnalog_getState(1);
}
bool switchesAnalog_getState_sw2(){
return switchesAnalog_getState(2);
}
bool switchesAnalog_getState_sw3(){
return switchesAnalog_getState(3);
}

21
main/switchesAnalog.hpp Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
extern "C"
{
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include "esp_log.h"
#include "driver/adc.h"
#include <math.h>
}
#include "config.hpp"
#include "gpio_adc.hpp"
//get current state of certain switch
bool switchesAnalog_getState(int swNumber);
bool switchesAnalog_getState_sw0();
bool switchesAnalog_getState_sw1();
bool switchesAnalog_getState_sw2();
bool switchesAnalog_getState_sw3();

View File

@@ -4,9 +4,9 @@
const char* vfd_directionStr[2] = {"FWD", "REV"}; const char* vfd_directionStr[2] = {"FWD", "REV"};
static const char *TAG = "vfd"; static const char *TAG = "vfd";
uint8_t level = 0; //current speed level static uint8_t level = 0; //current speed level
bool state = false; //current state static bool state = false; //current state
vfd_direction_t direction = FWD; //current direction static vfd_direction_t direction = FWD; //current direction
//============================= //=============================
@@ -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);
} }
} }

View File

@@ -0,0 +1,75 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"ratsnest_display_mode": 0,
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": true,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"meta": {
"filename": "4-switches-to-adc.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View File

@@ -0,0 +1,294 @@
{
"board": {
"layer_presets": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "4-switches-to-adc.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"0534e379-8bf0-4abf-a148-fc91b6440529",
""
]
],
"text_variables": {}
}

View File

@@ -0,0 +1,580 @@
(kicad_sch (version 20211123) (generator eeschema)
(uuid 0534e379-8bf0-4abf-a148-fc91b6440529)
(paper "A4")
(lib_symbols
(symbol "Device:R" (pin_numbers hide) (pin_names (offset 0)) (in_bom yes) (on_board yes)
(property "Reference" "R" (id 0) (at 2.032 0 90)
(effects (font (size 1.27 1.27)))
)
(property "Value" "R" (id 1) (at 0 0 90)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at -1.778 0 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "R res resistor" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Resistor" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "R_*" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "R_0_1"
(rectangle (start -1.016 -2.54) (end 1.016 2.54)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "R_1_1"
(pin passive line (at 0 3.81 270) (length 1.27)
(name "~" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 0 -3.81 90) (length 1.27)
(name "~" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "Switch:SW_Push" (pin_numbers hide) (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes)
(property "Reference" "SW" (id 0) (at 1.27 2.54 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "SW_Push" (id 1) (at 0 -1.524 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 0 5.08 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 0 5.08 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "switch normally-open pushbutton push-button" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Push button switch, generic, two pins" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "SW_Push_0_1"
(circle (center -2.032 0) (radius 0.508)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0 1.27)
(xy 0 3.048)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 2.54 1.27)
(xy -2.54 1.27)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(circle (center 2.032 0) (radius 0.508)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(pin passive line (at -5.08 0 0) (length 2.54)
(name "1" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 5.08 0 180) (length 2.54)
(name "2" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "power:+3V3" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes)
(property "Reference" "#PWR" (id 0) (at 0 -3.81 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Value" "+3V3" (id 1) (at 0 3.556 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "power-flag" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Power symbol creates a global label with name \"+3V3\"" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "+3V3_0_1"
(polyline
(pts
(xy -0.762 1.27)
(xy 0 2.54)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0 0)
(xy 0 2.54)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0 2.54)
(xy 0.762 1.27)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "+3V3_1_1"
(pin power_in line (at 0 0 90) (length 0) hide
(name "+3V3" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "power:GND" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes)
(property "Reference" "#PWR" (id 0) (at 0 -6.35 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Value" "GND" (id 1) (at 0 -3.81 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "power-flag" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Power symbol creates a global label with name \"GND\" , ground" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "GND_0_1"
(polyline
(pts
(xy 0 0)
(xy 0 -1.27)
(xy 1.27 -1.27)
(xy 0 -2.54)
(xy -1.27 -1.27)
(xy 0 -1.27)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "GND_1_1"
(pin power_in line (at 0 0 270) (length 0) hide
(name "GND" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
)
)
)
(junction (at 48.26 87.63) (diameter 0) (color 0 0 0 0)
(uuid 0595abd2-5372-4996-8c85-ea8e7ba6eaf5)
)
(junction (at 48.26 57.15) (diameter 0) (color 0 0 0 0)
(uuid 376c3252-bee9-4eae-8c35-3e8d8aea79a1)
)
(junction (at 60.96 57.15) (diameter 0) (color 0 0 0 0)
(uuid 37f07ef8-0bd0-4983-9e87-070da97b8027)
)
(junction (at 60.96 87.63) (diameter 0) (color 0 0 0 0)
(uuid b858a0b2-392b-42b8-814d-97eec6d10cf5)
)
(junction (at 73.66 57.15) (diameter 0) (color 0 0 0 0)
(uuid caf3ed74-8f3c-4ea2-9837-cc564ece24fc)
)
(junction (at 86.36 57.15) (diameter 0) (color 0 0 0 0)
(uuid e422a210-4268-4494-969d-097a39cbc71b)
)
(junction (at 73.66 87.63) (diameter 0) (color 0 0 0 0)
(uuid f688351c-21fd-46ff-a90d-cc366df00758)
)
(wire (pts (xy 60.96 57.15) (xy 60.96 60.325))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 04af43fa-9f39-49fa-af8f-f49b7bc05656)
)
(wire (pts (xy 60.96 84.455) (xy 60.96 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 0540396a-1bc2-4b04-906e-7d83c6b66195)
)
(wire (pts (xy 48.26 87.63) (xy 48.26 92.075))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 1787faca-1557-4d40-a0c4-911d17f0770d)
)
(wire (pts (xy 86.36 67.945) (xy 86.36 74.295))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 23b2ab5f-bdf4-4212-b143-bb49653e1b88)
)
(wire (pts (xy 48.26 57.15) (xy 48.26 60.325))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 25a6a709-3fde-41fe-9a0e-cb508d73834a)
)
(wire (pts (xy 73.66 84.455) (xy 73.66 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 2bc4885e-1811-40f7-9a6d-34ed596c1add)
)
(wire (pts (xy 48.26 41.275) (xy 48.26 45.085))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 2c7d8342-fe94-4a1b-baec-58cd6c3eeca7)
)
(wire (pts (xy 48.26 67.945) (xy 48.26 74.295))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 45921a4d-adb5-4631-b0f7-53468659bc65)
)
(wire (pts (xy 73.66 87.63) (xy 60.96 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 480fea58-4754-4988-b652-79892cbd4343)
)
(polyline (pts (xy 38.1 33.02) (xy 110.49 33.02))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 4d5b9ff9-ca59-4c44-bce2-c776250d20c0)
)
(wire (pts (xy 60.96 87.63) (xy 48.26 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 5f8390d2-5874-477d-abd8-600f48800de1)
)
(wire (pts (xy 73.66 57.15) (xy 73.66 60.325))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 689d4ae4-8fb6-467c-812a-f8189081bfa8)
)
(wire (pts (xy 60.96 57.15) (xy 48.26 57.15))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 69ba96dd-74a8-4f3b-85f6-a998f64b3b7e)
)
(wire (pts (xy 86.36 87.63) (xy 73.66 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 76bc9488-bd39-4e7f-ba21-8968e45bafbd)
)
(polyline (pts (xy 38.1 102.87) (xy 110.49 102.87))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 8fda66e6-cca3-4608-bf63-d40d2a979623)
)
(wire (pts (xy 86.36 60.325) (xy 86.36 57.15))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 92724cbb-f787-4755-8c00-fdaff5e7ac81)
)
(wire (pts (xy 86.36 57.15) (xy 92.71 57.15))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 937bec40-8b53-4b31-acdc-755c933ec2ac)
)
(wire (pts (xy 48.26 52.705) (xy 48.26 57.15))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 9a9c3b93-5397-4f20-8b92-a2c37f8c1874)
)
(wire (pts (xy 86.36 57.15) (xy 73.66 57.15))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid 9c65a4d5-2a36-456c-8138-19c6cad951eb)
)
(wire (pts (xy 60.96 67.945) (xy 60.96 74.295))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid a02e604e-10c2-4767-a22d-4a461b77881e)
)
(polyline (pts (xy 38.1 33.655) (xy 38.1 102.87))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid a2c30be3-07c7-4998-a3ab-a45d0d1aa278)
)
(wire (pts (xy 73.66 57.15) (xy 60.96 57.15))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid acd9d380-e80b-4364-af24-ac27f88537b5)
)
(wire (pts (xy 73.66 67.945) (xy 73.66 74.295))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid c5dfc4f2-d3c5-4fe8-81cc-954989ded559)
)
(wire (pts (xy 86.36 84.455) (xy 86.36 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid e013a703-8a26-45b6-b9ca-6cd0b0a9ceef)
)
(wire (pts (xy 48.26 84.455) (xy 48.26 87.63))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid e3a717ef-7fbb-42fd-bed3-8552fcbf95b5)
)
(polyline (pts (xy 110.49 102.87) (xy 110.49 33.02))
(stroke (width 0) (type default) (color 0 0 0 0))
(uuid f442d4ab-f8ba-49f9-b732-68585ed0f198)
)
(text "Stripboard\n4 switches to 1 analog input" (at 78.74 38.735 0)
(effects (font (size 1.27 1.27) (thickness 0.254) bold) (justify left bottom))
(uuid c525c9cc-a4a1-4f6e-a0cf-a2cc3419b679)
)
(global_label "esp32 ADC" (shape input) (at 92.71 57.15 0) (fields_autoplaced)
(effects (font (size 1.27 1.27)) (justify left))
(uuid b8dbce7d-0a95-4573-b764-9e68bdd24326)
(property "Intersheet References" "${INTERSHEET_REFS}" (id 0) (at 105.4041 57.0706 0)
(effects (font (size 1.27 1.27)) (justify left) hide)
)
)
(symbol (lib_id "power:GND") (at 48.26 92.075 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid 07a9d758-a267-455f-b30c-3770f3527e7a)
(property "Reference" "#PWR?" (id 0) (at 48.26 98.425 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Value" "GND" (id 1) (at 48.26 97.155 0))
(property "Footprint" "" (id 2) (at 48.26 92.075 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 48.26 92.075 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid e41399a7-f60b-4a80-a126-be056cb007e9))
)
(symbol (lib_id "Switch:SW_Push") (at 60.96 79.375 90) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid 28a1ca96-47e6-44c9-b9dc-c435e73ae941)
(property "Reference" "SW2" (id 0) (at 62.23 79.3749 90)
(effects (font (size 1.27 1.27)) (justify right))
)
(property "Value" "SW_Push" (id 1) (at 62.23 80.6449 90)
(effects (font (size 1.27 1.27)) (justify right) hide)
)
(property "Footprint" "" (id 2) (at 55.88 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 55.88 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 8b2bb3c1-68dc-4a33-bbda-8e3f735cb89c))
(pin "2" (uuid 19313efc-c6f8-4165-9f12-2f4d196a0916))
)
(symbol (lib_id "Switch:SW_Push") (at 86.36 79.375 90) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid 3742357e-3d4f-4d99-8094-756d8329e07a)
(property "Reference" "SW0" (id 0) (at 87.63 79.3749 90)
(effects (font (size 1.27 1.27)) (justify right))
)
(property "Value" "SW_Push" (id 1) (at 87.63 80.6449 90)
(effects (font (size 1.27 1.27)) (justify right) hide)
)
(property "Footprint" "" (id 2) (at 81.28 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 81.28 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid ed19ccea-334b-4c85-8502-092081da9b5f))
(pin "2" (uuid 2f87aad1-080c-4cf8-9298-8cf8962ebf0b))
)
(symbol (lib_id "Device:R") (at 48.26 48.895 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid 6eeba788-57b9-45a8-981d-ecd17efd1d54)
(property "Reference" "R_up" (id 0) (at 50.8 47.6249 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "1k" (id 1) (at 50.8 50.1649 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 46.482 48.895 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 48.26 48.895 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid a7fb192a-733f-4bea-a1d7-a207050754dc))
(pin "2" (uuid 76ba5816-0ef3-41eb-80a7-15d3d0d4102f))
)
(symbol (lib_id "Device:R") (at 48.26 64.135 0) (unit 1)
(in_bom yes) (on_board yes)
(uuid 769febe6-b95c-4d37-94fa-e3721ea908aa)
(property "Reference" "R3" (id 0) (at 50.8 62.8649 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "1k" (id 1) (at 50.8 65.4049 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 46.482 64.135 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 48.26 64.135 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid f91d18bf-da3d-43fe-8b9a-c8f17a1ef730))
(pin "2" (uuid 0e5a0907-c70d-45b4-9b1e-755718f7bf45))
)
(symbol (lib_id "Switch:SW_Push") (at 48.26 79.375 90) (unit 1)
(in_bom yes) (on_board yes)
(uuid 864b1f85-f995-433a-9a94-7965edbddf3c)
(property "Reference" "SW3" (id 0) (at 49.53 79.375 90)
(effects (font (size 1.27 1.27)) (justify right))
)
(property "Value" "SW_Push" (id 1) (at 49.53 80.6449 90)
(effects (font (size 1.27 1.27)) (justify right) hide)
)
(property "Footprint" "" (id 2) (at 43.18 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 43.18 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid ddb4c830-ad05-4916-ada4-5d3ceca231c4))
(pin "2" (uuid 1b4f3986-79e7-4778-acb7-b047f55e11e8))
)
(symbol (lib_id "Device:R") (at 60.96 64.135 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid 8c50ab84-72ab-438d-a9f1-a710a33b8e06)
(property "Reference" "R2" (id 0) (at 63.5 62.8649 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "2k2" (id 1) (at 63.5 65.4049 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 59.182 64.135 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 60.96 64.135 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid c171a640-9d38-495e-a5d9-7d8f95ea6fee))
(pin "2" (uuid 5e366793-5e2a-4a8a-ba3c-8de861c6f28d))
)
(symbol (lib_id "Switch:SW_Push") (at 73.66 79.375 90) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid 93d3db7a-9c33-4a6b-8a4f-9c98164fe8b8)
(property "Reference" "SW1" (id 0) (at 74.93 79.3749 90)
(effects (font (size 1.27 1.27)) (justify right))
)
(property "Value" "SW_Push" (id 1) (at 74.93 80.6449 90)
(effects (font (size 1.27 1.27)) (justify right) hide)
)
(property "Footprint" "" (id 2) (at 68.58 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 68.58 79.375 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 5f3464d1-5065-4af5-a2f2-3aa2e6eda618))
(pin "2" (uuid bd5f3ec3-2c19-4b99-96ae-a4b755f1a5e1))
)
(symbol (lib_id "power:+3V3") (at 48.26 41.275 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid a516e0a9-fe24-4120-873c-6f89d1fb49c0)
(property "Reference" "#PWR?" (id 0) (at 48.26 45.085 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Value" "+3V3" (id 1) (at 48.26 36.195 0))
(property "Footprint" "" (id 2) (at 48.26 41.275 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 48.26 41.275 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 7edde932-e6ea-4bb3-80d2-0dfb0b34dfdf))
)
(symbol (lib_id "Device:R") (at 73.66 64.135 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid e38a88e5-32b2-4c8e-8e29-fd613e9fce2a)
(property "Reference" "R1" (id 0) (at 76.2 62.8649 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "4k7" (id 1) (at 76.2 65.4049 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 71.882 64.135 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 73.66 64.135 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 14717925-77d8-4e5b-87f4-d527a7df25a2))
(pin "2" (uuid 042328ba-54db-4f0f-b129-1e89e595aa37))
)
(symbol (lib_id "Device:R") (at 86.36 64.135 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid f9457597-177c-435c-90d9-f31193f60883)
(property "Reference" "R0" (id 0) (at 88.9 62.8649 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "8k2" (id 1) (at 88.9 65.4049 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 84.582 64.135 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 86.36 64.135 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid a698459c-2acc-4346-a3d9-ec53ed63917d))
(pin "2" (uuid c6c22bf2-3a43-4c40-940f-495f13d46fdd))
)
(sheet_instances
(path "/" (page "1"))
)
(symbol_instances
(path "/07a9d758-a267-455f-b30c-3770f3527e7a"
(reference "#PWR?") (unit 1) (value "GND") (footprint "")
)
(path "/a516e0a9-fe24-4120-873c-6f89d1fb49c0"
(reference "#PWR?") (unit 1) (value "+3V3") (footprint "")
)
(path "/f9457597-177c-435c-90d9-f31193f60883"
(reference "R0") (unit 1) (value "8k2") (footprint "")
)
(path "/e38a88e5-32b2-4c8e-8e29-fd613e9fce2a"
(reference "R1") (unit 1) (value "4k7") (footprint "")
)
(path "/8c50ab84-72ab-438d-a9f1-a710a33b8e06"
(reference "R2") (unit 1) (value "2k2") (footprint "")
)
(path "/769febe6-b95c-4d37-94fa-e3721ea908aa"
(reference "R3") (unit 1) (value "1k") (footprint "")
)
(path "/6eeba788-57b9-45a8-981d-ecd17efd1d54"
(reference "R_up") (unit 1) (value "1k") (footprint "")
)
(path "/3742357e-3d4f-4d99-8094-756d8329e07a"
(reference "SW0") (unit 1) (value "SW_Push") (footprint "")
)
(path "/93d3db7a-9c33-4a6b-8a4f-9c98164fe8b8"
(reference "SW1") (unit 1) (value "SW_Push") (footprint "")
)
(path "/28a1ca96-47e6-44c9-b9dc-c435e73ae941"
(reference "SW2") (unit 1) (value "SW_Push") (footprint "")
)
(path "/864b1f85-f995-433a-9a94-7965edbddf3c"
(reference "SW3") (unit 1) (value "SW_Push") (footprint "")
)
)
)

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,75 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"ratsnest_display_mode": 0,
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": true,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"meta": {
"filename": "stepper-filter.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View File

@@ -0,0 +1,294 @@
{
"board": {
"layer_presets": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "stepper-filter.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"0534e379-8bf0-4abf-a148-fc91b6440529",
""
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,7 @@ CONFIG_BOOTLOADER_LOG_LEVEL=3
CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
# CONFIG_BOOTLOADER_FACTORY_RESET is not set # CONFIG_BOOTLOADER_FACTORY_RESET is not set
# CONFIG_BOOTLOADER_APP_TEST is not set # CONFIG_BOOTLOADER_APP_TEST is not set
CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
CONFIG_BOOTLOADER_WDT_ENABLE=y CONFIG_BOOTLOADER_WDT_ENABLE=y
# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set # CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
CONFIG_BOOTLOADER_WDT_TIME_MS=9000 CONFIG_BOOTLOADER_WDT_TIME_MS=9000
@@ -95,6 +96,9 @@ CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="2MB" CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_BEFORE_RESET=y CONFIG_ESPTOOLPY_BEFORE_RESET=y
@@ -263,8 +267,8 @@ CONFIG_EFUSE_MAX_BLK_LEN=192
# #
CONFIG_ESP_TLS_USING_MBEDTLS=y CONFIG_ESP_TLS_USING_MBEDTLS=y
# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set # CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
# CONFIG_ESP_TLS_SERVER is not set
# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set # CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
# CONFIG_ESP_TLS_SERVER is not set
# CONFIG_ESP_TLS_PSK_VERIFICATION is not set # CONFIG_ESP_TLS_PSK_VERIFICATION is not set
# CONFIG_ESP_TLS_INSECURE is not set # CONFIG_ESP_TLS_INSECURE is not set
# end of ESP-TLS # end of ESP-TLS
@@ -411,15 +415,17 @@ CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set
# end of MAC Config # end of MAC Config
# #
# Sleep Config # Sleep Config
# #
CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y # CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set
CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set # CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set
# CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND is not set CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y
# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set
# end of Sleep Config # end of Sleep Config
# #
@@ -472,6 +478,13 @@ CONFIG_ESP_PHY_REDUCE_TX_POWER=y
# CONFIG_PM_ENABLE is not set # CONFIG_PM_ENABLE is not set
# end of Power Management # end of Power Management
#
# ESP Ringbuf
#
# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set
# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set
# end of ESP Ringbuf
# #
# ESP System Settings # ESP System Settings
# #
@@ -555,6 +568,8 @@ CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set # CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set # CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
# end of Wi-Fi # end of Wi-Fi
# #
@@ -628,11 +643,7 @@ CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
# CONFIG_FMB_TIMER_PORT_ENABLED is not set # CONFIG_FMB_TIMER_PORT_ENABLED is not set
CONFIG_FMB_TIMER_GROUP=0 # CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD is not set
CONFIG_FMB_TIMER_INDEX=0
CONFIG_FMB_MASTER_TIMER_GROUP=0
CONFIG_FMB_MASTER_TIMER_INDEX=0
# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
# end of Modbus configuration # end of Modbus configuration
# #
@@ -791,6 +802,7 @@ CONFIG_LWIP_TCP_SYNMAXRTX=12
CONFIG_LWIP_TCP_MSS=1440 CONFIG_LWIP_TCP_MSS=1440
CONFIG_LWIP_TCP_TMR_INTERVAL=250 CONFIG_LWIP_TCP_TMR_INTERVAL=250
CONFIG_LWIP_TCP_MSL=60000 CONFIG_LWIP_TCP_MSL=60000
CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
CONFIG_LWIP_TCP_WND_DEFAULT=5744 CONFIG_LWIP_TCP_WND_DEFAULT=5744
CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
@@ -901,6 +913,7 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set # CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
# end of Certificate Bundle # end of Certificate Bundle
# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set # CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
@@ -1048,6 +1061,7 @@ CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
# #
# NVS # NVS
# #
# CONFIG_NVS_ASSERT_ERROR_CHECK is not set
# end of NVS # end of NVS
# #
@@ -1185,7 +1199,6 @@ CONFIG_VFS_SUPPORT_TERMIOS=y
# Host File System I/O (Semihosting) # Host File System I/O (Semihosting)
# #
CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
# end of Host File System I/O (Semihosting) # end of Host File System I/O (Semihosting)
# end of Virtual file system # end of Virtual file system
@@ -1202,6 +1215,7 @@ CONFIG_WL_SECTOR_SIZE=4096
# #
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set
# end of Wi-Fi Provisioning Manager # end of Wi-Fi Provisioning Manager
# #
@@ -1214,6 +1228,8 @@ CONFIG_WPA_MBEDTLS_CRYPTO=y
# CONFIG_WPA_TESTING_OPTIONS is not set # CONFIG_WPA_TESTING_OPTIONS is not set
# CONFIG_WPA_WPS_STRICT is not set # CONFIG_WPA_WPS_STRICT is not set
# CONFIG_WPA_11KV_SUPPORT is not set # CONFIG_WPA_11KV_SUPPORT is not set
# CONFIG_WPA_MBO_SUPPORT is not set
# CONFIG_WPA_DPP_SUPPORT is not set
# end of Supplicant # end of Supplicant
# end of Component config # end of Component config
@@ -1291,7 +1307,7 @@ CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
CONFIG_ESP_SYSTEM_PD_FLASH=y # CONFIG_ESP_SYSTEM_PD_FLASH is not set
# CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND is not set # CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND is not set
CONFIG_IPC_TASK_STACK_SIZE=1536 CONFIG_IPC_TASK_STACK_SIZE=1536
CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
@@ -1338,8 +1354,6 @@ CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
CONFIG_MB_CONTROLLER_STACK_SIZE=4096 CONFIG_MB_CONTROLLER_STACK_SIZE=4096
CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
# CONFIG_MB_TIMER_PORT_ENABLED is not set # CONFIG_MB_TIMER_PORT_ENABLED is not set
CONFIG_MB_TIMER_GROUP=0
CONFIG_MB_TIMER_INDEX=0
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set # CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
CONFIG_TIMER_TASK_PRIORITY=1 CONFIG_TIMER_TASK_PRIORITY=1
CONFIG_TIMER_TASK_STACK_DEPTH=2048 CONFIG_TIMER_TASK_STACK_DEPTH=2048
@@ -1382,5 +1396,4 @@ CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
CONFIG_SUPPORT_TERMIOS=y CONFIG_SUPPORT_TERMIOS=y
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
# End of deprecated options # End of deprecated options

104
testing/cnc-guide/main.c Normal file
View File

@@ -0,0 +1,104 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#define MAX 100
#define MIN 10
#define TRAVEL MAX-MIN
//==== VARIABLES ====
bool direction = true;
uint16_t posNow = 10;
//==== FUNCTIONS ====
//print position
//print line that illustrates the position pos between 0 and MAX
//e.g. "|----<=>--------|"
void printPos(int pos){
int width = 50;
printf("(%d)|", pos);
for (int i = 0; i<(pos) * width/MAX; i++) printf("-");
printf("<=>");
for (int i = 0; i<(MAX-pos) * width/MAX; i++) printf("-");
printf("|\n");
return;
}
//move "virtual axis" to absolute coordinate in mm
void moveToAbs(int d){
int posOld = posNow;
printf ("moving from %d %s to %d (%s)\n", posNow, direction ? "=>" : "<=", d, direction ? "RIGHT" : "LEFT");
posNow = d;
//illustrate movement (print position for each coordinate change)
for (int i=posOld; i!=posNow; i+=posNow>posOld?1:-1) printPos(i);
return;
}
//travel back and forth between MIN and MAX coordinate for a certain distance
//negative values are processed reversed
void travel(int length){
int d, remaining;
d = abs(length);
if(length < 0) direction = !direction; //invert direction in reverse mode
while (d != 0){
//--- currently moving right ---
if (direction == true){ //currently moving right
remaining = MAX - posNow; //calc remaining distance fom current position to limit
if (d > remaining){ //new distance will exceed limit
moveToAbs (MAX); //move to limit
direction = false; //change current direction for next iteration
d = d - remaining; //decrease target length by already traveled distance
printf(" --- changed direction (L) --- \n ");
}
else { //target distance does not reach the limit
moveToAbs (posNow + d); //move by (remaining) distance to reach target length
d = 0; //finished, reset target length (could as well exit loop/break)
}
}
//--- currently moving left ---
else {
remaining = posNow - MIN;
if (d > remaining){
moveToAbs (MIN);
direction = true;
d = d - remaining;
printf(" --- changed direction (R) --- \n ");
}
else {
moveToAbs (posNow - d); //when moving left the coordinate has to be decreased
d = 0;
}
}
}
if(length < 0) direction = !direction; //undo inversion of direction after reverse mode is finished
return;
}
//==== MAIN ====
int main (void)
{
int input;
printf("**cable-length-cutter testing cnc-guide**\n");
while(1){
printf("enter mm to travel:");
scanf("%d", &input);
travel(input);
printf("\n");
}
return 0;
}

View File

@@ -0,0 +1,7 @@
default: program
program:
gcc main.c -o a.out -lm
clean:
-rm -f a.out

1189
wire-labels.fods Normal file

File diff suppressed because it is too large Load Diff